diff --git a/DEPS b/DEPS
index 6582eec..d9d51039 100644
--- a/DEPS
+++ b/DEPS
@@ -231,11 +231,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '496b89cb74b389b0a1047919275033ef0630416e',
+  'skia_revision': 'de1d7fb07f93b6119555f30b70db2568f5bf32a5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '868556abbe8737b9dbf55273a4d03238ee66f3de',
+  'v8_revision': '8923c05bbd6a3e7d2124691898fbd347d39cd7e9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -306,7 +306,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': 'fdb326ff691d3e871b03c6a598cb7f662ad051fe',
+  'devtools_frontend_revision': '9bae60435628d3f34790eedcc522e2dad22325cc',
   # 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.
@@ -390,11 +390,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.
-  'libcxxabi_revision':    'c883cb129d0ed07c4ac457666f8d4ea4d7d3d565',
+  'libcxxabi_revision':    '50e90b8650bbc87d3b1d07dadb2381dc6dd1816e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libunwind_revision':    'a7e4ce09ec1b84245c0632006374084626afd268',
+  'libunwind_revision':    'a002c725cf03e16d3bc47dd9b7962aa22f7ee1d9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1021,7 +1021,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'ded3cad7cf8179fb859b1681c9655d3add6be677',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'e3a781a848551ae7bd5770b85fc00ed5ec21325f',
       'condition': 'checkout_linux',
   },
 
@@ -1579,7 +1579,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/turbine',
-              'version': 'EIJ2nS3aoQlV-cKpmxr4hNR4E1Qs82brcidjG4A1I5QC',
+              'version': 'OxN4BOHObt6tbi4fpsSFeUAxSiaf2Cto-QlpFzGzC_IC',
           },
       ],
       'condition': 'checkout_android',
@@ -1633,7 +1633,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'b0291fd966b55a5efc496772555b94842bde1085',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '96168abfb74cd800f2e18e7dcca5bed72ef36e2d',
+    Var('webrtc_git') + '/src.git' + '@' + '29b4049abc5928d995b51f8614dfb27dc7e3359e',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1691,7 +1691,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@484fedba9fd811ac5f78d5819f904f35a387f1a7',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d3297d09026c81e6a221d007598ec8349257d8c3',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/base/barrier_callback_unittest.cc b/base/barrier_callback_unittest.cc
index 055b4e85..fc1ab79 100644
--- a/base/barrier_callback_unittest.cc
+++ b/base/barrier_callback_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/callback_helpers.h"
 #include "base/test/bind.h"
 #include "base/test/gtest_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -26,7 +25,7 @@
 
 TEST(BarrierCallbackTest, ErrorToCallCallbackWithZeroCallbacks) {
   auto barrier_callback =
-      base::BarrierCallback<int>(0, base::DoNothing::Once<std::vector<int>>());
+      base::BarrierCallback<int>(0, base::BindOnce([](std::vector<int>) {}));
   EXPECT_FALSE(barrier_callback.is_null());
 
   EXPECT_CHECK_DEATH(barrier_callback.Run(3));
@@ -109,17 +108,17 @@
   // No need to assert anything here, since if BarrierCallback didn't work with
   // move-only types, this wouldn't compile.
   auto barrier_callback = base::BarrierCallback<MoveOnly>(
-      1, base::DoNothing::Once<std::vector<MoveOnly>>());
+      1, base::BindOnce([](std::vector<MoveOnly>) {}));
   barrier_callback.Run(MoveOnly());
 
   auto barrier_callback2 = base::BarrierCallback<MoveOnly>(
-      1, base::DoNothing::Once<const std::vector<MoveOnly>&>());
+      1, base::BindOnce([](const std::vector<MoveOnly>&) {}));
   barrier_callback2.Run(MoveOnly());
 }
 
 TEST(BarrierCallbackTest, SupportsConstRefResults) {
   auto barrier_callback = base::BarrierCallback<int>(
-      1, base::DoNothing::Once<const std::vector<int>&>());
+      1, base::BindOnce([](const std::vector<int>&) {}));
 
   barrier_callback.Run(1);
 }
@@ -133,11 +132,11 @@
   // No need to assert anything here, since if BarrierCallback didn't work with
   // by-reference args, this wouldn't compile.
   auto barrier_callback = base::BarrierCallback<const Referenceable&>(
-      1, base::DoNothing::Once<std::vector<Referenceable>>());
+      1, base::BindOnce([](std::vector<Referenceable>) {}));
   barrier_callback.Run(ref);
 
   auto barrier_callback2 = base::BarrierCallback<const Referenceable&>(
-      1, base::DoNothing::Once<const std::vector<Referenceable>&>());
+      1, base::BindOnce([](const std::vector<Referenceable>&) {}));
   barrier_callback2.Run(ref);
 }
 
diff --git a/base/time/time.h b/base/time/time.h
index 547d567..30e87f9 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -124,9 +124,9 @@
   // an is_min() or is_max() TimeDelta. WARNING: Floating point arithmetic is
   // such that FromXXXD(t.InXXXF()) may not precisely equal |t|. Hence, floating
   // point values should not be used for storage.
-  static constexpr TimeDelta FromDays(int days);
-  static constexpr TimeDelta FromHours(int hours);
-  static constexpr TimeDelta FromMinutes(int minutes);
+  static constexpr TimeDelta FromDays(int64_t days);
+  static constexpr TimeDelta FromHours(int64_t hours);
+  static constexpr TimeDelta FromMinutes(int64_t minutes);
   static constexpr TimeDelta FromSecondsD(double secs);
   static constexpr TimeDelta FromSeconds(int64_t secs);
   static constexpr TimeDelta FromMillisecondsD(double ms);
@@ -517,6 +517,13 @@
   int64_t us_;
 };
 
+template <typename T>
+using EnableIfIntegral = typename std::
+    enable_if<std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
+template <typename T>
+using EnableIfFloat =
+    typename std::enable_if<std::is_floating_point<T>::value, int>::type;
+
 }  // namespace time_internal
 
 template <class TimeClass>
@@ -858,78 +865,152 @@
   int64_t ToRoundedDownMillisecondsSinceUnixEpoch() const;
 };
 
-// TimeDelta functions that must appear below the declarations of Time/TimeDelta
+// Factory methods that return a TimeDelta of the given unit.
+
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Days(T n) {
+  return TimeDelta::FromInternalValue(
+      int64_t{ClampMul(int64_t{n}, Time::kMicrosecondsPerDay)});
+}
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Hours(T n) {
+  return TimeDelta::FromInternalValue(
+      int64_t{ClampMul(int64_t{n}, Time::kMicrosecondsPerHour)});
+}
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Minutes(T n) {
+  return TimeDelta::FromInternalValue(
+      int64_t{ClampMul(int64_t{n}, Time::kMicrosecondsPerMinute)});
+}
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Seconds(T n) {
+  return TimeDelta::FromInternalValue(
+      int64_t{ClampMul(int64_t{n}, Time::kMicrosecondsPerSecond)});
+}
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Milliseconds(T n) {
+  return TimeDelta::FromInternalValue(
+      int64_t{ClampMul(int64_t{n}, Time::kMicrosecondsPerMillisecond)});
+}
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Microseconds(T n) {
+  return TimeDelta::FromInternalValue(int64_t{n});
+}
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Nanoseconds(T n) {
+  return TimeDelta::FromInternalValue(int64_t{n} /
+                                      Time::kNanosecondsPerMicrosecond);
+}
+template <typename T, time_internal::EnableIfIntegral<T> = 0>
+constexpr TimeDelta Hertz(T n) {
+  return TimeDelta::FromInternalValue(Time::kMicrosecondsPerSecond /
+                                      int64_t{n});
+}
+
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Days(T n) {
+  return TimeDelta::FromInternalValue(
+      saturated_cast<int64_t>(n * Time::kMicrosecondsPerDay));
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Hours(T n) {
+  return TimeDelta::FromInternalValue(
+      saturated_cast<int64_t>(n * Time::kMicrosecondsPerHour));
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Minutes(T n) {
+  return TimeDelta::FromInternalValue(
+      saturated_cast<int64_t>(n * Time::kMicrosecondsPerMinute));
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Seconds(T n) {
+  return TimeDelta::FromInternalValue(
+      saturated_cast<int64_t>(n * Time::kMicrosecondsPerSecond));
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Milliseconds(T n) {
+  return TimeDelta::FromInternalValue(
+      saturated_cast<int64_t>(n * Time::kMicrosecondsPerMillisecond));
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Microseconds(T n) {
+  return TimeDelta::FromInternalValue(saturated_cast<int64_t>(n));
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Nanoseconds(T n) {
+  return TimeDelta::FromInternalValue(
+      saturated_cast<int64_t>(n / Time::kNanosecondsPerMicrosecond));
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+constexpr TimeDelta Hertz(T n) {
+  return TimeDelta::FromInternalValue(
+      saturated_cast<int64_t>(Time::kMicrosecondsPerSecond / n));
+}
+
+// Deprecated TimeDelta conversion functions, to be replaced by the above.
 
 // static
-constexpr TimeDelta TimeDelta::FromDays(int days) {
-  return (days == std::numeric_limits<int>::max())
-             ? Max()
-             : TimeDelta(days * Time::kMicrosecondsPerDay);
+constexpr TimeDelta TimeDelta::FromDays(int64_t days) {
+  return Days(days);
 }
 
 // static
-constexpr TimeDelta TimeDelta::FromHours(int hours) {
-  return (hours == std::numeric_limits<int>::max())
-             ? Max()
-             : TimeDelta(hours * Time::kMicrosecondsPerHour);
+constexpr TimeDelta TimeDelta::FromHours(int64_t hours) {
+  return Hours(hours);
 }
 
 // static
-constexpr TimeDelta TimeDelta::FromMinutes(int minutes) {
-  return (minutes == std::numeric_limits<int>::max())
-             ? Max()
-             : TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+constexpr TimeDelta TimeDelta::FromMinutes(int64_t minutes) {
+  return Minutes(minutes);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromSecondsD(double secs) {
-  return TimeDelta(
-      saturated_cast<int64_t>(secs * Time::kMicrosecondsPerSecond));
+  return Seconds(secs);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromSeconds(int64_t secs) {
-  return TimeDelta(int64_t{base::ClampMul(secs, Time::kMicrosecondsPerSecond)});
+  return Seconds(secs);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromMillisecondsD(double ms) {
-  return TimeDelta(
-      saturated_cast<int64_t>(ms * Time::kMicrosecondsPerMillisecond));
+  return Milliseconds(ms);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromMilliseconds(int64_t ms) {
-  return TimeDelta(
-      int64_t{base::ClampMul(ms, Time::kMicrosecondsPerMillisecond)});
+  return Milliseconds(ms);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromMicrosecondsD(double us) {
-  return TimeDelta(saturated_cast<int64_t>(us));
+  return Microseconds(us);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromMicroseconds(int64_t us) {
-  return TimeDelta(us);
+  return Microseconds(us);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromNanosecondsD(double ns) {
-  return TimeDelta(
-      saturated_cast<int64_t>(ns / Time::kNanosecondsPerMicrosecond));
+  return Nanoseconds(ns);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromNanoseconds(int64_t ns) {
-  return TimeDelta(ns / Time::kNanosecondsPerMicrosecond);
+  return Nanoseconds(ns);
 }
 
 // static
 constexpr TimeDelta TimeDelta::FromHz(double frequency) {
-  return FromSeconds(1) / frequency;
+  return Hertz(frequency);
 }
 
+// TimeDelta functions that must appear below the declarations of Time/TimeDelta
+
 constexpr int TimeDelta::InHours() const {
   // saturated_cast<> is necessary since very large (but still less than
   // min/max) deltas would result in overflow.
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 96de6f2..8380ab2 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -1747,14 +1747,14 @@
   EXPECT_EQ(kMax.InMilliseconds(), std::numeric_limits<int64_t>::max());
   EXPECT_EQ(kMax.InMillisecondsRoundedUp(), std::numeric_limits<int64_t>::max());
 
-  static_assert(TimeDelta::FromDays(std::numeric_limits<int>::max()).is_max(),
-                "");
-
-  static_assert(TimeDelta::FromHours(std::numeric_limits<int>::max()).is_max(),
-                "");
+  static_assert(
+      TimeDelta::FromDays(std::numeric_limits<int64_t>::max()).is_max(), "");
 
   static_assert(
-      TimeDelta::FromMinutes(std::numeric_limits<int>::max()).is_max(), "");
+      TimeDelta::FromHours(std::numeric_limits<int64_t>::max()).is_max(), "");
+
+  static_assert(
+      TimeDelta::FromMinutes(std::numeric_limits<int64_t>::max()).is_max(), "");
 
   constexpr int64_t max_int = std::numeric_limits<int64_t>::max();
   constexpr int64_t min_int = std::numeric_limits<int64_t>::min();
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index e1e1950..2f65679 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-6.20210926.0.1
+6.20210927.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index e1e1950..2f65679 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-6.20210926.0.1
+6.20210927.0.1
diff --git a/buildtools/third_party/libc++abi/BUILD.gn b/buildtools/third_party/libc++abi/BUILD.gn
index 8b1da01..b70deeb9 100644
--- a/buildtools/third_party/libc++abi/BUILD.gn
+++ b/buildtools/third_party/libc++abi/BUILD.gn
@@ -88,6 +88,6 @@
     configs += [ "//build/config/gcc:symbol_visibility_default" ]
   }
 
-  # stdlib_stdexcept.cpp depends on libc++ internals.
-  include_dirs = [ "../libc++/trunk" ]
+  # libc++abi depends on libc++ internals.
+  include_dirs = [ "../libc++/trunk/src" ]
 }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d3e18d7..07ef5041 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -7456,12 +7456,6 @@
      flag_descriptions::kExtensionWorkflowJustificationDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kExtensionWorkflowJustification)},
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    {"arc-web-app-share", flag_descriptions::kArcWebAppShareName,
-     flag_descriptions::kArcWebAppShareDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(arc::kEnableWebAppShareFeature)},
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
     {"tab-restore-sub-menus", flag_descriptions::kTabRestoreSubMenusName,
      flag_descriptions::kTabRestoreSubMenusDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kTabRestoreSubMenus)},
diff --git a/chrome/browser/apps/app_service/app_platform_metrics.cc b/chrome/browser/apps/app_service/app_platform_metrics.cc
index 9863091..a29eef5 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics.cc
+++ b/chrome/browser/apps/app_service/app_platform_metrics.cc
@@ -321,6 +321,52 @@
   }
 }
 
+// Returns AppTypeNameV2 used for app launch metrics.
+apps::AppTypeNameV2 GetAppTypeNameV2(Profile* profile,
+                                     apps::mojom::AppType app_type,
+                                     const std::string& app_id,
+                                     apps::mojom::LaunchContainer container) {
+  switch (app_type) {
+    case apps::mojom::AppType::kUnknown:
+      return apps::AppTypeNameV2::kUnknown;
+    case apps::mojom::AppType::kArc:
+      return apps::AppTypeNameV2::kArc;
+    case apps::mojom::AppType::kBuiltIn:
+      return apps::AppTypeNameV2::kBuiltIn;
+    case apps::mojom::AppType::kCrostini:
+      return apps::AppTypeNameV2::kCrostini;
+    case apps::mojom::AppType::kExtension:
+      return container == apps::mojom::LaunchContainer::kLaunchContainerWindow
+                 ? apps::AppTypeNameV2::kChromeAppWindow
+                 : apps::AppTypeNameV2::kChromeAppTab;
+    case apps::mojom::AppType::kWeb: {
+      apps::AppTypeName app_type_name =
+          GetAppTypeNameForWebApp(profile, app_id, container);
+      if (app_type_name == apps::AppTypeName::kChromeBrowser) {
+        return apps::AppTypeNameV2::kWebTab;
+      } else if (app_type_name == apps::AppTypeName::kSystemWeb) {
+        return apps::AppTypeNameV2::kSystemWeb;
+      } else {
+        return apps::AppTypeNameV2::kWebWindow;
+      }
+    }
+    case apps::mojom::AppType::kMacOs:
+      return apps::AppTypeNameV2::kMacOs;
+    case apps::mojom::AppType::kPluginVm:
+      return apps::AppTypeNameV2::kPluginVm;
+    case apps::mojom::AppType::kStandaloneBrowser:
+      return apps::AppTypeNameV2::kStandaloneBrowser;
+    case apps::mojom::AppType::kRemote:
+      return apps::AppTypeNameV2::kRemote;
+    case apps::mojom::AppType::kBorealis:
+      return apps::AppTypeNameV2::kBorealis;
+    case apps::mojom::AppType::kSystemWeb:
+      return apps::AppTypeNameV2::kSystemWeb;
+    case apps::mojom::AppType::kStandaloneBrowserExtension:
+      return apps::AppTypeNameV2::kStandaloneBrowserExtension;
+  }
+}
+
 // Records the number of times Chrome OS apps are launched grouped by the launch
 // source.
 void RecordAppLaunchSource(apps::mojom::LaunchSource launch_source) {
@@ -334,7 +380,19 @@
     return;
   }
 
-  base::UmaHistogramEnumeration("Apps.AppLaunchPerAppType", app_type_name);
+  base::UmaHistogramEnumeration(apps::kAppLaunchPerAppTypeHistogramName,
+                                app_type_name);
+}
+
+// Records the number of times Chrome OS apps are launched grouped by the app
+// type V2.
+void RecordAppLaunchPerAppTypeV2(apps::AppTypeNameV2 app_type_name_v2) {
+  if (app_type_name_v2 == apps::AppTypeNameV2::kUnknown) {
+    return;
+  }
+
+  base::UmaHistogramEnumeration(apps::kAppLaunchPerAppTypeV2HistogramName,
+                                app_type_name_v2);
 }
 
 // Due to the privacy limitation, only ARC apps, Chrome apps and web apps(PWA),
@@ -395,6 +453,10 @@
 constexpr char kAppActivatedCount[] =
     "app_platform_metrics.app_activated_count";
 
+constexpr char kAppLaunchPerAppTypeHistogramName[] = "Apps.AppLaunchPerAppType";
+constexpr char kAppLaunchPerAppTypeV2HistogramName[] =
+    "Apps.AppLaunchPerAppTypeV2";
+
 constexpr char kArcHistogramName[] = "Arc";
 constexpr char kBuiltInHistogramName[] = "BuiltIn";
 constexpr char kCrostiniHistogramName[] = "Crostini";
@@ -535,6 +597,8 @@
   RecordAppLaunchSource(launch_source);
   RecordAppLaunchPerAppType(
       GetAppTypeName(profile, app_type, app_id, container));
+  RecordAppLaunchPerAppTypeV2(
+      GetAppTypeNameV2(profile, app_type, app_id, container));
 
   auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
   if (proxy && proxy->AppPlatformMetrics()) {
diff --git a/chrome/browser/apps/app_service/app_platform_metrics.h b/chrome/browser/apps/app_service/app_platform_metrics.h
index dedd23d..fbe9ee60 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics.h
+++ b/chrome/browser/apps/app_service/app_platform_metrics.h
@@ -90,6 +90,9 @@
 extern const char kAppRunningDuration[];
 extern const char kAppActivatedCount[];
 
+extern const char kAppLaunchPerAppTypeHistogramName[];
+extern const char kAppLaunchPerAppTypeV2HistogramName[];
+
 extern const char kArcHistogramName[];
 extern const char kBuiltInHistogramName[];
 extern const char kCrostiniHistogramName[];
diff --git a/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc b/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc
index dcac5f50..47185133 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc
+++ b/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc
@@ -408,6 +408,18 @@
     return window;
   }
 
+  void VerifyAppLaunchPerAppTypeHistogram(base::HistogramBase::Count count,
+                                          AppTypeName app_type_name) {
+    histogram_tester().ExpectBucketCount(kAppLaunchPerAppTypeHistogramName,
+                                         app_type_name, count);
+  }
+
+  void VerifyAppLaunchPerAppTypeV2Histogram(base::HistogramBase::Count count,
+                                            AppTypeNameV2 app_type_name_v2) {
+    histogram_tester().ExpectBucketCount(kAppLaunchPerAppTypeV2HistogramName,
+                                         app_type_name_v2, count);
+  }
+
   void VerifyAppRunningDuration(const base::TimeDelta time_delta,
                                 AppTypeName app_type_name) {
     DictionaryPrefUpdate update(GetPrefService(), kAppRunningDuration);
@@ -1407,7 +1419,7 @@
                          InstallTime::kRunning);
 }
 
-TEST_F(AppPlatformMetricsServiceTest, LaunchAppsUkm) {
+TEST_F(AppPlatformMetricsServiceTest, LaunchApps) {
   auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
   proxy->SetAppPlatformMetricsServiceForTesting(GetAppPlatformMetricsService());
 
@@ -1419,17 +1431,33 @@
       test_ukm_recorder()->GetEntriesByName("ChromeOSApp.Launch");
   ASSERT_EQ(0U, entries.size());
 
+  VerifyAppLaunchPerAppTypeHistogram(1, AppTypeName::kCrostini);
+  VerifyAppLaunchPerAppTypeV2Histogram(1, AppTypeNameV2::kCrostini);
+
   proxy->Launch(
       /*app_id=*/"a", ui::EventFlags::EF_NONE,
       apps::mojom::LaunchSource::kFromChromeInternal, nullptr);
   VerifyAppsLaunchUkm("app://com.google.A", AppTypeName::kArc,
                       apps::mojom::LaunchSource::kFromChromeInternal);
+  VerifyAppLaunchPerAppTypeHistogram(1, AppTypeName::kArc);
+  VerifyAppLaunchPerAppTypeV2Histogram(1, AppTypeNameV2::kArc);
 
   proxy->LaunchAppWithUrl(
       /*app_id=*/"w", ui::EventFlags::EF_NONE, GURL("https://boo.com/a"),
       apps::mojom::LaunchSource::kFromFileManager, nullptr);
   VerifyAppsLaunchUkm("https://foo.com", AppTypeName::kWeb,
                       apps::mojom::LaunchSource::kFromFileManager);
+  VerifyAppLaunchPerAppTypeHistogram(1, AppTypeName::kWeb);
+  VerifyAppLaunchPerAppTypeV2Histogram(1, AppTypeNameV2::kWebWindow);
+
+  proxy->BrowserAppLauncher()->LaunchAppWithParams(apps::AppLaunchParams(
+      "w2", apps::mojom::LaunchContainer::kLaunchContainerTab,
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      apps::mojom::AppLaunchSource::kSourceTest));
+  VerifyAppsLaunchUkm("https://foo2.com", AppTypeName::kChromeBrowser,
+                      apps::mojom::LaunchSource::kFromTest);
+  VerifyAppLaunchPerAppTypeHistogram(1, AppTypeName::kChromeBrowser);
+  VerifyAppLaunchPerAppTypeV2Histogram(1, AppTypeNameV2::kWebTab);
 
   proxy->BrowserAppLauncher()->LaunchAppWithParams(apps::AppLaunchParams(
       "s", apps::mojom::LaunchContainer::kLaunchContainerTab,
@@ -1437,6 +1465,8 @@
       apps::mojom::AppLaunchSource::kSourceTest));
   VerifyAppsLaunchUkm("app://s", AppTypeName::kSystemWeb,
                       apps::mojom::LaunchSource::kFromTest);
+  VerifyAppLaunchPerAppTypeHistogram(1, AppTypeName::kSystemWeb);
+  VerifyAppLaunchPerAppTypeV2Histogram(1, AppTypeNameV2::kSystemWeb);
 }
 
 TEST_F(AppPlatformMetricsServiceTest, UninstallAppUkm) {
diff --git a/chrome/browser/ash/file_manager/io_task.cc b/chrome/browser/ash/file_manager/io_task.cc
new file mode 100644
index 0000000..10ceab6
--- /dev/null
+++ b/chrome/browser/ash/file_manager/io_task.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/file_manager/io_task.h"
+
+#include <vector>
+
+#include "base/bind_post_task.h"
+#include "base/callback.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "storage/browser/file_system/file_system_url.h"
+
+namespace file_manager {
+
+namespace io_task {
+
+ProgressStatus::ProgressStatus() = default;
+ProgressStatus::~ProgressStatus() = default;
+
+ProgressStatus::ProgressStatus(ProgressStatus&& other) = default;
+ProgressStatus& ProgressStatus::operator=(ProgressStatus&& other) = default;
+
+DummyIOTask::DummyIOTask(std::vector<storage::FileSystemURL> source_urls,
+                         storage::FileSystemURL destination_folder,
+                         OperationType type) {
+  progress_.state = State::kQueued;
+  progress_.type = type;
+  progress_.destination_folder = std::move(destination_folder);
+  progress_.bytes_transferred = 0;
+  progress_.total_bytes = 2;
+
+  progress_.errors.assign(source_urls.size(), {});
+  progress_.source_urls = std::move(source_urls);
+}
+
+DummyIOTask::~DummyIOTask() = default;
+
+void DummyIOTask::Execute(IOTask::ProgressCallback progress_callback,
+                          IOTask::CompleteCallback complete_callback) {
+  progress_callback_ = std::move(progress_callback);
+  complete_callback_ = std::move(complete_callback);
+
+  progress_.state = State::kInProgress;
+  progress_callback_.Run(progress_);
+
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DummyIOTask::DoProgress, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DummyIOTask::DoProgress() {
+  progress_.bytes_transferred = 1;
+  progress_callback_.Run(progress_);
+
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DummyIOTask::DoComplete, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DummyIOTask::DoComplete() {
+  progress_.state = State::kSuccess;
+  progress_.bytes_transferred = 2;
+  for (auto& error : progress_.errors) {
+    error.emplace(base::File::FILE_OK);
+  }
+  std::move(complete_callback_).Run(std::move(progress_));
+}
+
+void DummyIOTask::Cancel() {
+  progress_.state = State::kCancelled;
+}
+
+const ProgressStatus& DummyIOTask::progress() {
+  return progress_;
+}
+
+}  // namespace io_task
+
+}  // namespace file_manager
diff --git a/chrome/browser/ash/file_manager/io_task.h b/chrome/browser/ash/file_manager/io_task.h
new file mode 100644
index 0000000..d75236b
--- /dev/null
+++ b/chrome/browser/ash/file_manager/io_task.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_H_
+#define CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/memory/weak_ptr.h"
+#include "storage/browser/file_system/file_system_url.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace file_manager {
+
+namespace io_task {
+
+enum class State {
+  // Task has been queued, but not yet started.
+  kQueued,
+
+  // Task is currently running.
+  kInProgress,
+
+  // Task has been successfully completed.
+  kSuccess,
+
+  // Task has completed with errors.
+  kError,
+
+  // Task has been canceled without finishing.
+  kCancelled,
+};
+
+enum class OperationType {
+  kCopy,
+  kMove,
+  kDelete,
+  kZip,
+};
+
+// Represents the current progress of an I/O task.
+struct ProgressStatus {
+  // Out-of-line constructors to appease the style linter.
+  ProgressStatus();
+  ProgressStatus(const ProgressStatus& other) = delete;
+  ProgressStatus& operator=(const ProgressStatus& other) = delete;
+  ~ProgressStatus();
+
+  // Allow ProgressStatus to be moved.
+  ProgressStatus(ProgressStatus&& other);
+  ProgressStatus& operator=(ProgressStatus&& other);
+
+  // Task state.
+  State state;
+
+  // I/O Operation type (e.g. copy, move).
+  OperationType type;
+
+  // Files the operation processes.
+  std::vector<storage::FileSystemURL> source_urls;
+
+  // One error per source_url. Absence of value indicates file has not been
+  // processed yet.
+  std::vector<absl::optional<base::File::Error>> errors;
+
+  // Optional destination folder for operations that transfer files to a
+  // directory (e.g. copy or move).
+  storage::FileSystemURL destination_folder;
+
+  // ProgressStatus over all |source_urls|.
+  int64_t bytes_transferred;
+
+  // Total size of all |source_urls|.
+  int64_t total_bytes;
+};
+
+// An IOTask represents an I/O operation over multiple files, and is responsible
+// for executing the operation and providing progress/completion reports.
+class IOTask {
+ public:
+  virtual ~IOTask() = default;
+
+  using ProgressCallback = base::RepeatingCallback<void(const ProgressStatus&)>;
+  using CompleteCallback = base::OnceCallback<void(ProgressStatus)>;
+
+  // Executes the task. |progress_callback| should be called every so often to
+  // give updates, and |complete_callback| should be only called once at the end
+  // to signify completion with a |kSuccess|, |kError| or |kCancelled| state.
+  // |progress_callback| should be called on the same sequeuence Execute() was.
+  virtual void Execute(ProgressCallback progress_callback,
+                       CompleteCallback complete_callback) = 0;
+
+  // Cancels the task. This should set the progress state to be |kCancelled|,
+  // but not call any of Execute()'s callbacks. The task will be deleted
+  // synchronously after this call returns.
+  virtual void Cancel() = 0;
+
+  // Gets the current progress status of the task.
+  virtual const ProgressStatus& progress() = 0;
+
+ protected:
+  IOTask() = default;
+  IOTask(const IOTask& other) = delete;
+  IOTask& operator=(const IOTask& other) = delete;
+};
+
+// No-op IO Task for testing.
+// TODO(austinct): Move into io_task_controller_unittest file when the other
+// IOTasks have been implemented.
+class DummyIOTask : public IOTask {
+ public:
+  DummyIOTask(std::vector<storage::FileSystemURL> source_urls,
+              storage::FileSystemURL destination_folder,
+              OperationType type);
+  ~DummyIOTask() override;
+
+  void Execute(ProgressCallback progress_callback,
+               CompleteCallback complete_callback) override;
+
+  void Cancel() override;
+
+  const ProgressStatus& progress() override;
+
+ private:
+  void DoProgress();
+  void DoComplete();
+
+  ProgressStatus progress_;
+
+  ProgressCallback progress_callback_;
+  CompleteCallback complete_callback_;
+
+  base::WeakPtrFactory<DummyIOTask> weak_ptr_factory_{this};
+};
+
+}  // namespace io_task
+
+}  // namespace file_manager
+
+#endif  // CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_H_
diff --git a/chrome/browser/ash/file_manager/io_task_controller.cc b/chrome/browser/ash/file_manager/io_task_controller.cc
new file mode 100644
index 0000000..d6d6b1c
--- /dev/null
+++ b/chrome/browser/ash/file_manager/io_task_controller.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/file_manager/io_task_controller.h"
+
+#include "base/bind_post_task.h"
+
+namespace file_manager {
+
+namespace io_task {
+
+IOTaskController::IOTaskController() {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+IOTaskController::~IOTaskController() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void IOTaskController::NotifyIOTaskObservers(const ProgressStatus& status) {
+  for (IOTaskController::Observer& observer : observers_) {
+    observer.OnIOTaskStatus(status);
+  }
+}
+
+void IOTaskController::OnIOTaskProgress(const ProgressStatus& status) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  NotifyIOTaskObservers(status);
+}
+
+void IOTaskController::OnIOTaskComplete(IOTaskId task_id,
+                                        ProgressStatus status) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  NotifyIOTaskObservers(status);
+  tasks_.erase(task_id);
+}
+
+void IOTaskController::AddObserver(IOTaskController::Observer* observer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  observers_.AddObserver(observer);
+}
+
+void IOTaskController::RemoveObserver(IOTaskController::Observer* observer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  observers_.RemoveObserver(observer);
+}
+
+IOTaskController::IOTaskId IOTaskController::Add(std::unique_ptr<IOTask> task) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Notify observers that the task has been queued.
+  NotifyIOTaskObservers(task->progress());
+
+  // TODO(b/199807189): Queue the task.
+  task->Execute(base::BindRepeating(&IOTaskController::OnIOTaskProgress,
+                                    weak_ptr_factory_.GetWeakPtr()),
+                base::BindPostTask(
+                    base::SequencedTaskRunnerHandle::Get(),
+                    base::BindOnce(&IOTaskController::OnIOTaskComplete,
+                                   weak_ptr_factory_.GetWeakPtr(), last_id_)));
+  tasks_[last_id_] = std::move(task);
+  return last_id_++;
+}
+
+void IOTaskController::Cancel(IOTaskId task_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto it = tasks_.find(task_id);
+  if (it != tasks_.end()) {
+    IOTask* task = it->second.get();
+    task->Cancel();
+    NotifyIOTaskObservers(task->progress());
+    tasks_.erase(it);
+  }
+}
+
+}  // namespace io_task
+
+}  // namespace file_manager
diff --git a/chrome/browser/ash/file_manager/io_task_controller.h b/chrome/browser/ash/file_manager/io_task_controller.h
new file mode 100644
index 0000000..0dd7054
--- /dev/null
+++ b/chrome/browser/ash/file_manager/io_task_controller.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_CONTROLLER_H_
+#define CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_CONTROLLER_H_
+
+#include <map>
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/browser/ash/file_manager/io_task.h"
+#include "storage/browser/file_system/file_system_file_util.h"
+
+namespace file_manager {
+
+namespace io_task {
+
+// |IOTaskController| queues and executes IOTasks given to it from Files app. It
+// also notifies observers when tasks progress or finish. This class must only
+// be used from one sequence.
+class IOTaskController {
+ public:
+  using IOTaskId = uint64_t;
+
+  IOTaskController();
+  IOTaskController(const IOTaskController& other) = delete;
+  IOTaskController operator=(const IOTaskController& other) = delete;
+  ~IOTaskController();
+
+  class Observer : public base::CheckedObserver {
+   public:
+    // Called whenever a queued IOTask progresses or completes. Will be called
+    // on the same sequence as Add().
+    virtual void OnIOTaskStatus(const ProgressStatus& status) = 0;
+  };
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  // Queues an IOTask and returns its ID.
+  IOTaskId Add(std::unique_ptr<IOTask> task);
+
+  // Cancels or removes a task from the queue.
+  void Cancel(IOTaskId task_id);
+
+ private:
+  void NotifyIOTaskObservers(const ProgressStatus& status);
+  void OnIOTaskProgress(const ProgressStatus& status);
+  void OnIOTaskComplete(IOTaskId task_id, ProgressStatus status);
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::ObserverList<Observer> observers_;
+
+  IOTaskId last_id_ = 0;
+  std::map<IOTaskId, std::unique_ptr<IOTask>> tasks_;
+
+  base::WeakPtrFactory<IOTaskController> weak_ptr_factory_{this};
+};
+
+}  // namespace io_task
+
+}  // namespace file_manager
+
+#endif  // CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_CONTROLLER_H_
diff --git a/chrome/browser/ash/file_manager/io_task_controller_unittest.cc b/chrome/browser/ash/file_manager/io_task_controller_unittest.cc
new file mode 100644
index 0000000..6ffb9e3a
--- /dev/null
+++ b/chrome/browser/ash/file_manager/io_task_controller_unittest.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/file_manager/io_task_controller.h"
+
+#include <memory>
+
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/task_environment.h"
+#include "storage/browser/file_system/file_system_url.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::test::RunClosure;
+using testing::_;
+using testing::AllOf;
+using testing::Field;
+using testing::Invoke;
+
+namespace file_manager {
+namespace io_task {
+namespace {
+
+storage::FileSystemURL CreateFileSystemURL(std::string url) {
+  return storage::FileSystemURL::CreateForTest(GURL(url));
+}
+
+class IOTaskStatusObserver : public IOTaskController::Observer {
+ public:
+  MOCK_METHOD(void, OnIOTaskStatus, (const ProgressStatus&), (override));
+};
+
+class IOTaskControllerTest : public testing::Test {
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+
+  IOTaskController io_task_controller_;
+};
+
+TEST_F(IOTaskControllerTest, SimpleQueueing) {
+  IOTaskStatusObserver observer;
+  io_task_controller_.AddObserver(&observer);
+
+  std::vector<storage::FileSystemURL> source_urls{
+      CreateFileSystemURL("filesystem:chrome-extension://abc/external/foo/src"),
+  };
+  auto dest = CreateFileSystemURL(
+      "filesystem:chrome-extension://abc/external/foo/dest");
+
+  // All progress statuses should return the same |type|, |source_urls| and
+  // |destination_folder| as given, so set up a base matcher to check this.
+  auto base_matcher = AllOf(Field(&ProgressStatus::type, OperationType::kCopy),
+                            Field(&ProgressStatus::source_urls, source_urls),
+                            Field(&ProgressStatus::destination_folder, dest));
+
+  // The controller should synchronously send out a progress status when queued.
+  EXPECT_CALL(observer, OnIOTaskStatus(
+                            AllOf(Field(&ProgressStatus::state, State::kQueued),
+                                  base_matcher)));
+
+  // The controller should also synchronously execute the I/O task, which will
+  // send out another status.
+  EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                            Field(&ProgressStatus::state, State::kInProgress),
+                            base_matcher)));
+
+  // Queue the I/O task, which will also synchronously execute it.
+  auto task_id = io_task_controller_.Add(
+      std::make_unique<DummyIOTask>(source_urls, dest, OperationType::kCopy));
+
+  // Wait for the two callbacks posted to the main sequence to finish.
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                              Field(&ProgressStatus::state, State::kInProgress),
+                              base_matcher)))
+        .WillOnce(RunClosure(run_loop.QuitClosure()));
+    run_loop.Run();
+  }
+
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                              Field(&ProgressStatus::state, State::kSuccess),
+                              base_matcher)))
+        .WillOnce(RunClosure(run_loop.QuitClosure()));
+    run_loop.Run();
+  }
+
+  // Cancel() should have no effect once a task is completed.
+  io_task_controller_.Cancel(task_id);
+  base::RunLoop().RunUntilIdle();
+
+  io_task_controller_.RemoveObserver(&observer);
+}
+
+TEST_F(IOTaskControllerTest, Cancel) {
+  IOTaskStatusObserver observer;
+  io_task_controller_.AddObserver(&observer);
+
+  std::vector<storage::FileSystemURL> source_urls{
+      CreateFileSystemURL("filesystem:chrome-extension://abc/external/foo/src"),
+  };
+  auto dest = CreateFileSystemURL(
+      "filesystem:chrome-extension://abc/external/foo/dest");
+
+  // All progress statuses should return the same |type|, |source_urls| and
+  // |destination_folder| given, so set up a base matcher to check this.
+  auto base_matcher = AllOf(Field(&ProgressStatus::type, OperationType::kMove),
+                            Field(&ProgressStatus::source_urls, source_urls),
+                            Field(&ProgressStatus::destination_folder, dest));
+
+  // The controller should synchronously send out a progress status when queued.
+  EXPECT_CALL(observer, OnIOTaskStatus(
+                            AllOf(Field(&ProgressStatus::state, State::kQueued),
+                                  base_matcher)));
+
+  // The controller should also synchronously execute the I/O task, which will
+  // send out another status.
+  EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                            Field(&ProgressStatus::state, State::kInProgress),
+                            base_matcher)));
+
+  auto task_id = io_task_controller_.Add(
+      std::make_unique<DummyIOTask>(source_urls, dest, OperationType::kMove));
+
+  // Cancel should synchronously send a progress status.
+  EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                            Field(&ProgressStatus::state, State::kCancelled),
+                            base_matcher)));
+
+  io_task_controller_.Cancel(task_id);
+
+  // No more observer notifications should come after Cancel() as the task is
+  // deleted.
+  base::RunLoop().RunUntilIdle();
+
+  io_task_controller_.RemoveObserver(&observer);
+}
+
+}  // namespace
+}  // namespace io_task
+}  // namespace file_manager
diff --git a/chrome/browser/ash/file_manager/volume_manager.cc b/chrome/browser/ash/file_manager/volume_manager.cc
index c04edfa..9848555 100644
--- a/chrome/browser/ash/file_manager/volume_manager.cc
+++ b/chrome/browser/ash/file_manager/volume_manager.cc
@@ -490,7 +490,8 @@
           std::make_unique<DocumentsProviderRootManager>(
               profile_,
               arc::ArcFileSystemOperationRunner::GetForBrowserContext(
-                  profile_))) {
+                  profile_))),
+      io_task_controller_() {
   DCHECK(disk_mount_manager);
 }
 
diff --git a/chrome/browser/ash/file_manager/volume_manager.h b/chrome/browser/ash/file_manager/volume_manager.h
index 4ece0ad2..dba5191 100644
--- a/chrome/browser/ash/file_manager/volume_manager.h
+++ b/chrome/browser/ash/file_manager/volume_manager.h
@@ -19,6 +19,7 @@
 #include "chrome/browser/ash/arc/session/arc_session_manager_observer.h"
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #include "chrome/browser/ash/file_manager/documents_provider_root_manager.h"
+#include "chrome/browser/ash/file_manager/io_task_controller.h"
 #include "chrome/browser/ash/file_system_provider/icon_set.h"
 #include "chrome/browser/ash/file_system_provider/observer.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_info.h"
@@ -456,6 +457,10 @@
 
   SnapshotManager* snapshot_manager() { return snapshot_manager_.get(); }
 
+  io_task::IOTaskController* io_task_controller() {
+    return &io_task_controller_;
+  }
+
  private:
   void OnDiskMountManagerRefreshed(bool success);
   void OnStorageMonitorInitialized();
@@ -489,6 +494,7 @@
   std::unique_ptr<DocumentsProviderRootManager>
       documents_provider_root_manager_;
   bool arc_volumes_mounted_ = false;
+  io_task::IOTaskController io_task_controller_;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/chrome/browser/ash/input_method/input_method_manager_impl.cc b/chrome/browser/ash/input_method/input_method_manager_impl.cc
index 8507b14..07690e2 100644
--- a/chrome/browser/ash/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/ash/input_method/input_method_manager_impl.cc
@@ -140,7 +140,7 @@
     : profile(profile), manager_(manager) {
   if (initial_input_method) {
     enabled_input_method_ids_.push_back(initial_input_method->id());
-    current_input_method = *initial_input_method;
+    current_input_method_ = *initial_input_method;
   }
 }
 
@@ -155,7 +155,7 @@
   scoped_refptr<StateImpl> new_state(new StateImpl(this->manager_, profile));
 
   new_state->last_used_input_method_id_ = last_used_input_method_id_;
-  new_state->current_input_method = current_input_method;
+  new_state->current_input_method_ = current_input_method_;
 
   new_state->enabled_input_method_ids_ = enabled_input_method_ids_;
   new_state->allowed_keyboard_layout_input_method_ids_ =
@@ -164,7 +164,7 @@
   new_state->pending_input_method_id_ = pending_input_method_id_;
 
   new_state->enabled_extension_imes_ = enabled_extension_imes_;
-  new_state->available_input_methods = available_input_methods;
+  new_state->available_input_methods_ = available_input_methods_;
   new_state->menu_activated = menu_activated;
   new_state->input_view_url_ = input_view_url_;
   new_state->input_view_url_overridden_ = input_view_url_overridden_;
@@ -184,8 +184,8 @@
     if (descriptor) {
       result->push_back(*descriptor);
     } else {
-      const auto ix = available_input_methods.find(input_method_id);
-      if (ix != available_input_methods.end())
+      const auto ix = available_input_methods_.find(input_method_id);
+      if (ix != available_input_methods_.end())
         result->push_back(ix->second);
       else
         DVLOG(1) << "Descriptor is not found for: " << input_method_id;
@@ -215,8 +215,8 @@
   const InputMethodDescriptor* ime =
       manager_->util_.GetInputMethodDescriptorFromId(input_method_id);
   if (!ime) {
-    const auto ix = available_input_methods.find(input_method_id);
-    if (ix != available_input_methods.end())
+    const auto ix = available_input_methods_.find(input_method_id);
+    if (ix != available_input_methods_.end())
       ime = &ix->second;
   }
   return ime;
@@ -326,8 +326,8 @@
 
   enabled_input_method_ids_.swap(new_enabled_input_method_ids);
 
-  // Re-check current_input_method.
-  ChangeInputMethod(current_input_method.id(), false);
+  // Re-check current_input_method_.
+  ChangeInputMethod(current_input_method_.id(), false);
 }
 
 // Adds new input method to given list.
@@ -388,9 +388,9 @@
 
   manager_->ReconfigureIMFramework(this);
 
-  // If |current_input_method| is no longer in |enabled_input_method_ids_|,
+  // If |current_input_method_| is no longer in |enabled_input_method_ids_|,
   // ChangeInputMethod() picks the first one in |enabled_input_method_ids_|.
-  ChangeInputMethod(current_input_method.id(), false);
+  ChangeInputMethod(current_input_method_.id(), false);
 
   // Record histogram for enabled input method count; "active" in the metric
   // name is a legacy misnomer; "active" should refer to just the single current
@@ -479,14 +479,13 @@
   bool notify_menu = false;
 
   // Always lookup input method, even if it is the same as
-  // |current_input_method| because If it is no longer in
+  // |current_input_method_| because If it is no longer in
   // |enabled_input_method_ids_|, pick the first one in
   // |enabled_input_method_ids_|.
-  const InputMethodDescriptor* descriptor =
-      manager_->LookupInputMethod(input_method_id, this);
+  const InputMethodDescriptor* descriptor = LookupInputMethod(input_method_id);
   if (!descriptor) {
-    descriptor = manager_->LookupInputMethod(
-        manager_->util_.MigrateInputMethod(input_method_id), this);
+    descriptor =
+        LookupInputMethod(manager_->util_.MigrateInputMethod(input_method_id));
     if (!descriptor) {
       LOG(ERROR) << "Can't find InputMethodDescriptor for \"" << input_method_id
                  << "\"";
@@ -501,9 +500,9 @@
   if (MethodAwaitsExtensionLoad(input_method_id))
     pending_input_method_id_ = input_method_id;
 
-  if (descriptor->id() != current_input_method.id()) {
-    last_used_input_method_id_ = current_input_method.id();
-    current_input_method = *descriptor;
+  if (descriptor->id() != current_input_method_.id()) {
+    last_used_input_method_id_ = current_input_method_.id();
+    current_input_method_ = *descriptor;
     notify_menu = true;
   }
 
@@ -514,7 +513,7 @@
                                                        notify_menu);
   }
 
-  manager_->RecordInputMethodUsage(current_input_method.id());
+  manager_->RecordInputMethodUsage(current_input_method_.id());
 }
 
 void InputMethodManagerImpl::StateImpl::ChangeInputMethodToJpKeyboard() {
@@ -562,7 +561,7 @@
   bool contain = false;
   for (const auto& descriptor : descriptors) {
     const std::string& id = descriptor.id();
-    available_input_methods[id] = descriptor;
+    available_input_methods_[id] = descriptor;
     if (base::Contains(enabled_extension_imes_, id)) {
       if (!base::Contains(enabled_input_method_ids_, id)) {
         enabled_input_method_ids_.push_back(id);
@@ -576,10 +575,10 @@
 
   if (IsActive()) {
     if (extension_id == extension_ime_util::GetExtensionIDFromInputMethodID(
-                            current_input_method.id())) {
+                            current_input_method_.id())) {
       ui::IMEBridge::Get()->SetCurrentEngineHandler(engine);
       engine->Enable(extension_ime_util::GetComponentIDByInputMethodID(
-          current_input_method.id()));
+          current_input_method_.id()));
     }
 
     // Ensure that the input method daemon is running.
@@ -604,12 +603,12 @@
 
   // Remove the input methods registered by `extension_id`.
   std::map<std::string, InputMethodDescriptor> new_available_input_methods;
-  for (const auto& entry : available_input_methods) {
+  for (const auto& entry : available_input_methods_) {
     if (extension_id !=
         extension_ime_util::GetExtensionIDFromInputMethodID(entry.first))
       new_available_input_methods[entry.first] = entry.second;
   }
-  available_input_methods.swap(new_available_input_methods);
+  available_input_methods_.swap(new_available_input_methods);
 
   if (IsActive()) {
     if (ui::IMEBridge::Get()->GetCurrentEngineHandler() ==
@@ -619,17 +618,17 @@
     manager_->engine_map_[profile].erase(extension_id);
   }
 
-  // If |current_input_method| is no longer in |enabled_input_method_ids_|,
+  // If |current_input_method_| is no longer in |enabled_input_method_ids_|,
   // switch to the first one in |enabled_input_method_ids_|.
-  ChangeInputMethod(current_input_method.id(), false);
+  ChangeInputMethod(current_input_method_.id(), false);
   manager_->NotifyInputMethodExtensionRemoved(extension_id);
 }
 
 void InputMethodManagerImpl::StateImpl::GetInputMethodExtensions(
     InputMethodDescriptors* result) {
   // Build the extension input method descriptors from the input methods cache
-  // `available_input_methods`.
-  for (const auto& entry : available_input_methods) {
+  // `available_input_methods_`.
+  for (const auto& entry : available_input_methods_) {
     if (extension_ime_util::IsExtensionIME(entry.first) ||
         extension_ime_util::IsArcIME(entry.first)) {
       result->push_back(entry.second);
@@ -645,7 +644,7 @@
   bool enabled_imes_changed = false;
   bool switch_to_pending = false;
 
-  for (const auto& entry : available_input_methods) {
+  for (const auto& entry : available_input_methods_) {
     if (extension_ime_util::IsComponentExtensionIME(entry.first))
       continue;  // Do not filter component extension.
 
@@ -677,9 +676,9 @@
       ChangeInputMethod(pending_input_method_id_, false);
       pending_input_method_id_.clear();
     } else {
-      // If |current_input_method| is no longer in |enabled_input_method_ids_|,
+      // If |current_input_method_| is no longer in |enabled_input_method_ids_|,
       // switch to the first one in |enabled_input_method_ids_|.
-      ChangeInputMethod(current_input_method.id(), false);
+      ChangeInputMethod(current_input_method_.id(), false);
     }
   }
 }
@@ -762,8 +761,8 @@
     return false;
   }
 
-  if (current_input_method.id().empty()) {
-    DVLOG(1) << "current_input_method is unknown";
+  if (current_input_method_.id().empty()) {
+    DVLOG(1) << "current_input_method_ is unknown";
     return false;
   }
 
@@ -776,7 +775,7 @@
 
   auto iter =
       std::find(enabled_input_method_ids_.begin(),
-                enabled_input_method_ids_.end(), current_input_method.id());
+                enabled_input_method_ids_.end(), current_input_method_.id());
   if (iter != enabled_input_method_ids_.end())
     ++iter;
   if (iter == enabled_input_method_ids_.end())
@@ -789,7 +788,7 @@
     return;
 
   if (last_used_input_method_id_.empty() ||
-      last_used_input_method_id_ == current_input_method.id()) {
+      last_used_input_method_id_ == current_input_method_.id()) {
     SwitchToNextInputMethod();
     return;
   }
@@ -807,10 +806,10 @@
 
 InputMethodDescriptor InputMethodManagerImpl::StateImpl::GetCurrentInputMethod()
     const {
-  if (current_input_method.id().empty())
+  if (current_input_method_.id().empty())
     return InputMethodUtil::GetFallbackInputMethodDescriptor();
 
-  return current_input_method;
+  return current_input_method_;
 }
 
 bool InputMethodManagerImpl::StateImpl::InputMethodIsEnabled(
@@ -820,7 +819,7 @@
 
 void InputMethodManagerImpl::StateImpl::EnableInputView() {
   if (!input_view_url_overridden_) {
-    input_view_url_ = current_input_method.input_view_url();
+    input_view_url_ = current_input_method_.input_view_url();
   }
 }
 
@@ -848,7 +847,7 @@
 }
 
 void InputMethodManagerImpl::StateImpl::ResetInputViewUrl() {
-  input_view_url_ = current_input_method.input_view_url();
+  input_view_url_ = current_input_method_.input_view_url();
   input_view_url_overridden_ = false;
 }
 
@@ -880,6 +879,40 @@
   }
 }
 
+const InputMethodDescriptor*
+InputMethodManagerImpl::StateImpl::LookupInputMethod(
+    const std::string& input_method_id) {
+  std::string input_method_id_to_switch = input_method_id;
+
+  // Sanity check
+  if (!InputMethodIsEnabled(input_method_id)) {
+    std::unique_ptr<InputMethodDescriptors> input_methods(
+        GetEnabledInputMethods());
+    DCHECK(!input_methods->empty());
+    input_method_id_to_switch = input_methods->at(0).id();
+    if (!input_method_id.empty()) {
+      DVLOG(1) << "Can't change the current input method to " << input_method_id
+               << " since the engine is not enabled. "
+               << "Switch to " << input_method_id_to_switch << " instead.";
+    }
+  }
+
+  const InputMethodDescriptor* descriptor = NULL;
+  if (extension_ime_util::IsExtensionIME(input_method_id_to_switch) ||
+      extension_ime_util::IsArcIME(input_method_id_to_switch)) {
+    DCHECK(available_input_methods_.find(input_method_id_to_switch) !=
+           available_input_methods_.end());
+    descriptor = &(available_input_methods_[input_method_id_to_switch]);
+  } else {
+    descriptor = manager_->util_.GetInputMethodDescriptorFromId(
+        input_method_id_to_switch);
+    if (!descriptor)
+      LOG(ERROR) << "Unknown input method id: " << input_method_id_to_switch;
+  }
+  DCHECK(descriptor);
+  return descriptor;
+}
+
 // ------------------------ InputMethodManagerImpl
 bool InputMethodManagerImpl::IsLoginKeyboard(
     const std::string& layout) const {
@@ -1021,42 +1054,6 @@
   ime_menu_observers_.RemoveObserver(observer);
 }
 
-const InputMethodDescriptor* InputMethodManagerImpl::LookupInputMethod(
-    const std::string& input_method_id,
-    InputMethodManagerImpl::StateImpl* state) {
-  DCHECK(state);
-
-  std::string input_method_id_to_switch = input_method_id;
-
-  // Sanity check
-  if (!state->InputMethodIsEnabled(input_method_id)) {
-    std::unique_ptr<InputMethodDescriptors> input_methods(
-        state->GetEnabledInputMethods());
-    DCHECK(!input_methods->empty());
-    input_method_id_to_switch = input_methods->at(0).id();
-    if (!input_method_id.empty()) {
-      DVLOG(1) << "Can't change the current input method to "
-               << input_method_id << " since the engine is not enabled. "
-               << "Switch to " << input_method_id_to_switch << " instead.";
-    }
-  }
-
-  const InputMethodDescriptor* descriptor = NULL;
-  if (extension_ime_util::IsExtensionIME(input_method_id_to_switch) ||
-      extension_ime_util::IsArcIME(input_method_id_to_switch)) {
-    DCHECK(state->available_input_methods.find(input_method_id_to_switch) !=
-           state->available_input_methods.end());
-    descriptor = &(state->available_input_methods[input_method_id_to_switch]);
-  } else {
-    descriptor =
-        util_.GetInputMethodDescriptorFromId(input_method_id_to_switch);
-    if (!descriptor)
-      LOG(ERROR) << "Unknown input method id: " << input_method_id_to_switch;
-  }
-  DCHECK(descriptor);
-  return descriptor;
-}
-
 void InputMethodManagerImpl::ChangeInputMethodInternalFromActiveState(
     bool show_message,
     bool notify_menu) {
@@ -1088,14 +1085,14 @@
     engine->Disable();
 
   // Configure the next engine handler.
-  // This must be after |current_input_method| has been set to new input
+  // This must be after |current_input_method_| has been set to new input
   // method, because engine's Enable() method needs to access it.
   const std::string& extension_id =
       extension_ime_util::GetExtensionIDFromInputMethodID(
-          state_->current_input_method.id());
+          state_->GetCurrentInputMethod().id());
   const std::string& component_id =
       extension_ime_util::GetComponentIDByInputMethodID(
-          state_->current_input_method.id());
+          state_->GetCurrentInputMethod().id());
   if (!engine_map_.count(state_->profile) ||
       !engine_map_[state_->profile].count(extension_id)) {
     LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS())
@@ -1116,9 +1113,9 @@
 
   // Change the keyboard layout to a preferred layout for the input method.
   if (!keyboard_->SetCurrentKeyboardLayoutByName(
-          state_->current_input_method.keyboard_layout())) {
+          state_->GetCurrentInputMethod().keyboard_layout())) {
     LOG(ERROR) << "Failed to change keyboard layout to "
-               << state_->current_input_method.keyboard_layout();
+               << state_->GetCurrentInputMethod().keyboard_layout();
   }
 
   // Update input method indicators (e.g. "US", "DV") in Chrome windows.
diff --git a/chrome/browser/ash/input_method/input_method_manager_impl.h b/chrome/browser/ash/input_method/input_method_manager_impl.h
index 3a17650..69d0da81 100644
--- a/chrome/browser/ash/input_method/input_method_manager_impl.h
+++ b/chrome/browser/ash/input_method/input_method_manager_impl.h
@@ -111,12 +111,6 @@
     // ------------------------- Data members.
     Profile* const profile;
 
-    InputMethodDescriptor current_input_method;
-
-    // All input methods that have been registered by InputMethodEngines.
-    // The key is the input method ID.
-    std::map<std::string, InputMethodDescriptor> available_input_methods;
-
     // True if the opt-in IME menu is activated.
     bool menu_activated = false;
 
@@ -151,12 +145,22 @@
     // allowed input method, if no hardware input method is allowed.
     std::string GetAllowedFallBackKeyboardLayout() const;
 
+    // Returns Input Method that best matches given id.
+    const InputMethodDescriptor* LookupInputMethod(
+        const std::string& input_method_id);
+
     InputMethodManagerImpl* const manager_;
 
     std::string last_used_input_method_id_;
 
+    InputMethodDescriptor current_input_method_;
+
     std::vector<std::string> enabled_input_method_ids_;
 
+    // All input methods that have been registered by InputMethodEngines.
+    // The key is the input method ID.
+    std::map<std::string, InputMethodDescriptor> available_input_methods_;
+
     // The allowed keyboard layout input methods (e.g. by policy).
     std::vector<std::string> allowed_keyboard_layout_input_method_ids_;
 
@@ -258,11 +262,6 @@
   // done.
   void MaybeInitializeAssistiveWindowController();
 
-  // Returns Input Method that best matches given id.
-  const InputMethodDescriptor* LookupInputMethod(
-      const std::string& input_method_id,
-      StateImpl* state);
-
   // Change system input method to the one specified in the active state.
   void ChangeInputMethodInternalFromActiveState(bool show_message,
                                                 bool notify_menu);
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
index 67caf12..c396bd2 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
@@ -116,6 +116,23 @@
   return IsBlocked(restriction_info);
 }
 
+bool DlpContentManager::IsScreenshotApiRestricted(
+    const ScreenshotArea& area) const {
+  RestrictionLevelAndUrl restriction_info =
+      GetAreaRestrictionInfo(area, DlpContentRestriction::kScreenshot);
+  if (IsReported(restriction_info)) {
+    SYSLOG(INFO) << "DLP blocked taking a screenshot";
+    if (reporting_manager_)
+      ReportEvent(restriction_info.url,
+                  DlpRulesManager::Restriction::kScreenshot,
+                  restriction_info.level, reporting_manager_);
+  }
+  DlpBooleanHistogram(dlp::kScreenshotBlockedUMA, IsBlocked(restriction_info));
+  // TODO(crbug.com/1247190): Add reporting and metrics for WARN
+  // TODO(crbug.com/1252736): Properly handle WARN for screenshots API
+  return IsBlocked(restriction_info) || IsWarn(restriction_info);
+}
+
 bool DlpContentManager::IsVideoCaptureRestricted(
     const ScreenshotArea& area) const {
   RestrictionLevelAndUrl restriction_info =
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager.h b/chrome/browser/ash/policy/dlp/dlp_content_manager.h
index 2d25f0ee..35bf9dec 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager.h
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager.h
@@ -59,6 +59,9 @@
   // Returns whether screenshots should be restricted.
   virtual bool IsScreenshotRestricted(const ScreenshotArea& area) const;
 
+  // Returns whether screenshots should be restricted for extensions API.
+  virtual bool IsScreenshotApiRestricted(const ScreenshotArea& area) const;
+
   // Returns whether video capture should be restricted.
   bool IsVideoCaptureRestricted(const ScreenshotArea& area) const;
 
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc
index 8408866..f4e6fb0 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc
@@ -51,6 +51,9 @@
 const DlpContentRestrictionSet kScreenshotRestricted(
     DlpContentRestriction::kScreenshot,
     DlpRulesManager::Level::kBlock);
+const DlpContentRestrictionSet kScreenshotWarned(
+    DlpContentRestriction::kScreenshot,
+    DlpRulesManager::Level::kWarn);
 const DlpContentRestrictionSet kScreenshotReported(
     DlpContentRestriction::kScreenshot,
     DlpRulesManager::Level::kReport);
@@ -162,10 +165,10 @@
   ScreenshotArea partial_in =
       ScreenshotArea::CreateForPartialWindow(root_window, in_rect);
 
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(window));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   histogram_tester_.ExpectBucketCount(
       GetDlpHistogramPrefix() + dlp::kScreenshotBlockedUMA, true, 0);
   histogram_tester_.ExpectBucketCount(
@@ -174,10 +177,10 @@
               DlpRulesManager::Level::kBlock, 0u);
 
   helper_.ChangeConfidentiality(web_contents, kScreenshotRestricted);
-  EXPECT_TRUE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_TRUE(manager->IsScreenshotRestricted(window));
-  EXPECT_TRUE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   histogram_tester_.ExpectBucketCount(
       GetDlpHistogramPrefix() + dlp::kScreenshotBlockedUMA, true, 3);
   histogram_tester_.ExpectBucketCount(
@@ -187,10 +190,10 @@
 
   web_contents->WasHidden();
   helper_.ChangeVisibility(web_contents);
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_TRUE(manager->IsScreenshotRestricted(window));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   histogram_tester_.ExpectBucketCount(
       GetDlpHistogramPrefix() + dlp::kScreenshotBlockedUMA, true, 4);
   histogram_tester_.ExpectBucketCount(
@@ -200,10 +203,10 @@
 
   web_contents->WasShown();
   helper_.ChangeVisibility(web_contents);
-  EXPECT_TRUE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_TRUE(manager->IsScreenshotRestricted(window));
-  EXPECT_TRUE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   histogram_tester_.ExpectBucketCount(
       GetDlpHistogramPrefix() + dlp::kScreenshotBlockedUMA, true, 7);
   histogram_tester_.ExpectBucketCount(
@@ -212,9 +215,9 @@
               DlpRulesManager::Level::kBlock, 7u);
 
   helper_.DestroyWebContents(web_contents);
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   histogram_tester_.ExpectBucketCount(
       GetDlpHistogramPrefix() + dlp::kScreenshotBlockedUMA, true, 7);
   histogram_tester_.ExpectBucketCount(
@@ -223,6 +226,58 @@
               DlpRulesManager::Level::kBlock, 7u);
 }
 
+IN_PROC_BROWSER_TEST_F(DlpContentManagerBrowserTest, ScreenshotsWarned) {
+  DlpContentManager* manager = helper_.GetContentManager();
+  ASSERT_TRUE(
+      ui_test_utils::NavigateToURL(browser(), GURL("https://example.com")));
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  aura::Window* root_window =
+      browser()->window()->GetNativeWindow()->GetRootWindow();
+  ScreenshotArea fullscreen = ScreenshotArea::CreateForAllRootWindows();
+  ScreenshotArea window =
+      ScreenshotArea::CreateForWindow(web_contents->GetNativeView());
+  const gfx::Rect web_contents_rect = web_contents->GetContainerBounds();
+  gfx::Rect out_rect(web_contents_rect);
+  out_rect.Offset(web_contents_rect.width(), web_contents_rect.height());
+  gfx::Rect in_rect(web_contents_rect);
+  in_rect.Offset(web_contents_rect.width() / 2, web_contents_rect.height() / 2);
+  ScreenshotArea partial_out =
+      ScreenshotArea::CreateForPartialWindow(root_window, out_rect);
+  ScreenshotArea partial_in =
+      ScreenshotArea::CreateForPartialWindow(root_window, in_rect);
+
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
+
+  helper_.ChangeConfidentiality(web_contents, kScreenshotWarned);
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
+
+  web_contents->WasHidden();
+  helper_.ChangeVisibility(web_contents);
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
+
+  web_contents->WasShown();
+  helper_.ChangeVisibility(web_contents);
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_TRUE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
+
+  helper_.DestroyWebContents(web_contents);
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
+}
+
 IN_PROC_BROWSER_TEST_F(DlpContentManagerBrowserTest, ScreenshotsReported) {
   SetupReporting();
   DlpContentManager* manager = helper_.GetContentManager();
@@ -245,43 +300,43 @@
   ScreenshotArea partial_in =
       ScreenshotArea::CreateForPartialWindow(root_window, in_rect);
 
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(window));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   CheckEvents(DlpRulesManager::Restriction::kScreenshot,
               DlpRulesManager::Level::kReport, 0u);
 
   helper_.ChangeConfidentiality(web_contents, kScreenshotReported);
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(window));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   CheckEvents(DlpRulesManager::Restriction::kScreenshot,
               DlpRulesManager::Level::kReport, 3u);
 
   web_contents->WasHidden();
   helper_.ChangeVisibility(web_contents);
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(window));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   CheckEvents(DlpRulesManager::Restriction::kScreenshot,
               DlpRulesManager::Level::kReport, 4u);
 
   web_contents->WasShown();
   helper_.ChangeVisibility(web_contents);
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(window));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(window));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   CheckEvents(DlpRulesManager::Restriction::kScreenshot,
               DlpRulesManager::Level::kReport, 7u);
 
   helper_.DestroyWebContents(web_contents);
-  EXPECT_FALSE(manager->IsScreenshotRestricted(fullscreen));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_in));
-  EXPECT_FALSE(manager->IsScreenshotRestricted(partial_out));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(fullscreen));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_in));
+  EXPECT_FALSE(manager->IsScreenshotApiRestricted(partial_out));
   histogram_tester_.ExpectBucketCount(
       GetDlpHistogramPrefix() + dlp::kScreenshotBlockedUMA, true, 0);
   histogram_tester_.ExpectBucketCount(
diff --git a/chrome/browser/ash/policy/dlp/mock_dlp_content_manager.h b/chrome/browser/ash/policy/dlp/mock_dlp_content_manager.h
index 207184b..ac10bc0 100644
--- a/chrome/browser/ash/policy/dlp/mock_dlp_content_manager.h
+++ b/chrome/browser/ash/policy/dlp/mock_dlp_content_manager.h
@@ -22,7 +22,8 @@
   MOCK_CONST_METHOD1(GetRestrictionSetForURL,
                      DlpContentRestrictionSet(const GURL&));
   MOCK_METHOD1(OnVisibilityChanged, void(content::WebContents*));
-  MOCK_CONST_METHOD1(IsScreenshotRestricted, bool(const ScreenshotArea& area));
+  MOCK_CONST_METHOD1(IsScreenshotApiRestricted,
+                     bool(const ScreenshotArea& area));
   MOCK_CONST_METHOD1(IsScreenCaptureRestricted,
                      bool(const content::DesktopMediaID& media_id));
 
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
index ed3bc85..1c908714 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
@@ -948,15 +948,6 @@
         chromeos::kReportDeviceNetworkConfiguration, false);
   }
 
-  void IsolateReportingSetting(const std::string& isolated_path) {
-    for (int i = 0; chromeos::kDeviceReportingSettings[i] != nullptr; i++) {
-      scoped_testing_cros_settings_.device_settings()->SetBoolean(
-          chromeos::kDeviceReportingSettings[i], false);
-    }
-    scoped_testing_cros_settings_.device_settings()->SetBoolean(isolated_path,
-                                                                true);
-  }
-
   void TearDown() override { status_collector_.reset(); }
 
  protected:
@@ -3914,6 +3905,30 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  // TODO(b/192252043): Iterate over a list to remove these.
+  void DisableDefaultSettings() {
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceVersionInfo, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceActivityTimes, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceBootMode, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceNetworkInterfaces, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceUsers, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceHardwareStatus, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceSessionStatus, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceAudioStatus, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceNetworkConfiguration, false);
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        chromeos::kReportDeviceNetworkStatus, false);
+  }
+
   virtual void VerifyReporting() = 0;
 
  private:
@@ -3960,7 +3975,9 @@
 // TODO(crbug.com/1253206): Revive this test.
 TEST_F(DeviceStatusCollectorNetworkInterfacesTest, DISABLED_TestNoInterfaces) {
   ClearNetworkData();
-  IsolateReportingSetting(chromeos::kReportDeviceNetworkConfiguration);
+  DisableDefaultSettings();
+  scoped_testing_cros_settings_.device_settings()->SetBoolean(
+      chromeos::kReportDeviceNetworkConfiguration, true);
 
   // If no interfaces are found, nothing should be reported.
   GetStatus();
@@ -4099,7 +4116,9 @@
 // TODO(crbug.com/1253206): Revive this test.
 TEST_F(DeviceStatusCollectorNetworkStateTest, DISABLED_TestNoNetworks) {
   ClearNetworkData();
-  IsolateReportingSetting(chromeos::kReportDeviceNetworkStatus);
+  DisableDefaultSettings();
+  scoped_testing_cros_settings_.device_settings()->SetBoolean(
+      chromeos::kReportDeviceNetworkConfiguration, true);
 
   // If no networks are found, nothing should be reported.
   GetStatus();
diff --git a/chrome/browser/attribution_reporting/OWNERS b/chrome/browser/attribution_reporting/OWNERS
index 8b8a4832..6a3b4dd 100644
--- a/chrome/browser/attribution_reporting/OWNERS
+++ b/chrome/browser/attribution_reporting/OWNERS
@@ -1 +1 @@
-file://content/browser/conversions/OWNERS
+file://content/browser/attribution_reporting/OWNERS
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index 34288aa..256f760 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -684,9 +684,6 @@
       histogram_tester_.ExpectTotalCount(
           "ServiceWorker.StartWorker.StatusByPurpose_NAVIGATION_HINT", 0);
     }
-    histogram_tester_.ExpectBucketCount(
-        "ServiceWorker.StartForNavigationHint.Result",
-        static_cast<int>(expected_result), 1);
   }
 
   void TestStarted(const char* test_script) {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index a5c1b86..be444a7 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1358,6 +1358,10 @@
     "../ash/file_manager/filesystem_api_util.h",
     "../ash/file_manager/guest_os_file_tasks.cc",
     "../ash/file_manager/guest_os_file_tasks.h",
+    "../ash/file_manager/io_task.cc",
+    "../ash/file_manager/io_task.h",
+    "../ash/file_manager/io_task_controller.cc",
+    "../ash/file_manager/io_task_controller.h",
     "../ash/file_manager/open_util.cc",
     "../ash/file_manager/open_util.h",
     "../ash/file_manager/open_with_browser.cc",
@@ -3917,6 +3921,7 @@
     "../ash/file_manager/file_watcher_unittest.cc",
     "../ash/file_manager/fileapi_util_unittest.cc",
     "../ash/file_manager/guest_os_file_tasks_unittest.cc",
+    "../ash/file_manager/io_task_controller_unittest.cc",
     "../ash/file_manager/path_util_unittest.cc",
     "../ash/file_manager/url_util_unittest.cc",
     "../ash/file_manager/volume_manager_unittest.cc",
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc
index 3bc3a08..bd1e584 100644
--- a/chrome/browser/download/download_request_limiter_unittest.cc
+++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -514,8 +514,8 @@
 
   // History back shouldn't reset the state, either.
   auto backward_navigation =
-      content::NavigationSimulator::CreateHistoryNavigation(
-          -1 /* Offset */, web_contents(), false /* is_renderer_initiated */);
+      content::NavigationSimulator::CreateHistoryNavigation(-1 /* Offset */,
+                                                            web_contents());
   backward_navigation->Start();
   backward_navigation->Commit();
   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
@@ -541,7 +541,7 @@
   // History back should use the old download state, as one of the origin
   // is in a restricted state.
   backward_navigation = content::NavigationSimulator::CreateHistoryNavigation(
-      -1 /* Offset */, web_contents(), false /* is_renderer_initiated */);
+      -1 /* Offset */, web_contents());
   backward_navigation->Start();
   backward_navigation->Commit();
   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
@@ -576,8 +576,8 @@
 
   // History back shouldn't reset the state, either.
   auto backward_navigation =
-      content::NavigationSimulator::CreateHistoryNavigation(
-          -1 /* Offset */, web_contents(), false /* is_renderer_initiated */);
+      content::NavigationSimulator::CreateHistoryNavigation(-1 /* Offset */,
+                                                            web_contents());
   backward_navigation->Start();
   backward_navigation->Commit();
   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
@@ -588,8 +588,8 @@
   // History forward shouldn't reset the state, as the host is encountered
   // before.
   auto forward_navigation =
-      content::NavigationSimulator::CreateHistoryNavigation(
-          1 /* Offset */, web_contents(), false /* is_renderer_initiated */);
+      content::NavigationSimulator::CreateHistoryNavigation(1 /* Offset */,
+                                                            web_contents());
   forward_navigation->Start();
   forward_navigation->Commit();
   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
@@ -599,7 +599,7 @@
 
   // History backward again, nothing should change.
   backward_navigation = content::NavigationSimulator::CreateHistoryNavigation(
-      -1 /* Offset */, web_contents(), false /* is_renderer_initiated */);
+      -1 /* Offset */, web_contents());
   backward_navigation->Start();
   backward_navigation->Commit();
   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
index d1a7dac..9b515b50 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -1191,7 +1191,7 @@
   policy::MockDlpContentManager mock_dlp_content_manager;
   policy::ScopedDlpContentManagerForTesting scoped_dlp_content_manager_(
       &mock_dlp_content_manager);
-  EXPECT_CALL(mock_dlp_content_manager, IsScreenshotRestricted(testing::_))
+  EXPECT_CALL(mock_dlp_content_manager, IsScreenshotApiRestricted(testing::_))
       .Times(1)
       .WillOnce(testing::Return(true));
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_util_chromeos.cc b/chrome/browser/extensions/api/tabs/tabs_util_chromeos.cc
index 82931e0c..8552078 100644
--- a/chrome/browser/extensions/api/tabs/tabs_util_chromeos.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_util_chromeos.cc
@@ -67,7 +67,7 @@
 }
 
 bool IsScreenshotRestricted(content::WebContents* web_contents) {
-  return policy::DlpContentManager::Get()->IsScreenshotRestricted(
+  return policy::DlpContentManager::Get()->IsScreenshotApiRestricted(
       ScreenshotArea::CreateForWindow(web_contents->GetNativeView()));
 }
 
diff --git a/chrome/browser/extensions/navigation_observer_browsertest.cc b/chrome/browser/extensions/navigation_observer_browsertest.cc
index d12ac3d..fe0bec7 100644
--- a/chrome/browser/extensions/navigation_observer_browsertest.cc
+++ b/chrome/browser/extensions/navigation_observer_browsertest.cc
@@ -183,11 +183,6 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_EQ(web_contents->GetMainFrame()->GetLastCommittedURL(), main_url);
 
-  // Emulate a user gesture so that the current entry won't be skipped due to
-  // the history manipulation intervention when we try to navigate back to it.
-  web_contents->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
-      std::u16string());
-
   // Navigate subframe to an enabled extension URL.
   scoped_refptr<const Extension> extension =
       ChromeTestExtensionLoader(profile()).LoadExtension(
@@ -199,7 +194,6 @@
   content::RenderFrameHost* subframe =
       ChildFrameAt(web_contents->GetMainFrame(), 0);
   EXPECT_EQ(subframe->GetLastCommittedURL(), extension_url);
-  EXPECT_EQ(web_contents->GetController().GetEntryCount(), 3);
   scoped_refptr<content::SiteInstance> extension_site_instance =
       subframe->GetSiteInstance();
 
@@ -220,10 +214,8 @@
   // which is important for reproducing https://crbug.com/1197360.
   web_contents->GetController().GoBack();
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  EXPECT_EQ(web_contents->GetController().GetLastCommittedEntryIndex(), 1);
   web_contents->GetController().GoForward();
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  EXPECT_EQ(web_contents->GetController().GetLastCommittedEntryIndex(), 2);
 
   subframe = ChildFrameAt(web_contents->GetMainFrame(), 0);
   EXPECT_EQ(subframe->GetLastCommittedURL(), extension_url);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 29af3902..24d01ed5 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -195,13 +195,13 @@
   },
   {
     "name": "arc-file-picker-experiment",
-    "owners": [ "niwa" ],
-    "expiry_milestone": 95
+    "owners": [ "youkichihosoi", "risan", "niwa" ],
+    "expiry_milestone": 100
   },
   {
     "name": "arc-ghost-window",
     "owners": [ "sstan" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 100
   },
   {
     "name": "arc-image-copy-paste-compat",
@@ -264,11 +264,6 @@
     "expiry_milestone": 97
   },
   {
-    "name": "arc-web-app-share",
-    "owners": [ "tsergeant", "chromeos-apps-foundation-team@google.com" ],
-    "expiry_milestone": 95
-  },
-  {
     "name": "ash-bento-bar",
     "owners": [ "minch", "janetmac" ],
     "expiry_milestone": 100
@@ -882,7 +877,7 @@
   },
   {
     "name": "conversion-measurement-debug-mode",
-    "owners": [ "//content/browser/conversions/OWNERS" ],
+    "owners": [ "//content/browser/attribution_reporting/OWNERS" ],
     "expiry_milestone": 98
   },
   {
@@ -1958,7 +1953,7 @@
   {
     "name": "enable-generated-webapks",
     "owners": [ "tsergeant@chromium.org" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 96
   },
   {
     "name": "enable-generic-sensor-extra-classes",
@@ -2962,17 +2957,17 @@
   {
     "name": "exo-lock-notification",
     "owners": [ "cpelling@google.com" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 103
   },
   {
     "name": "exo-ordinal-motion",
     "owners": [ "hollingum@google.com" ],
-    "expiry_milestone": 96
+    "expiry_milestone": 103
   },
   {
     "name": "exo-pointer-lock",
     "owners": [ "hollingum@google.com" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 103
   },
   {
     "name": "expanded-tab-strip",
@@ -3388,7 +3383,7 @@
   {
     "name": "incognito-brand-consistency-for-android",
     "owners": [ "sideyilmaz", "rhalavati", "chrome-incognito@google.com" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 100
   },
   {
     "name": "incognito-brand-consistency-for-desktop",
@@ -3398,7 +3393,7 @@
   {
     "name": "incognito-brand-consistency-for-ios",
     "owners": [ "sideyilmaz", "rhalavati", "chrome-incognito@google.com" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 100
   },
   {
     "name": "incognito-clear-browsing-data-dialog-for-desktop",
@@ -4558,7 +4553,7 @@
   {
     "name": "raw-audio-capture",
     "owners": [ "henrika@google.com", "video-cmi-mpp@google.com" ],
-    "expiry_milestone": 95
+    "expiry_milestone": 99
   },
   {
     "name": "raw-clipboard",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c507c14..930c3c9 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4105,12 +4105,6 @@
     "Trigger reclaim in ARCVM to reduce memory use when ChromeOS is running "
     "low on memory.";
 
-const char kArcWebAppShareName[] = "Enable sharing to Web Apps from ARC";
-const char kArcWebAppShareDescription[] =
-    "Allow Android apps to send shared text and files to web apps. When "
-    "disabled, web apps may still appear in share sheets, but will not "
-    "receive any shared content.";
-
 const char kArcEnableUsapName[] =
     "Enable ARC Unspecialized Application Processes";
 const char kArcEnableUsapDesc[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index ecf3a33..4ef74025 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2343,9 +2343,6 @@
 extern const char kArcVmBalloonPolicyName[];
 extern const char kArcVmBalloonPolicyDesc[];
 
-extern const char kArcWebAppShareName[];
-extern const char kArcWebAppShareDescription[];
-
 extern const char kArcEnableUsapName[];
 extern const char kArcEnableUsapDesc[];
 
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
index 8177688..d2eb353e 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
@@ -15,9 +15,6 @@
 
 namespace internal {
 
-const char kHistogramServiceWorkerPageTransition[] =
-    "PageLoad.Clients.ServiceWorker2.PageTransition";
-
 const char kHistogramServiceWorkerParseStart[] =
     "PageLoad.Clients.ServiceWorker2.ParseTiming.NavigationToParseStart";
 const char kHistogramServiceWorkerParseStartForwardBack[] =
@@ -265,16 +262,6 @@
   if (!IsServiceWorkerControlled())
     return;
 
-  // TODO(falken): It may be cleaner to record page transition in OnCommit() but
-  // at that point we don't yet know if the page is controlled by a service
-  // worker. It should be possible to plumb the information there since the
-  // browser process already sends the controller service worker in the
-  // navigation commit IPC.
-  UMA_HISTOGRAM_ENUMERATION(
-      internal::kHistogramServiceWorkerPageTransition,
-      static_cast<int>(ui::PageTransitionStripQualifier(transition_)),
-      static_cast<int>(ui::PAGE_TRANSITION_LAST_CORE) + 1);
-
   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
           timing.parse_timing->parse_start, GetDelegate())) {
     PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerParseStart,
diff --git a/chrome/browser/predictors/loading_predictor_browsertest.cc b/chrome/browser/predictors/loading_predictor_browsertest.cc
index 044e744c..0a7ef792 100644
--- a/chrome/browser/predictors/loading_predictor_browsertest.cc
+++ b/chrome/browser/predictors/loading_predictor_browsertest.cc
@@ -2067,6 +2067,8 @@
   EXPECT_EQ(status.error_code, net::ERR_FAILED);
   EXPECT_THAT(status.cors_error_status,
               Optional(network::CorsErrorStatus(
+                  network::mojom::CorsError::kInsecurePrivateNetwork,
+                  network::mojom::IPAddressSpace::kUnknown,
                   network::mojom::IPAddressSpace::kLocal)));
 }
 
diff --git a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
index 1dffe5b..283b0d95 100644
--- a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
@@ -276,8 +276,7 @@
   // Forward) but modify the navigation type while pending to look like an
   // address bar + typed transition (like Gmail auto navigation)
   std::unique_ptr<content::NavigationSimulator> forward_nav =
-      content::NavigationSimulator::CreateHistoryNavigation(
-          1, web_contents, false /* is_renderer_initiated */);
+      content::NavigationSimulator::CreateHistoryNavigation(1, web_contents);
   forward_nav->Start();
   web_contents->GetController().GetPendingEntry()->SetTransitionType(
       ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
@@ -318,8 +317,8 @@
   // Try to simulate renderer reloading a PWA page: Navigate to an existing page
   // (via Forward) but modify the navigation type while pending to look like a
   // PAGE_TRANSITION_AUTO_BOOKMARK.
-  forward_nav = content::NavigationSimulator::CreateHistoryNavigation(
-      1, web_contents, false /* is_renderer_initiated */);
+  forward_nav =
+      content::NavigationSimulator::CreateHistoryNavigation(1, web_contents);
   forward_nav->Start();
   web_contents->GetController().GetPendingEntry()->SetTransitionType(
       ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_BOOKMARK));
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h b/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
index 92bcb1c..bcd0e34 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
@@ -90,6 +90,8 @@
                            HistogramsTabSwitchLoadTime);
   FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorParameterizedTest,
                            HistogramsTabCount);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorPrerenderingTest,
+                           KeepingWebContentsMapInPrerendering);
 
   // Create and initialize the swap metrics driver if needed.
   void CreateAndInitSwapMetricsDriverIfNeeded();
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
index 68417fc..259b320 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/metrics_hashes.h"
 #include "base/task/current_thread.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/time/tick_clock.h"
@@ -27,11 +28,13 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
 #include "content/public/test/web_contents_tester.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 
 using base::Bucket;
 using ::testing::ElementsAre;
@@ -234,4 +237,65 @@
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime, 2);
 }
+
+class TabManagerStatsCollectorPrerenderingTest
+    : public TabManagerStatsCollectorTabSwitchTest {
+ public:
+  TabManagerStatsCollectorPrerenderingTest() {
+    scoped_feature_list_.InitWithFeatures(
+        {blink::features::kPrerender2},
+        // Disable the memory requirement of Prerender2 so the test can run on
+        // any bot.
+        {blink::features::kPrerender2MemoryControls});
+  }
+  ~TabManagerStatsCollectorPrerenderingTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Tests that prerendering loading doesn't remove its WebContents from
+// `foreground_contents_switched_to_times_` and doesn't add the histogram
+// since it's not a primary page.
+TEST_F(TabManagerStatsCollectorPrerenderingTest,
+       KeepingWebContentsMapInPrerendering) {
+  std::unique_ptr<WebContents> tab1(CreateTestWebContents());
+  std::unique_ptr<WebContents> tab2(CreateTestWebContents());
+
+  GURL init_url("https://example1.test/");
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(tab2.get(),
+                                                             init_url);
+
+  SetForegroundAndBackgroundTabs(tab1.get(), tab2.get());
+
+  StartSessionRestore();
+
+  SetBackgroundTabLoadingState(UNLOADED);
+  SetForegroundTabLoadingState(LOADED);
+  SwitchToBackgroundTab();
+
+  // Set prerendering loading.
+  const GURL kPrerenderingUrl("https://example1.test/?prerendering");
+  auto* prerender_rfh = content::WebContentsTester::For(tab2.get())
+                            ->AddPrerenderAndCommitNavigation(kPrerenderingUrl);
+  DCHECK_NE(prerender_rfh, nullptr);
+
+  // Even though prerendering navigation is committed, TabManagerStatsCollector
+  // should keep `tab2` at `foreground_contents_switched_to_times_`.
+  EXPECT_TRUE(base::Contains(
+      tab_manager_stats_collector()->foreground_contents_switched_to_times_,
+      tab2.get()));
+  histogram_tester_.ExpectTotalCount(
+      TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime, 0);
+
+  FinishLoadingForegroundTab();
+  // `tab2` is removed from `foreground_contents_switched_to_times_` in
+  // OnTabIsLoaded().
+  EXPECT_FALSE(base::Contains(
+      tab_manager_stats_collector()->foreground_contents_switched_to_times_,
+      tab2.get()));
+  histogram_tester_.ExpectTotalCount(
+      TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime, 1);
+}
+
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
index f123bc4..c782c25 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
@@ -28,9 +28,6 @@
   // Only change to the loading state if there is a navigation in the main
   // frame. DidStartLoading() happens before this, but at that point we don't
   // know if the load is happening in the main frame or an iframe.
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (!navigation_handle->IsInPrimaryMainFrame() ||
       navigation_handle->IsSameDocument()) {
     return;
diff --git a/chrome/browser/resources/ntp4/revamped_incognito_tab.css b/chrome/browser/resources/ntp4/revamped_incognito_tab.css
index cfd612a..94ecebcb 100644
--- a/chrome/browser/resources/ntp4/revamped_incognito_tab.css
+++ b/chrome/browser/resources/ntp4/revamped_incognito_tab.css
@@ -150,7 +150,7 @@
 }
 
 .descriptions {
-  flex-basis: calc((var(--content-max-width) - var(--description-item-spacing)) / 2);
+  flex-basis: calc((100% - var(--description-item-spacing)) / 2);
   flex-grow: 1;
   flex-shrink: 0;
 }
@@ -161,11 +161,14 @@
 
 h1,
 .learn-more-wrapper,
-.descriptions,
-.icon {
+.descriptions {
   margin-block-end: 32px;
 }
 
+.icon {
+  margin-block-end: 16px;
+}
+
 /* On narrow screens, align everything to the left. */
 @media (max-width: 720px) {
   .content {
@@ -181,6 +184,14 @@
   h1 {
     text-align: start;
   }
+
+  #descriptions-wrapper {
+    flex-direction: column;
+  }
+
+  .descriptions.first {
+    margin-inline-end: 0;
+  }
 }
 
 /** Paddings and margins ---------------------------------------------------- */
@@ -191,9 +202,8 @@
 }
 
 /* Wide screens. */
-@media (min-width: 720px) {
-  .icon,
-  h1 {
+@media (min-width: 721px) {
+  .icon {
     margin-top: 1.5rem;
   }
 
@@ -224,13 +234,6 @@
                            * otherwise the screen height would be 100% + 32px */
     }
   }
-
-  /* Smaller vertical margins on very short screens. */
-  @media (max-height: 320px) {
-    h1 {
-      margin-top: 16px;
-    }
-  }
 }
 
 /* Narrow screens */
@@ -241,7 +244,6 @@
   }
 
   .icon {
-    margin-bottom: 1.5rem;
     margin-top: 1.5rem;
   }
 
@@ -252,7 +254,6 @@
     }
 
     .icon {
-      margin-bottom: 1rem;
       margin-top: 1rem;
     }
   }
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 9f3ccfe..927df44 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -108,7 +108,7 @@
     "about_page/about_page_browser_proxy.ts",
     "appearance_page/appearance_browser_proxy.ts",
     "appearance_page/fonts_browser_proxy.ts",
-    "autofill_page/merge_exceptions_store_copies_behavior.js",
+    "autofill_page/merge_exceptions_store_copies_mixin.ts",
     "autofill_page/merge_passwords_store_copies_behavior.js",
     "autofill_page/multi_store_exception_entry.ts",
     "autofill_page/multi_store_id_handler.ts",
@@ -116,7 +116,7 @@
     "autofill_page/password_check_mixin.ts",
     "autofill_page/password_manager_proxy.ts",
     "autofill_page/show_password_mixin.ts",
-    "base_mixin.js",
+    "base_mixin.ts",
     "chrome_cleanup_page/chrome_cleanup_proxy.ts",
     "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts",
     "controls/pref_control_behavior.js",
@@ -125,7 +125,7 @@
     "downloads_page/downloads_browser_proxy.ts",
     "ensure_lazy_loaded.js",
     "extension_control_browser_proxy.ts",
-    "global_scroll_target_mixin.js",
+    "global_scroll_target_mixin.ts",
     "hats_browser_proxy.ts",
     "i18n_setup.ts",
     "incompatible_applications_page/incompatible_applications_browser_proxy.ts",
@@ -153,7 +153,7 @@
     "search_settings.ts",
     "setting_id_param_util.ts",
     "settings.ts",
-    "settings_page/main_page_mixin.js",
+    "settings_page/main_page_mixin.ts",
     "settings_routes.js",
     "site_settings/constants.ts",
     "site_settings/cookie_info.ts",
@@ -406,7 +406,6 @@
   is_polymer3 = true
   closure_flags = settings_closure_flags
   deps = [
-    ":base_mixin",
     ":extension_control_browser_proxy",
     ":i18n_setup",
     ":lifetime_browser_proxy",
@@ -436,12 +435,6 @@
   extra_deps = [ ":build_ts" ]
 }
 
-js_library("base_mixin") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
 js_library("extension_control_browser_proxy") {
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/extension_control_browser_proxy.js" ]
   deps = [ "//ui/webui/resources/js:cr.m" ]
@@ -456,14 +449,6 @@
   extra_deps = [ ":build_ts" ]
 }
 
-js_library("global_scroll_target_mixin") {
-  deps = [
-    ":router",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:promise_resolver.m",
-  ]
-}
-
 js_library("lifetime_browser_proxy") {
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/lifetime_browser_proxy.js" ]
   deps = [ "//ui/webui/resources/js:cr.m" ]
@@ -597,7 +582,7 @@
     "autofill_page/avatar_icon.ts",
     "autofill_page/credit_card_edit_dialog.ts",
     "autofill_page/credit_card_list_entry.ts",
-    "autofill_page/merge_exceptions_store_copies_behavior.js",
+    "autofill_page/merge_exceptions_store_copies_mixin.ts",
     "autofill_page/merge_passwords_store_copies_behavior.js",
     "autofill_page/multi_store_exception_entry.ts",
     "autofill_page/multi_store_id_handler.ts",
@@ -623,7 +608,7 @@
     "autofill_page/payments_section.ts",
     "autofill_page/show_password_mixin.ts",
     "autofill_page/upi_id_list_entry.ts",
-    "base_mixin.js",
+    "base_mixin.ts",
     "basic_page/basic_page.ts",
     "clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts",
     "clear_browsing_data_dialog/clear_browsing_data_dialog.ts",
@@ -647,7 +632,7 @@
     "downloads_page/downloads_page.ts",
     "ensure_lazy_loaded.js",
     "extension_control_browser_proxy.ts",
-    "global_scroll_target_mixin.js",
+    "global_scroll_target_mixin.ts",
     "hats_browser_proxy.ts",
     "i18n_setup.ts",
     "icons.ts",
@@ -728,7 +713,7 @@
     "settings_main/settings_main.ts",
     "settings_menu/settings_menu.ts",
     "settings_page_css.ts",
-    "settings_page/main_page_mixin.js",
+    "settings_page/main_page_mixin.ts",
     "settings_page/settings_animated_pages.js",
     "settings_page/settings_section.ts",
     "settings_page/settings_subpage.ts",
diff --git a/chrome/browser/resources/settings/autofill_page/merge_exceptions_store_copies_behavior.js b/chrome/browser/resources/settings/autofill_page/merge_exceptions_store_copies_behavior.js
deleted file mode 100644
index 7d7ca0a2..0000000
--- a/chrome/browser/resources/settings/autofill_page/merge_exceptions_store_copies_behavior.js
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview This behavior bundles the functionality for retrieving password
- * exceptions (websites where the user has chosen never to save passwords) from
- * the password manager, and deduplicating eventual copies stored both on the
- * device and in the account.
- */
-
-import {assert} from 'chrome://resources/js/assert.m.js';
-
-import {MultiStoreExceptionEntry} from './multi_store_exception_entry.js';
-import {PasswordManagerImpl, PasswordManagerProxy} from './password_manager_proxy.js';
-
-/**
- * @polymerBehavior
- */
-export const MergeExceptionsStoreCopiesBehavior = {
-
-  properties: {
-    /**
-     * An array of sites to display.
-     * @type {!Array<!MultiStoreExceptionEntry>}
-     */
-    passwordExceptions: {
-      type: Array,
-      value: () => [],
-    },
-  },
-
-  /**
-   * @type {?function(!Array<chrome.passwordsPrivate.ExceptionEntry>):void}
-   * @private
-   */
-  setPasswordExceptionsListener_: null,
-
-  /** @override */
-  attached() {
-    this.setPasswordExceptionsListener_ = list => {
-      this.passwordExceptions = this.mergeExceptionsStoreDuplicates_(list);
-    };
-
-    PasswordManagerImpl.getInstance().getExceptionList(
-        this.setPasswordExceptionsListener_);
-    PasswordManagerImpl.getInstance().addExceptionListChangedListener(
-        this.setPasswordExceptionsListener_);
-  },
-
-  /** @override */
-  detached() {
-    PasswordManagerImpl.getInstance().removeExceptionListChangedListener(
-        assert(this.setPasswordExceptionsListener_));
-  },
-
-  /**
-   * @param {!Array<!chrome.passwordsPrivate.ExceptionEntry>} exceptionList
-   * @return {!Array<!MultiStoreExceptionEntry>}
-   * @private
-   */
-  mergeExceptionsStoreDuplicates_(exceptionList) {
-    /** @type {!Array<!MultiStoreExceptionEntry>} */
-    const multiStoreEntries = [];
-    /** @type {!Map<number, !MultiStoreExceptionEntry>} */
-    const frontendIdToMergedEntry = new Map();
-    for (const entry of exceptionList) {
-      if (frontendIdToMergedEntry.has(entry.frontendId)) {
-        const mergeSucceded =
-            frontendIdToMergedEntry.get(entry.frontendId).mergeInPlace(entry);
-        if (mergeSucceded) {
-          // The merge is in-place, so nothing to be done.
-        } else {
-          // The merge can fail in weird cases despite |frontendId| matching.
-          // If so, just create another entry in the UI for |entry|. See also
-          // crbug.com/1114697.
-          multiStoreEntries.push(new MultiStoreExceptionEntry(entry));
-        }
-      } else {
-        const multiStoreEntry = new MultiStoreExceptionEntry(entry);
-        frontendIdToMergedEntry.set(entry.frontendId, multiStoreEntry);
-        multiStoreEntries.push(multiStoreEntry);
-      }
-    }
-    return multiStoreEntries;
-  },
-};
-
-/** @interface */
-export class MergeExceptionsStoreCopiesBehaviorInterface {
-  /** @return {!Array<!MultiStoreExceptionEntry>} */
-  get passwordExceptions() {}
-}
diff --git a/chrome/browser/resources/settings/autofill_page/merge_exceptions_store_copies_mixin.ts b/chrome/browser/resources/settings/autofill_page/merge_exceptions_store_copies_mixin.ts
new file mode 100644
index 0000000..78cd6a33
--- /dev/null
+++ b/chrome/browser/resources/settings/autofill_page/merge_exceptions_store_copies_mixin.ts
@@ -0,0 +1,92 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview This behavior bundles the functionality for retrieving password
+ * exceptions (websites where the user has chosen never to save passwords) from
+ * the password manager, and deduplicating eventual copies stored both on the
+ * device and in the account.
+ */
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {MultiStoreExceptionEntry} from './multi_store_exception_entry.js';
+import {PasswordExceptionListChangedListener, PasswordManagerImpl} from './password_manager_proxy.js';
+
+type Constructor<T> = new (...args: any[]) => T;
+
+export interface MergeExceptionsStoreCopiesMixinInterface {
+  passwordExceptions: Array<MultiStoreExceptionEntry>;
+}
+
+export const MergeExceptionsStoreCopiesMixin = dedupingMixin(
+    <T extends Constructor<PolymerElement>>(superClass: T): T&
+    Constructor<MergeExceptionsStoreCopiesMixinInterface> => {
+      class MergeExceptionsStoreCopiesMixin extends superClass {
+        static get properties() {
+          return {
+            /** An array of sites to display. */
+            passwordExceptions: {
+              type: Array,
+              value: () => [],
+            },
+          };
+        }
+
+        passwordExceptions: Array<MultiStoreExceptionEntry>;
+        private setPasswordExceptionsListener_:
+            PasswordExceptionListChangedListener|null = null;
+
+        connectedCallback() {
+          super.connectedCallback();
+
+          this.setPasswordExceptionsListener_ = list => {
+            this.passwordExceptions = mergeExceptionsStoreDuplicates(list);
+          };
+
+          PasswordManagerImpl.getInstance().getExceptionList(
+              this.setPasswordExceptionsListener_);
+          PasswordManagerImpl.getInstance().addExceptionListChangedListener(
+              this.setPasswordExceptionsListener_);
+        }
+
+        disconnectedCallback() {
+          super.disconnectedCallback();
+
+          PasswordManagerImpl.getInstance().removeExceptionListChangedListener(
+              assert(this.setPasswordExceptionsListener_!));
+          this.setPasswordExceptionsListener_ = null;
+        }
+      }
+
+      return MergeExceptionsStoreCopiesMixin;
+    });
+
+function mergeExceptionsStoreDuplicates(
+    exceptionList: Array<chrome.passwordsPrivate.ExceptionEntry>):
+    Array<MultiStoreExceptionEntry> {
+  const multiStoreEntries: Array<MultiStoreExceptionEntry> = [];
+  const frontendIdToMergedEntry: Map<number, MultiStoreExceptionEntry> =
+      new Map();
+  for (const entry of exceptionList) {
+    if (frontendIdToMergedEntry.has(entry.frontendId)) {
+      const mergeSucceded =
+          frontendIdToMergedEntry.get(entry.frontendId)!.mergeInPlace(entry);
+      if (mergeSucceded) {
+        // The merge is in-place, so nothing to be done.
+      } else {
+        // The merge can fail in weird cases despite |frontendId| matching.
+        // If so, just create another entry in the UI for |entry|. See also
+        // crbug.com/1114697.
+        multiStoreEntries.push(new MultiStoreExceptionEntry(entry));
+      }
+    } else {
+      const multiStoreEntry = new MultiStoreExceptionEntry(entry);
+      frontendIdToMergedEntry.set(entry.frontendId, multiStoreEntry);
+      multiStoreEntries.push(multiStoreEntry);
+    }
+  }
+  return multiStoreEntries;
+}
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
index 007e50a..f158093 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
@@ -60,13 +60,19 @@
   };
 }
 
+// TODO(crbug.com/1234307): Remove when RouteObserverMixin is converted to
+// TypeScript.
+type Constructor<T> = new (...args: any[]) => T;
+
 const PasswordsDeviceSectionElementBase =
     mixinBehaviors(
         [
           MergePasswordsStoreCopiesBehavior,
           WebUIListenerBehavior,
         ],
-        GlobalScrollTargetMixin(RouteObserverMixin(PolymerElement))) as {
+        GlobalScrollTargetMixin(
+            RouteObserverMixin(PolymerElement) as unknown as
+            Constructor<PolymerElement>)) as {
       new (): PolymerElement & WebUIListenerBehavior &
       MergePasswordsStoreCopiesBehaviorInterface & RouteObserverMixinInterface
     };
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_section.ts
index 5bc9b2ad..85ea4c7 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.ts
@@ -51,7 +51,7 @@
 // <if expr="chromeos">
 import {BlockingRequestManager} from './blocking_request_manager.js';
 // </if>
-import {MergeExceptionsStoreCopiesBehavior, MergeExceptionsStoreCopiesBehaviorInterface} from './merge_exceptions_store_copies_behavior.js';
+import {MergeExceptionsStoreCopiesMixin, MergeExceptionsStoreCopiesMixinInterface} from './merge_exceptions_store_copies_mixin.js';
 import {MergePasswordsStoreCopiesBehavior, MergePasswordsStoreCopiesBehaviorInterface} from './merge_passwords_store_copies_behavior.js';
 import {MultiStoreExceptionEntry} from './multi_store_exception_entry.js';
 import {MultiStorePasswordUiEntry} from './multi_store_password_ui_entry.js';
@@ -92,13 +92,13 @@
         [
           I18nBehavior,
           WebUIListenerBehavior,
-          MergeExceptionsStoreCopiesBehavior,
           MergePasswordsStoreCopiesBehavior,
           PrefsBehavior,
         ],
-        GlobalScrollTargetMixin(PasswordCheckMixin(PolymerElement))) as {
+        GlobalScrollTargetMixin(MergeExceptionsStoreCopiesMixin(
+            PasswordCheckMixin(PolymerElement)))) as {
       new (): PolymerElement & I18nBehavior & WebUIListenerBehavior &
-      MergeExceptionsStoreCopiesBehaviorInterface &
+      MergeExceptionsStoreCopiesMixinInterface &
       MergePasswordsStoreCopiesBehaviorInterface & PasswordCheckMixinInterface
     };
 
diff --git a/chrome/browser/resources/settings/base_mixin.js b/chrome/browser/resources/settings/base_mixin.js
deleted file mode 100644
index 71d6475..0000000
--- a/chrome/browser/resources/settings/base_mixin.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Provides a couple of helper methods used by several Polymer
- * elements.
- */
-
-import {dedupingMixin} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-/** @interface */
-export class BaseMixinInterface {
-  /**
-   * @param {string} query
-   * @return {?HTMLElement}
-   */
-  $$(query) {}
-
-  /**
-   * @param {string} eventName
-   * @param {*=} detail
-   */
-  fire(eventName, detail) {}
-}
-
-/**
- * @polymer
- * @mixinFunction
- */
-export const BaseMixin = dedupingMixin(superClass => {
-  /**
-   * @polymer
-   * @mixinClass
-   * @implements {BaseMixinInterface}
-   */
-  class BaseMixin extends superClass {
-    /** @override */
-    $$(query) {
-      return this.shadowRoot.querySelector(query);
-    }
-
-    /** @override */
-    fire(eventName, detail) {
-      this.dispatchEvent(
-          new CustomEvent(eventName, {bubbles: true, composed: true, detail}));
-    }
-  }
-
-  return BaseMixin;
-});
diff --git a/chrome/browser/resources/settings/base_mixin.ts b/chrome/browser/resources/settings/base_mixin.ts
new file mode 100644
index 0000000..fb6b4c5
--- /dev/null
+++ b/chrome/browser/resources/settings/base_mixin.ts
@@ -0,0 +1,34 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Provides a couple of helper methods used by several Polymer
+ * elements.
+ */
+
+import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+type Constructor<T> = new (...args: any[]) => T;
+
+export interface BaseMixinInterface {
+  $$<E extends Element = Element>(query: string): E|null;
+  fire(eventName: string, detail?: any): void;
+}
+
+export const BaseMixin = dedupingMixin(
+    <T extends Constructor<PolymerElement>>(superClass: T): T&
+    Constructor<BaseMixinInterface> => {
+      class BaseMixin extends superClass {
+        $$<E extends Element = Element>(query: string) {
+          return this.shadowRoot!.querySelector<E>(query);
+        }
+
+        fire(eventName: string, detail?: any) {
+          this.dispatchEvent(new CustomEvent(
+              eventName, {bubbles: true, composed: true, detail}));
+        }
+      }
+
+      return BaseMixin;
+    });
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.ts b/chrome/browser/resources/settings/basic_page/basic_page.ts
index ea5d91b..a53d102 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.ts
+++ b/chrome/browser/resources/settings/basic_page/basic_page.ts
@@ -63,6 +63,9 @@
 };
 // </if>
 
+// TODO(crbug.com/1234307): Remove when RouteObserverMixin is converted to
+// TypeScript.
+type Constructor<T> = new (...args: any[]) => T;
 
 const SettingsBasicPageElementBase =
     mixinBehaviors(
@@ -71,7 +74,9 @@
           PrefsBehavior,
           // </if>
         ],
-        MainPageMixin(RouteObserverMixin(PolymerElement))) as {
+        MainPageMixin(
+            RouteObserverMixin(PolymerElement) as unknown as
+            Constructor<PolymerElement>)) as {
       new (): PolymerElement &
       // <if expr="chromeos or lacros">
       PrefsBehaviorInterface &
@@ -204,7 +209,7 @@
   /**
    * Override MainPageMixin method.
    */
-  containsRoute(route?: Route): boolean {
+  containsRoute(route: Route|null): boolean {
     return !route || routes.BASIC.contains(route) ||
         routes.ADVANCED.contains(route);
   }
diff --git a/chrome/browser/resources/settings/global_scroll_target_mixin.js b/chrome/browser/resources/settings/global_scroll_target_mixin.js
deleted file mode 100644
index 5e17705d..0000000
--- a/chrome/browser/resources/settings/global_scroll_target_mixin.js
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview |GlobalScrollTargetMixin| allows an element to be aware of
- * the global scroll target.
- *
- * |scrollTarget| will be populated async by |setGlobalScrollTarget|.
- *
- * |subpageScrollTarget| will be equal to the |scrollTarget|, but will only be
- * populated when the current route is the |subpageRoute|.
- *
- * |setGlobalScrollTarget| should only be called once.
- */
-
-import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
-import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from './router.js';
-
-let scrollTargetResolver = new PromiseResolver();
-
-/**
- * @polymer
- * @mixinFunction
- */
-export const GlobalScrollTargetMixin = dedupingMixin(superClass => {
-  /**
-   * @constructor
-   * @implements {RouteObserverMixinInterface}
-   * @extends {PolymerElement}
-   * @private
-   */
-  const superClassBase = RouteObserverMixin(superClass);
-
-  /**
-   * @polymer
-   * @mixinClass
-   */
-  class GlobalScrollTargetMixin extends superClassBase {
-    static get properties() {
-      return {
-        /**
-         * Read only property for the scroll target.
-         * @type {HTMLElement}
-         */
-        scrollTarget: {
-          type: Object,
-          readOnly: true,
-        },
-
-        /**
-         * Read only property for the scroll target that a subpage should use.
-         * It will be set/cleared based on the current route.
-         * @type {HTMLElement}
-         */
-        subpageScrollTarget: {
-          type: Object,
-          computed: 'getActiveTarget_(scrollTarget, active_)',
-        },
-
-        /**
-         * The |subpageScrollTarget| should only be set for this route.
-         * @type {Route}
-         * @private
-         */
-        subpageRoute: Object,
-
-        /** Whether the |subpageRoute| is active or not. */
-        active_: Boolean,
-      };
-    }
-
-    /** @override */
-    connectedCallback() {
-      super.connectedCallback();
-
-      this.active_ =
-          Router.getInstance().getCurrentRoute() === this.subpageRoute;
-      scrollTargetResolver.promise.then(this._setScrollTarget.bind(this));
-    }
-
-    /** @param {!Route} route */
-    currentRouteChanged(route) {
-      // Immediately set the scroll target to active when this page is
-      // activated, but wait a task to remove the scroll target when the page is
-      // deactivated. This gives scroll handlers like iron-list a chance to
-      // handle scroll events that are fired as a result of the route changing.
-      // TODO(https://crbug.com/859794): Having this timeout can result some
-      // jumpy behaviour in the scroll handlers. |this.active_| can be set
-      // immediately when this bug is fixed.
-      if (route === this.subpageRoute) {
-        this.active_ = true;
-      } else {
-        setTimeout(() => {
-          this.active_ = false;
-        });
-      }
-    }
-
-    /**
-     * Returns the target only when the route is active.
-     * @param {HTMLElement} target
-     * @param {boolean} active
-     * @return {?HTMLElement|undefined}
-     * @private
-     */
-    getActiveTarget_(target, active) {
-      if (target === undefined || active === undefined) {
-        return undefined;
-      }
-
-      return active ? target : null;
-    }
-  }
-
-  return GlobalScrollTargetMixin;
-});
-
-/**
- * This should only be called once.
- * @param {HTMLElement} scrollTarget
- */
-export function setGlobalScrollTarget(scrollTarget) {
-  scrollTargetResolver.resolve(scrollTarget);
-}
-
-export function resetGlobalScrollTargetForTesting() {
-  scrollTargetResolver = new PromiseResolver();
-}
diff --git a/chrome/browser/resources/settings/global_scroll_target_mixin.ts b/chrome/browser/resources/settings/global_scroll_target_mixin.ts
new file mode 100644
index 0000000..2673328
--- /dev/null
+++ b/chrome/browser/resources/settings/global_scroll_target_mixin.ts
@@ -0,0 +1,118 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview |GlobalScrollTargetMixin| allows an element to be aware of
+ * the global scroll target.
+ *
+ * |scrollTarget| will be populated async by |setGlobalScrollTarget|.
+ *
+ * |subpageScrollTarget| will be equal to the |scrollTarget|, but will only be
+ * populated when the current route is the |subpageRoute|.
+ *
+ * |setGlobalScrollTarget| should only be called once.
+ */
+
+import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
+import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from './router.js';
+
+let scrollTargetResolver = new PromiseResolver<HTMLElement>();
+
+type Constructor<T> = new (...args: any[]) => T;
+
+export const GlobalScrollTargetMixin = dedupingMixin(
+    <T extends Constructor<PolymerElement>>(superClass: T): T&
+    Constructor<GlobalScrollTargetMixinInterface> => {
+      const superClassBase = RouteObserverMixin(superClass) as unknown as T;
+
+      class GlobalScrollTargetMixin extends superClassBase {
+        static get properties() {
+          return {
+            scrollTarget: Object,
+
+            /**
+             * Read only property for the scroll target that a subpage should
+             * use. It will be set/cleared based on the current route.
+             */
+            subpageScrollTarget: {
+              type: Object,
+              computed: 'getActiveTarget_(scrollTarget, active_)',
+            },
+
+            /**
+             * The |subpageScrollTarget| should only be set for this route.
+             */
+            subpageRoute: Object,
+
+            /** Whether the |subpageRoute| is active or not. */
+            active_: Boolean,
+          };
+        }
+
+        scrollTarget: HTMLElement;
+        subpageScrollTarget: HTMLElement|null;
+        subpageRoute: Route;
+        private active_: boolean;
+
+        connectedCallback() {
+          super.connectedCallback();
+
+          this.active_ =
+              Router.getInstance().getCurrentRoute() === this.subpageRoute;
+          scrollTargetResolver.promise.then((scrollTarget: HTMLElement) => {
+            this.scrollTarget = scrollTarget;
+          });
+        }
+
+        currentRouteChanged(route: Route) {
+          // Immediately set the scroll target to active when this page is
+          // activated, but wait a task to remove the scroll target when the
+          // page is deactivated. This gives scroll handlers like iron-list a
+          // chance to handle scroll events that are fired as a result of the
+          // route changing.
+          // TODO(https://crbug.com/859794): Having this timeout can result some
+          // jumpy behaviour in the scroll handlers. |this.active_| can be set
+          // immediately when this bug is fixed.
+          if (route === this.subpageRoute) {
+            this.active_ = true;
+          } else {
+            setTimeout(() => {
+              this.active_ = false;
+            });
+          }
+        }
+
+        /**
+         * Returns the target only when the route is active.
+         */
+        private getActiveTarget_(
+            target: HTMLElement|undefined,
+            active: boolean|undefined): HTMLElement|null|undefined {
+          if (target === undefined || active === undefined) {
+            return undefined;
+          }
+
+          return active ? target : null;
+        }
+      }
+
+      return GlobalScrollTargetMixin;
+    });
+
+export interface GlobalScrollTargetMixinInterface {
+  scrollTarget: HTMLElement;
+}
+
+/**
+ * This should only be called once.
+ */
+export function setGlobalScrollTarget(scrollTarget: HTMLElement) {
+  scrollTargetResolver.resolve(scrollTarget);
+}
+
+export function resetGlobalScrollTargetForTesting() {
+  scrollTargetResolver = new PromiseResolver();
+}
diff --git a/chrome/browser/resources/settings/settings_page/BUILD.gn b/chrome/browser/resources/settings/settings_page/BUILD.gn
index e676af4..a55b55df 100644
--- a/chrome/browser/resources/settings/settings_page/BUILD.gn
+++ b/chrome/browser/resources/settings/settings_page/BUILD.gn
@@ -9,20 +9,7 @@
 js_type_check("closure_compile") {
   is_polymer3 = true
   closure_flags = settings_closure_flags
-  deps = [
-    ":main_page_mixin",
-    ":settings_animated_pages",
-  ]
-}
-
-js_library("main_page_mixin") {
-  deps = [
-    "..:route",
-    "..:router",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:util.m",
-  ]
+  deps = [ ":settings_animated_pages" ]
 }
 
 js_library("settings_animated_pages") {
diff --git a/chrome/browser/resources/settings/settings_page/main_page_mixin.js b/chrome/browser/resources/settings/settings_page/main_page_mixin.js
deleted file mode 100644
index 15e912e..0000000
--- a/chrome/browser/resources/settings/settings_page/main_page_mixin.js
+++ /dev/null
@@ -1,611 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// clang-format off
-import {assert} from 'chrome://resources/js/assert.m.js';
-import {beforeNextRender, dedupingMixin} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {ensureLazyLoaded} from '../ensure_lazy_loaded.js';
-import {loadTimeData} from '../i18n_setup.js';
-import {routes} from '../route.js';
-import {MinimumRoutes, Route, Router} from '../router.js';
-// clang-format on
-
-  /**
-   * @enum {string}
-   * A categorization of every possible Settings URL, necessary for implementing
-   * a finite state machine.
-   */
-  export const RouteState = {
-    // Initial state before anything has loaded yet.
-    INITIAL: 'initial',
-    // A dialog that has a dedicated URL (e.g. /importData).
-    DIALOG: 'dialog',
-    // A section (basically a scroll position within the top level page, e.g,
-    // /appearance.
-    SECTION: 'section',
-    // A subpage, or sub-subpage e.g, /searchEngins.
-    SUBPAGE: 'subpage',
-    // The top level Settings page, '/'.
-    TOP_LEVEL: 'top-level',
-  };
-
-  let guestTopLevelRoute = routes.SEARCH;
-  // <if expr="chromeos">
-  guestTopLevelRoute = routes.PRIVACY;
-  // </if>
-
-  /** @type {!Route} */
-  const TOP_LEVEL_EQUIVALENT_ROUTE =
-      loadTimeData.getBoolean('isGuest') ? guestTopLevelRoute : routes.PEOPLE;
-
-  /**
-   * @param {?Route} route
-   * @return {!RouteState}
-   */
-  function classifyRoute(route) {
-    if (!route) {
-      return RouteState.INITIAL;
-    }
-    const routes = /** @type {!MinimumRoutes} */ (
-        Router.getInstance().getRoutes());
-    if (route === routes.BASIC) {
-      return RouteState.TOP_LEVEL;
-    }
-    if (route.isSubpage()) {
-      return RouteState.SUBPAGE;
-    }
-    if (route.isNavigableDialog) {
-      return RouteState.DIALOG;
-    }
-    return RouteState.SECTION;
-  }
-
-  /**
-   * Responds to route changes by expanding, collapsing, or scrolling to
-   * sections on the page. Expanded sections take up the full height of the
-   * container. At most one section should be expanded at any given time.
-   * @polymer
-   * @mixinFunction
-   */
-  export const MainPageMixin = dedupingMixin(superClass => {
-    /**
-     * @polymer
-     * @mixinClass
-     */
-    class MainPageMixin extends superClass {
-      static get properties() {
-        return {
-          /**
-           * Whether a search operation is in progress or previous search
-           * results are being displayed.
-           * @private
-           */
-          inSearchMode: {
-            type: Boolean,
-            value: false,
-            observer: 'inSearchModeChanged_',
-            reflectToAttribute: true,
-          },
-        };
-      }
-
-      constructor() {
-        super();
-
-        /** @type {?HTMLElement} */
-        this.scroller = null;
-
-        /**
-         * A map holding all valid state transitions.
-         * @private {!Map<!RouteState, !Set<RouteState>>}
-         */
-        this.validTransitions_ = (function() {
-          const allStates = new Set([
-            RouteState.DIALOG,
-            RouteState.SECTION,
-            RouteState.SUBPAGE,
-            RouteState.TOP_LEVEL,
-          ]);
-
-          return new Map([
-            [RouteState.INITIAL, allStates],
-            [
-              RouteState.DIALOG, new Set([
-                RouteState.SECTION,
-                RouteState.SUBPAGE,
-                RouteState.TOP_LEVEL,
-              ])
-            ],
-            [RouteState.SECTION, allStates],
-            [RouteState.SUBPAGE, allStates],
-            [RouteState.TOP_LEVEL, allStates],
-          ]);
-        })();
-      }
-
-      /** @override */
-      connectedCallback() {
-        this.scroller = this.domHost ? this.domHost.parentNode : document.body;
-
-        // Purposefully calling this after |scroller| has been initialized.
-        super.connectedCallback();
-      }
-
-      /**
-       * Method to be overridden by users of MainPageMixin.
-       * @param {Route} route
-       * @return {boolean} Whether the given route is part of |this| page.
-       */
-      containsRoute(route) {
-        return false;
-      }
-
-      /**
-       * @param {boolean} current
-       * @param {boolean} previous
-       * @private
-       */
-      inSearchModeChanged_(current, previous) {
-        if (loadTimeData.getBoolean('enableLandingPageRedesign')) {
-          // No need to deal with overscroll, as only one section is shown at
-          // any given time.
-          return;
-        }
-
-        // Ignore 1st occurrence which happens while the element is being
-        // initialized.
-        if (previous === undefined) {
-          return;
-        }
-
-        if (!this.inSearchMode) {
-          const route = Router.getInstance().getCurrentRoute();
-          if (this.containsRoute(route) &&
-              classifyRoute(route) === RouteState.SECTION) {
-            // Re-fire the showing-section event to trigger settings-main
-            // recalculation of the overscroll, now that sections are not
-            // hidden-by-search.
-            this.fire('showing-section', this.getSection(route.section));
-          }
-        }
-      }
-
-      /**
-       * @param {!Route} route
-       * @return {boolean}
-       * @private
-       */
-      shouldExpandAdvanced_(route) {
-        const routes =
-            /** @type {!MinimumRoutes} */ (Router.getInstance().getRoutes());
-        return this.tagName === 'SETTINGS-BASIC-PAGE' && routes.ADVANCED &&
-            routes.ADVANCED.contains(route);
-      }
-
-      /**
-       * Finds the settings section corresponding to the given route. If the
-       * section is lazily loaded it force-renders it.
-       * Note: If the section resides within "advanced" settings, a
-       * 'hide-container' event is fired (necessary to avoid flashing). Callers
-       * are responsible for firing a 'show-container' event.
-       * @param {!Route} route
-       * @return {!Promise<!HTMLElement>}
-       * @private
-       */
-      ensureSectionForRoute_(route) {
-        const section = this.getSection(route.section);
-        if (section !== null) {
-          return Promise.resolve(section);
-        }
-
-        // The function to use to wait for <dom-if>s to render.
-        const waitFn = beforeNextRender.bind(null, this);
-
-        return new Promise(resolve => {
-          if (this.shouldExpandAdvanced_(route)) {
-            this.fire('hide-container');
-            waitFn(() => {
-              this.$$('#advancedPageTemplate').get().then(() => {
-                resolve(this.getSection(route.section));
-              });
-            });
-          } else {
-            waitFn(() => {
-              resolve(this.getSection(route.section));
-            });
-          }
-        });
-      }
-
-      /**
-       * Finds the settings-section instances corresponding to the given route.
-       * If the section is lazily loaded it force-renders it. Note: If the
-       * section resides within "advanced" settings, a 'hide-container' event is
-       * fired (necessary to avoid flashing). Callers are responsible for firing
-       * a 'show-container' event.
-       * @param {!Route} route
-       * @return {!Promise<!Array<!HTMLElement>>}
-       * @private
-       */
-      ensureSectionsForRoute_(route) {
-        const sections = this.querySettingsSections_(route.section);
-        if (sections.length > 0) {
-          return Promise.resolve(sections);
-        }
-
-        // The function to use to wait for <dom-if>s to render.
-        const waitFn = beforeNextRender.bind(null, this);
-
-        return new Promise(resolve => {
-          if (this.shouldExpandAdvanced_(route)) {
-            this.fire('hide-container');
-            waitFn(() => {
-              this.$$('#advancedPageTemplate').get().then(() => {
-                resolve(this.querySettingsSections_(route.section));
-              });
-            });
-          } else {
-            waitFn(() => {
-              resolve(this.querySettingsSections_(route.section));
-            });
-          }
-        });
-      }
-
-      /**
-       * @param {!Route} route
-       * @private
-       */
-      enterSubpage_(route) {
-        this.lastScrollTop_ = this.scroller.scrollTop;
-        this.scroller.scrollTop = 0;
-        this.classList.add('showing-subpage');
-        this.fire('subpage-expand');
-
-        // Explicitly load the lazy_load.html module, since all subpages reside
-        // in the lazy loaded module.
-        ensureLazyLoaded();
-
-        this.ensureSectionForRoute_(route).then(section => {
-          section.classList.add('expanded');
-          // Fire event used by a11y tests only.
-          this.fire('settings-section-expanded');
-
-          this.fire('show-container');
-        });
-      }
-
-      /**
-       * @param {!Route} oldRoute
-       * @return {!Promise<void>}
-       * @private
-       */
-      enterMainPage_(oldRoute) {
-        const oldSection = this.getSection(oldRoute.section);
-        oldSection.classList.remove('expanded');
-        this.classList.remove('showing-subpage');
-        return new Promise((res, rej) => {
-          requestAnimationFrame(() => {
-            if (Router.getInstance().lastRouteChangeWasPopstate()) {
-              this.scroller.scrollTop = this.lastScrollTop_;
-            }
-            this.fire('showing-main-page');
-            res();
-          });
-        });
-      }
-
-      /**
-       * @param {!Route} route
-       * @private
-       */
-      scrollToSection_(route) {
-        this.ensureSectionForRoute_(route).then(section => {
-          if (!this.inSearchMode) {
-            this.fire('showing-section', section);
-          }
-          this.fire('show-container');
-        });
-      }
-
-      /**
-       * Shows the section(s) corresponding to |newRoute| and hides the
-       * previously |active| section(s), if any.
-       * @param {!Route} newRoute
-       */
-      switchToSections_(newRoute) {
-        this.ensureSectionsForRoute_(newRoute).then(sections => {
-          // Clear any previously |active| section.
-          const oldSections =
-              this.shadowRoot.querySelectorAll(`settings-section[active]`);
-          for (const s of oldSections) {
-            s.toggleAttribute('active', false);
-          }
-
-          for (const s of sections) {
-            s.toggleAttribute('active', true);
-          }
-
-          this.fire('show-container');
-        });
-      }
-
-      /**
-       * Detects which state transition is appropriate for the given new/old
-       * routes.
-       * @param {!Route} newRoute
-       * @param {Route} oldRoute
-       * @private
-       */
-      getStateTransition_(newRoute, oldRoute) {
-        const containsNew = this.containsRoute(newRoute);
-        const containsOld = this.containsRoute(oldRoute);
-
-        if (!containsNew && !containsOld) {
-          // Nothing to do, since none of the old/new routes belong to this
-          // page.
-          return null;
-        }
-
-        // Case where going from |this| page to an unrelated page. For example:
-        //  |this| is settings-basic-page AND
-        //  oldRoute is /searchEngines AND
-        //  newRoute is /help.
-        if (containsOld && !containsNew) {
-          return [classifyRoute(oldRoute), RouteState.TOP_LEVEL];
-        }
-
-        // Case where return from an unrelated page to |this| page. For example:
-        //  |this| is settings-basic-page AND
-        //  oldRoute is /help AND
-        //  newRoute is /searchEngines
-        if (!containsOld && containsNew) {
-          return [RouteState.TOP_LEVEL, classifyRoute(newRoute)];
-        }
-
-        // Case where transitioning between routes that both belong to |this|
-        // page.
-        return [classifyRoute(oldRoute), classifyRoute(newRoute)];
-      }
-
-      /**
-       * @param {!Route} newRoute
-       * @param {Route} oldRoute
-       */
-      currentRouteChanged(newRoute, oldRoute) {
-        const transition = this.getStateTransition_(newRoute, oldRoute);
-        if (transition === null) {
-          return;
-        }
-
-        const oldState = transition[0];
-        const newState = transition[1];
-        assert(this.validTransitions_.get(oldState).has(newState));
-
-        loadTimeData.getBoolean('enableLandingPageRedesign') ?
-            this.processTransitionRedesign_(
-                oldRoute, newRoute, oldState, newState) :
-            this.processTransition_(oldRoute, newRoute, oldState, newState);
-      }
-
-      /**
-       * @param {Route} oldRoute
-       * @param {!Route} newRoute
-       * @param {!RouteState} oldState
-       * @param {!RouteState} newState
-       * @private
-       */
-      processTransition_(oldRoute, newRoute, oldState, newState) {
-        if (oldState === RouteState.TOP_LEVEL) {
-          if (newState === RouteState.SECTION) {
-            this.scrollToSection_(newRoute);
-          } else if (newState === RouteState.SUBPAGE) {
-            this.enterSubpage_(newRoute);
-          }
-          // Nothing to do here for the case of RouteState.DIALOG or TOP_LEVEL.
-          // The latter happens when navigating from '/?search=foo' to '/'
-          // (clearing search results).
-          return;
-        }
-
-        if (oldState === RouteState.SECTION) {
-          if (newState === RouteState.SECTION) {
-            this.scrollToSection_(newRoute);
-          } else if (newState === RouteState.SUBPAGE) {
-            this.enterSubpage_(newRoute);
-          } else if (newState === RouteState.TOP_LEVEL) {
-            this.scroller.scrollTop = 0;
-          }
-          // Nothing to do here for the case of RouteState.DIALOG.
-          return;
-        }
-
-        if (oldState === RouteState.SUBPAGE) {
-          if (newState === RouteState.SECTION) {
-            this.enterMainPage_(/** @type {!Route} */ (oldRoute));
-
-            // Scroll to the corresponding section, only if the user explicitly
-            // navigated to a section (via the menu).
-            if (!Router.getInstance().lastRouteChangeWasPopstate()) {
-              this.scrollToSection_(newRoute);
-            }
-          } else if (newState === RouteState.SUBPAGE) {
-            // Handle case where the two subpages belong to
-            // different sections, but are linked to each other. For example
-            // /storage and /accounts (in ChromeOS).
-            if (!oldRoute.contains(newRoute) && !newRoute.contains(oldRoute)) {
-              this.enterMainPage_(oldRoute).then(() => {
-                this.enterSubpage_(newRoute);
-              });
-              return;
-            }
-
-            // Handle case of subpage to sub-subpage navigation.
-            if (oldRoute.contains(newRoute)) {
-              this.scroller.scrollTop = 0;
-              return;
-            }
-            // When going from a sub-subpage to its parent subpage, scroll
-            // position is automatically restored, because we focus the
-            // sub-subpage entry point.
-          } else if (newState === RouteState.TOP_LEVEL) {
-            this.enterMainPage_(/** @type {!Route} */ (oldRoute));
-          } else if (newState === RouteState.DIALOG) {
-            // The only known case currently for such a transition is from
-            // /syncSetup to /signOut.
-            this.enterMainPage_(/** @type {!Route} */ (oldRoute));
-          }
-          return;
-        }
-
-        if (oldState === RouteState.INITIAL) {
-          if (newState === RouteState.SECTION) {
-            this.scrollToSection_(newRoute);
-          } else if (newState === RouteState.SUBPAGE) {
-            this.enterSubpage_(newRoute);
-          }
-          // Nothing to do here for the case of RouteState.DIALOG and TOP_LEVEL.
-          return;
-        }
-
-        if (oldState === RouteState.DIALOG) {
-          if (newState === RouteState.SUBPAGE) {
-            // The only known case currently for such a transition is from
-            // /signOut to /syncSetup.
-            this.enterSubpage_(newRoute);
-          }
-          // Nothing to do for all other cases.
-        }
-
-        // Nothing to do for when oldState === RouteState.DIALOG.
-      }
-
-      /**
-       * @param {Route} oldRoute
-       * @param {!Route} newRoute
-       * @param {!RouteState} oldState
-       * @param {!RouteState} newState
-       * @private
-       */
-      processTransitionRedesign_(oldRoute, newRoute, oldState, newState) {
-        if (oldState === RouteState.TOP_LEVEL) {
-          if (newState === RouteState.SECTION) {
-            this.switchToSections_(newRoute);
-          } else if (newState === RouteState.SUBPAGE) {
-            this.enterSubpage_(newRoute);
-          } else if (newState === RouteState.TOP_LEVEL) {
-            // Case when navigating from '/?search=foo' to '/' (clearing search
-            // results).
-            this.switchToSections_(TOP_LEVEL_EQUIVALENT_ROUTE);
-          }
-          // Nothing to do here for the case of RouteState.DIALOG.
-          return;
-        }
-
-        if (oldState === RouteState.SECTION) {
-          if (newState === RouteState.SECTION) {
-            this.switchToSections_(newRoute);
-          } else if (newState === RouteState.SUBPAGE) {
-            this.switchToSections_(newRoute);
-            this.enterSubpage_(newRoute);
-          } else if (newState === RouteState.TOP_LEVEL) {
-            this.switchToSections_(TOP_LEVEL_EQUIVALENT_ROUTE);
-            this.scroller.scrollTop = 0;
-          }
-          // Nothing to do here for the case of RouteState.DIALOG.
-          return;
-        }
-
-        if (oldState === RouteState.SUBPAGE) {
-          if (newState === RouteState.SECTION) {
-            this.enterMainPage_(/** @type {!Route} */ (oldRoute));
-            this.switchToSections_(newRoute);
-          } else if (newState === RouteState.SUBPAGE) {
-            // Handle case where the two subpages belong to
-            // different sections, but are linked to each other. For example
-            // /storage and /accounts (in ChromeOS).
-            if (!oldRoute.contains(newRoute) && !newRoute.contains(oldRoute)) {
-              this.enterMainPage_(oldRoute).then(() => {
-                this.enterSubpage_(newRoute);
-              });
-              return;
-            }
-
-            // Handle case of subpage to sub-subpage navigation.
-            if (oldRoute.contains(newRoute)) {
-              this.scroller.scrollTop = 0;
-              return;
-            }
-            // When going from a sub-subpage to its parent subpage, scroll
-            // position is automatically restored, because we focus the
-            // sub-subpage entry point.
-          } else if (newState === RouteState.TOP_LEVEL) {
-            this.enterMainPage_(/** @type {!Route} */ (oldRoute));
-          }
-          return;
-        }
-
-        if (oldState === RouteState.INITIAL) {
-          if ([RouteState.SECTION, RouteState.DIALOG].includes(newState)) {
-            this.switchToSections_(newRoute);
-          } else if (newState === RouteState.SUBPAGE) {
-            this.switchToSections_(newRoute);
-            this.enterSubpage_(newRoute);
-          } else if (newState === RouteState.TOP_LEVEL) {
-            this.switchToSections_(TOP_LEVEL_EQUIVALENT_ROUTE);
-          }
-          return;
-        }
-
-        // Nothing to do for when oldState === RouteState.DIALOG.
-      }
-
-      /**
-       * TODO(dpapad): Rename this to |querySection| to distinguish it from
-       * ensureSectionForRoute_() which force-renders the section as needed.
-       * Helper function to get a section from the local DOM.
-       * @param {string} section Section name of the element to get.
-       * @return {?HTMLElement}
-       */
-      getSection(section) {
-        if (!section) {
-          return null;
-        }
-        return /** @type {?HTMLElement} */ (
-            this.$$(`settings-section[section="${section}"]`));
-      }
-
-      /*
-       * @param {string} sectionName Section name of the element to get.
-       * @return {!Array<!HTMLElement>}
-       */
-      querySettingsSections_(sectionName) {
-        const result = [];
-        const section = this.getSection(sectionName);
-
-        if (section) {
-          result.push(section);
-        }
-
-        const extraSections = this.shadowRoot.querySelectorAll(
-            `settings-section[nest-under-section="${sectionName}"]`);
-        if (extraSections.length > 0) {
-          result.push(...extraSections);
-        }
-        return result;
-      }
-    }
-
-    return MainPageMixin;
-  });
-
-  /** @interface */
-  export class MainPageMixinInterface {
-    /**
-     * @param {Route} route
-     * @return {boolean}
-     */
-    containsRoute(route) {}
-  }
diff --git a/chrome/browser/resources/settings/settings_page/main_page_mixin.ts b/chrome/browser/resources/settings/settings_page/main_page_mixin.ts
new file mode 100644
index 0000000..7934fbe
--- /dev/null
+++ b/chrome/browser/resources/settings/settings_page/main_page_mixin.ts
@@ -0,0 +1,561 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {beforeNextRender, dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {BaseMixin} from '../base_mixin.js';
+import {SettingsIdleLoadElement} from '../controls/settings_idle_load.js';
+import {ensureLazyLoaded} from '../ensure_lazy_loaded.js';
+import {loadTimeData} from '../i18n_setup.js';
+import {routes} from '../route.js';
+import {MinimumRoutes, Route, Router} from '../router.js';
+// clang-format on
+
+/**
+ * A categorization of every possible Settings URL, necessary for implementing
+ * a finite state machine.
+ */
+export enum RouteState {
+  // Initial state before anything has loaded yet.
+  INITIAL = 'initial',
+  // A dialog that has a dedicated URL (e.g. /importData).
+  DIALOG = 'dialog',
+  // A section (basically a scroll position within the top level page, e.g,
+  // /appearance.
+  SECTION = 'section',
+  // A subpage, or sub-subpage e.g, /searchEngins.
+  SUBPAGE = 'subpage',
+  // The top level Settings page, '/'.
+  TOP_LEVEL = 'top-level',
+}
+
+let guestTopLevelRoute = routes.SEARCH;
+// <if expr="chromeos">
+guestTopLevelRoute = routes.PRIVACY;
+// </if>
+
+const TOP_LEVEL_EQUIVALENT_ROUTE: Route =
+    loadTimeData.getBoolean('isGuest') ? guestTopLevelRoute : routes.PEOPLE;
+
+function classifyRoute(route: Route|null): RouteState {
+  if (!route) {
+    return RouteState.INITIAL;
+  }
+  const routes = Router.getInstance().getRoutes() as MinimumRoutes;
+  if (route === routes.BASIC) {
+    return RouteState.TOP_LEVEL;
+  }
+  if (route.isSubpage()) {
+    return RouteState.SUBPAGE;
+  }
+  if (route.isNavigableDialog) {
+    return RouteState.DIALOG;
+  }
+  return RouteState.SECTION;
+}
+
+type Constructor<T> = new (...args: any[]) => T;
+
+/**
+ * Responds to route changes by expanding, collapsing, or scrolling to
+ * sections on the page. Expanded sections take up the full height of the
+ * container. At most one section should be expanded at any given time.
+ */
+export const MainPageMixin = dedupingMixin(
+    <T extends Constructor<PolymerElement>>(superClass: T): T&
+    Constructor<MainPageMixinInterface> => {
+      const superClassBase = BaseMixin(superClass);
+
+      class MainPageMixin extends superClassBase {
+        static get properties() {
+          return {
+            /**
+             * Whether a search operation is in progress or previous search
+             * results are being displayed.
+             */
+            inSearchMode: {
+              type: Boolean,
+              value: false,
+              observer: 'inSearchModeChanged_',
+              reflectToAttribute: true,
+            },
+          };
+        }
+
+        inSearchMode: boolean;
+        scroller: HTMLElement|null = null;
+        private validTransitions_: Map<RouteState, Set<RouteState>>;
+        private lastScrollTop_: number = 0;
+
+        // Populated by Polymer itself.
+        domHost: HTMLElement|null;
+
+        constructor(...args: any[]) {
+          super(...args);
+
+          /**
+           * A map holding all valid state transitions.
+           */
+          this.validTransitions_ = (function() {
+            const allStates = new Set([
+              RouteState.DIALOG,
+              RouteState.SECTION,
+              RouteState.SUBPAGE,
+              RouteState.TOP_LEVEL,
+            ]);
+
+            return new Map([
+              [RouteState.INITIAL, allStates],
+              [
+                RouteState.DIALOG, new Set([
+                  RouteState.SECTION,
+                  RouteState.SUBPAGE,
+                  RouteState.TOP_LEVEL,
+                ])
+              ],
+              [RouteState.SECTION, allStates],
+              [RouteState.SUBPAGE, allStates],
+              [RouteState.TOP_LEVEL, allStates],
+            ]);
+          })();
+        }
+
+        connectedCallback() {
+          this.scroller =
+              this.domHost ? this.domHost.parentElement : document.body;
+
+          // Purposefully calling this after |scroller| has been initialized.
+          super.connectedCallback();
+        }
+
+        /**
+         * Method to be overridden by users of MainPageMixin.
+         * @return Whether the given route is part of |this| page.
+         */
+        containsRoute(_route: Route|null): boolean {
+          return false;
+        }
+
+        private inSearchModeChanged_(_current: boolean, previous: boolean) {
+          if (loadTimeData.getBoolean('enableLandingPageRedesign')) {
+            // No need to deal with overscroll, as only one section is shown at
+            // any given time.
+            return;
+          }
+
+          // Ignore 1st occurrence which happens while the element is being
+          // initialized.
+          if (previous === undefined) {
+            return;
+          }
+
+          if (!this.inSearchMode) {
+            const route = Router.getInstance().getCurrentRoute();
+            if (this.containsRoute(route) &&
+                classifyRoute(route) === RouteState.SECTION) {
+              // Re-fire the showing-section event to trigger settings-main
+              // recalculation of the overscroll, now that sections are not
+              // hidden-by-search.
+              this.fire('showing-section', this.getSection(route.section));
+            }
+          }
+        }
+
+        private shouldExpandAdvanced_(route: Route): boolean {
+          const routes = Router.getInstance().getRoutes() as MinimumRoutes;
+          return this.tagName === 'SETTINGS-BASIC-PAGE' && routes.ADVANCED &&
+              routes.ADVANCED.contains(route);
+        }
+
+        /**
+         * Finds the settings section corresponding to the given route. If the
+         * section is lazily loaded it force-renders it.
+         * Note: If the section resides within "advanced" settings, a
+         * 'hide-container' event is fired (necessary to avoid flashing).
+         * Callers are responsible for firing a 'show-container' event.
+         */
+        private ensureSectionForRoute_(route: Route): Promise<HTMLElement> {
+          const section = this.getSection(route.section);
+          if (section !== null) {
+            return Promise.resolve(section);
+          }
+
+          // The function to use to wait for <dom-if>s to render.
+          const waitFn = beforeNextRender.bind(null, this);
+
+          return new Promise<HTMLElement>(resolve => {
+            if (this.shouldExpandAdvanced_(route)) {
+              this.fire('hide-container');
+              waitFn(() => {
+                this.$$<SettingsIdleLoadElement>('#advancedPageTemplate')!.get()
+                    .then(() => {
+                      resolve(this.getSection(route.section)!);
+                    });
+              });
+            } else {
+              waitFn(() => {
+                resolve(this.getSection(route.section)!);
+              });
+            }
+          });
+        }
+
+        /**
+         * Finds the settings-section instances corresponding to the given
+         * route. If the section is lazily loaded it force-renders it. Note: If
+         * the section resides within "advanced" settings, a 'hide-container'
+         * event is fired (necessary to avoid flashing). Callers are responsible
+         * for firing a 'show-container' event.
+         */
+        private ensureSectionsForRoute_(route: Route):
+            Promise<Array<HTMLElement>> {
+          const sections = this.querySettingsSections_(route.section);
+          if (sections.length > 0) {
+            return Promise.resolve(sections);
+          }
+
+          // The function to use to wait for <dom-if>s to render.
+          const waitFn = beforeNextRender.bind(null, this);
+
+          return new Promise(resolve => {
+            if (this.shouldExpandAdvanced_(route)) {
+              this.fire('hide-container');
+              waitFn(() => {
+                this.$$<SettingsIdleLoadElement>('#advancedPageTemplate')!.get()
+                    .then(() => {
+                      resolve(this.querySettingsSections_(route.section));
+                    });
+              });
+            } else {
+              waitFn(() => {
+                resolve(this.querySettingsSections_(route.section));
+              });
+            }
+          });
+        }
+
+        private enterSubpage_(route: Route) {
+          this.lastScrollTop_ = this.scroller!.scrollTop;
+          this.scroller!.scrollTop = 0;
+          this.classList.add('showing-subpage');
+          this.fire('subpage-expand');
+
+          // Explicitly load the lazy_load.html module, since all subpages
+          // reside in the lazy loaded module.
+          ensureLazyLoaded();
+
+          this.ensureSectionForRoute_(route).then(section => {
+            section.classList.add('expanded');
+            // Fire event used by a11y tests only.
+            this.fire('settings-section-expanded');
+
+            this.fire('show-container');
+          });
+        }
+
+        private enterMainPage_(oldRoute: Route): Promise<void> {
+          const oldSection = this.getSection(oldRoute.section)!;
+          oldSection.classList.remove('expanded');
+          this.classList.remove('showing-subpage');
+          return new Promise((res) => {
+            requestAnimationFrame(() => {
+              if (Router.getInstance().lastRouteChangeWasPopstate()) {
+                this.scroller!.scrollTop = this.lastScrollTop_;
+              }
+              this.fire('showing-main-page');
+              res();
+            });
+          });
+        }
+
+        private scrollToSection_(route: Route) {
+          this.ensureSectionForRoute_(route).then(section => {
+            if (!this.inSearchMode) {
+              this.fire('showing-section', section);
+            }
+            this.fire('show-container');
+          });
+        }
+
+        /**
+         * Shows the section(s) corresponding to |newRoute| and hides the
+         * previously |active| section(s), if any.
+         */
+        private switchToSections_(newRoute: Route) {
+          this.ensureSectionsForRoute_(newRoute).then(sections => {
+            // Clear any previously |active| section.
+            const oldSections =
+                this.shadowRoot!.querySelectorAll(`settings-section[active]`);
+            for (const s of oldSections) {
+              s.toggleAttribute('active', false);
+            }
+
+            for (const s of sections) {
+              s.toggleAttribute('active', true);
+            }
+
+            this.fire('show-container');
+          });
+        }
+
+        /**
+         * Detects which state transition is appropriate for the given new/old
+         * routes.
+         */
+        private getStateTransition_(newRoute: Route, oldRoute: Route|null) {
+          const containsNew = this.containsRoute(newRoute);
+          const containsOld = this.containsRoute(oldRoute);
+
+          if (!containsNew && !containsOld) {
+            // Nothing to do, since none of the old/new routes belong to this
+            // page.
+            return null;
+          }
+
+          // Case where going from |this| page to an unrelated page. For
+          // example:
+          //  |this| is settings-basic-page AND
+          //  oldRoute is /searchEngines AND
+          //  newRoute is /help.
+          if (containsOld && !containsNew) {
+            return [classifyRoute(oldRoute), RouteState.TOP_LEVEL];
+          }
+
+          // Case where return from an unrelated page to |this| page. For
+          // example:
+          //  |this| is settings-basic-page AND
+          //  oldRoute is /help AND
+          //  newRoute is /searchEngines
+          if (!containsOld && containsNew) {
+            return [RouteState.TOP_LEVEL, classifyRoute(newRoute)];
+          }
+
+          // Case where transitioning between routes that both belong to |this|
+          // page.
+          return [classifyRoute(oldRoute), classifyRoute(newRoute)];
+        }
+
+        currentRouteChanged(newRoute: Route, oldRoute: Route|null) {
+          const transition = this.getStateTransition_(newRoute, oldRoute);
+          if (transition === null) {
+            return;
+          }
+
+          const oldState = transition[0];
+          const newState = transition[1];
+          assert(this.validTransitions_.get(oldState)!.has(newState));
+
+          loadTimeData.getBoolean('enableLandingPageRedesign') ?
+              this.processTransitionRedesign_(
+                  oldRoute, newRoute, oldState, newState) :
+              this.processTransition_(oldRoute, newRoute, oldState, newState);
+        }
+
+        private processTransition_(
+            oldRoute: Route|null, newRoute: Route, oldState: RouteState,
+            newState: RouteState) {
+          if (oldState === RouteState.TOP_LEVEL) {
+            if (newState === RouteState.SECTION) {
+              this.scrollToSection_(newRoute);
+            } else if (newState === RouteState.SUBPAGE) {
+              this.enterSubpage_(newRoute);
+            }
+            // Nothing to do here for the case of RouteState.DIALOG or
+            // TOP_LEVEL. The latter happens when navigating from '/?search=foo'
+            // to '/' (clearing search results).
+            return;
+          }
+
+          if (oldState === RouteState.SECTION) {
+            if (newState === RouteState.SECTION) {
+              this.scrollToSection_(newRoute);
+            } else if (newState === RouteState.SUBPAGE) {
+              this.enterSubpage_(newRoute);
+            } else if (newState === RouteState.TOP_LEVEL) {
+              this.scroller!.scrollTop = 0;
+            }
+            // Nothing to do here for the case of RouteState.DIALOG.
+            return;
+          }
+
+          if (oldState === RouteState.SUBPAGE) {
+            if (newState === RouteState.SECTION) {
+              this.enterMainPage_(oldRoute!);
+
+              // Scroll to the corresponding section, only if the user
+              // explicitly navigated to a section (via the menu).
+              if (!Router.getInstance().lastRouteChangeWasPopstate()) {
+                this.scrollToSection_(newRoute);
+              }
+            } else if (newState === RouteState.SUBPAGE) {
+              // Handle case where the two subpages belong to
+              // different sections, but are linked to each other. For example
+              // /storage and /accounts (in ChromeOS).
+              if (!oldRoute!.contains(newRoute) &&
+                  !newRoute.contains(oldRoute!)) {
+                this.enterMainPage_(oldRoute!).then(() => {
+                  this.enterSubpage_(newRoute);
+                });
+                return;
+              }
+
+              // Handle case of subpage to sub-subpage navigation.
+              if (oldRoute!.contains(newRoute)) {
+                this.scroller!.scrollTop = 0;
+                return;
+              }
+              // When going from a sub-subpage to its parent subpage, scroll
+              // position is automatically restored, because we focus the
+              // sub-subpage entry point.
+            } else if (newState === RouteState.TOP_LEVEL) {
+              this.enterMainPage_(oldRoute!);
+            } else if (newState === RouteState.DIALOG) {
+              // The only known case currently for such a transition is from
+              // /syncSetup to /signOut.
+              this.enterMainPage_(oldRoute!);
+            }
+            return;
+          }
+
+          if (oldState === RouteState.INITIAL) {
+            if (newState === RouteState.SECTION) {
+              this.scrollToSection_(newRoute);
+            } else if (newState === RouteState.SUBPAGE) {
+              this.enterSubpage_(newRoute);
+            }
+            // Nothing to do here for the case of RouteState.DIALOG and
+            // TOP_LEVEL.
+            return;
+          }
+
+          if (oldState === RouteState.DIALOG) {
+            if (newState === RouteState.SUBPAGE) {
+              // The only known case currently for such a transition is from
+              // /signOut to /syncSetup.
+              this.enterSubpage_(newRoute);
+            }
+            // Nothing to do for all other cases.
+          }
+
+          // Nothing to do for when oldState === RouteState.DIALOG.
+        }
+
+        private processTransitionRedesign_(
+            oldRoute: Route|null, newRoute: Route, oldState: RouteState,
+            newState: RouteState) {
+          if (oldState === RouteState.TOP_LEVEL) {
+            if (newState === RouteState.SECTION) {
+              this.switchToSections_(newRoute);
+            } else if (newState === RouteState.SUBPAGE) {
+              this.enterSubpage_(newRoute);
+            } else if (newState === RouteState.TOP_LEVEL) {
+              // Case when navigating from '/?search=foo' to '/' (clearing
+              // search results).
+              this.switchToSections_(TOP_LEVEL_EQUIVALENT_ROUTE);
+            }
+            // Nothing to do here for the case of RouteState.DIALOG.
+            return;
+          }
+
+          if (oldState === RouteState.SECTION) {
+            if (newState === RouteState.SECTION) {
+              this.switchToSections_(newRoute);
+            } else if (newState === RouteState.SUBPAGE) {
+              this.switchToSections_(newRoute);
+              this.enterSubpage_(newRoute);
+            } else if (newState === RouteState.TOP_LEVEL) {
+              this.switchToSections_(TOP_LEVEL_EQUIVALENT_ROUTE);
+              this.scroller!.scrollTop = 0;
+            }
+            // Nothing to do here for the case of RouteState.DIALOG.
+            return;
+          }
+
+          if (oldState === RouteState.SUBPAGE) {
+            if (newState === RouteState.SECTION) {
+              this.enterMainPage_(oldRoute!);
+              this.switchToSections_(newRoute);
+            } else if (newState === RouteState.SUBPAGE) {
+              // Handle case where the two subpages belong to
+              // different sections, but are linked to each other. For example
+              // /storage and /accounts (in ChromeOS).
+              if (!oldRoute!.contains(newRoute) &&
+                  !newRoute.contains(oldRoute!)) {
+                this.enterMainPage_(oldRoute!).then(() => {
+                  this.enterSubpage_(newRoute);
+                });
+                return;
+              }
+
+              // Handle case of subpage to sub-subpage navigation.
+              if (oldRoute!.contains(newRoute)) {
+                this.scroller!.scrollTop = 0;
+                return;
+              }
+              // When going from a sub-subpage to its parent subpage, scroll
+              // position is automatically restored, because we focus the
+              // sub-subpage entry point.
+            } else if (newState === RouteState.TOP_LEVEL) {
+              this.enterMainPage_(oldRoute!);
+            }
+            return;
+          }
+
+          if (oldState === RouteState.INITIAL) {
+            if ([RouteState.SECTION, RouteState.DIALOG].includes(newState)) {
+              this.switchToSections_(newRoute);
+            } else if (newState === RouteState.SUBPAGE) {
+              this.switchToSections_(newRoute);
+              this.enterSubpage_(newRoute);
+            } else if (newState === RouteState.TOP_LEVEL) {
+              this.switchToSections_(TOP_LEVEL_EQUIVALENT_ROUTE);
+            }
+            return;
+          }
+
+          // Nothing to do for when oldState === RouteState.DIALOG.
+        }
+
+        /**
+         * TODO(dpapad): Rename this to |querySection| to distinguish it from
+         * ensureSectionForRoute_() which force-renders the section as needed.
+         * Helper function to get a section from the local DOM.
+         * @param section Section name of the element to get.
+         */
+        getSection(section: string): HTMLElement|null {
+          if (!section) {
+            return null;
+          }
+          return this.$$(`settings-section[section="${section}"]`);
+        }
+
+        /*
+         * @param sectionName Section name of the element to get.
+         */
+        private querySettingsSections_(sectionName: string):
+            Array<HTMLElement> {
+          const result = [];
+          const section = this.getSection(sectionName);
+
+          if (section) {
+            result.push(section);
+          }
+
+          const extraSections = this.shadowRoot!.querySelectorAll<HTMLElement>(
+              `settings-section[nest-under-section="${sectionName}"]`);
+          if (extraSections.length > 0) {
+            result.push(...extraSections);
+          }
+          return result;
+        }
+      }
+
+      return MainPageMixin;
+    });
+
+export interface MainPageMixinInterface {
+  containsRoute(route: Route|null): boolean;
+}
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.ts b/chrome/browser/resources/settings/site_settings/all_sites.ts
index 39824b59..992fad9 100644
--- a/chrome/browser/resources/settings/site_settings/all_sites.ts
+++ b/chrome/browser/resources/settings/site_settings/all_sites.ts
@@ -72,16 +72,22 @@
   };
 }
 
-const AllSitesElementBase = mixinBehaviors(
-                                [
-                                  I18nBehavior,
-                                  WebUIListenerBehavior,
-                                ],
-                                GlobalScrollTargetMixin(RouteObserverMixin(
-                                    SiteSettingsMixin(PolymerElement)))) as {
-  new (): PolymerElement & I18nBehavior & WebUIListenerBehavior &
-  SiteSettingsMixinInterface & RouteObserverMixinInterface
-};
+// TODO(crbug.com/1234307): Remove when RouteObserverMixin is converted to
+// TypeScript.
+type Constructor<T> = new (...args: any[]) => T;
+
+const AllSitesElementBase =
+    mixinBehaviors(
+        [
+          I18nBehavior,
+          WebUIListenerBehavior,
+        ],
+        GlobalScrollTargetMixin(
+            RouteObserverMixin(SiteSettingsMixin(PolymerElement)) as unknown as
+            Constructor<PolymerElement>)) as {
+      new (): PolymerElement & I18nBehavior & WebUIListenerBehavior &
+      SiteSettingsMixinInterface & RouteObserverMixinInterface
+    };
 
 class AllSitesElement extends AllSitesElementBase {
   static get is() {
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_list.ts b/chrome/browser/resources/settings/site_settings_page/site_settings_list.ts
index c57768c..322fd1a 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_list.ts
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_list.ts
@@ -192,7 +192,7 @@
    */
   private updateDefaultValueLabel_(
       category: ContentSettingsTypes, setting: ContentSetting) {
-    const element = this.shadowRoot!.querySelector<HTMLElement>(`#${category}`);
+    const element = this.$$<HTMLElement>(`#${category}`);
     if (!element) {
       // |category| is not part of this list.
       return;
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.cc b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.cc
index 7b46e38f4..e6cc6ff 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.cc
@@ -317,7 +317,7 @@
 void ChromeOmniboxNavigationObserver::OnAlternativeLoaderDone(bool success) {
   TRACE_EVENT("omnibox",
               "ChromeOmniboxNavigationObserver::OnAlternativeLoaderDone",
-              "success", success)
+              "success", success);
   if (success) {
     fetch_state_ = AlternativeFetchState::kFetchSucceeded;
   } else {
diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
index 2427e61f..0934b90e 100644
--- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
@@ -279,7 +279,8 @@
 }
 
 // https://crbug.com/1250386
-#if defined(OS_WIN) || defined(OS_MAC)
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    defined(OS_LINUX) && defined(USE_OZONE)
 #define MAYBE_OriginNameTest DISABLED_OriginNameTest
 #else
 #define MAYBE_OriginNameTest OriginNameTest
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_base.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_base.cc
index 3a8d925ea..8832e12b 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_base.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_base.cc
@@ -80,9 +80,6 @@
 
 void PageInfoBubbleViewBase::DidStartNavigation(
     content::NavigationHandle* handle) {
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (handle->IsInPrimaryMainFrame())
     GetWidget()->Close();
 }
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
index 9e8f441..ca20ab7 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
@@ -40,6 +40,7 @@
 #include "content/public/common/referrer.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/prerender_test_util.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/embedded_test_server/http_request.h"
@@ -140,6 +141,11 @@
   PageInfoBubbleViewBrowserTest& operator=(
       const PageInfoBubbleViewBrowserTest& test) = delete;
 
+  void SetUp() override {
+    ASSERT_TRUE(embedded_test_server()->Start());
+    InProcessBrowserTest::SetUp();
+  }
+
   void SetUpOnMainThread() override {
     mock_sentiment_service_ = static_cast<MockTrustSafetySentimentService*>(
         TrustSafetySentimentServiceFactory::GetInstance()
@@ -148,6 +154,10 @@
                 base::BindRepeating(&BuildMockTrustSafetySentimentService)));
   }
 
+  content::WebContents* web_contents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
  protected:
   bool is_page_info_v2_enabled() const { return GetParam(); }
 
@@ -165,17 +175,13 @@
 
   void ExecuteJavaScriptForTests(const std::string& js) {
     base::RunLoop run_loop;
-    browser()
-        ->tab_strip_model()
-        ->GetActiveWebContents()
-        ->GetMainFrame()
-        ->ExecuteJavaScriptForTests(
-            base::ASCIIToUTF16(js),
-            base::BindOnce(
-                [](base::OnceClosure quit_callback, base::Value result) {
-                  std::move(quit_callback).Run();
-                },
-                run_loop.QuitClosure()));
+    web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(
+        base::ASCIIToUTF16(js),
+        base::BindOnce(
+            [](base::OnceClosure quit_callback, base::Value result) {
+              std::move(quit_callback).Run();
+            },
+            run_loop.QuitClosure()));
     run_loop.Run();
   }
 
@@ -291,7 +297,7 @@
   EXPECT_EQ(PageInfoBubbleView::BUBBLE_PAGE_INFO,
             PageInfoBubbleView::GetShownBubbleType());
 
-  browser()->tab_strip_model()->GetActiveWebContents()->Close();
+  web_contents()->Close();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(PageInfoBubbleView::BUBBLE_NONE,
             PageInfoBubbleView::GetShownBubbleType());
@@ -324,11 +330,7 @@
 IN_PROC_BROWSER_TEST_P(PageInfoBubbleViewBrowserTest, ViewSourceURL) {
   ASSERT_TRUE(
       ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
-  browser()
-      ->tab_strip_model()
-      ->GetActiveWebContents()
-      ->GetMainFrame()
-      ->ViewSource();
+  web_contents()->GetMainFrame()->ViewSource();
   OpenPageInfoBubble(browser());
   EXPECT_EQ(PageInfoBubbleView::BUBBLE_INTERNAL_PAGE,
             PageInfoBubbleView::GetShownBubbleType());
@@ -376,7 +378,6 @@
 // SB_THREAT_TYPE_ENTERPRISE_PASSWORD_REUSE threat type.
 IN_PROC_BROWSER_TEST_P(PageInfoBubbleViewBrowserTest,
                        VerifyEnterprisePasswordReusePageInfoBubble) {
-  ASSERT_TRUE(embedded_test_server()->Start());
   base::HistogramTester histograms;
   ASSERT_TRUE(ui_test_utils::NavigateToURL(
       browser(), embedded_test_server()->GetURL("/")));
@@ -386,8 +387,6 @@
   safe_browsing::ChromePasswordProtectionService* service =
       safe_browsing::ChromePasswordProtectionService::
           GetPasswordProtectionService(browser()->profile());
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
   safe_browsing::ReusedPasswordAccountType reused_password_account_type;
   reused_password_account_type.set_account_type(
       safe_browsing::ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
@@ -395,7 +394,7 @@
       reused_password_account_type);
 
   scoped_refptr<safe_browsing::PasswordProtectionRequest> request =
-      safe_browsing::CreateDummyRequest(contents);
+      safe_browsing::CreateDummyRequest(web_contents());
   service->ShowModalWarning(
       request.get(),
       safe_browsing::LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
@@ -409,7 +408,7 @@
       PageInfoViewFactory::VIEW_ID_PAGE_INFO_BUTTON_ALLOWLIST_PASSWORD_REUSE);
 
   SecurityStateTabHelper* helper =
-      SecurityStateTabHelper::FromWebContents(contents);
+      SecurityStateTabHelper::FromWebContents(web_contents());
   std::unique_ptr<security_state::VisibleSecurityState> visible_security_state =
       helper->GetVisibleSecurityState();
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_ENTERPRISE_PASSWORD_REUSE,
@@ -459,7 +458,6 @@
 // SB_THREAT_TYPE_SAVED_PASSWORD_REUSE threat type.
 IN_PROC_BROWSER_TEST_P(PageInfoBubbleViewBrowserTest,
                        VerifySavedPasswordReusePageInfoBubble) {
-  ASSERT_TRUE(embedded_test_server()->Start());
   base::HistogramTester histograms;
   ASSERT_TRUE(ui_test_utils::NavigateToURL(
       browser(), embedded_test_server()->GetURL("/")));
@@ -469,8 +467,6 @@
   safe_browsing::ChromePasswordProtectionService* service =
       safe_browsing::ChromePasswordProtectionService::
           GetPasswordProtectionService(browser()->profile());
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
   safe_browsing::ReusedPasswordAccountType reused_password_account_type;
   reused_password_account_type.set_account_type(
       safe_browsing::ReusedPasswordAccountType::SAVED_PASSWORD);
@@ -478,7 +474,7 @@
       reused_password_account_type);
 
   scoped_refptr<safe_browsing::PasswordProtectionRequest> request =
-      safe_browsing::CreateDummyRequest(contents);
+      safe_browsing::CreateDummyRequest(web_contents());
   service->ShowModalWarning(
       request.get(),
       safe_browsing::LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
@@ -492,7 +488,7 @@
       PageInfoViewFactory::VIEW_ID_PAGE_INFO_BUTTON_ALLOWLIST_PASSWORD_REUSE);
 
   SecurityStateTabHelper* helper =
-      SecurityStateTabHelper::FromWebContents(contents);
+      SecurityStateTabHelper::FromWebContents(web_contents());
   std::unique_ptr<security_state::VisibleSecurityState> visible_security_state =
       helper->GetVisibleSecurityState();
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_SAVED_PASSWORD_REUSE,
@@ -570,9 +566,7 @@
   OpenPageInfoBubble(browser());
   EXPECT_EQ(PageInfoBubbleView::BUBBLE_INTERNAL_PAGE,
             PageInfoBubbleView::GetShownBubbleType());
-  content::NavigateIframeToURL(
-      browser()->tab_strip_model()->GetActiveWebContents(), "test",
-      GetSimplePageUrl());
+  content::NavigateIframeToURL(web_contents(), "test", GetSimplePageUrl());
   // Expect that the bubble is still open even after a subframe navigation has
   // happened.
   EXPECT_EQ(PageInfoBubbleView::BUBBLE_INTERNAL_PAGE,
@@ -850,10 +844,8 @@
 // contents pane.
 IN_PROC_BROWSER_TEST_P(PageInfoBubbleViewBrowserTest,
                        MAYBE_FocusReturnsToContentOnClose) {
-  content::WebContents* const web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  WebContentsFocusTracker web_contents_focus_tracker(web_contents);
-  web_contents->Focus();
+  WebContentsFocusTracker web_contents_focus_tracker(web_contents());
+  web_contents()->Focus();
   web_contents_focus_tracker.WaitForFocus(true);
 
   OpenPageInfoBubble(browser());
@@ -882,12 +874,10 @@
 // before getting back to web contents (see https://crbug.com/910067).
 IN_PROC_BROWSER_TEST_P(PageInfoBubbleViewBrowserTest,
                        MAYBE_FocusDoesNotReturnToContentsOnReloadPrompt) {
-  content::WebContents* const web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  WebContentsFocusTracker web_contents_focus_tracker(web_contents);
+  WebContentsFocusTracker web_contents_focus_tracker(web_contents());
   ViewFocusTracker location_bar_focus_tracker(
       BrowserView::GetBrowserViewForBrowser(browser())->GetLocationBarView());
-  web_contents->Focus();
+  web_contents()->Focus();
   web_contents_focus_tracker.WaitForFocus(true);
 
   OpenPageInfoBubble(browser());
@@ -908,3 +898,43 @@
 INSTANTIATE_TEST_SUITE_P(All,
                          PageInfoBubbleViewBrowserTest,
                          ::testing::Values(false, true));
+
+class PageInfoBubbleViewPrerenderBrowserTest
+    : public PageInfoBubbleViewBrowserTest {
+ public:
+  PageInfoBubbleViewPrerenderBrowserTest()
+      : prerender_helper_(
+            base::BindRepeating(&PageInfoBubbleViewBrowserTest::web_contents,
+                                base::Unretained(this))) {}
+  ~PageInfoBubbleViewPrerenderBrowserTest() override = default;
+
+  void SetUp() override {
+    prerender_helper_.SetUp(embedded_test_server());
+    PageInfoBubbleViewBrowserTest::SetUp();
+  }
+
+ protected:
+  content::test::PrerenderTestHelper prerender_helper_;
+};
+
+IN_PROC_BROWSER_TEST_P(PageInfoBubbleViewPrerenderBrowserTest,
+                       DoesntCloseOnPrerenderNavigate) {
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/simple.html")));
+  EXPECT_EQ(PageInfoBubbleView::BUBBLE_NONE,
+            PageInfoBubbleView::GetShownBubbleType());
+  OpenPageInfoBubble(browser());
+  EXPECT_EQ(PageInfoBubbleView::BUBBLE_PAGE_INFO,
+            PageInfoBubbleView::GetShownBubbleType());
+  // Start a prerender.
+  prerender_helper_.AddPrerender(
+      embedded_test_server()->GetURL("/title1.html"));
+  // Ensure the bubble is still open after prerender navigation.
+  EXPECT_EQ(PageInfoBubbleView::BUBBLE_PAGE_INFO,
+            PageInfoBubbleView::GetShownBubbleType());
+}
+
+// Run tests with kPageInfoV2Desktop flag enabled and disabled.
+INSTANTIATE_TEST_SUITE_P(All,
+                         PageInfoBubbleViewPrerenderBrowserTest,
+                         ::testing::Values(false, true));
diff --git a/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc b/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc
index da09ac36..d096e1e1 100644
--- a/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc
+++ b/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/common/chrome_paths.h"
-#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/common/extension.h"
@@ -97,8 +96,8 @@
     NavigateToURLAndWait(browser(), url);
     AppId app_id = InstallShortcutAppForCurrentUrl();
 
-    absl::optional<int> install_source = GetIntWebAppPref(
-        profile()->GetPrefs(), app_id, kLatestWebAppInstallSource);
+    absl::optional<int> install_source =
+        GetWebAppInstallSource(profile()->GetPrefs(), app_id);
     EXPECT_TRUE(install_source.has_value());
     EXPECT_EQ(static_cast<webapps::WebappInstallSource>(*install_source),
               webapps::WebappInstallSource::MENU_CREATE_SHORTCUT);
diff --git a/chrome/browser/ui/web_applications/web_app_metrics.cc b/chrome/browser/ui/web_applications/web_app_metrics.cc
index bf54cfc..5ea5d701 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics.cc
+++ b/chrome/browser/ui/web_applications/web_app_metrics.cc
@@ -23,7 +23,6 @@
 #include "components/site_engagement/content/engagement_type.h"
 #include "components/site_engagement/content/site_engagement_service.h"
 #include "components/webapps/browser/banners/app_banner_manager.h"
-#include "components/webapps/browser/installable/installable_metrics.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 
@@ -63,16 +62,6 @@
   RecordTabOrWindowHistogram(histogram_prefix, in_window, engagement_type);
 }
 
-optional<int> GetLatestWebAppInstallSource(const AppId& app_id,
-                                           PrefService* prefs) {
-  optional<int> value =
-      GetIntWebAppPref(prefs, app_id, kLatestWebAppInstallSource);
-  DCHECK_GE(value.value_or(0), 0);
-  DCHECK_LT(value.value_or(0),
-            static_cast<int>(webapps::WebappInstallSource::COUNT));
-  return value;
-}
-
 }  // namespace
 
 // static
@@ -334,7 +323,7 @@
     features.start_url = provider->registrar().GetAppStartUrl(app_id);
     features.installed = true;
     features.install_source =
-        GetLatestWebAppInstallSource(app_id, profile_->GetPrefs());
+        GetWebAppInstallSource(profile_->GetPrefs(), app_id);
     DisplayMode display_mode =
         provider->registrar().GetAppEffectiveDisplayMode(app_id);
     features.effective_display_mode = static_cast<int>(display_mode);
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc b/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc
index 57814cb..f668b52 100644
--- a/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc
@@ -35,10 +35,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/policy/profile_policy_connector.h"
+#endif
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_switches.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/policy/profile_policy_connector.h"
 #include "components/user_manager/scoped_user_manager.h"
 #endif
 
@@ -46,22 +49,21 @@
 
 namespace {
 
-#if !BUILDFLAG(IS_CHROMEOS_LACROS)
 constexpr char kUserTypesTestDir[] = "user_types";
-#endif
 
 #if defined(OS_CHROMEOS)
 constexpr char kGoodJsonTestDir[] = "good_json";
-#endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr char kAppAllUrl[] = "https://www.google.com/all";
-constexpr char kAppChildUrl[] = "https://www.google.com/child";
 constexpr char kAppGuestUrl[] = "https://www.google.com/guest";
 constexpr char kAppManagedUrl[] = "https://www.google.com/managed";
 constexpr char kAppUnmanagedUrl[] = "https://www.google.com/unmanaged";
 #endif
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+constexpr char kAppChildUrl[] = "https://www.google.com/child";
+#endif
+
 }  // namespace
 
 class PreinstalledWebAppManagerTest : public testing::Test {
@@ -93,12 +95,9 @@
                                                Profile* profile = nullptr) {
     std::unique_ptr<TestingProfile> testing_profile;
     if (!profile) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if defined(OS_CHROMEOS)
       testing_profile = CreateProfileAndLogin();
       profile = testing_profile.get();
-#elif BUILDFLAG(IS_CHROMEOS_LACROS)
-      testing_profile = CreateProfile();
-      profile = testing_profile.get();
 #else
       NOTREACHED();
 #endif
@@ -144,7 +143,7 @@
     return profile_builder.Build();
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if defined(OS_CHROMEOS)
   // Helper that creates simple test guest profile.
   std::unique_ptr<TestingProfile> CreateGuestProfile() {
     TestingProfile::Builder profile_builder;
@@ -156,10 +155,12 @@
   // This makes profile appears as a primary profile in ChromeOS.
   std::unique_ptr<TestingProfile> CreateProfileAndLogin() {
     std::unique_ptr<TestingProfile> profile = CreateProfile();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     const AccountId account_id(AccountId::FromUserEmailGaiaId(
         profile->GetProfileUserName(), "1234567890"));
     user_manager()->AddUser(account_id);
     user_manager()->LoginUser(account_id);
+#endif
     return profile;
   }
 
@@ -167,8 +168,10 @@
   // manager. This makes profile appears as a primary profile in ChromeOS.
   std::unique_ptr<TestingProfile> CreateGuestProfileAndLogin() {
     std::unique_ptr<TestingProfile> profile = CreateGuestProfile();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     user_manager()->AddGuestUser();
     user_manager()->LoginUser(user_manager()->GetGuestAccountId());
+#endif
     return profile;
   }
 
@@ -178,7 +181,7 @@
     for (const auto& install_options : install_options_list)
       ASSERT_EQ(1u, expectations.count(install_options.install_url));
   }
-#endif
+#endif  // defined(OS_CHROMEOS)
 
   void ExpectHistograms(int enabled, int disabled, int errors) {
     histograms_.ExpectUniqueSample(
@@ -461,6 +464,22 @@
   EXPECT_EQ(0u, app_infos.size());
   ExpectHistograms(/*enabled=*/0, /*disabled=*/2, /*errors=*/0);
 }
+
+TEST_F(PreinstalledWebAppManagerTest, GuestUser) {
+  VerifySetOfApps(CreateGuestProfileAndLogin().get(),
+                  {GURL(kAppAllUrl), GURL(kAppGuestUrl)});
+}
+
+TEST_F(PreinstalledWebAppManagerTest, UnmanagedUser) {
+  VerifySetOfApps(CreateProfileAndLogin().get(),
+                  {GURL(kAppAllUrl), GURL(kAppUnmanagedUrl)});
+}
+
+TEST_F(PreinstalledWebAppManagerTest, ManagedUser) {
+  const auto profile = CreateProfileAndLogin();
+  profile->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true);
+  VerifySetOfApps(profile.get(), {GURL(kAppAllUrl), GURL(kAppManagedUrl)});
+}
 #else
 // No app is expected for non-ChromeOS builds.
 TEST_F(PreinstalledWebAppManagerTest, NoApp) {
@@ -469,33 +488,19 @@
 #endif  // defined(OS_CHROMEOS)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+// TODO(crbug.com/1252273): Enable test for Lacros.
 TEST_F(PreinstalledWebAppManagerTest, ChildUser) {
   const auto profile = CreateProfileAndLogin();
   profile->SetSupervisedUserId(supervised_users::kChildAccountSUID);
   VerifySetOfApps(profile.get(), {GURL(kAppAllUrl), GURL(kAppChildUrl)});
 }
 
-TEST_F(PreinstalledWebAppManagerTest, GuestUser) {
-  VerifySetOfApps(CreateGuestProfileAndLogin().get(),
-                  {GURL(kAppAllUrl), GURL(kAppGuestUrl)});
-}
-
-TEST_F(PreinstalledWebAppManagerTest, ManagedUser) {
-  const auto profile = CreateProfileAndLogin();
-  profile->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true);
-  VerifySetOfApps(profile.get(), {GURL(kAppAllUrl), GURL(kAppManagedUrl)});
-}
-
-TEST_F(PreinstalledWebAppManagerTest, UnmanagedUser) {
-  VerifySetOfApps(CreateProfileAndLogin().get(),
-                  {GURL(kAppAllUrl), GURL(kAppUnmanagedUrl)});
-}
-
 TEST_F(PreinstalledWebAppManagerTest, NonPrimaryProfile) {
   VerifySetOfApps(CreateProfile().get(),
                   {GURL(kAppAllUrl), GURL(kAppUnmanagedUrl)});
 }
 
+// TODO(crbug.com/1252272): Enable extra web apps tests for Lacros.
 TEST_F(PreinstalledWebAppManagerTest, ExtraWebApps) {
   // The extra_web_apps directory contains two JSON files in different named
   // subdirectories. The --extra-web-apps-dir switch should control which
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 61729dd..e0d8cbe 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -40,7 +40,6 @@
 #include "chrome/browser/web_applications/web_application_info.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -208,8 +207,8 @@
   web_app->AddSource(source);
   web_app->SetIsFromSyncAndPendingInstallation(false);
 
-  UpdateIntWebAppPref(profile_->GetPrefs(), app_id, kLatestWebAppInstallSource,
-                      static_cast<int>(options.install_source));
+  UpdateWebAppInstallSource(profile_->GetPrefs(), app_id,
+                            static_cast<int>(options.install_source));
 
   file_handlers_helper_->WillInstallApp(web_app_info);
 
diff --git a/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc
index 235b90f..ea95905 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc
@@ -185,8 +185,7 @@
   FinalizeInstallResult result = AwaitFinalizeInstall(*info, options);
 
   absl::optional<int> install_source =
-      GetIntWebAppPref(profile()->GetPrefs(), result.installed_app_id,
-                       kLatestWebAppInstallSource);
+      GetWebAppInstallSource(profile()->GetPrefs(), result.installed_app_id);
   EXPECT_TRUE(install_source.has_value());
   EXPECT_EQ(static_cast<webapps::WebappInstallSource>(*install_source),
             webapps::WebappInstallSource::INTERNAL_DEFAULT);
diff --git a/chrome/browser/web_applications/web_app_prefs_utils.cc b/chrome/browser/web_applications/web_app_prefs_utils.cc
index 9b8ef85f..62e3ede 100644
--- a/chrome/browser/web_applications/web_app_prefs_utils.cc
+++ b/chrome/browser/web_applications/web_app_prefs_utils.cc
@@ -15,6 +15,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/browser_thread.h"
 #include "services/preferences/public/cpp/dictionary_value_update.h"
 #include "services/preferences/public/cpp/scoped_pref_update.h"
@@ -216,6 +217,26 @@
   web_app_prefs->Remove(path);
 }
 
+absl::optional<int> GetWebAppInstallSource(PrefService* prefs,
+                                           const AppId& app_id) {
+  absl::optional<int> value =
+      GetIntWebAppPref(prefs, app_id, kLatestWebAppInstallSource);
+  DCHECK_GE(value.value_or(0), 0);
+  DCHECK_LT(value.value_or(0),
+            static_cast<int>(webapps::WebappInstallSource::COUNT));
+  return value;
+}
+
+void UpdateWebAppInstallSource(PrefService* prefs,
+                               const AppId& app_id,
+                               int install_source) {
+  DCHECK_GE(install_source, 0);
+  DCHECK_LT(install_source,
+            static_cast<int>(webapps::WebappInstallSource::COUNT));
+  UpdateIntWebAppPref(prefs, app_id, kLatestWebAppInstallSource,
+                      install_source);
+}
+
 void RecordInstallIphIgnored(PrefService* pref_service,
                              const AppId& app_id,
                              base::Time time) {
diff --git a/chrome/browser/web_applications/web_app_prefs_utils.h b/chrome/browser/web_applications/web_app_prefs_utils.h
index e251140e..965e69c 100644
--- a/chrome/browser/web_applications/web_app_prefs_utils.h
+++ b/chrome/browser/web_applications/web_app_prefs_utils.h
@@ -73,6 +73,13 @@
 void WebAppPrefsUtilsRegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry);
 
+absl::optional<int> GetWebAppInstallSource(PrefService* prefs,
+                                           const AppId& app_id);
+
+void UpdateWebAppInstallSource(PrefService* prefs,
+                               const AppId& app_id,
+                               int install_source);
+
 void RecordInstallIphIgnored(PrefService* pref_service,
                              const AppId& app_id,
                              base::Time time);
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index dd205d2..7d331e9 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1632698636-c3516a56f935f3ae726a994fdaad4f491adff7fb.profdata
+chrome-linux-main-1632743903-1532c35d47dab49f28de77cdbc8161508b4173bd.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 4b84bba..bc34c8c 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1632698636-51c2cd6230686b1459abef0abcaa8b802a658e64.profdata
+chrome-mac-main-1632722301-a892c31a95e7069d32436dcf24e7c8398296f61f.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 9a54061..62eb06a 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1632698636-26ed7605ab2dc8abc363c8c6fb92aca8c9412fac.profdata
+chrome-win32-main-1632733038-54f3d4b03c5c3f67de8f63c0ae179afc34d9cd39.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 1582cf5..cebddd2e 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1632698636-62df3ec3d383304eaafde294f9f1ad4d4f23d2fe.profdata
+chrome-win64-main-1632733038-326cf0884ab554ce1a5d23a1aed0f2f61f7009ca.profdata
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index fdeeaf8..6c7305c 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-14243.0.0
\ No newline at end of file
+14245.0.0
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/record_time.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/record_time.js
index c746547..20fe625 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/record_time.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/record_time.js
@@ -35,7 +35,7 @@
 
     /**
      * @const {?MaxTimeOption}
-     * @private
+     * @protected
      */
     this.maxTimeOption_ = maxTimeOption || null;
 
diff --git a/chromeos/components/camera_app_ui/resources/tsconfig.json b/chromeos/components/camera_app_ui/resources/tsconfig.json
index 5fa54ed..4e47884ea 100644
--- a/chromeos/components/camera_app_ui/resources/tsconfig.json
+++ b/chromeos/components/camera_app_ui/resources/tsconfig.json
@@ -18,7 +18,7 @@
     "js/init.js",
     "js/main.js",
     "js/models/barcode_worker.js",
-    "js/models/mp4_video_processor.js",
+    "js/models/ffmpeg/video_processor.js",
     "js/test_bridge.js",
     "js/untrusted_ga_helper.js",
     "js/untrusted_script_loader.js",
diff --git a/chromeos/services/ime/BUILD.gn b/chromeos/services/ime/BUILD.gn
index f3cf4219..6fc7712 100644
--- a/chromeos/services/ime/BUILD.gn
+++ b/chromeos/services/ime/BUILD.gn
@@ -25,6 +25,7 @@
 
   deps = [
     ":constants",
+    "//ash/constants",
     "//base",
     "//chromeos/services/ime/public/cpp/shared_lib:interfaces",
   ]
diff --git a/chromeos/services/ime/ime_decoder.cc b/chromeos/services/ime/ime_decoder.cc
index 0c8141d..195c336 100644
--- a/chromeos/services/ime/ime_decoder.cc
+++ b/chromeos/services/ime/ime_decoder.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/services/ime/ime_decoder.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -58,6 +59,10 @@
 }  // namespace
 
 ImeDecoder::ImeDecoder() : status_(Status::kUninitialized) {
+  if (!base::FeatureList::IsEnabled(chromeos::features::kImeMojoDecoder)) {
+    return;
+  }
+
   if (g_fake_decoder_entry_points_for_testing) {
     entry_points_ = *g_fake_decoder_entry_points_for_testing;
     status_ = Status::kSuccess;
diff --git a/chromeos/services/ime/ime_sandbox_hook.cc b/chromeos/services/ime/ime_sandbox_hook.cc
index 8b6f3ed..832d81d 100644
--- a/chromeos/services/ime/ime_sandbox_hook.cc
+++ b/chromeos/services/ime/ime_sandbox_hook.cc
@@ -74,6 +74,9 @@
                                options);
 
   // Try to load IME decoder shared library by creating its instance.
+  // TODO(crbug.com/1217513): This is not ideal, as it means rule-based
+  // input methods will unnecessarily load the IME decoder shared library.
+  // Either remove this line, or use a separate sandbox for rule-based.
   ImeDecoder::GetInstance();
   instance->EngageNamespaceSandboxIfPossible();
   return true;
diff --git a/chromeos/services/ime/ime_service.cc b/chromeos/services/ime/ime_service.cc
index b5eff7ee..f7f998b 100644
--- a/chromeos/services/ime/ime_service.cc
+++ b/chromeos/services/ime/ime_service.cc
@@ -78,6 +78,11 @@
     mojo::PendingRemote<mojom::InputChannel> from_engine,
     const std::vector<uint8_t>& extra,
     ConnectToImeEngineCallback callback) {
+  if (!base::FeatureList::IsEnabled(chromeos::features::kImeMojoDecoder)) {
+    std::move(callback).Run(/*bound=*/false);
+    return;
+  }
+
   // There can only be one client using the decoder at any time. There are two
   // possible clients: NativeInputMethodEngine (for physical keyboard) and the
   // XKB extension (for virtual keyboard). The XKB extension may try to
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc
index 9406a8e..c8cebd7 100644
--- a/chromeos/settings/cros_settings_names.cc
+++ b/chromeos/settings/cros_settings_names.cc
@@ -210,37 +210,6 @@
 const char kReportRunningKioskApp[] =
     "cros.device_status.report_running_kiosk_app";
 
-const char* const kDeviceReportingSettings[] = {
-    kReportDeviceVersionInfo,
-    kReportDeviceActivityTimes,
-    kReportDeviceAudioStatus,
-    kReportDeviceBoardStatus,
-    kReportDeviceBootMode,
-    kReportDeviceCpuInfo,
-    kReportDeviceTimezoneInfo,
-    kReportDeviceMemoryInfo,
-    kReportDeviceBacklightInfo,
-    kReportDeviceLocation,
-    kReportDeviceNetworkConfiguration,
-    kReportDeviceNetworkInterfaces,
-    kReportDeviceNetworkStatus,
-    kReportDevicePowerStatus,
-    kReportDeviceStorageStatus,
-    kReportDeviceUsers,
-    kReportDeviceHardwareStatus,
-    kReportDeviceSessionStatus,
-    kReportDeviceGraphicsStatus,
-    kReportDeviceCrashReportInfo,
-    kReportOsUpdateStatus,
-    kReportRunningKioskApp,
-    kReportDeviceAppInfo,
-    kReportDeviceBluetoothInfo,
-    kReportDeviceFanInfo,
-    kReportDeviceVpdInfo,
-    kReportDeviceSystemInfo,
-    kReportDevicePrintJobs,
-    kReportDeviceLoginLogout};
-
 // How frequently device status reports are uploaded, in milliseconds.
 const char kReportUploadFrequency[] =
     "cros.device_status.report_upload_frequency";
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h
index 58a59c7..3f91560 100644
--- a/chromeos/settings/cros_settings_names.h
+++ b/chromeos/settings/cros_settings_names.h
@@ -133,9 +133,6 @@
 COMPONENT_EXPORT(CHROMEOS_SETTINGS)
 extern const char kReportDeviceLoginLogout[];
 
-COMPONENT_EXPORT(CHROMEOS_SETTINGS)
-extern const char* const kDeviceReportingSettings[];
-
 COMPONENT_EXPORT(CHROMEOS_SETTINGS) extern const char kHeartbeatEnabled[];
 COMPONENT_EXPORT(CHROMEOS_SETTINGS) extern const char kHeartbeatFrequency[];
 
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index a41f149..ae17721 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -44,10 +44,6 @@
 const base::Feature kEnableUsap{"ArcEnableUsap",
                                 base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls whether ARC apps can share to Web Apps through WebAPKs and TWAs.
-const base::Feature kEnableWebAppShareFeature{"ArcEnableWebAppShare",
-                                              base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Controls experimental file picker feature for ARC.
 const base::Feature kFilePickerExperimentFeature{
     "ArcFilePickerExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index 781372e..d0b1172 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -23,7 +23,6 @@
 extern const base::Feature kEnableUnifiedAudioFocusFeature;
 extern const base::Feature kEnableUnmanagedToManagedTransitionFeature;
 extern const base::Feature kEnableUsap;
-extern const base::Feature kEnableWebAppShareFeature;
 extern const base::Feature kFilePickerExperimentFeature;
 extern const base::Feature kImageCopyPasteCompatFeature;
 extern const base::Feature kKeyboardShortcutHelperIntegrationFeature;
diff --git a/components/arc/intent_helper/arc_intent_helper_bridge.cc b/components/arc/intent_helper/arc_intent_helper_bridge.cc
index 9c67756..1d806bc 100644
--- a/components/arc/intent_helper/arc_intent_helper_bridge.cc
+++ b/components/arc/intent_helper/arc_intent_helper_bridge.cc
@@ -17,7 +17,6 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
-#include "components/arc/arc_features.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/audio/arc_audio_bridge.h"
 #include "components/arc/intent_helper/control_camera_app_delegate.h"
@@ -362,14 +361,6 @@
 void ArcIntentHelperBridge::OnOpenAppWithIntent(
     const GURL& start_url,
     arc::mojom::LaunchIntentPtr intent) {
-  // Fall-back to the previous behavior where the web app opens without any
-  // share data.
-  if (!base::FeatureList::IsEnabled(arc::kEnableWebAppShareFeature)) {
-    if (intent->data)
-      OnOpenWebApp(intent->data->spec());
-    return;
-  }
-
   // Web app launches should only be invoked on HTTPS URLs.
   if (CanOpenWebAppForUrl(start_url)) {
     RecordOpenType(ArcIntentHelperOpenType::WEB_APP);
diff --git a/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc b/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
index c5a229e2..df2d6700 100644
--- a/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
+++ b/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
@@ -9,10 +9,9 @@
 #include <utility>
 #include <vector>
 
+#include "base/files/file_path.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "components/arc/arc_features.h"
 #include "components/arc/intent_helper/intent_constants.h"
 #include "components/arc/intent_helper/open_url_delegate.h"
 #include "components/arc/mojom/intent_helper.mojom.h"
@@ -416,59 +415,33 @@
 
 // Tests that OnOpenAppWithIntents opens only HTTPS URLs.
 TEST_F(ArcIntentHelperTest, TestOnOpenAppWithIntent) {
-  {
-    // When the feature is enabled, open the Intent through the delegate.
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitAndEnableFeature(arc::kEnableWebAppShareFeature);
-    base::HistogramTester histograms;
+  base::HistogramTester histograms;
 
-    auto intent = mojom::LaunchIntent::New();
-    intent->action = arc::kIntentActionSend;
-    intent->extra_text = "Foo";
-    instance_->OnOpenAppWithIntent(GURL("https://www.google.com"),
-                                   std::move(intent));
-    EXPECT_EQ(GURL("https://www.google.com"),
-              test_open_url_delegate_->TakeLastOpenedUrl());
-    EXPECT_EQ("Foo",
-              test_open_url_delegate_->TakeLastOpenedIntent()->extra_text);
-    histograms.ExpectBucketCount("Arc.IntentHelper.OpenAppWithIntentAction",
-                                 2 /* OpenIntentAction::kSend */, 1);
+  auto intent = mojom::LaunchIntent::New();
+  intent->action = arc::kIntentActionSend;
+  intent->extra_text = "Foo";
+  instance_->OnOpenAppWithIntent(GURL("https://www.google.com"),
+                                 std::move(intent));
+  EXPECT_EQ(GURL("https://www.google.com"),
+            test_open_url_delegate_->TakeLastOpenedUrl());
+  EXPECT_EQ("Foo", test_open_url_delegate_->TakeLastOpenedIntent()->extra_text);
+  histograms.ExpectBucketCount("Arc.IntentHelper.OpenAppWithIntentAction",
+                               2 /* OpenIntentAction::kSend */, 1);
 
-    instance_->OnOpenAppWithIntent(GURL("http://www.google.com"),
-                                   mojom::LaunchIntent::New());
-    EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
-    EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
+  instance_->OnOpenAppWithIntent(GURL("http://www.google.com"),
+                                 mojom::LaunchIntent::New());
+  EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
+  EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
 
-    instance_->OnOpenAppWithIntent(GURL("http://localhost:8000/foo"),
-                                   mojom::LaunchIntent::New());
-    EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
-    EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
+  instance_->OnOpenAppWithIntent(GURL("http://localhost:8000/foo"),
+                                 mojom::LaunchIntent::New());
+  EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
+  EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
 
-    instance_->OnOpenAppWithIntent(GURL("chrome://settings"),
-                                   mojom::LaunchIntent::New());
-    EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
-    EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
-  }
-  {
-    // When the feature is disabled, open the Intent's URL through the delegate.
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitAndDisableFeature(arc::kEnableWebAppShareFeature);
-
-    auto intent = mojom::LaunchIntent::New();
-    intent->data = GURL("https://www.google.com/maps");
-    instance_->OnOpenAppWithIntent(GURL("https://www.google.com"),
-                                   std::move(intent));
-    EXPECT_EQ(GURL("https://www.google.com/maps"),
-              test_open_url_delegate_->TakeLastOpenedUrl());
-    EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
-
-    intent = mojom::LaunchIntent::New();
-    intent->data = GURL("chrome://settings");
-    instance_->OnOpenAppWithIntent(GURL("https://www.google.com"),
-                                   std::move(intent));
-    EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
-    EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
-  }
+  instance_->OnOpenAppWithIntent(GURL("chrome://settings"),
+                                 mojom::LaunchIntent::New());
+  EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
+  EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
 }
 
 // Tests that AppendStringToIntentHelperPackageName works.
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc b/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
index af37c50..e6b33838 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
@@ -168,6 +168,10 @@
       // Name with multiple middle names.
       {"George Walker Junior Bush", "", "George", "Walker Junior", "Bush", "",
        "", "Bush"},
+      // Name with a middle name initial.
+      {"George W Bush", "", "George", "W", "Bush", "", "", "Bush"},
+      // Name with a middle name initial.
+      {"George W. Bush", "", "George", "W.", "Bush", "", "", "Bush"},
       // Name with a single middle name.
       {"George Walker Bush", "", "George", "Walker", "Bush", "", "", "Bush"},
       // Name without names.
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
index 5182966..5030c17 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
@@ -126,7 +126,7 @@
   EXPECT_EQ(1, no_expiry_strike_database_->GetStrikes());
 
   // Advance clock very far into the future.
-  test_clock.Advance(base::TimeDelta::FromDays(INT_MAX));
+  test_clock.Advance(base::TimeDelta::Max());
 
   no_expiry_strike_database_->RemoveExpiredStrikes();
 
diff --git a/components/autofill_assistant/browser/DEPS b/components/autofill_assistant/browser/DEPS
index 4220b59c..e1b3844 100644
--- a/components/autofill_assistant/browser/DEPS
+++ b/components/autofill_assistant/browser/DEPS
@@ -30,3 +30,9 @@
   "+ui/base/l10n/l10n_util.h",
   "+ui/events/keycodes",
 ]
+
+specific_include_rules = {
+  ".*_unittest\.cc": [
+    "+third_party/blink/public/common/features.h",
+  ]
+}
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index ee17116..39d4b3d 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -286,9 +286,6 @@
   // string.
   virtual std::string GetEmailAddressForAccessTokenAccount() const = 0;
 
-  // Returns the locale for the current device or platform.
-  virtual std::string GetLocale() const = 0;
-
   // Sets or updates contextual information.
   // Passing nullptr clears the contextual information.
   virtual void SetDetails(std::unique_ptr<Details> details,
diff --git a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
index 0e5e499..b616b6a 100644
--- a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
+++ b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
@@ -447,9 +447,15 @@
     FillStatusDetailsWithError(
         required_field, element_click_status.proto_status(), &client_status_);
 
-    // Fallback failed: we stop the script without checking the other fields.
-    std::move(status_update_callback_)
-        .Run(ErrorStatusWithDefault(client_status_));
+    // Main element to click does not exist. We either continue or stop the
+    // script without checking the other fields.
+    if (required_field.proto.is_optional() &&
+        element_click_status.proto_status() == ELEMENT_RESOLUTION_FAILED) {
+      std::move(set_next_field).Run();
+    } else {
+      std::move(status_update_callback_)
+          .Run(ErrorStatusWithDefault(client_status_));
+    }
     return;
   }
 
@@ -473,8 +479,14 @@
     base::TimeDelta wait_time) {
   total_wait_time_ += wait_time;
   if (!find_element_status.ok()) {
+    // We're looking for the option element to click, if it cannot be found,
+    // change the error status to reflect that.
     FillStatusDetailsWithError(
-        required_field, find_element_status.proto_status(), &client_status_);
+        required_field,
+        find_element_status.proto_status() == ELEMENT_RESOLUTION_FAILED
+            ? OPTION_VALUE_NOT_FOUND
+            : find_element_status.proto_status(),
+        &client_status_);
 
     // Fallback failed: we stop the script without checking the other fields.
     std::move(status_update_callback_)
diff --git a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc
index f4b5bd8..3bba006 100644
--- a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc
+++ b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc
@@ -631,6 +631,48 @@
       }));
 }
 
+TEST_F(RequiredFieldsFallbackHandlerTest, SkipsOptionalCustomDropdown) {
+  EXPECT_CALL(mock_web_controller_, GetFieldValue(_, _)).Times(0);
+  EXPECT_CALL(mock_web_controller_, SetValueAttribute(_, _, _)).Times(0);
+  Selector expected_main_selector({"#card_expiry"});
+  EXPECT_CALL(mock_action_delegate_, FindElement(expected_main_selector, _))
+      .WillOnce(
+          RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+  EXPECT_CALL(mock_web_controller_, ClickOrTapElement(ClickType::TAP, _, _))
+      .Times(0);
+
+  std::vector<RequiredField> required_fields = {
+      CreateRequiredField(57, {"#card_expiry"})};
+  *required_fields[0].proto.mutable_option_element_to_click() =
+      ToSelectorProto(".option");
+  required_fields[0].proto.set_is_optional(true);
+
+  std::map<field_formatter::Key, std::string> fallback_values = {
+      {field_formatter::Key(
+           autofill::ServerFieldType::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR),
+       "05/2050"}};
+
+  RequiredFieldsFallbackHandler fallback_handler(
+      required_fields, fallback_values, &mock_action_delegate_);
+  fallback_handler.CheckAndFallbackRequiredFields(
+      OkClientStatus(), base::BindOnce([](const ClientStatus& status) {
+        EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
+        ASSERT_EQ(
+            status.details().autofill_error_info().autofill_field_error_size(),
+            1);
+        EXPECT_EQ(status.details()
+                      .autofill_error_info()
+                      .autofill_field_error(0)
+                      .value_expression(),
+                  "${57}");
+        EXPECT_EQ(status.details()
+                      .autofill_error_info()
+                      .autofill_field_error(0)
+                      .status(),
+                  ELEMENT_RESOLUTION_FAILED);
+      }));
+}
+
 TEST_F(RequiredFieldsFallbackHandlerTest, CustomDropdownClicksStopOnError) {
   EXPECT_CALL(mock_web_controller_, GetFieldValue(_, _)).Times(0);
   EXPECT_CALL(mock_web_controller_, SetValueAttribute(_, _, _)).Times(0);
@@ -672,6 +714,19 @@
   fallback_handler.CheckAndFallbackRequiredFields(
       OkClientStatus(), base::BindOnce([](const ClientStatus& status) {
         EXPECT_EQ(status.proto_status(), AUTOFILL_INCOMPLETE);
+        ASSERT_EQ(
+            status.details().autofill_error_info().autofill_field_error_size(),
+            1);
+        EXPECT_EQ(status.details()
+                      .autofill_error_info()
+                      .autofill_field_error(0)
+                      .value_expression(),
+                  "${57}");
+        EXPECT_EQ(status.details()
+                      .autofill_error_info()
+                      .autofill_field_error(0)
+                      .status(),
+                  OPTION_VALUE_NOT_FOUND);
       }));
 }
 
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 13b48a9..c60c78bea 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -129,7 +129,6 @@
   MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
   MOCK_CONST_METHOD0(GetWebController, WebController*());
   MOCK_CONST_METHOD0(GetEmailAddressForAccessTokenAccount, std::string());
-  MOCK_CONST_METHOD0(GetLocale, std::string());
   MOCK_METHOD2(SetDetails,
                void(std::unique_ptr<Details> details, base::TimeDelta delay));
   MOCK_METHOD2(AppendDetails,
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 8a17973d..259bcbdf 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -158,14 +158,10 @@
   return client_->GetEmailAddressForAccessTokenAccount();
 }
 
-std::string Controller::GetLocale() {
-  return client_->GetLocale();
-}
-
 std::string Controller::GetDisplayStringsLocale() {
   if (GetSettings().display_strings_locale.empty()) {
     // Fallback locale
-    return GetLocale();
+    return client_->GetLocale();
   }
   return GetSettings().display_strings_locale;
 }
@@ -2037,9 +2033,6 @@
 
 void Controller::DidStartNavigation(
     content::NavigationHandle* navigation_handle) {
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (!navigation_handle->IsInPrimaryMainFrame() ||
       navigation_handle->IsSameDocument()) {
     return;
@@ -2056,12 +2049,8 @@
     return;
   }
 
-  bool is_user_initiated_or_back_forward =
-      !navigation_handle->IsRendererInitiated() ||
-      navigation_handle->GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK;
-
   if (state_ == AutofillAssistantState::STOPPED &&
-      is_user_initiated_or_back_forward &&
+      !navigation_handle->IsRendererInitiated() &&
       !navigation_handle->WasServerRedirect()) {
     if (can_recover_from_stopped_) {
       // Usually when in STOPPED (e.g. through |OnScriptError|) the
@@ -2089,24 +2078,23 @@
   //  In the last two cases, autofill assistant might still give up later on if
   //  it discovers that the new page has no scripts.
   //
-  // Everything else, such as going back to a previous page (whether
-  // user-initiated or javascript-initiated), or refreshing the page is
-  // considered an end condition. If going back to a previous page is required,
-  // consider using the BROWSE state instead.
+  // Everything else, such as going back to a previous page, or refreshing the
+  // page is considered an end condition. If going back to a previous page is
+  // required, consider using the BROWSE state instead.
   if (state_ == AutofillAssistantState::PROMPT &&
       web_contents()->GetLastCommittedURL().is_valid() &&
       !navigation_handle->WasServerRedirect() &&
-      is_user_initiated_or_back_forward) {
+      !navigation_handle->IsRendererInitiated()) {
     OnNavigationShutdownOrError(navigation_handle->GetURL(),
                                 Metrics::DropOutReason::NAVIGATION);
     return;
   }
 
-  // When in RUNNING state, all renderer initiated navigation except
-  // back/forward is allowed, user initiated navigation will cause an error.
+  // When in RUNNING state, all renderer initiated navigation is allowed,
+  // user initiated navigation will cause an error.
   if (state_ == AutofillAssistantState::RUNNING &&
       !navigation_handle->WasServerRedirect() &&
-      is_user_initiated_or_back_forward) {
+      !navigation_handle->IsRendererInitiated()) {
     OnNavigationShutdownOrError(
         navigation_handle->GetURL(),
         Metrics::DropOutReason::NAVIGATION_WHILE_RUNNING);
@@ -2121,9 +2109,6 @@
     content::NavigationHandle* navigation_handle) {
   // TODO(b/159871774): Rethink how we handle navigation events. The early
   // return here may prevent us from updating |navigating_to_new_document_|.
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (!navigation_handle->IsInPrimaryMainFrame() ||
       navigation_handle->IsSameDocument() ||
       !navigation_handle->HasCommitted() || !IsNavigatingToNewDocument()) {
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 8fc4022e..3a7cb447 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -122,7 +122,6 @@
   WebsiteLoginManager* GetWebsiteLoginManager() override;
   content::WebContents* GetWebContents() override;
   std::string GetEmailAddressForAccessTokenAccount() override;
-  std::string GetLocale() override;
 
   void SetTouchableElementArea(const ElementAreaProto& area) override;
   void SetStatusMessage(const std::string& message) override;
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 148b0ed..576f7b2 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -38,6 +38,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "net/http/http_status_code.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/common/features.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace autofill_assistant {
@@ -95,14 +96,14 @@
 
 class ControllerTest : public testing::Test {
  public:
-  ControllerTest() = default;
+  ControllerTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kAutofillAssistantChromeEntry);
+  }
 
   void SetUp() override {
     web_contents_ = content::WebContentsTester::CreateTestWebContents(
         &browser_context_, nullptr);
-
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kAutofillAssistantChromeEntry);
     auto web_controller = std::make_unique<NiceMock<MockWebController>>();
     mock_web_controller_ = web_controller.get();
     auto service = std::make_unique<NiceMock<MockService>>();
@@ -1780,39 +1781,6 @@
   content::NavigationSimulator::GoBack(web_contents());
 }
 
-TEST_F(ControllerTest, PromptStateStopsOnRendererInitiatedBack) {
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable")
-      ->mutable_presentation()
-      ->set_autostart(true);
-  ActionsResponseProto runnable_script;
-  auto* prompt = runnable_script.add_actions()->mutable_prompt();
-  prompt->set_browse_mode(false);
-  prompt->add_choices()->mutable_chip()->set_text("continue");
-  SetupActionsForScript("runnable", runnable_script);
-  std::string response_str;
-  script_response.SerializeToString(&response_str);
-  EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
-      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
-
-  Start("http://example.com/");
-  EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
-
-  SimulateNavigateToUrl(GURL("http://b.example.com/"));
-  EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
-
-  SimulateNavigateToUrl(GURL("http://c.example.com/"));
-  EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
-
-  // Go back, emulating a history navigation initiated from JS.
-  EXPECT_CALL(mock_client_, RecordDropOut(Metrics::DropOutReason::NAVIGATION));
-  SetLastCommittedUrl(GURL("http://b.example.com"));
-  content::NavigationSimulator::CreateHistoryNavigation(
-      -1, web_contents(), true /* is_renderer_initiated */)
-      ->Commit();
-}
-
 TEST_F(ControllerTest, UnexpectedNavigationDuringPromptAction_Tracking) {
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "runnable");
@@ -3348,4 +3316,53 @@
   controller_->OnInputTextFocusChanged(false);
 }
 
+class ControllerPrerenderTest : public ControllerTest {
+ public:
+  ControllerPrerenderTest() {
+    feature_list_.InitWithFeatures(
+        {blink::features::kPrerender2},
+        // Disable the memory requirement of Prerender2 so the test can run on
+        // any bot.
+        {blink::features::kPrerender2MemoryControls});
+  }
+
+  ~ControllerPrerenderTest() override = default;
+
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(ControllerPrerenderTest, SuccessfulNavigation) {
+  EXPECT_FALSE(controller_->IsNavigatingToNewDocument());
+  EXPECT_FALSE(controller_->HasNavigationError());
+
+  NavigationStateChangeListener listener(controller_.get());
+  controller_->AddNavigationListener(&listener);
+
+  content::NavigationSimulator::NavigateAndCommitFromDocument(
+      GURL("http://initialurl.com"), web_contents()->GetMainFrame());
+
+  EXPECT_THAT(
+      listener.events,
+      ElementsAre(
+          NavigationState{/* navigating= */ true, /* has_errors= */ false},
+          NavigationState{/* navigating= */ false, /* has_errors= */ false}));
+
+  listener.events.clear();
+
+  // Start prerendering a page.
+  const GURL prerendering_url("http://initialurl.com?prerendering");
+  auto simulator = content::WebContentsTester::For(web_contents())
+                       ->AddPrerenderAndStartNavigation(prerendering_url);
+  EXPECT_FALSE(controller_->IsNavigatingToNewDocument());
+  EXPECT_FALSE(controller_->HasNavigationError());
+
+  simulator->Commit();
+  EXPECT_FALSE(controller_->IsNavigatingToNewDocument());
+  EXPECT_FALSE(controller_->HasNavigationError());
+
+  controller_->RemoveNavigationListener(&listener);
+
+  EXPECT_THAT(listener.events, IsEmpty());
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index a3d18dca..e7ccd6c 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -58,10 +58,6 @@
   return std::string();
 }
 
-std::string FakeScriptExecutorDelegate::GetLocale() {
-  return "en-US";
-}
-
 bool FakeScriptExecutorDelegate::EnterState(AutofillAssistantState state) {
   if (GetState() == state)
     return false;
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h
index 975a6e3..9a676db1 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -40,7 +40,6 @@
   WebsiteLoginManager* GetWebsiteLoginManager() override;
   content::WebContents* GetWebContents() override;
   std::string GetEmailAddressForAccessTokenAccount() override;
-  std::string GetLocale() override;
   bool EnterState(AutofillAssistantState state) override;
   void SetTouchableElementArea(const ElementAreaProto& element) override;
   void SetStatusMessage(const std::string& message) override;
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 3d986ba..840dbfd 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -650,10 +650,6 @@
   return delegate_->GetEmailAddressForAccessTokenAccount();
 }
 
-std::string ScriptExecutor::GetLocale() const {
-  return delegate_->GetLocale();
-}
-
 void ScriptExecutor::SetDetails(std::unique_ptr<Details> details,
                                 base::TimeDelta delay) {
   return delegate_->SetDetails(std::move(details), delay);
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 270ba216..d061f734 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -225,7 +225,6 @@
   ElementStore* GetElementStore() const override;
   WebController* GetWebController() const override;
   std::string GetEmailAddressForAccessTokenAccount() const override;
-  std::string GetLocale() const override;
   void SetDetails(std::unique_ptr<Details> details,
                   base::TimeDelta delay) override;
   void AppendDetails(std::unique_ptr<Details> details,
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h
index 4222ce5..ebf2f2d 100644
--- a/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -66,7 +66,6 @@
   virtual WebsiteLoginManager* GetWebsiteLoginManager() = 0;
   virtual content::WebContents* GetWebContents() = 0;
   virtual std::string GetEmailAddressForAccessTokenAccount() = 0;
-  virtual std::string GetLocale() = 0;
 
   // Enters the given state. Returns true if the state was changed.
   virtual bool EnterState(AutofillAssistantState state) = 0;
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc
index b3cd1ea8..b2eb64f 100644
--- a/components/autofill_assistant/browser/starter.cc
+++ b/components/autofill_assistant/browser/starter.cc
@@ -191,9 +191,6 @@
 
 void Starter::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (!navigation_handle->IsInPrimaryMainFrame()) {
     return;
   }
diff --git a/components/autofill_assistant/browser/starter_unittest.cc b/components/autofill_assistant/browser/starter_unittest.cc
index afc3d6c..84494947 100644
--- a/components/autofill_assistant/browser/starter_unittest.cc
+++ b/components/autofill_assistant/browser/starter_unittest.cc
@@ -37,6 +37,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "net/http/http_status_code.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/common/features.h"
 
 namespace autofill_assistant {
 
@@ -61,21 +62,7 @@
 
 class StarterTest : public testing::Test {
  public:
-  StarterTest() = default;
-
-  void SetUp() override {
-    web_contents_ = content::WebContentsTester::CreateTestWebContents(
-        &browser_context_, nullptr);
-    ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
-    SimulateNavigateToUrl(GURL(kExampleDeeplink));
-    PrepareTriggerScriptUiDelegate();
-    PrepareTriggerScriptRequestSender();
-    fake_platform_delegate_.website_login_manager_ =
-        &mock_website_login_manager_;
-    ON_CALL(mock_website_login_manager_, GetLoginsForUrl)
-        .WillByDefault(
-            RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>()));
-
+  StarterTest() {
     // Must be initialized before |starter_| is instantiated to take effect.
     enable_fake_heuristic_ = std::make_unique<base::test::ScopedFeatureList>();
     enable_fake_heuristic_->InitAndEnableFeatureWithParameters(
@@ -92,6 +79,20 @@
             ]
           }
           )"}});
+  }
+
+  void SetUp() override {
+    web_contents_ = content::WebContentsTester::CreateTestWebContents(
+        &browser_context_, nullptr);
+    ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
+    SimulateNavigateToUrl(GURL(kExampleDeeplink));
+    PrepareTriggerScriptUiDelegate();
+    PrepareTriggerScriptRequestSender();
+    fake_platform_delegate_.website_login_manager_ =
+        &mock_website_login_manager_;
+    ON_CALL(mock_website_login_manager_, GetLoginsForUrl)
+        .WillByDefault(
+            RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>()));
 
     starter_ = std::make_unique<Starter>(
         web_contents(), &fake_platform_delegate_, &ukm_recorder_,
@@ -2037,4 +2038,61 @@
   task_environment.RunUntilIdle();
 }
 
+class StarterPrerenderTest : public StarterTest {
+ public:
+  StarterPrerenderTest() {
+    feature_list_.InitWithFeatures(
+        {blink::features::kPrerender2},
+        // Disable the memory requirement of Prerender2 so the test can run on
+        // any bot.
+        {blink::features::kPrerender2MemoryControls});
+  }
+  ~StarterPrerenderTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(StarterPrerenderTest, DoNotAffectRecordUkmDuringPrendering) {
+  SetupPlatformDelegateForFirstTimeUser();
+
+  fake_platform_delegate_.feature_module_installed_ = true;
+  // Empty callback to keep the onboarding open indefinitely.
+  fake_platform_delegate_.on_show_onboarding_callback_ =
+      base::DoNothing::Once<base::OnceCallback<void(bool, OnboardingResult)>>();
+
+  EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0);
+
+  TriggerContext::Options options;
+  options.initial_url = kExampleDeeplink;
+  std::map<std::string, std::string> script_parameters = {
+      {"ENABLED", "true"},
+      {"START_IMMEDIATELY", "false"},
+      {"REQUEST_TRIGGER_SCRIPT", "true"},
+      {"ORIGINAL_DEEPLINK", kExampleDeeplink}};
+
+  SimulateNavigateToUrl(GURL("https://www.different.com"));
+
+  // Trigger scripts wait for navigation to the deeplink domain.
+  starter_->Start(std::make_unique<TriggerContext>(
+      std::make_unique<ScriptParameters>(script_parameters), options));
+
+  // Start prerendering a page.
+  const GURL prerendering_url("https://www.different.com/prerendering");
+  auto* prerender_rfh = content::WebContentsTester::For(web_contents())
+                            ->AddPrerenderAndCommitNavigation(prerendering_url);
+  ASSERT_TRUE(prerender_rfh);
+
+  // Prerendering should not affect any trigger script's behaviour and not
+  // record anything.
+  EXPECT_THAT(GetUkmTriggerScriptStarted(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmTriggerScriptFinished(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
+  histogram_tester_.ExpectUniqueSample(
+      "Android.AutofillAssistant.FeatureModuleInstallation",
+      Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 0u);
+  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
+                                     0u);
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
index 3a2849ee..935bd6ce 100644
--- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
+++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -344,9 +344,6 @@
   // - not in the main frame.
   // - document does not change (e.g., same page history navigation).
   // - WebContents stays at the existing URL (e.g., downloads).
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (!is_checking_trigger_conditions_ ||
       !navigation_handle->IsInPrimaryMainFrame() ||
       navigation_handle->IsSameDocument() ||
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
index 1b11cc3..ed6ec81 100644
--- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
+++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
@@ -30,6 +30,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "net/http/http_status_code.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/common/features.h"
 
 namespace autofill_assistant {
 
@@ -38,6 +39,7 @@
 using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
 using ::testing::Eq;
+using ::testing::IsEmpty;
 using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::UnorderedElementsAre;
@@ -1455,4 +1457,71 @@
           {navigation_ids_[0], {{kTriggerConditionTimingMs, 300}}}}));
 }
 
+TEST_F(TriggerScriptCoordinatorTest, RecordIfPrimaryPageFailed) {
+  GetTriggerScriptsResponseProto response;
+  response.add_trigger_scripts();
+  std::string serialized_response;
+  response.SerializeToString(&serialized_response);
+  EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+
+  coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
+                      mock_callback_.Get());
+
+  // Start prerendering a page.
+  EXPECT_CALL(mock_callback_,
+              Run(Metrics::TriggerScriptFinishedState::NAVIGATION_ERROR, _, _))
+      .Times(1);
+  auto simulator = content::NavigationSimulator::CreateBrowserInitiated(
+      GURL(kFakeDeepLink), web_contents());
+  simulator->Fail(net::ERR_TIMED_OUT);
+  simulator->CommitErrorPage();
+
+  // UKM should not be recorded by the prerendering's fail response.
+  EXPECT_THAT(GetUkmTriggerScriptFinished(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0],
+                    {Metrics::TriggerScriptFinishedState::NAVIGATION_ERROR,
+                     TriggerScriptProto::UNSPECIFIED_TRIGGER_UI_TYPE}}})));
+}
+
+class TriggerScriptCoordinatorPrerenderTest
+    : public TriggerScriptCoordinatorTest {
+ public:
+  TriggerScriptCoordinatorPrerenderTest() {
+    feature_list_.InitWithFeatures(
+        {blink::features::kPrerender2},
+        // Disable the memory requirement of Prerender2 so the test can run on
+        // any bot.
+        {blink::features::kPrerender2MemoryControls});
+  }
+
+  ~TriggerScriptCoordinatorPrerenderTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(TriggerScriptCoordinatorPrerenderTest, DoNotRecordIfPrerenderingFailed) {
+  GetTriggerScriptsResponseProto response;
+  response.add_trigger_scripts();
+  std::string serialized_response;
+  response.SerializeToString(&serialized_response);
+  EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+
+  EXPECT_CALL(mock_callback_, Run).Times(0);
+  coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
+                      mock_callback_.Get());
+
+  // Start prerendering a page.
+  auto simulator = content::WebContentsTester::For(web_contents())
+                       ->AddPrerenderAndStartNavigation(GURL(kFakeDeepLink));
+  simulator->Fail(net::ERR_TIMED_OUT);
+  simulator->CommitErrorPage();
+
+  // UKM should not be recorded by the prerendering's fail response.
+  EXPECT_THAT(GetUkmTriggerScriptFinished(ukm_recorder_), IsEmpty());
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc
index c5384cd..2f14dfb8 100644
--- a/components/autofill_assistant/browser/web/web_controller.cc
+++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -135,8 +135,13 @@
 // See |WebController::OnSelectOptionJavascriptResult| for result handling.
 const char* const kSelectOptionScript =
     R"(function(re2, valueSourceAttribute, caseSensitive, strict) {
-      if (this.options == null) return -1;
-      const regexp = RegExp(re2, caseSensitive ? '' : 'i');
+      if (this.options == null) return 31; // INVALID_TARGET
+      let regexp;
+      try {
+        regexp = RegExp(re2, caseSensitive ? '' : 'i');
+      } catch (e) {
+        return 11; // INVALID_ACTION
+      }
       let numResults = 0;
       let newIndex = -1;
       for (let i = 0; i < this.options.length; ++i) {
@@ -148,14 +153,17 @@
           }
         }
       }
-      if (numResults == 1 || (numResults > 1 && !strict)) {
+      if (numResults === 0) {
+        return 16; // OPTION_VALUE_NOT_FOUND
+      }
+      if (numResults == 1 || !strict) {
         this.options.selectedIndex = newIndex;
         const e = document.createEvent('HTMLEvents');
         e.initEvent('change', true, true);
         this.dispatchEvent(e);
-        return 1;
+        return 2; // ACTION_APPLIED
       }
-      return numResults;
+      return 30; // TOO_MANY_OPTION_VALUES_FOUND
     })";
 
 // Javascript to select the option element in a select element. This does *not*
@@ -163,14 +171,14 @@
 // See |WebController::OnSelectOptionJavascriptResult| for result handling.
 const char* const kSelectOptionElementScript =
     R"(function(option) {
-      if (this.options == null) return -1;
+      if (this.options == null) return 31; // INVALID_TARGET
       for (let i = 0; i < this.options.length; ++i) {
         if (this.options[i] === option) {
           this.options.selectedIndex = i;
-          return 1;
+          return 2; // ACTION_APPLIED
         }
       }
-      return 0;
+      return 16; // OPTION_VALUE_NOT_FOUND
     })";
 
 // Javascript to check the option element in a select element against an
@@ -178,8 +186,11 @@
 // See |WebController::OnSelectOptionJavascriptResult| for result handling.
 const char* const kCheckOptionElementScript =
     R"(function(option) {
-      if (this.options == null) return -1;
-      return (this.options[this.options.selectedIndex] === option) ? 1 : 0;
+      if (this.options == null) return 31; // INVALID_TARGET
+      if (this.options[this.options.selectedIndex] === option) {
+        return 2; // ACTION_APPLIED
+      }
+      return 26; // ELEMENT_MISMATCH
     })";
 
 // Javascript to highlight an element.
@@ -1137,8 +1148,7 @@
                      weak_ptr_factory_.GetWeakPtr(),
                      base::BindOnce(&DecorateWebControllerStatus,
                                     WebControllerErrorInfoProto::SELECT_OPTION,
-                                    std::move(callback)),
-                     /* status_if_false= */ OPTION_VALUE_NOT_FOUND));
+                                    std::move(callback))));
 }
 
 void WebController::SelectOptionElement(
@@ -1160,8 +1170,7 @@
           weak_ptr_factory_.GetWeakPtr(),
           base::BindOnce(&DecorateWebControllerStatus,
                          WebControllerErrorInfoProto::SELECT_OPTION_ELEMENT,
-                         std::move(callback)),
-          /* status_if_false= */ OPTION_VALUE_NOT_FOUND));
+                         std::move(callback))));
 }
 
 void WebController::CheckSelectedOptionElement(
@@ -1183,13 +1192,11 @@
           weak_ptr_factory_.GetWeakPtr(),
           base::BindOnce(&DecorateWebControllerStatus,
                          WebControllerErrorInfoProto::CHECK_OPTION_ELEMENT,
-                         std::move(callback)),
-          /* status_if_false= */ ELEMENT_MISMATCH));
+                         std::move(callback))));
 }
 
 void WebController::OnSelectOptionJavascriptResult(
     base::OnceCallback<void(const ClientStatus&)> callback,
-    ProcessedActionStatusProto status_if_zero,
     const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   ClientStatus status =
@@ -1198,25 +1205,14 @@
     std::move(callback).Run(status);
     return;
   }
-  int int_result;
-  if (!SafeGetIntValue(result->GetResult(), &int_result)) {
+  int status_result;
+  if (!SafeGetIntValue(result->GetResult(), &status_result)) {
     std::move(callback).Run(
         UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
     return;
   }
-  if (int_result < 0) {
-    std::move(callback).Run(ClientStatus(INVALID_TARGET));
-    return;
-  }
-  if (int_result == 0) {
-    std::move(callback).Run(ClientStatus(status_if_zero));
-    return;
-  }
-  if (int_result > 1) {
-    std::move(callback).Run(ClientStatus(TOO_MANY_OPTION_VALUES_FOUND));
-    return;
-  }
-  std::move(callback).Run(OkClientStatus());
+  std::move(callback).Run(
+      ClientStatus(static_cast<ProcessedActionStatusProto>(status_result)));
 }
 
 void WebController::HighlightElement(
diff --git a/components/autofill_assistant/browser/web/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h
index 75c52ab..782b6e4 100644
--- a/components/autofill_assistant/browser/web/web_controller.h
+++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -510,14 +510,9 @@
       const autofill::FormData& form_data,
       const autofill::FormFieldData& form_field);
   // Handling a JS result for a "SelectOption" action. This expects the JS
-  // result to contain an integer and returns the following status:
-  // * -1 -> INVALID_TARGET
-  // *  0 -> OPTION_ELEMENT_NOT_FOUND
-  // *  1 -> ACTION_APPLIED
-  // *  n -> TOO_MANY_OPTION_VALUES_FOUND
+  // result to contain an integer mapped to a ClientStatus.
   void OnSelectOptionJavascriptResult(
       base::OnceCallback<void(const ClientStatus&)> callback,
-      ProcessedActionStatusProto status_if_zero,
       const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void SendKeyEvents(WebControllerErrorInfoProto::WebAction web_action,
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
index 6285614..7044656 100644
--- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -1711,6 +1711,13 @@
                          /* strict= */ true)
                 .proto_status());
 
+  // Selecting with an invalid regular expression.
+  EXPECT_EQ(INVALID_ACTION,
+            SelectOption(selector, "*",
+                         /* case_sensitive= */ false, SelectOptionProto::LABEL,
+                         /* strict= */ true)
+                .proto_status());
+
   // Fails if no comparison attribute is set.
   EXPECT_EQ(INVALID_ACTION,
             SelectOption(selector, "one", /* case_sensitive= */ false,
diff --git a/components/embedder_support/user_agent_utils_unittest.cc b/components/embedder_support/user_agent_utils_unittest.cc
index caa4fbd2..9e96b58e 100644
--- a/components/embedder_support/user_agent_utils_unittest.cc
+++ b/components/embedder_support/user_agent_utils_unittest.cc
@@ -23,7 +23,7 @@
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "third_party/re2/src/re2/re2.h"
 
-#if defined(USE_X11) || defined(USE_OZONE)
+#if defined(USE_OZONE)
 #include <sys/utsname.h>
 #endif
 
@@ -128,7 +128,7 @@
   ASSERT_LE(0, value);
   ASSERT_TRUE(base::StringToInt(pieces[2], &value));
   ASSERT_LE(0, value);
-#elif defined(USE_X11) || defined(USE_OZONE)
+#elif defined(USE_OZONE)
   // X11; Linux x86_64
   // X11; CrOS armv7l 4537.56.0
   struct utsname unixinfo;
diff --git a/components/password_manager/content/browser/form_submission_tracker_util.cc b/components/password_manager/content/browser/form_submission_tracker_util.cc
index c5fc3c17..3631d1b 100644
--- a/components/password_manager/content/browser/form_submission_tracker_util.cc
+++ b/components/password_manager/content/browser/form_submission_tracker_util.cc
@@ -17,15 +17,12 @@
 
   // Password manager is interested in
   // - form submission navigations,
-  // - any JavaScript initiated navigations besides history navigations, because
-  //   many form submissions are done with JavaScript.
-  // Password manager is not interested in
+  // - any JavaScript initiated navigations, because many form submissions are
+  // done with JavaScript. Password manager is not interested in
   // - browser initiated navigations (e.g. reload, bookmark click),
   // - hyperlink navigations.
-  // - session history navigations
   bool form_may_be_submitted =
       is_renderer_initiated &&
-      !(transition & ui::PAGE_TRANSITION_FORWARD_BACK) &&
       (ui::PageTransitionCoreTypeIs(transition,
                                     ui::PAGE_TRANSITION_FORM_SUBMIT) ||
        !was_initiated_by_link_click);
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 936de2f..75353eb 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -514,6 +514,8 @@
     "mock_smart_bubble_stats_store.h",
     "password_manager_test_utils.cc",
     "password_manager_test_utils.h",
+    "site_affiliation/fake_affiliation_service.cc",
+    "site_affiliation/fake_affiliation_service.h",
     "site_affiliation/mock_affiliation_fetcher_factory.cc",
     "site_affiliation/mock_affiliation_fetcher_factory.h",
     "site_affiliation/mock_affiliation_service.cc",
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
index deb423e..a5b61da47 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <utility>
 
-#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/threading/sequenced_task_runner_handle.h"
@@ -57,72 +56,6 @@
   }
 }
 
-void AffiliatedMatchHelper::InjectAffiliationAndBrandingInformation(
-    std::vector<std::unique_ptr<PasswordForm>> forms,
-    AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
-    PasswordFormsCallback result_callback) {
-  std::vector<PasswordForm*> android_credentials;
-  for (const auto& form : forms) {
-    if (IsValidAndroidCredential(PasswordFormDigest(*form)))
-      android_credentials.push_back(form.get());
-  }
-  base::OnceClosure on_get_all_realms(
-      base::BindOnce(std::move(result_callback), std::move(forms)));
-  base::RepeatingClosure barrier_closure = base::BarrierClosure(
-      android_credentials.size(), std::move(on_get_all_realms));
-  for (auto* form : android_credentials) {
-    affiliation_service_->GetAffiliationsAndBranding(
-        FacetURI::FromPotentiallyInvalidSpec(form->signon_realm),
-        strategy_on_cache_miss,
-        base::BindOnce(&AffiliatedMatchHelper::
-                           CompleteInjectAffiliationAndBrandingInformation,
-                       weak_ptr_factory_.GetWeakPtr(), base::Unretained(form),
-                       barrier_closure));
-  }
-}
-
-void AffiliatedMatchHelper::CompleteInjectAffiliationAndBrandingInformation(
-    PasswordForm* form,
-    base::OnceClosure barrier_closure,
-    const AffiliatedFacets& results,
-    bool success) {
-  const FacetURI facet_uri(
-      FacetURI::FromPotentiallyInvalidSpec(form->signon_realm));
-
-  // Facet can also be web URI, in this case we do nothing.
-  if (!success || !facet_uri.IsValidAndroidFacetURI()) {
-    std::move(barrier_closure).Run();
-    return;
-  }
-
-  // Inject branding information into the form (e.g. the Play Store name and
-  // icon URL). We expect to always find a matching facet URI in the results.
-  auto facet = base::ranges::find(results, facet_uri, &Facet::uri);
-
-  DCHECK(facet != results.end());
-  form->app_display_name = facet->branding_info.name;
-  form->app_icon_url = facet->branding_info.icon_url;
-
-  // Inject the affiliated web realm into the form, if available. In case
-  // multiple web realms are available, this will always choose the first
-  // available web realm for injection.
-  auto affiliated_facet = std::find_if(
-      results.begin(), results.end(), [](const Facet& affiliated_facet) {
-        return affiliated_facet.uri.IsValidWebFacetURI();
-      });
-  if (affiliated_facet != results.end())
-    form->affiliated_web_realm = affiliated_facet->uri.canonical_spec() + "/";
-
-  std::move(barrier_closure).Run();
-}
-
-// static
-bool AffiliatedMatchHelper::IsValidAndroidCredential(
-    const PasswordFormDigest& form) {
-  return form.scheme == PasswordForm::Scheme::kHtml &&
-         IsValidAndroidFacetURI(form.signon_realm);
-}
-
 // static
 bool AffiliatedMatchHelper::IsValidWebCredential(
     const PasswordFormDigest& form) {
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
index 3398170..305b8112 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
@@ -43,9 +43,6 @@
   using AffiliatedRealmsCallback =
       base::OnceCallback<void(const std::vector<std::string>&)>;
 
-  using PasswordFormsCallback =
-      base::OnceCallback<void(std::vector<std::unique_ptr<PasswordForm>>)>;
-
   // The |password_store| must outlive |this|. Both arguments must be non-NULL,
   // except in tests which do not Initialize() the object.
   AffiliatedMatchHelper(PasswordStore* password_store,
@@ -65,21 +62,6 @@
       const PasswordFormDigest& observed_form,
       AffiliatedRealmsCallback result_callback);
 
-  // Retrieves affiliation and branding information about the Android
-  // credentials in |forms|, sets |affiliated_web_realm|, |app_display_name| and
-  // |app_icon_url| of forms, and invokes |result_callback|.
-  // NOTE: When |strategy_on_cache_miss| is set to |FAIL|, this will not issue
-  // an on-demand network request. And if a request to cache fails, no
-  // affiliation and branding information will be injected into corresponding
-  // form.
-  virtual void InjectAffiliationAndBrandingInformation(
-      std::vector<std::unique_ptr<PasswordForm>> forms,
-      AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
-      PasswordFormsCallback result_callback);
-
-  // Returns whether or not |form| represents an Android credential.
-  static bool IsValidAndroidCredential(const PasswordFormDigest& form);
-
   // Returns whether or not |form| represents a valid Web credential for the
   // purposes of affiliation-based matching.
   static bool IsValidWebCredential(const PasswordFormDigest& form);
@@ -92,6 +74,8 @@
   static constexpr base::TimeDelta kInitializationDelayOnStartup =
       base::TimeDelta::FromSeconds(8);
 
+  AffiliationService* get_affiliation_service() { return affiliation_service_; }
+
  private:
   // Reads all autofillable credentials from the password store and starts
   // observing the store for future changes.
@@ -106,17 +90,6 @@
       const AffiliatedFacets& results,
       bool success);
 
-  // Called back by AffiliationService to supply the list of facets
-  // affiliated with the Android credential in |form|. Injects affiliation and
-  // branding information by setting |affiliated_web_realm|, |app_display_name|
-  // and |app_icon_url| on |form| if |success| is true and |results| is
-  // non-empty. Invokes |barrier_closure|.
-  void CompleteInjectAffiliationAndBrandingInformation(
-      PasswordForm* form,
-      base::OnceClosure barrier_closure,
-      const AffiliatedFacets& results,
-      bool success);
-
   // PasswordStoreInterface::Observer:
   void OnLoginsChanged(PasswordStoreInterface* store,
                        const PasswordStoreChangeList& changes) override;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index db5b339b..f0c62e8 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -298,19 +298,6 @@
     return last_result_realms_;
   }
 
-  std::vector<std::unique_ptr<PasswordForm>>
-  InjectAffiliationAndBrandingInformation(
-      std::vector<std::unique_ptr<PasswordForm>> forms) {
-    expecting_result_callback_ = true;
-    match_helper()->InjectAffiliationAndBrandingInformation(
-        std::move(forms), AffiliationService::StrategyOnCacheMiss::FAIL,
-        base::BindOnce(&AffiliatedMatchHelperTest::OnFormsCallback,
-                       base::Unretained(this)));
-    RunUntilIdle();
-    EXPECT_FALSE(expecting_result_callback_);
-    return std::move(last_result_forms_);
-  }
-
   void DestroyMatchHelper() { match_helper_.reset(); }
 
   TestPasswordStore* password_store() { return password_store_.get(); }
@@ -329,12 +316,6 @@
     last_result_realms_ = affiliated_realms;
   }
 
-  void OnFormsCallback(std::vector<std::unique_ptr<PasswordForm>> forms) {
-    EXPECT_TRUE(expecting_result_callback_);
-    expecting_result_callback_ = false;
-    last_result_forms_.swap(forms);
-  }
-
   // testing::Test:
   void SetUp() override {
     mock_affiliation_service_ = std::make_unique<
@@ -358,7 +339,6 @@
   base::ScopedMockTimeMessageLoopTaskRunner mock_time_task_runner_;
 
   std::vector<std::string> last_result_realms_;
-  std::vector<std::unique_ptr<PasswordForm>> last_result_forms_;
   bool expecting_result_callback_ = false;
 
   scoped_refptr<TestPasswordStore> password_store_ =
@@ -436,83 +416,6 @@
               testing::IsEmpty());
 }
 
-// Verifies that InjectAffiliationAndBrandingInformation() injects the realms of
-// web sites affiliated with the given Android application into the password
-// forms, as well as branding information corresponding to the application, if
-// any.
-TEST_P(AffiliatedMatchHelperTest, InjectAffiliationAndBrandingInformation) {
-  std::vector<std::unique_ptr<PasswordForm>> forms;
-
-  forms.push_back(std::make_unique<PasswordForm>(
-      GetTestAndroidCredentials(kTestAndroidRealmAlpha3)));
-  mock_affiliation_service()
-      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
-          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
-          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
-
-  forms.push_back(std::make_unique<PasswordForm>(
-      GetTestAndroidCredentials(kTestAndroidRealmBeta2)));
-  mock_affiliation_service()
-      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
-          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
-          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
-
-  forms.push_back(std::make_unique<PasswordForm>(
-      GetTestAndroidCredentials(kTestAndroidRealmBeta3)));
-  mock_affiliation_service()
-      ->ExpectCallToGetAffiliationsAndBrandingAndSucceedWithResult(
-          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
-          StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
-
-  forms.push_back(std::make_unique<PasswordForm>(
-      GetTestAndroidCredentials(kTestAndroidRealmGamma)));
-  mock_affiliation_service()
-      ->ExpectCallToGetAffiliationsAndBrandingAndEmulateFailure(
-          FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma),
-          StrategyOnCacheMiss::FAIL);
-
-  PasswordFormDigest digest =
-      GetTestObservedWebForm(kTestWebRealmBeta1, nullptr);
-  PasswordForm web_form;
-  web_form.scheme = digest.scheme;
-  web_form.signon_realm = digest.signon_realm;
-  web_form.url = digest.url;
-  forms.push_back(std::make_unique<PasswordForm>(web_form));
-
-  size_t expected_form_count = forms.size();
-  std::vector<std::unique_ptr<PasswordForm>> results(
-      InjectAffiliationAndBrandingInformation(std::move(forms)));
-  ASSERT_EQ(expected_form_count, results.size());
-  EXPECT_THAT(results[0]->affiliated_web_realm,
-              testing::AnyOf(kTestWebRealmAlpha1, kTestWebRealmAlpha2));
-  EXPECT_EQ(kTestAndroidFacetNameAlpha3, results[0]->app_display_name);
-  EXPECT_EQ(kTestAndroidFacetIconURLAlpha3,
-            results[0]->app_icon_url.possibly_invalid_spec());
-  EXPECT_THAT(results[1]->affiliated_web_realm,
-              testing::Eq(kTestWebRealmBeta1));
-  EXPECT_EQ(kTestAndroidFacetNameBeta2, results[1]->app_display_name);
-  EXPECT_EQ(kTestAndroidFacetIconURLBeta2,
-            results[1]->app_icon_url.possibly_invalid_spec());
-  EXPECT_THAT(results[2]->affiliated_web_realm,
-              testing::Eq(kTestWebRealmBeta1));
-  EXPECT_EQ(kTestAndroidFacetNameBeta3, results[2]->app_display_name);
-  EXPECT_EQ(kTestAndroidFacetIconURLBeta3,
-            results[2]->app_icon_url.possibly_invalid_spec());
-  EXPECT_THAT(results[3]->affiliated_web_realm, testing::IsEmpty());
-  EXPECT_THAT(results[4]->affiliated_web_realm, testing::IsEmpty());
-}
-
-// Note: IsValidWebCredential() is tested as part of
-// GetAffiliatedAndroidAndWebRealms tests above.
-TEST_P(AffiliatedMatchHelperTest, IsValidAndroidCredential) {
-  EXPECT_FALSE(AffiliatedMatchHelper::IsValidAndroidCredential(
-      GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)));
-  PasswordFormDigest android_credential(
-      GetTestAndroidCredentials(kTestAndroidRealmBeta2));
-  EXPECT_TRUE(
-      AffiliatedMatchHelper::IsValidAndroidCredential(android_credential));
-}
-
 // Verifies that affiliations for Android applications with pre-existing
 // credentials on start-up are prefetched.
 TEST_P(
diff --git a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
index e19facd..e9d7b80 100644
--- a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
@@ -15,6 +15,11 @@
 MockAffiliatedMatchHelper::MockAffiliatedMatchHelper()
     : AffiliatedMatchHelper(nullptr, nullptr) {}
 
+MockAffiliatedMatchHelper::MockAffiliatedMatchHelper(
+    PasswordStore* password_store,
+    AffiliationService* affiliation_service)
+    : AffiliatedMatchHelper(password_store, affiliation_service) {}
+
 MockAffiliatedMatchHelper::~MockAffiliatedMatchHelper() = default;
 
 void MockAffiliatedMatchHelper::ExpectCallToGetAffiliatedAndroidRealms(
@@ -24,14 +29,6 @@
       .WillOnce(testing::Return(results_to_return));
 }
 
-void MockAffiliatedMatchHelper::
-    ExpectCallToInjectAffiliationAndBrandingInformation(
-        const std::vector<AffiliationAndBrandingInformation>&
-            results_to_inject) {
-  EXPECT_CALL(*this, OnInjectAffiliationAndBrandingInformationCalled())
-      .WillOnce(testing::Return(results_to_inject));
-}
-
 void MockAffiliatedMatchHelper::GetAffiliatedAndroidAndWebRealms(
     const PasswordFormDigest& observed_form,
     AffiliatedRealmsCallback result_callback) {
@@ -40,24 +37,4 @@
   std::move(result_callback).Run(affiliated_android_realms);
 }
 
-void MockAffiliatedMatchHelper::InjectAffiliationAndBrandingInformation(
-    std::vector<std::unique_ptr<PasswordForm>> forms,
-    AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
-    PasswordFormsCallback result_callback) {
-  const std::vector<AffiliationAndBrandingInformation>& information =
-      OnInjectAffiliationAndBrandingInformationCalled();
-  if (information.empty()) {
-    std::move(result_callback).Run(std::move(forms));
-    return;
-  }
-
-  ASSERT_EQ(information.size(), forms.size());
-  for (size_t i = 0; i < forms.size(); ++i) {
-    forms[i]->affiliated_web_realm = information[i].affiliated_web_realm;
-    forms[i]->app_display_name = information[i].app_display_name;
-    forms[i]->app_icon_url = information[i].app_icon_url;
-  }
-  std::move(result_callback).Run(std::move(forms));
-}
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
index ffa95950a..994c393 100644
--- a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
+++ b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
@@ -17,19 +17,11 @@
 
 namespace password_manager {
 
-struct PasswordForm;
-
 class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
  public:
-  // This struct mirrors the corresponding affiliation and branding information
-  // related fields from PasswordForm.
-  struct AffiliationAndBrandingInformation {
-    std::string affiliated_web_realm;
-    std::string app_display_name;
-    GURL app_icon_url;
-  };
-
   MockAffiliatedMatchHelper();
+  MockAffiliatedMatchHelper(PasswordStore* password_store,
+                            AffiliationService* affiliation_service);
 
   MockAffiliatedMatchHelper(const MockAffiliatedMatchHelper&) = delete;
   MockAffiliatedMatchHelper& operator=(const MockAffiliatedMatchHelper&) =
@@ -44,25 +36,14 @@
       const PasswordFormDigest& expected_observed_form,
       const std::vector<std::string>& results_to_return);
 
-  void ExpectCallToInjectAffiliationAndBrandingInformation(
-      const std::vector<AffiliationAndBrandingInformation>& results_to_inject);
-
  private:
   MOCK_METHOD(std::vector<std::string>,
               OnGetAffiliatedAndroidRealmsCalled,
               (const PasswordFormDigest&));
-  MOCK_METHOD(std::vector<AffiliationAndBrandingInformation>,
-              OnInjectAffiliationAndBrandingInformationCalled,
-              ());
 
   void GetAffiliatedAndroidAndWebRealms(
       const PasswordFormDigest& observed_form,
       AffiliatedRealmsCallback result_callback) override;
-
-  void InjectAffiliationAndBrandingInformation(
-      std::vector<std::unique_ptr<PasswordForm>> forms,
-      AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
-      PasswordFormsCallback result_callback) override;
 };
 
 }  // namespace password_manager
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 41a6045..27a5650 100644
--- a/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -25,6 +25,7 @@
 #include "components/password_manager/core/browser/leak_detection/leak_detection_check_factory.h"
 #include "components/password_manager/core/browser/leak_detection/mock_leak_detection_check_factory.h"
 #include "components/password_manager/core/browser/password_manager.h"
+#include "components/password_manager/core/browser/site_affiliation/mock_affiliation_service.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
@@ -822,8 +823,11 @@
   store_->AddLogin(affiliated_form1_);
   store_->AddLogin(affiliated_form2_);
 
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   std::vector<std::string> affiliated_realms;
@@ -1083,8 +1087,11 @@
        CredentialManagerOnRequestCredentialAffiliatedPasswordMatch) {
   store_->AddLogin(affiliated_form1_);
   client_->set_first_run_seen(true);
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   std::vector<std::string> affiliated_realms;
@@ -1104,8 +1111,11 @@
        CredentialManagerOnRequestCredentialAffiliatedPasswordNoMatch) {
   store_->AddLogin(affiliated_form1_);
   client_->set_first_run_seen(true);
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   std::vector<std::string> affiliated_realms;
@@ -1127,8 +1137,11 @@
   affiliated_form1_.password_value = std::u16string();
   store_->AddLogin(affiliated_form1_);
   client_->set_first_run_seen(true);
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   federations.emplace_back("https://example.com/");
@@ -1151,8 +1164,11 @@
   affiliated_form1_.password_value = std::u16string();
   store_->AddLogin(affiliated_form1_);
   client_->set_first_run_seen(true);
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   federations.emplace_back("https://not-example.com/");
@@ -1471,8 +1487,11 @@
   // ought to be returned automagically.
   store_->AddLogin(affiliated_form1_);
 
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   std::vector<std::string> affiliated_realms = {kTestAndroidRealm1};
@@ -1492,8 +1511,11 @@
   store_->AddLogin(affiliated_form1_);
   store_->AddLogin(affiliated_form2_);
 
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   std::vector<std::string> affiliated_realms;
@@ -1514,8 +1536,11 @@
   // in.
   store_->AddLogin(affiliated_form1_);
 
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<std::string> affiliated_realms;
   PasswordFormDigest digest = cm_service_impl_->GetSynthesizedFormForOrigin();
@@ -1542,8 +1567,11 @@
   store_->AddLogin(form_);
   store_->AddLogin(affiliated_form1_);
 
-  store_->SetAffiliatedMatchHelper(
-      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>());
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_match_helper =
+      std::make_unique<NiceMock<MockAffiliatedMatchHelper>>(
+          store_.get(), mock_affiliation_service.get());
+  store_->SetAffiliatedMatchHelper(std::move(mock_match_helper));
 
   std::vector<GURL> federations;
   std::vector<std::string> affiliated_realms;
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index ea3f0ce..ae288aec 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -434,9 +434,10 @@
     LoginsReply callback,
     LoginsResult forms) {
   if (affiliated_match_helper_ && !forms.empty()) {
-    affiliated_match_helper_->InjectAffiliationAndBrandingInformation(
-        std::move(forms), AffiliationService::StrategyOnCacheMiss::FAIL,
-        std::move(callback));
+    affiliated_match_helper_->get_affiliation_service()
+        ->InjectAffiliationAndBrandingInformation(
+            std::move(forms), AffiliationService::StrategyOnCacheMiss::FAIL,
+            std::move(callback));
   } else {
     std::move(callback).Run(std::move(forms));
   }
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 9569b41..f45b6ee3 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -84,6 +84,8 @@
   // must already be initialized if it is non-null.
   // TODO(crbug.bom/1218413): Inject into constructor or `Init()` instead.
   void SetAffiliatedMatchHelper(std::unique_ptr<AffiliatedMatchHelper> helper);
+
+  // TODO(crbug.com/1252350): Delete this method once it's no longer used.
   AffiliatedMatchHelper* affiliated_match_helper() const {
     return affiliated_match_helper_.get();
   }
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 309f3ae..b1ab99d3 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -22,7 +22,6 @@
 #include "build/build_config.h"
 #include "components/autofill/core/common/signatures.h"
 #include "components/os_crypt/os_crypt_mocker.h"
-#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h"
 #include "components/password_manager/core/browser/fake_password_store_backend.h"
 #include "components/password_manager/core/browser/form_parsing/form_parser.h"
@@ -36,6 +35,8 @@
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "components/password_manager/core/browser/password_store_impl.h"
 #include "components/password_manager/core/browser/password_store_signin_notifier.h"
+#include "components/password_manager/core/browser/site_affiliation/affiliation_service.h"
+#include "components/password_manager/core/browser/site_affiliation/mock_affiliation_service.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -676,7 +677,9 @@
   }
 
   std::vector<std::string> no_affiliated_android_realms;
-  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>(
+      store.get(), mock_affiliation_service.get());
   mock_helper->ExpectCallToGetAffiliatedAndroidRealms(
       observed_form, no_affiliated_android_realms);
   store->SetAffiliatedMatchHelper(std::move(mock_helper));
@@ -792,7 +795,9 @@
   affiliated_android_realms.push_back(kTestAndroidRealm2);
   affiliated_android_realms.push_back(kTestAndroidRealm3);
 
-  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>(
+      store.get(), mock_affiliation_service.get());
   mock_helper->ExpectCallToGetAffiliatedAndroidRealms(
       observed_form, affiliated_android_realms);
   store->SetAffiliatedMatchHelper(std::move(mock_helper));
@@ -831,11 +836,13 @@
   std::vector<std::unique_ptr<PasswordForm>> expected_results;
   expected_results.push_back(std::make_unique<PasswordForm>(*credential));
 
-  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
-  std::vector<MockAffiliatedMatchHelper::AffiliationAndBrandingInformation>
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>(
+      store.get(), mock_affiliation_service.get());
+  std::vector<MockAffiliationService::AffiliationAndBrandingInformation>
       affiliation_info_for_results = {
           {kTestWebRealm1, kTestAndroidName1, GURL(kTestAndroidIconURL1)}};
-  mock_helper->ExpectCallToInjectAffiliationAndBrandingInformation(
+  mock_affiliation_service->ExpectCallToInjectAffiliationAndBrandingInformation(
       affiliation_info_for_results);
   store->SetAffiliatedMatchHelper(std::move(mock_helper));
 
@@ -878,13 +885,15 @@
   expected_results.push_back(std::make_unique<PasswordForm>(*credential));
   expected_results[0]->is_affiliation_based_match = true;
 
-  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>(
+      store.get(), mock_affiliation_service.get());
   mock_helper->ExpectCallToGetAffiliatedAndroidRealms(observed_form,
                                                       {kTestAndroidRealm1});
-  std::vector<MockAffiliatedMatchHelper::AffiliationAndBrandingInformation>
+  std::vector<MockAffiliationService::AffiliationAndBrandingInformation>
       affiliation_info_for_results = {
           {kTestWebRealm1, kTestAndroidName1, GURL(kTestAndroidIconURL1)}};
-  mock_helper->ExpectCallToInjectAffiliationAndBrandingInformation(
+  mock_affiliation_service->ExpectCallToInjectAffiliationAndBrandingInformation(
       affiliation_info_for_results);
   store->SetAffiliatedMatchHelper(std::move(mock_helper));
 
@@ -970,7 +979,9 @@
   std::vector<std::string> affiliated_realms = {kTestWebRealm1, kTestWebRealm2,
                                                 kTestAffiliatedRealm};
 
-  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>(
+      store.get(), mock_affiliation_service.get());
   mock_helper->ExpectCallToGetAffiliatedAndroidRealms(observed_form,
                                                       affiliated_realms);
   store->SetAffiliatedMatchHelper(std::move(mock_helper));
@@ -1098,7 +1109,7 @@
   for (const auto& credential : all_credentials)
     expected_results.push_back(std::make_unique<PasswordForm>(*credential));
 
-  std::vector<MockAffiliatedMatchHelper::AffiliationAndBrandingInformation>
+  std::vector<MockAffiliationService::AffiliationAndBrandingInformation>
       affiliation_info_for_results = {
           {kTestWebRealm1, kTestAndroidName1, GURL(kTestAndroidIconURL1)},
           {kTestWebRealm2, kTestAndroidName2, GURL(kTestAndroidIconURL2)},
@@ -1107,8 +1118,10 @@
           {/* Pretend affiliation or branding info is unavailable. */},
           {/* Pretend affiliation or branding info is unavailable. */}};
 
-  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
-  mock_helper->ExpectCallToInjectAffiliationAndBrandingInformation(
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>(
+      store.get(), mock_affiliation_service.get());
+  mock_affiliation_service->ExpectCallToInjectAffiliationAndBrandingInformation(
       affiliation_info_for_results);
   store->SetAffiliatedMatchHelper(std::move(mock_helper));
   for (size_t i = 0; i < expected_results.size(); ++i) {
@@ -1330,7 +1343,9 @@
                                       kTestWebRealm1, GURL(kTestWebRealm1)};
 
   // Add affiliated android form corresponding to a 'observed_form'.
-  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
+  auto mock_affiliation_service = std::make_unique<MockAffiliationService>();
+  auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>(
+      store.get(), mock_affiliation_service.get());
   mock_helper->ExpectCallToGetAffiliatedAndroidRealms(observed_form,
                                                       {kTestAndroidRealm1});
   store->SetAffiliatedMatchHelper(std::move(mock_helper));
diff --git a/components/password_manager/core/browser/site_affiliation/affiliation_service.h b/components/password_manager/core/browser/site_affiliation/affiliation_service.h
index cdc2ddc..87ee401b 100644
--- a/components/password_manager/core/browser/site_affiliation/affiliation_service.h
+++ b/components/password_manager/core/browser/site_affiliation/affiliation_service.h
@@ -15,6 +15,8 @@
 
 namespace password_manager {
 
+struct PasswordForm;
+
 // A service that can be used to query the list of facets that are affiliated
 // with a given facet, i.e., facets that belong to the same logical application.
 // See affiliation_utils.h for details of what this means.
@@ -27,6 +29,9 @@
       base::OnceCallback<void(const AffiliatedFacets& /* results */,
                               bool /* success */)>;
 
+  using PasswordFormsCallback =
+      base::OnceCallback<void(std::vector<std::unique_ptr<PasswordForm>>)>;
+
   // Prefetches change password URLs for sites requested. Receives a callback to
   // run when the prefetch finishes.
   virtual void PrefetchChangePasswordURLs(const std::vector<GURL>& urls,
@@ -78,6 +83,18 @@
   // remove data corresponding to the given |facet_uri|, but still only as
   // long as the data is no longer needed.
   virtual void TrimCacheForFacetURI(const FacetURI& facet_uri) = 0;
+
+  // Retrieves affiliation and branding information about the Android
+  // credentials in |forms|, sets |affiliated_web_realm|, |app_display_name| and
+  // |app_icon_url| of forms, and invokes |result_callback|.
+  // NOTE: When |strategy_on_cache_miss| is set to |FAIL|, this will not issue
+  // an on-demand network request. And if a request to cache fails, no
+  // affiliation and branding information will be injected into corresponding
+  // form.
+  virtual void InjectAffiliationAndBrandingInformation(
+      std::vector<std::unique_ptr<PasswordForm>> forms,
+      AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+      PasswordFormsCallback result_callback) = 0;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc b/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc
index 84de7b1..8e19773 100644
--- a/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc
+++ b/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc
@@ -4,6 +4,7 @@
 
 #include "components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h"
 
+#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/containers/contains.h"
@@ -263,4 +264,77 @@
                                 base::Unretained(backend_), facet_uri));
 }
 
+void AffiliationServiceImpl::InjectAffiliationAndBrandingInformation(
+    std::vector<std::unique_ptr<PasswordForm>> forms,
+    AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+    PasswordFormsCallback result_callback) {
+  std::vector<PasswordForm*> android_credentials;
+  for (const auto& form : forms) {
+    if (IsValidAndroidCredential(PasswordFormDigest(*form)))
+      android_credentials.push_back(form.get());
+  }
+
+  // Create a closure that runs after affiliations are injected and
+  // CompleteInjectAffiliationAndBrandingInformation is called for
+  // all forms in |android_credentials|.
+  base::OnceClosure on_get_all_realms(
+      base::BindOnce(std::move(result_callback), std::move(forms)));
+  base::RepeatingClosure barrier_closure = base::BarrierClosure(
+      android_credentials.size(), std::move(on_get_all_realms));
+
+  for (auto* form : android_credentials) {
+    // |forms| are not destroyed until the |barrier_closure| executes,
+    // making it safe to use base::Unretained(form) below.
+    GetAffiliationsAndBranding(
+        FacetURI::FromPotentiallyInvalidSpec(form->signon_realm),
+        strategy_on_cache_miss,
+        base::BindOnce(&AffiliationServiceImpl::
+                           CompleteInjectAffiliationAndBrandingInformation,
+                       weak_ptr_factory_.GetWeakPtr(), base::Unretained(form),
+                       barrier_closure));
+  }
+}
+
+void AffiliationServiceImpl::CompleteInjectAffiliationAndBrandingInformation(
+    PasswordForm* form,
+    base::OnceClosure barrier_closure,
+    const AffiliatedFacets& results,
+    bool success) {
+  const FacetURI facet_uri(
+      FacetURI::FromPotentiallyInvalidSpec(form->signon_realm));
+
+  // Facet can also be web URI, in this case we do nothing.
+  if (!success || !facet_uri.IsValidAndroidFacetURI()) {
+    std::move(barrier_closure).Run();
+    return;
+  }
+
+  // Inject branding information into the form (e.g. the Play Store name and
+  // icon URL). We expect to always find a matching facet URI in the results.
+  auto facet = base::ranges::find(results, facet_uri, &Facet::uri);
+
+  DCHECK(facet != results.end());
+  form->app_display_name = facet->branding_info.name;
+  form->app_icon_url = facet->branding_info.icon_url;
+
+  // Inject the affiliated web realm into the form, if available. In case
+  // multiple web realms are available, this will always choose the first
+  // available web realm for injection.
+  auto affiliated_facet = std::find_if(
+      results.begin(), results.end(), [](const Facet& affiliated_facet) {
+        return affiliated_facet.uri.IsValidWebFacetURI();
+      });
+  if (affiliated_facet != results.end())
+    form->affiliated_web_realm = affiliated_facet->uri.canonical_spec() + "/";
+
+  std::move(barrier_closure).Run();
+}
+
+// static
+bool AffiliationServiceImpl::IsValidAndroidCredential(
+    const PasswordFormDigest& form) {
+  return form.scheme == PasswordForm::Scheme::kHtml &&
+         IsValidAndroidFacetURI(form.signon_realm);
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h b/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h
index 9045f62c..1d2fe42 100644
--- a/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h
+++ b/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_delegate.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_interface.h"
+#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.h"
 
@@ -35,6 +36,7 @@
 namespace password_manager {
 
 class AffiliationBackend;
+struct PasswordFormDigest;
 
 extern const char kGetChangePasswordURLMetricName[];
 
@@ -97,6 +99,13 @@
   void CancelPrefetch(const FacetURI& facet_uri,
                       const base::Time& keep_fresh_until) override;
   void TrimCacheForFacetURI(const FacetURI& facet_uri) override;
+  void InjectAffiliationAndBrandingInformation(
+      std::vector<std::unique_ptr<PasswordForm>> forms,
+      AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+      PasswordFormsCallback result_callback) override;
+
+  // Returns whether or not |form| represents an Android credential.
+  static bool IsValidAndroidCredential(const PasswordFormDigest& form);
 
   AffiliationBackend* GetBackendForTesting() { return backend_; }
 
@@ -110,6 +119,17 @@
   void OnFetchFailed(AffiliationFetcherInterface* fetcher) override;
   void OnMalformedResponse(AffiliationFetcherInterface* fetcher) override;
 
+  // Called back by AffiliationService to supply the list of facets
+  // affiliated with the Android credential in |form|. Injects affiliation and
+  // branding information by setting |affiliated_web_realm|, |app_display_name|
+  // and |app_icon_url| on |form| if |success| is true and |results| is
+  // non-empty. Invokes |barrier_closure|.
+  void CompleteInjectAffiliationAndBrandingInformation(
+      PasswordForm* form,
+      base::OnceClosure barrier_closure,
+      const AffiliatedFacets& results,
+      bool success);
+
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   std::map<url::SchemeHostPort, ChangePasswordUrlMatch> change_password_urls_;
   std::vector<FetchInfo> pending_fetches_;
diff --git a/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc b/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc
index 7d6e95f..afc14e1 100644
--- a/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc
+++ b/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/password_manager/core/browser/android_affiliation/fake_affiliation_api.h"
 #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h"
 #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_fetcher.h"
+#include "components/password_manager/core/browser/password_form_digest.h"
 #include "components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.h"
 #include "components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h"
 #include "components/password_manager/core/browser/site_affiliation/mock_affiliation_fetcher_factory.h"
@@ -60,11 +61,64 @@
 constexpr char kTestFacetURIAlpha3[] = "https://three.alpha.example.com";
 constexpr char kTestFacetURIBeta1[] = "https://one.beta.example.com";
 
+const char kTestAndroidFacetURIAlpha[] =
+    "android://hash@com.example.alpha.android";
+const char kTestAndroidFacetNameAlpha1[] = "Facet Name Alpha 1";
+const char kTestAndroidFacetIconURLAlpha1[] = "https://example.com/alpha_1.png";
+const char kTestAndroidRealmAlpha1[] =
+    "android://hash@com.example.alpha.android/";
+const char kTestWebRealmAlpha1[] = "https://one.alpha.example.com/";
+const char kTestWebRealmAlpha2[] = "https://two.alpha.example.com/";
+
+const char kTestAndroidFacetURIBeta1[] =
+    "android://hash@com.example.beta.android";
+const char kTestAndroidFacetNameBeta1[] = "Facet Name Beta 1";
+const char kTestAndroidFacetIconURLBeta1[] = "https://example.com/beta_1.png";
+const char kTestWebRealmBeta1[] = "https://one.beta.example.com/";
+const char kTestAndroidRealmBeta1[] =
+    "android://hash@com.example.beta.android/";
+
+const char kTestAndroidFacetURIBeta2[] =
+    "android://hash@com.yetanother.beta.android";
+const char kTestAndroidFacetNameBeta2[] = "Facet Name Beta 2";
+const char kTestAndroidFacetIconURLBeta2[] = "https://example.com/beta_2.png";
+const char kTestAndroidRealmBeta2[] =
+    "android://hash@com.yetanother.beta.android/";
+
+const char kTestAndroidFacetURIGamma[] =
+    "android://hash@com.example.gamma.android";
+const char kTestAndroidRealmGamma[] =
+    "android://hash@com.example.gamma.android";
+
+const char16_t kTestUsername[] = u"JohnDoe";
+const char16_t kTestPassword[] = u"secret";
+
 AffiliatedFacets GetTestEquivalenceClassAlpha() {
   return {
       {FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)},
       {FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)},
       {FacetURI::FromCanonicalSpec(kTestFacetURIAlpha3)},
+      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha),
+       FacetBrandingInfo{kTestAndroidFacetNameAlpha1,
+                         GURL(kTestAndroidFacetIconURLAlpha1)}},
+  };
+}
+
+AffiliatedFacets GetTestEquivalenceClassBeta() {
+  return {
+      {FacetURI::FromCanonicalSpec(kTestFacetURIBeta1)},
+      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta1),
+       FacetBrandingInfo{kTestAndroidFacetNameBeta1,
+                         GURL(kTestAndroidFacetIconURLBeta1)}},
+      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
+       FacetBrandingInfo{kTestAndroidFacetNameBeta2,
+                         GURL(kTestAndroidFacetIconURLBeta2)}},
+  };
+}
+
+AffiliatedFacets GetTestEquivalenceClassGamma() {
+  return {
+      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma)},
   };
 }
 
@@ -77,6 +131,15 @@
   return facet_URIs;
 }
 
+PasswordForm GetTestAndroidCredentials(const char* signon_realm) {
+  PasswordForm form;
+  form.scheme = PasswordForm::Scheme::kHtml;
+  form.signon_realm = signon_realm;
+  form.username_value = kTestUsername;
+  form.password_value = kTestPassword;
+  return form;
+}
+
 }  // namespace
 
 class AffiliationServiceImplTest : public testing::Test {
@@ -503,6 +566,15 @@
             service()->GetChangePasswordURL(origin2));
 }
 
+TEST_F(AffiliationServiceImplTest, IsValidAndroidCredential) {
+  EXPECT_FALSE(AffiliationServiceImpl::IsValidAndroidCredential(
+      {PasswordForm::Scheme::kHtml, kTestWebRealmBeta1, GURL()}));
+  PasswordFormDigest android_credential(
+      GetTestAndroidCredentials(kTestAndroidRealmBeta2));
+  EXPECT_TRUE(
+      AffiliationServiceImpl::IsValidAndroidCredential(android_credential));
+}
+
 // Test fixture to imitate a fetch factory for testing and not just mock it.
 class AffiliationServiceImplTestWithFetcherFactory
     : public AffiliationServiceImplTest {
@@ -515,12 +587,22 @@
     fake_affiliation_api_.SetFetcherFactory(fake_fetcher_factory.get());
     fake_affiliation_api_.AddTestEquivalenceClass(
         GetTestEquivalenceClassAlpha());
+    fake_affiliation_api_.AddTestEquivalenceClass(
+        GetTestEquivalenceClassBeta());
+    fake_affiliation_api_.AddTestEquivalenceClass(
+        GetTestEquivalenceClassGamma());
     background_task_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(&AffiliationBackend::SetFetcherFactoryForTesting,
                        base::Unretained(service_->GetBackendForTesting()),
                        std::move(fake_fetcher_factory)));
   }
+
+  void OnFormsCallback(std::vector<std::unique_ptr<PasswordForm>> forms) {
+    result_forms_.swap(forms);
+  }
+
+  std::vector<std::unique_ptr<PasswordForm>> result_forms_;
 };
 
 TEST_F(AffiliationServiceImplTestWithFetcherFactory,
@@ -591,4 +673,61 @@
   testing::Mock::VerifyAndClearExpectations(mock_consumer());
 }
 
+TEST_F(AffiliationServiceImplTestWithFetcherFactory,
+       InjectAffiliationAndBrandingInformation) {
+  std::vector<std::unique_ptr<PasswordForm>> forms;
+  forms.push_back(std::make_unique<PasswordForm>(
+      GetTestAndroidCredentials(kTestAndroidRealmAlpha1)));
+  forms.push_back(std::make_unique<PasswordForm>(
+      GetTestAndroidCredentials(kTestAndroidRealmBeta1)));
+  forms.push_back(std::make_unique<PasswordForm>(
+      GetTestAndroidCredentials(kTestAndroidRealmBeta2)));
+  forms.push_back(std::make_unique<PasswordForm>(
+      GetTestAndroidCredentials(kTestAndroidRealmGamma)));
+
+  PasswordFormDigest digest = {PasswordForm::Scheme::kHtml, kTestWebRealmBeta1,
+                               GURL()};
+  PasswordForm web_form;
+  web_form.scheme = digest.scheme;
+  web_form.signon_realm = digest.signon_realm;
+  web_form.url = digest.url;
+  forms.push_back(std::make_unique<PasswordForm>(web_form));
+
+  size_t expected_form_count = forms.size();
+
+  service()->InjectAffiliationAndBrandingInformation(
+      std::move(forms),
+      AffiliationService::StrategyOnCacheMiss::FETCH_OVER_NETWORK,
+      base::BindOnce(
+          &AffiliationServiceImplTestWithFetcherFactory::OnFormsCallback,
+          base::Unretained(this)));
+
+  background_task_runner()->RunUntilIdle();
+  ASSERT_TRUE(fake_affiliation_api()->HasPendingRequest());
+  fake_affiliation_api()->ServeNextRequest();
+  RunUntilIdle();
+
+  ASSERT_EQ(expected_form_count, result_forms_.size());
+  EXPECT_THAT(result_forms_[0]->affiliated_web_realm,
+              testing::AnyOf(kTestWebRealmAlpha1, kTestWebRealmAlpha2));
+  EXPECT_EQ(kTestAndroidFacetNameAlpha1, result_forms_[0]->app_display_name);
+  EXPECT_EQ(kTestAndroidFacetIconURLAlpha1,
+            result_forms_[0]->app_icon_url.possibly_invalid_spec());
+
+  EXPECT_THAT(result_forms_[1]->affiliated_web_realm,
+              testing::Eq(kTestWebRealmBeta1));
+  EXPECT_EQ(kTestAndroidFacetNameBeta1, result_forms_[1]->app_display_name);
+  EXPECT_EQ(kTestAndroidFacetIconURLBeta1,
+            result_forms_[1]->app_icon_url.possibly_invalid_spec());
+
+  EXPECT_THAT(result_forms_[2]->affiliated_web_realm,
+              testing::Eq(kTestWebRealmBeta1));
+  EXPECT_EQ(kTestAndroidFacetNameBeta2, result_forms_[2]->app_display_name);
+  EXPECT_EQ(kTestAndroidFacetIconURLBeta2,
+            result_forms_[2]->app_icon_url.possibly_invalid_spec());
+
+  EXPECT_THAT(result_forms_[3]->affiliated_web_realm, testing::IsEmpty());
+  EXPECT_THAT(result_forms_[4]->affiliated_web_realm, testing::IsEmpty());
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/site_affiliation/fake_affiliation_service.cc b/components/password_manager/core/browser/site_affiliation/fake_affiliation_service.cc
new file mode 100644
index 0000000..dcc32a2a
--- /dev/null
+++ b/components/password_manager/core/browser/site_affiliation/fake_affiliation_service.cc
@@ -0,0 +1,38 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// 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/site_affiliation/fake_affiliation_service.h"
+
+namespace password_manager {
+
+FakeAffiliationService::FakeAffiliationService() = default;
+
+FakeAffiliationService::~FakeAffiliationService() = default;
+
+void FakeAffiliationService::PrefetchChangePasswordURLs(
+    const std::vector<GURL>& urls,
+    base::OnceClosure callback) {}
+void FakeAffiliationService::Clear() {}
+GURL FakeAffiliationService::GetChangePasswordURL(const GURL& url) const {
+  return GURL();
+}
+void FakeAffiliationService::GetAffiliationsAndBranding(
+    const FacetURI& facet_uri,
+    AffiliationService::StrategyOnCacheMiss cache_miss_strategy,
+    ResultCallback result_callback) {}
+void FakeAffiliationService::Prefetch(const FacetURI& facet_uri,
+                                      const base::Time& keep_fresh_until) {}
+void FakeAffiliationService::CancelPrefetch(
+    const FacetURI& facet_uri,
+    const base::Time& keep_fresh_until) {}
+void FakeAffiliationService::TrimCacheForFacetURI(const FacetURI& facet_uri) {}
+
+void FakeAffiliationService::InjectAffiliationAndBrandingInformation(
+    std::vector<std::unique_ptr<PasswordForm>> forms,
+    AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+    PasswordFormsCallback result_callback) {
+  std::move(result_callback).Run(std::move(forms));
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/site_affiliation/fake_affiliation_service.h b/components/password_manager/core/browser/site_affiliation/fake_affiliation_service.h
new file mode 100644
index 0000000..894097e
--- /dev/null
+++ b/components/password_manager/core/browser/site_affiliation/fake_affiliation_service.h
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// 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_SITE_AFFILIATION_FAKE_AFFILIATION_SERVICE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SITE_AFFILIATION_FAKE_AFFILIATION_SERVICE_H_
+
+#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/site_affiliation/affiliation_service.h"
+
+namespace password_manager {
+
+class FakeAffiliationService : public AffiliationService {
+ public:
+  FakeAffiliationService();
+  ~FakeAffiliationService() override;
+
+  void PrefetchChangePasswordURLs(const std::vector<GURL>& urls,
+                                  base::OnceClosure callback) override;
+  void Clear() override;
+  GURL GetChangePasswordURL(const GURL& url) const override;
+  void GetAffiliationsAndBranding(
+      const FacetURI& facet_uri,
+      AffiliationService::StrategyOnCacheMiss cache_miss_strategy,
+      ResultCallback result_callback) override;
+  void Prefetch(const FacetURI& facet_uri,
+                const base::Time& keep_fresh_until) override;
+  void CancelPrefetch(const FacetURI& facet_uri,
+                      const base::Time& keep_fresh_until) override;
+  void TrimCacheForFacetURI(const FacetURI& facet_uri) override;
+
+  void InjectAffiliationAndBrandingInformation(
+      std::vector<std::unique_ptr<PasswordForm>> forms,
+      AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+      PasswordFormsCallback result_callback) override;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SITE_AFFILIATION_MOCK_AFFILIATION_SERVICE_H_
diff --git a/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.cc b/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.cc
index 04cb4756..eabd7c65b 100644
--- a/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.cc
+++ b/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.cc
@@ -10,4 +10,32 @@
 
 MockAffiliationService::~MockAffiliationService() = default;
 
+void MockAffiliationService::
+    ExpectCallToInjectAffiliationAndBrandingInformation(
+        const std::vector<AffiliationAndBrandingInformation>&
+            results_to_inject) {
+  EXPECT_CALL(*this, OnInjectAffiliationAndBrandingInformationCalled())
+      .WillOnce(testing::Return(results_to_inject));
+}
+
+void MockAffiliationService::InjectAffiliationAndBrandingInformation(
+    std::vector<std::unique_ptr<PasswordForm>> forms,
+    AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+    PasswordFormsCallback result_callback) {
+  const std::vector<AffiliationAndBrandingInformation>& information =
+      OnInjectAffiliationAndBrandingInformationCalled();
+  if (information.empty()) {
+    std::move(result_callback).Run(std::move(forms));
+    return;
+  }
+
+  ASSERT_EQ(information.size(), forms.size());
+  for (size_t i = 0; i < forms.size(); ++i) {
+    forms[i]->affiliated_web_realm = information[i].affiliated_web_realm;
+    forms[i]->app_display_name = information[i].app_display_name;
+    forms[i]->app_icon_url = information[i].app_icon_url;
+  }
+  std::move(result_callback).Run(std::move(forms));
+}
+
 }  // namespace password_manager
\ No newline at end of file
diff --git a/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.h b/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.h
index 4bb392a..b30aa42c 100644
--- a/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.h
+++ b/components/password_manager/core/browser/site_affiliation/mock_affiliation_service.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SITE_AFFILIATION_MOCK_AFFILIATION_SERVICE_H_
 
 #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
+#include "components/password_manager/core/browser/password_form.h"
 #include "components/password_manager/core/browser/site_affiliation/affiliation_service.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -14,6 +15,14 @@
 
 class MockAffiliationService : public AffiliationService {
  public:
+  // This struct mirrors the corresponding affiliation and branding information
+  // related fields from PasswordForm.
+  struct AffiliationAndBrandingInformation {
+    std::string affiliated_web_realm;
+    std::string app_display_name;
+    GURL app_icon_url;
+  };
+
   MockAffiliationService();
   ~MockAffiliationService() override;
 
@@ -35,6 +44,19 @@
               (const FacetURI&, const base::Time&),
               (override));
   MOCK_METHOD(void, TrimCacheForFacetURI, (const FacetURI&), (override));
+
+  void ExpectCallToInjectAffiliationAndBrandingInformation(
+      const std::vector<AffiliationAndBrandingInformation>& results_to_inject);
+
+  void InjectAffiliationAndBrandingInformation(
+      std::vector<std::unique_ptr<PasswordForm>> forms,
+      AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+      PasswordFormsCallback result_callback) override;
+
+ private:
+  MOCK_METHOD(std::vector<AffiliationAndBrandingInformation>,
+              OnInjectAffiliationAndBrandingInformationCalled,
+              ());
 };
 
 }  // namespace password_manager
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index 0768d0f..6334f1a8c 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -127,7 +127,7 @@
   // web::WebStatePolicyDecider override.
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const web::WebStatePolicyDecider::RequestInfo& request_info,
+      web::WebStatePolicyDecider::RequestInfo request_info,
       web::WebStatePolicyDecider::PolicyDecisionCallback callback) override;
   // Decides on navigation corresponding to |response| whether the navigation
   // should continue and updates authentication cookies on Google domains.
@@ -167,7 +167,7 @@
 
 void AccountConsistencyService::AccountConsistencyHandler::ShouldAllowRequest(
     NSURLRequest* request,
-    const web::WebStatePolicyDecider::RequestInfo& request_info,
+    web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   GURL url = net::GURLWithNSURL(request.URL);
   if (base::FeatureList::IsEnabled(signin::kRestoreGaiaCookiesOnUserAction) &&
diff --git a/components/sync_device_info/device_info.cc b/components/sync_device_info/device_info.cc
index e0fc68c..55db74a 100644
--- a/components/sync_device_info/device_info.cc
+++ b/components/sync_device_info/device_info.cc
@@ -7,7 +7,7 @@
 // device_info.h's size can impact build time. Try not to raise this limit
 // unless absolutely necessary. See
 // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
-#pragma clang max_tokens_here 506000
+#pragma clang max_tokens_here 507000
 
 #include <utility>
 
diff --git a/content/BUILD.gn b/content/BUILD.gn
index bc9040c8..cd5655c2 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -136,7 +136,7 @@
     "dev_ui_content_resources.pak",
   ]
   deps = [
-    "//content/browser/conversions:mojo_bindings_webui_js",
+    "//content/browser/attribution_reporting:mojo_bindings_webui_js",
     "//content/browser/process_internals:mojo_bindings_webui_js",
   ]
 }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index fa8a39e..49127b9a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -103,11 +103,11 @@
     "//content:content_resources",
     "//content:dev_ui_content_resources",
     "//content/app/resources",
+    "//content/browser/attribution_reporting:mojo_bindings",
     "//content/browser/background_fetch:background_fetch_proto",
     "//content/browser/background_sync:background_sync_proto",
     "//content/browser/cache_storage:cache_storage_proto",
     "//content/browser/content_index:content_index_proto",
-    "//content/browser/conversions:mojo_bindings",
     "//content/browser/cookie_store:cookie_store_proto",
     "//content/browser/devtools:devtools_background_services_proto",
     "//content/browser/devtools:protocol_sources",
@@ -424,6 +424,49 @@
     "appcache/appcache_working_set.h",
     "appcache/chrome_appcache_service.cc",
     "appcache/chrome_appcache_service.h",
+    "attribution_reporting/conversion_host.cc",
+    "attribution_reporting/conversion_host.h",
+    "attribution_reporting/conversion_host_utils.cc",
+    "attribution_reporting/conversion_host_utils.h",
+    "attribution_reporting/conversion_internals_handler_impl.cc",
+    "attribution_reporting/conversion_internals_handler_impl.h",
+    "attribution_reporting/conversion_internals_ui.cc",
+    "attribution_reporting/conversion_internals_ui.h",
+    "attribution_reporting/conversion_manager.h",
+    "attribution_reporting/conversion_manager_impl.cc",
+    "attribution_reporting/conversion_manager_impl.h",
+    "attribution_reporting/conversion_network_sender_impl.cc",
+    "attribution_reporting/conversion_network_sender_impl.h",
+    "attribution_reporting/conversion_page_metrics.cc",
+    "attribution_reporting/conversion_page_metrics.h",
+    "attribution_reporting/conversion_policy.cc",
+    "attribution_reporting/conversion_policy.h",
+    "attribution_reporting/conversion_report.cc",
+    "attribution_reporting/conversion_report.h",
+    "attribution_reporting/conversion_reporter_impl.cc",
+    "attribution_reporting/conversion_reporter_impl.h",
+    "attribution_reporting/conversion_session_storage.cc",
+    "attribution_reporting/conversion_session_storage.h",
+    "attribution_reporting/conversion_storage.cc",
+    "attribution_reporting/conversion_storage.h",
+    "attribution_reporting/conversion_storage_delegate_impl.cc",
+    "attribution_reporting/conversion_storage_delegate_impl.h",
+    "attribution_reporting/conversion_storage_sql.cc",
+    "attribution_reporting/conversion_storage_sql.h",
+    "attribution_reporting/conversion_storage_sql_migrations.cc",
+    "attribution_reporting/conversion_storage_sql_migrations.h",
+    "attribution_reporting/conversion_utils.cc",
+    "attribution_reporting/conversion_utils.h",
+    "attribution_reporting/rate_limit_table.cc",
+    "attribution_reporting/rate_limit_table.h",
+    "attribution_reporting/sent_report_info.cc",
+    "attribution_reporting/sent_report_info.h",
+    "attribution_reporting/sql_utils.cc",
+    "attribution_reporting/sql_utils.h",
+    "attribution_reporting/storable_conversion.cc",
+    "attribution_reporting/storable_conversion.h",
+    "attribution_reporting/storable_impression.cc",
+    "attribution_reporting/storable_impression.h",
     "audio/audio_service.cc",
     "background_fetch/background_fetch_context.cc",
     "background_fetch/background_fetch_context.h",
@@ -675,49 +718,6 @@
     "content_index/content_index_metrics.h",
     "content_index/content_index_service_impl.cc",
     "content_index/content_index_service_impl.h",
-    "conversions/conversion_host.cc",
-    "conversions/conversion_host.h",
-    "conversions/conversion_host_utils.cc",
-    "conversions/conversion_host_utils.h",
-    "conversions/conversion_internals_handler_impl.cc",
-    "conversions/conversion_internals_handler_impl.h",
-    "conversions/conversion_internals_ui.cc",
-    "conversions/conversion_internals_ui.h",
-    "conversions/conversion_manager.h",
-    "conversions/conversion_manager_impl.cc",
-    "conversions/conversion_manager_impl.h",
-    "conversions/conversion_network_sender_impl.cc",
-    "conversions/conversion_network_sender_impl.h",
-    "conversions/conversion_page_metrics.cc",
-    "conversions/conversion_page_metrics.h",
-    "conversions/conversion_policy.cc",
-    "conversions/conversion_policy.h",
-    "conversions/conversion_report.cc",
-    "conversions/conversion_report.h",
-    "conversions/conversion_reporter_impl.cc",
-    "conversions/conversion_reporter_impl.h",
-    "conversions/conversion_session_storage.cc",
-    "conversions/conversion_session_storage.h",
-    "conversions/conversion_storage.cc",
-    "conversions/conversion_storage.h",
-    "conversions/conversion_storage_delegate_impl.cc",
-    "conversions/conversion_storage_delegate_impl.h",
-    "conversions/conversion_storage_sql.cc",
-    "conversions/conversion_storage_sql.h",
-    "conversions/conversion_storage_sql_migrations.cc",
-    "conversions/conversion_storage_sql_migrations.h",
-    "conversions/conversion_utils.cc",
-    "conversions/conversion_utils.h",
-    "conversions/rate_limit_table.cc",
-    "conversions/rate_limit_table.h",
-    "conversions/sent_report_info.cc",
-    "conversions/sent_report_info.h",
-    "conversions/sql_utils.cc",
-    "conversions/sql_utils.h",
-    "conversions/storable_conversion.cc",
-    "conversions/storable_conversion.h",
-    "conversions/storable_impression.cc",
-    "conversions/storable_impression.h",
     "cookie_store/cookie_change_subscription.cc",
     "cookie_store/cookie_change_subscription.h",
     "cookie_store/cookie_store_host.cc",
@@ -2196,9 +2196,9 @@
       "android/text_suggestion_host_android.h",
       "android/text_suggestion_host_mojo_impl_android.cc",
       "android/text_suggestion_host_mojo_impl_android.h",
+      "attribution_reporting/attribution_reporter_android.cc",
+      "attribution_reporting/attribution_reporter_android.h",
       "child_process_launcher_helper_android.cc",
-      "conversions/attribution_reporter_android.cc",
-      "conversions/attribution_reporter_android.h",
       "media/android/browser_gpu_video_accelerator_factories.cc",
       "media/android/browser_gpu_video_accelerator_factories.h",
       "media/android/media_player_renderer.cc",
diff --git a/content/browser/android/navigation_handle_proxy.cc b/content/browser/android/navigation_handle_proxy.cc
index a388c640..720d16c 100644
--- a/content/browser/android/navigation_handle_proxy.cc
+++ b/content/browser/android/navigation_handle_proxy.cc
@@ -7,7 +7,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
-#include "content/browser/conversions/conversion_host.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
 #include "content/public/android/content_jni_headers/NavigationHandle_jni.h"
 #include "content/public/browser/navigation_handle.h"
 #include "third_party/blink/public/common/navigation/impression.h"
diff --git a/content/browser/conversions/BUILD.gn b/content/browser/attribution_reporting/BUILD.gn
similarity index 100%
rename from content/browser/conversions/BUILD.gn
rename to content/browser/attribution_reporting/BUILD.gn
diff --git a/content/browser/conversions/DIR_METADATA b/content/browser/attribution_reporting/DIR_METADATA
similarity index 100%
rename from content/browser/conversions/DIR_METADATA
rename to content/browser/attribution_reporting/DIR_METADATA
diff --git a/content/browser/conversions/OWNERS b/content/browser/attribution_reporting/OWNERS
similarity index 100%
rename from content/browser/conversions/OWNERS
rename to content/browser/attribution_reporting/OWNERS
diff --git a/content/browser/conversions/PRESUBMIT.py b/content/browser/attribution_reporting/PRESUBMIT.py
similarity index 95%
rename from content/browser/conversions/PRESUBMIT.py
rename to content/browser/attribution_reporting/PRESUBMIT.py
index 768e7f0..3d8938b6 100644
--- a/content/browser/conversions/PRESUBMIT.py
+++ b/content/browser/attribution_reporting/PRESUBMIT.py
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Presubmit script for the content/browser/conversions directory.
+"""Presubmit script for the content/browser/attribution_reporting directory.
 
 See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts
 for more details about the presubmit API built into depot_tools.
diff --git a/content/browser/conversions/attribution_reporter_android.cc b/content/browser/attribution_reporting/attribution_reporter_android.cc
similarity index 91%
rename from content/browser/conversions/attribution_reporter_android.cc
rename to content/browser/attribution_reporting/attribution_reporter_android.cc
index e28b66bc..06bfe94 100644
--- a/content/browser/conversions/attribution_reporter_android.cc
+++ b/content/browser/attribution_reporting/attribution_reporter_android.cc
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/attribution_reporter_android.h"
+#include "content/browser/attribution_reporting/attribution_reporter_android.h"
 
 #include <string>
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/strings/strcat.h"
-#include "content/browser/conversions/conversion_host.h"
-#include "content/browser/conversions/conversion_host_utils.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
+#include "content/browser/attribution_reporting/conversion_host_utils.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
 #include "content/browser/renderer_host/navigation_controller_android.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/common/url_utils.h"
diff --git a/content/browser/conversions/attribution_reporter_android.h b/content/browser/attribution_reporting/attribution_reporter_android.h
similarity index 80%
rename from content/browser/conversions/attribution_reporter_android.h
rename to content/browser/attribution_reporting/attribution_reporter_android.h
index 52f0aec..c28e816 100644
--- a/content/browser/conversions/attribution_reporter_android.h
+++ b/content/browser/attribution_reporting/attribution_reporter_android.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_ATTRIBUTION_REPORTER_ANDROID_H_
-#define CONTENT_BROWSER_CONVERSIONS_ATTRIBUTION_REPORTER_ANDROID_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_REPORTER_ANDROID_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_REPORTER_ANDROID_H_
 
 #include <cstdint>
 #include <memory>
@@ -31,4 +31,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_ATTRIBUTION_REPORTER_ANDROID_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_REPORTER_ANDROID_H_
diff --git a/content/browser/conversions/attribution_reporter_android_unittest.cc b/content/browser/attribution_reporting/attribution_reporter_android_unittest.cc
similarity index 88%
rename from content/browser/conversions/attribution_reporter_android_unittest.cc
rename to content/browser/attribution_reporting/attribution_reporter_android_unittest.cc
index 2541bc26..5410a17 100644
--- a/content/browser/conversions/attribution_reporter_android_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_reporter_android_unittest.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/attribution_reporter_android.h"
+#include "content/browser/attribution_reporting/attribution_reporter_android.h"
 
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/url_utils.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_constants.h"
diff --git a/content/browser/conversions/conversion_host.cc b/content/browser/attribution_reporting/conversion_host.cc
similarity index 96%
rename from content/browser/conversions/conversion_host.cc
rename to content/browser/attribution_reporting/conversion_host.cc
index 222ce0d..172cd8a 100644
--- a/content/browser/conversions/conversion_host.cc
+++ b/content/browser/attribution_reporting/conversion_host.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_host.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
 
 #include <utility>
 
@@ -12,12 +12,12 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
-#include "content/browser/conversions/conversion_host_utils.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
-#include "content/browser/conversions/conversion_page_metrics.h"
-#include "content/browser/conversions/conversion_policy.h"
-#include "content/browser/conversions/storable_conversion.h"
+#include "content/browser/attribution_reporting/conversion_host_utils.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_page_metrics.h"
+#include "content/browser/attribution_reporting/conversion_policy.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
 #include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
diff --git a/content/browser/conversions/conversion_host.h b/content/browser/attribution_reporting/conversion_host.h
similarity index 93%
rename from content/browser/conversions/conversion_host.h
rename to content/browser/attribution_reporting/conversion_host.h
index 54044130..533bede 100644
--- a/content/browser/conversions/conversion_host.h
+++ b/content/browser/attribution_reporting/conversion_host.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_HOST_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_HOST_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_HOST_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_HOST_H_
 
 #include <memory>
 
 #include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/render_frame_host_receiver_set.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -130,4 +130,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_HOST_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_HOST_H_
diff --git a/content/browser/conversions/conversion_host_unittest.cc b/content/browser/attribution_reporting/conversion_host_unittest.cc
similarity index 99%
rename from content/browser/conversions/conversion_host_unittest.cc
rename to content/browser/attribution_reporting/conversion_host_unittest.cc
index 01b0e3e..b751c84 100644
--- a/content/browser/conversions/conversion_host_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_host_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_host.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
 
 #include <memory>
 
 #include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_constants.h"
diff --git a/content/browser/conversions/conversion_host_utils.cc b/content/browser/attribution_reporting/conversion_host_utils.cc
similarity index 92%
rename from content/browser/conversions/conversion_host_utils.cc
rename to content/browser/attribution_reporting/conversion_host_utils.cc
index eb5a2241..1b3b2f8 100644
--- a/content/browser/conversions/conversion_host_utils.cc
+++ b/content/browser/attribution_reporting/conversion_host_utils.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_host_utils.h"
+#include "content/browser/attribution_reporting/conversion_host_utils.h"
 
 #include <memory>
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_policy.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_policy.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/url_utils.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
diff --git a/content/browser/conversions/conversion_host_utils.h b/content/browser/attribution_reporting/conversion_host_utils.h
similarity index 83%
rename from content/browser/conversions/conversion_host_utils.h
rename to content/browser/attribution_reporting/conversion_host_utils.h
index 796d4d3..bd534f7 100644
--- a/content/browser/conversions/conversion_host_utils.h
+++ b/content/browser/attribution_reporting/conversion_host_utils.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_HOST_UTILS_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_HOST_UTILS_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_HOST_UTILS_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_HOST_UTILS_H_
 
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/content_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/navigation/impression.h"
@@ -42,4 +42,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_HOST_UTILS_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_HOST_UTILS_H_
diff --git a/content/browser/conversions/conversion_host_utils_unittest.cc b/content/browser/attribution_reporting/conversion_host_utils_unittest.cc
similarity index 96%
rename from content/browser/conversions/conversion_host_utils_unittest.cc
rename to content/browser/attribution_reporting/conversion_host_utils_unittest.cc
index de867ab5..db86001 100644
--- a/content/browser/conversions/conversion_host_utils_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_host_utils_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_host_utils.h"
+#include "content/browser/attribution_reporting/conversion_host_utils.h"
 
 #include <memory>
 
diff --git a/content/browser/conversions/conversion_internals.mojom b/content/browser/attribution_reporting/conversion_internals.mojom
similarity index 100%
rename from content/browser/conversions/conversion_internals.mojom
rename to content/browser/attribution_reporting/conversion_internals.mojom
diff --git a/content/browser/conversions/conversion_internals_browsertest.cc b/content/browser/attribution_reporting/conversion_internals_browsertest.cc
similarity index 98%
rename from content/browser/conversions/conversion_internals_browsertest.cc
rename to content/browser/attribution_reporting/conversion_internals_browsertest.cc
index d3a09ef4..6d69fe5a 100644
--- a/content/browser/conversions/conversion_internals_browsertest.cc
+++ b/content/browser/attribution_reporting/conversion_internals_browsertest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_internals_ui.h"
+#include "content/browser/attribution_reporting/conversion_internals_ui.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_controller.h"
diff --git a/content/browser/conversions/conversion_internals_handler_impl.cc b/content/browser/attribution_reporting/conversion_internals_handler_impl.cc
similarity index 94%
rename from content/browser/conversions/conversion_internals_handler_impl.cc
rename to content/browser/attribution_reporting/conversion_internals_handler_impl.cc
index 6d3081c..4a1f6668 100644
--- a/content/browser/conversions/conversion_internals_handler_impl.cc
+++ b/content/browser/attribution_reporting/conversion_internals_handler_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_internals_handler_impl.h"
+#include "content/browser/attribution_reporting/conversion_internals_handler_impl.h"
 
 #include <utility>
 #include <vector>
@@ -13,11 +13,11 @@
 #include "base/containers/circular_deque.h"
 #include "base/ranges/algorithm.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_session_storage.h"
-#include "content/browser/conversions/sent_report_info.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_session_storage.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
diff --git a/content/browser/conversions/conversion_internals_handler_impl.h b/content/browser/attribution_reporting/conversion_internals_handler_impl.h
similarity index 83%
rename from content/browser/conversions/conversion_internals_handler_impl.h
rename to content/browser/attribution_reporting/conversion_internals_handler_impl.h
index 3cab1949..0429348 100644
--- a/content/browser/conversions/conversion_internals_handler_impl.h
+++ b/content/browser/attribution_reporting/conversion_internals_handler_impl.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_INTERNALS_HANDLER_IMPL_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_INTERNALS_HANDLER_IMPL_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_INTERNALS_HANDLER_IMPL_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_INTERNALS_HANDLER_IMPL_H_
 
-#include "content/browser/conversions/conversion_internals.mojom.h"
-#include "content/browser/conversions/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_internals.mojom.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
@@ -60,4 +60,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_INTERNALS_HANDLER_IMPL_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_INTERNALS_HANDLER_IMPL_H_
diff --git a/content/browser/conversions/conversion_internals_ui.cc b/content/browser/attribution_reporting/conversion_internals_ui.cc
similarity index 93%
rename from content/browser/conversions/conversion_internals_ui.cc
rename to content/browser/attribution_reporting/conversion_internals_ui.cc
index 6faf073..a91fe3c 100644
--- a/content/browser/conversions/conversion_internals_ui.cc
+++ b/content/browser/attribution_reporting/conversion_internals_ui.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_internals_ui.h"
+#include "content/browser/attribution_reporting/conversion_internals_ui.h"
 
-#include "content/browser/conversions/conversion_internals_handler_impl.h"
+#include "content/browser/attribution_reporting/conversion_internals_handler_impl.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/grit/dev_ui_content_resources.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/content/browser/conversions/conversion_internals_ui.h b/content/browser/attribution_reporting/conversion_internals_ui.h
similarity index 79%
rename from content/browser/conversions/conversion_internals_ui.h
rename to content/browser/attribution_reporting/conversion_internals_ui.h
index c37822f..ac603da2 100644
--- a/content/browser/conversions/conversion_internals_ui.h
+++ b/content/browser/attribution_reporting/conversion_internals_ui.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_INTERNALS_UI_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_INTERNALS_UI_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_INTERNALS_UI_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_INTERNALS_UI_H_
 
 #include <memory>
 
-#include "content/browser/conversions/conversion_internals.mojom.h"
-#include "content/browser/conversions/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_internals.mojom.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -45,4 +45,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_INTERNALS_UI_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_INTERNALS_UI_H_
diff --git a/content/browser/conversions/conversion_manager.h b/content/browser/attribution_reporting/conversion_manager.h
similarity index 89%
rename from content/browser/conversions/conversion_manager.h
rename to content/browser/attribution_reporting/conversion_manager.h
index 9d45ea9..4cd685d 100644
--- a/content/browser/conversions/conversion_manager.h
+++ b/content/browser/attribution_reporting/conversion_manager.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_MANAGER_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_MANAGER_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_MANAGER_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_MANAGER_H_
 
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 #include "content/common/content_export.h"
 
 namespace base {
@@ -93,4 +93,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_MANAGER_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_MANAGER_H_
diff --git a/content/browser/conversions/conversion_manager_impl.cc b/content/browser/attribution_reporting/conversion_manager_impl.cc
similarity index 95%
rename from content/browser/conversions/conversion_manager_impl.cc
rename to content/browser/attribution_reporting/conversion_manager_impl.cc
index 2ed74057..27a82f8 100644
--- a/content/browser/conversions/conversion_manager_impl.cc
+++ b/content/browser/attribution_reporting/conversion_manager_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
 
 #include <utility>
 
@@ -14,13 +14,13 @@
 #include "base/task/lazy_thread_pool_task_runner.h"
 #include "base/threading/sequence_bound.h"
 #include "base/time/default_clock.h"
-#include "content/browser/conversions/conversion_policy.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_reporter_impl.h"
-#include "content/browser/conversions/conversion_storage_delegate_impl.h"
-#include "content/browser/conversions/conversion_storage_sql.h"
-#include "content/browser/conversions/storable_conversion.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_policy.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_reporter_impl.h"
+#include "content/browser/attribution_reporting/conversion_storage_delegate_impl.h"
+#include "content/browser/attribution_reporting/conversion_storage_sql.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
diff --git a/content/browser/conversions/conversion_manager_impl.h b/content/browser/attribution_reporting/conversion_manager_impl.h
similarity index 92%
rename from content/browser/conversions/conversion_manager_impl.h
rename to content/browser/attribution_reporting/conversion_manager_impl.h
index ff8b8a9..3e3136a 100644
--- a/content/browser/conversions/conversion_manager_impl.h
+++ b/content/browser/attribution_reporting/conversion_manager_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_MANAGER_IMPL_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_MANAGER_IMPL_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_MANAGER_IMPL_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_MANAGER_IMPL_H_
 
 #include <memory>
 #include <vector>
@@ -17,11 +17,11 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/sequence_bound.h"
 #include "base/timer/timer.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_session_storage.h"
-#include "content/browser/conversions/conversion_storage.h"
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_session_storage.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -196,4 +196,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_MANAGER_IMPL_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_MANAGER_IMPL_H_
diff --git a/content/browser/conversions/conversion_manager_impl_unittest.cc b/content/browser/attribution_reporting/conversion_manager_impl_unittest.cc
similarity index 98%
rename from content/browser/conversions/conversion_manager_impl_unittest.cc
rename to content/browser/attribution_reporting/conversion_manager_impl_unittest.cc
index e2e1525b..617dda2 100644
--- a/content/browser/conversions/conversion_manager_impl_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_manager_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
 
 #include <stdint.h>
 
@@ -21,11 +21,11 @@
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/sent_report_info.h"
-#include "content/browser/conversions/storable_conversion.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/public/test/browser_task_environment.h"
 #include "storage/browser/test/mock_special_storage_policy.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/conversions/conversion_network_sender_impl.cc b/content/browser/attribution_reporting/conversion_network_sender_impl.cc
similarity index 96%
rename from content/browser/conversions/conversion_network_sender_impl.cc
rename to content/browser/attribution_reporting/conversion_network_sender_impl.cc
index f1e8c78..5efca44 100644
--- a/content/browser/conversions/conversion_network_sender_impl.cc
+++ b/content/browser/attribution_reporting/conversion_network_sender_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_network_sender_impl.h"
+#include "content/browser/attribution_reporting/conversion_network_sender_impl.h"
 
 #include <string>
 #include <utility>
@@ -12,9 +12,9 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_utils.h"
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_utils.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 #include "content/public/browser/storage_partition.h"
 #include "net/base/isolation_info.h"
 #include "net/base/load_flags.h"
diff --git a/content/browser/conversions/conversion_network_sender_impl.h b/content/browser/attribution_reporting/conversion_network_sender_impl.h
similarity index 88%
rename from content/browser/conversions/conversion_network_sender_impl.h
rename to content/browser/attribution_reporting/conversion_network_sender_impl.h
index 86c3b6e6..1b130ac8 100644
--- a/content/browser/conversions/conversion_network_sender_impl.h
+++ b/content/browser/attribution_reporting/conversion_network_sender_impl.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_NETWORK_SENDER_IMPL_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_NETWORK_SENDER_IMPL_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_NETWORK_SENDER_IMPL_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_NETWORK_SENDER_IMPL_H_
 
 #include <list>
 #include <memory>
 
 #include "base/callback_forward.h"
-#include "content/browser/conversions/conversion_reporter_impl.h"
+#include "content/browser/attribution_reporting/conversion_reporter_impl.h"
 #include "content/common/content_export.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
@@ -76,4 +76,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_NETWORK_SENDER_IMPL_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_NETWORK_SENDER_IMPL_H_
diff --git a/content/browser/conversions/conversion_network_sender_impl_unittest.cc b/content/browser/attribution_reporting/conversion_network_sender_impl_unittest.cc
similarity index 98%
rename from content/browser/conversions/conversion_network_sender_impl_unittest.cc
rename to content/browser/attribution_reporting/conversion_network_sender_impl_unittest.cc
index 2b0d0fd8..aae184aa 100644
--- a/content/browser/conversions/conversion_network_sender_impl_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_network_sender_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_network_sender_impl.h"
+#include "content/browser/attribution_reporting/conversion_network_sender_impl.h"
 
 #include <string>
 #include <utility>
@@ -15,8 +15,8 @@
 #include "base/task/post_task.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
diff --git a/content/browser/conversions/conversion_page_metrics.cc b/content/browser/attribution_reporting/conversion_page_metrics.cc
similarity index 92%
rename from content/browser/conversions/conversion_page_metrics.cc
rename to content/browser/attribution_reporting/conversion_page_metrics.cc
index 3284c521..9857b99 100644
--- a/content/browser/conversions/conversion_page_metrics.cc
+++ b/content/browser/attribution_reporting/conversion_page_metrics.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_page_metrics.h"
+#include "content/browser/attribution_reporting/conversion_page_metrics.h"
 
 #include "base/metrics/histogram_functions.h"
 
diff --git a/content/browser/conversions/conversion_page_metrics.h b/content/browser/attribution_reporting/conversion_page_metrics.h
similarity index 83%
rename from content/browser/conversions/conversion_page_metrics.h
rename to content/browser/attribution_reporting/conversion_page_metrics.h
index 0e46b32..acf93e4 100644
--- a/content/browser/conversions/conversion_page_metrics.h
+++ b/content/browser/attribution_reporting/conversion_page_metrics.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_PAGE_METRICS_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_PAGE_METRICS_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_PAGE_METRICS_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_PAGE_METRICS_H_
 
 namespace content {
 
@@ -37,4 +37,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_PAGE_METRICS_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_PAGE_METRICS_H_
diff --git a/content/browser/conversions/conversion_policy.cc b/content/browser/attribution_reporting/conversion_policy.cc
similarity index 98%
rename from content/browser/conversions/conversion_policy.cc
rename to content/browser/attribution_reporting/conversion_policy.cc
index f23d7f5..311e8c9 100644
--- a/content/browser/conversions/conversion_policy.cc
+++ b/content/browser/attribution_reporting/conversion_policy.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_policy.h"
+#include "content/browser/attribution_reporting/conversion_policy.h"
 
 #include <math.h>
 
diff --git a/content/browser/conversions/conversion_policy.h b/content/browser/attribution_reporting/conversion_policy.h
similarity index 91%
rename from content/browser/conversions/conversion_policy.h
rename to content/browser/attribution_reporting/conversion_policy.h
index a01d1b1..c0f9126 100644
--- a/content/browser/conversions/conversion_policy.h
+++ b/content/browser/attribution_reporting/conversion_policy.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_POLICY_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_POLICY_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_POLICY_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_POLICY_H_
 
 #include <stdint.h>
 
 #include "base/compiler_specific.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/content_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -84,4 +84,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_POLICY_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_POLICY_H_
diff --git a/content/browser/conversions/conversion_policy_unittest.cc b/content/browser/attribution_reporting/conversion_policy_unittest.cc
similarity index 96%
rename from content/browser/conversions/conversion_policy_unittest.cc
rename to content/browser/attribution_reporting/conversion_policy_unittest.cc
index ce7a44c..a59aa42 100644
--- a/content/browser/conversions/conversion_policy_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_policy_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_policy.h"
+#include "content/browser/attribution_reporting/conversion_policy.h"
 
 #include <memory>
 #include <vector>
 
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
diff --git a/content/browser/conversions/conversion_registration_browsertest.cc b/content/browser/attribution_reporting/conversion_registration_browsertest.cc
similarity index 98%
rename from content/browser/conversions/conversion_registration_browsertest.cc
rename to content/browser/attribution_reporting/conversion_registration_browsertest.cc
index a5b0c926c..73af8cf 100644
--- a/content/browser/conversions/conversion_registration_browsertest.cc
+++ b/content/browser/attribution_reporting/conversion_registration_browsertest.cc
@@ -6,8 +6,8 @@
 #include <memory>
 
 #include "base/bind.h"
-#include "content/browser/conversions/conversion_host.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
diff --git a/content/browser/conversions/conversion_report.cc b/content/browser/attribution_reporting/conversion_report.cc
similarity index 97%
rename from content/browser/conversions/conversion_report.cc
rename to content/browser/attribution_reporting/conversion_report.cc
index ada43e6..8ff9f45 100644
--- a/content/browser/conversions/conversion_report.cc
+++ b/content/browser/attribution_reporting/conversion_report.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
 
 #include "base/check.h"
 #include "base/json/json_writer.h"
diff --git a/content/browser/conversions/conversion_report.h b/content/browser/attribution_reporting/conversion_report.h
similarity index 89%
rename from content/browser/conversions/conversion_report.h
rename to content/browser/attribution_reporting/conversion_report.h
index 6e2ddb8..cc06de600 100644
--- a/content/browser/conversions/conversion_report.h
+++ b/content/browser/attribution_reporting/conversion_report.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_REPORT_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_REPORT_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_REPORT_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_REPORT_H_
 
 #include <stdint.h>
 
@@ -12,7 +12,7 @@
 #include "base/compiler_specific.h"
 #include "base/time/time.h"
 #include "base/types/strong_alias.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/content_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -74,4 +74,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_REPORT_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_REPORT_H_
diff --git a/content/browser/conversions/conversion_reporter_impl.cc b/content/browser/attribution_reporting/conversion_reporter_impl.cc
similarity index 93%
rename from content/browser/conversions/conversion_reporter_impl.cc
rename to content/browser/attribution_reporting/conversion_reporter_impl.cc
index c8de47b..d6a076c1 100644
--- a/content/browser/conversions/conversion_reporter_impl.cc
+++ b/content/browser/attribution_reporting/conversion_reporter_impl.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_reporter_impl.h"
+#include "content/browser/attribution_reporting/conversion_reporter_impl.h"
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/rand_util.h"
 #include "base/time/clock.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_network_sender_impl.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_network_sender_impl.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/network_service_instance.h"
diff --git a/content/browser/conversions/conversion_reporter_impl.h b/content/browser/attribution_reporting/conversion_reporter_impl.h
similarity index 92%
rename from content/browser/conversions/conversion_reporter_impl.h
rename to content/browser/attribution_reporting/conversion_reporter_impl.h
index ff969431..1240f85 100644
--- a/content/browser/conversions/conversion_reporter_impl.h
+++ b/content/browser/attribution_reporting/conversion_reporter_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_REPORTER_IMPL_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_REPORTER_IMPL_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_REPORTER_IMPL_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_REPORTER_IMPL_H_
 
 #include <stdint.h>
 #include <memory>
@@ -13,8 +13,8 @@
 #include "base/callback_forward.h"
 #include "base/containers/flat_set.h"
 #include "base/timer/timer.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
-#include "content/browser/conversions/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
 #include "content/common/content_export.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -131,4 +131,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_REPORTER_IMPL_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_REPORTER_IMPL_H_
diff --git a/content/browser/conversions/conversion_reporter_impl_unittest.cc b/content/browser/attribution_reporting/conversion_reporter_impl_unittest.cc
similarity index 97%
rename from content/browser/conversions/conversion_reporter_impl_unittest.cc
rename to content/browser/attribution_reporting/conversion_reporter_impl_unittest.cc
index dd685e7..5829848 100644
--- a/content/browser/conversions/conversion_reporter_impl_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_reporter_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_reporter_impl.h"
+#include "content/browser/attribution_reporting/conversion_reporter_impl.h"
 
 #include <stdint.h>
 
@@ -13,9 +13,9 @@
 #include "base/task/post_task.h"
 #include "base/test/bind.h"
 #include "base/test/simple_test_clock.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/network_service_instance.h"
diff --git a/content/browser/conversions/conversion_session_storage.cc b/content/browser/attribution_reporting/conversion_session_storage.cc
similarity index 93%
rename from content/browser/conversions/conversion_session_storage.cc
rename to content/browser/attribution_reporting/conversion_session_storage.cc
index 6533fb3..1bced0c 100644
--- a/content/browser/conversions/conversion_session_storage.cc
+++ b/content/browser/attribution_reporting/conversion_session_storage.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_session_storage.h"
+#include "content/browser/attribution_reporting/conversion_session_storage.h"
 
 #include "base/check.h"
 
diff --git a/content/browser/conversions/conversion_session_storage.h b/content/browser/attribution_reporting/conversion_session_storage.h
similarity index 78%
rename from content/browser/conversions/conversion_session_storage.h
rename to content/browser/attribution_reporting/conversion_session_storage.h
index 6c97a5a..b547a96 100644
--- a/content/browser/conversions/conversion_session_storage.h
+++ b/content/browser/attribution_reporting/conversion_session_storage.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_SESSION_STORAGE_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_SESSION_STORAGE_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_SESSION_STORAGE_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_SESSION_STORAGE_H_
 
 #include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -48,4 +48,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_SESSION_STORAGE_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_SESSION_STORAGE_H_
diff --git a/content/browser/conversions/conversion_storage.cc b/content/browser/attribution_reporting/conversion_storage.cc
similarity index 92%
rename from content/browser/conversions/conversion_storage.cc
rename to content/browser/attribution_reporting/conversion_storage.cc
index e9cc58f1..542b9ded 100644
--- a/content/browser/conversions/conversion_storage.cc
+++ b/content/browser/attribution_reporting/conversion_storage.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
 
 namespace content {
 
diff --git a/content/browser/conversions/conversion_storage.h b/content/browser/attribution_reporting/conversion_storage.h
similarity index 95%
rename from content/browser/conversions/conversion_storage.h
rename to content/browser/attribution_reporting/conversion_storage.h
index 19a4cce..2f8186a1 100644
--- a/content/browser/conversions/conversion_storage.h
+++ b/content/browser/attribution_reporting/conversion_storage.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_H_
 
 #include <stdint.h>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 
 namespace base {
 class Time;
@@ -204,4 +204,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_H_
diff --git a/content/browser/conversions/conversion_storage_delegate_impl.cc b/content/browser/attribution_reporting/conversion_storage_delegate_impl.cc
similarity index 92%
rename from content/browser/conversions/conversion_storage_delegate_impl.cc
rename to content/browser/attribution_reporting/conversion_storage_delegate_impl.cc
index bfcc847b..0b862dc 100644
--- a/content/browser/conversions/conversion_storage_delegate_impl.cc
+++ b/content/browser/attribution_reporting/conversion_storage_delegate_impl.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage_delegate_impl.h"
+#include "content/browser/attribution_reporting/conversion_storage_delegate_impl.h"
 
 #include "base/rand_util.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_policy.h"
-#include "content/browser/conversions/conversion_utils.h"
+#include "content/browser/attribution_reporting/conversion_policy.h"
+#include "content/browser/attribution_reporting/conversion_utils.h"
 
 namespace content {
 
diff --git a/content/browser/conversions/conversion_storage_delegate_impl.h b/content/browser/attribution_reporting/conversion_storage_delegate_impl.h
similarity index 84%
rename from content/browser/conversions/conversion_storage_delegate_impl.h
rename to content/browser/attribution_reporting/conversion_storage_delegate_impl.h
index 524690d..1935c03f 100644
--- a/content/browser/conversions/conversion_storage_delegate_impl.h
+++ b/content/browser/attribution_reporting/conversion_storage_delegate_impl.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_DELEGATE_IMPL_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_DELEGATE_IMPL_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_DELEGATE_IMPL_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_DELEGATE_IMPL_H_
 
 #include "base/sequence_checker.h"
-#include "content/browser/conversions/conversion_storage.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/content_export.h"
 
 namespace base {
@@ -58,4 +58,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_DELEGATE_IMPL_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_DELEGATE_IMPL_H_
diff --git a/content/browser/conversions/conversion_storage_delegate_impl_unittest.cc b/content/browser/attribution_reporting/conversion_storage_delegate_impl_unittest.cc
similarity index 95%
rename from content/browser/conversions/conversion_storage_delegate_impl_unittest.cc
rename to content/browser/attribution_reporting/conversion_storage_delegate_impl_unittest.cc
index 3a686e3..aa3e582 100644
--- a/content/browser/conversions/conversion_storage_delegate_impl_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_storage_delegate_impl_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage_delegate_impl.h"
+#include "content/browser/attribution_reporting/conversion_storage_delegate_impl.h"
 
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
diff --git a/content/browser/conversions/conversion_storage_sql.cc b/content/browser/attribution_reporting/conversion_storage_sql.cc
similarity index 99%
rename from content/browser/conversions/conversion_storage_sql.cc
rename to content/browser/attribution_reporting/conversion_storage_sql.cc
index 7588d6a..2acd883 100644
--- a/content/browser/conversions/conversion_storage_sql.cc
+++ b/content/browser/attribution_reporting/conversion_storage_sql.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage_sql.h"
+#include "content/browser/attribution_reporting/conversion_storage_sql.h"
 
 #include <stdint.h>
 #include <string>
@@ -19,11 +19,11 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_storage_sql_migrations.h"
-#include "content/browser/conversions/sql_utils.h"
-#include "content/browser/conversions/storable_conversion.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_storage_sql_migrations.h"
+#include "content/browser/attribution_reporting/sql_utils.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "sql/database.h"
 #include "sql/recovery.h"
 #include "sql/statement.h"
diff --git a/content/browser/conversions/conversion_storage_sql.h b/content/browser/attribution_reporting/conversion_storage_sql.h
similarity index 94%
rename from content/browser/conversions/conversion_storage_sql.h
rename to content/browser/attribution_reporting/conversion_storage_sql.h
index ef50adf..760c501 100644
--- a/content/browser/conversions/conversion_storage_sql.h
+++ b/content/browser/attribution_reporting/conversion_storage_sql.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_SQL_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_SQL_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_SQL_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_SQL_H_
 
 #include <memory>
 #include <vector>
@@ -13,9 +13,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
-#include "content/browser/conversions/conversion_storage.h"
-#include "content/browser/conversions/rate_limit_table.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
+#include "content/browser/attribution_reporting/rate_limit_table.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/content_export.h"
 #include "sql/meta_table.h"
 
@@ -227,4 +227,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_SQL_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_SQL_H_
diff --git a/content/browser/conversions/conversion_storage_sql_migrations.cc b/content/browser/attribution_reporting/conversion_storage_sql_migrations.cc
similarity index 99%
rename from content/browser/conversions/conversion_storage_sql_migrations.cc
rename to content/browser/attribution_reporting/conversion_storage_sql_migrations.cc
index 7f03b14..2db31d2 100644
--- a/content/browser/conversions/conversion_storage_sql_migrations.cc
+++ b/content/browser/attribution_reporting/conversion_storage_sql_migrations.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage_sql_migrations.h"
+#include "content/browser/attribution_reporting/conversion_storage_sql_migrations.h"
 
 #include <vector>
 
 #include "base/metrics/histogram_functions.h"
-#include "content/browser/conversions/sql_utils.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/sql_utils.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "net/base/schemeful_site.h"
 #include "sql/database.h"
 #include "sql/meta_table.h"
diff --git a/content/browser/conversions/conversion_storage_sql_migrations.h b/content/browser/attribution_reporting/conversion_storage_sql_migrations.h
similarity index 88%
rename from content/browser/conversions/conversion_storage_sql_migrations.h
rename to content/browser/attribution_reporting/conversion_storage_sql_migrations.h
index d315173..d54b36a 100644
--- a/content/browser/conversions/conversion_storage_sql_migrations.h
+++ b/content/browser/attribution_reporting/conversion_storage_sql_migrations.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_SQL_MIGRATIONS_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_SQL_MIGRATIONS_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_SQL_MIGRATIONS_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_SQL_MIGRATIONS_H_
 
 #include "base/compiler_specific.h"
 
@@ -50,4 +50,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_STORAGE_SQL_MIGRATIONS_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_STORAGE_SQL_MIGRATIONS_H_
diff --git a/content/browser/conversions/conversion_storage_sql_migrations_unittest.cc b/content/browser/attribution_reporting/conversion_storage_sql_migrations_unittest.cc
similarity index 98%
rename from content/browser/conversions/conversion_storage_sql_migrations_unittest.cc
rename to content/browser/attribution_reporting/conversion_storage_sql_migrations_unittest.cc
index 58aa508..a4b03c3 100644
--- a/content/browser/conversions/conversion_storage_sql_migrations_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_storage_sql_migrations_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage_sql.h"
+#include "content/browser/attribution_reporting/conversion_storage_sql.h"
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -13,8 +13,8 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_storage.h"
-#include "content/browser/conversions/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
 #include "sql/database.h"
 #include "sql/statement.h"
 #include "sql/test/test_helpers.h"
diff --git a/content/browser/conversions/conversion_storage_sql_unittest.cc b/content/browser/attribution_reporting/conversion_storage_sql_unittest.cc
similarity index 98%
rename from content/browser/conversions/conversion_storage_sql_unittest.cc
rename to content/browser/attribution_reporting/conversion_storage_sql_unittest.cc
index 351f22c..af1ef1a 100644
--- a/content/browser/conversions/conversion_storage_sql_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_storage_sql_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage_sql.h"
+#include "content/browser/attribution_reporting/conversion_storage_sql.h"
 
 #include <functional>
 #include <memory>
@@ -14,10 +14,10 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/storable_conversion.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "sql/database.h"
 #include "sql/test/scoped_error_expecter.h"
 #include "sql/test/test_helpers.h"
diff --git a/content/browser/conversions/conversion_storage_unittest.cc b/content/browser/attribution_reporting/conversion_storage_unittest.cc
similarity index 98%
rename from content/browser/conversions/conversion_storage_unittest.cc
rename to content/browser/attribution_reporting/conversion_storage_unittest.cc
index ad25741..b25ac58 100644
--- a/content/browser/conversions/conversion_storage_unittest.cc
+++ b/content/browser/attribution_reporting/conversion_storage_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_storage.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
 
 #include <functional>
 #include <list>
@@ -18,11 +18,11 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/simple_test_clock.h"
 #include "build/build_config.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_storage_sql.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/storable_conversion.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_storage_sql.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/public/common/url_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
diff --git a/content/browser/conversions/conversion_test_utils.cc b/content/browser/attribution_reporting/conversion_test_utils.cc
similarity index 98%
rename from content/browser/conversions/conversion_test_utils.cc
rename to content/browser/attribution_reporting/conversion_test_utils.cc
index ca636fbc..804ec938 100644
--- a/content/browser/conversions/conversion_test_utils.cc
+++ b/content/browser/attribution_reporting/conversion_test_utils.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
 
 #include <limits.h>
 #include <algorithm>
@@ -16,7 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
 #include "base/test/bind.h"
-#include "content/browser/conversions/storable_conversion.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
 #include "url/gurl.h"
 
 namespace content {
diff --git a/content/browser/conversions/conversion_test_utils.h b/content/browser/attribution_reporting/conversion_test_utils.h
similarity index 92%
rename from content/browser/conversions/conversion_test_utils.h
rename to content/browser/attribution_reporting/conversion_test_utils.h
index f38db72..30cd56e 100644
--- a/content/browser/conversions/conversion_test_utils.h
+++ b/content/browser/attribution_reporting/conversion_test_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_TEST_UTILS_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_TEST_UTILS_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_TEST_UTILS_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_TEST_UTILS_H_
 
 #include <stdint.h>
 
@@ -13,15 +13,15 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_manager.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
-#include "content/browser/conversions/conversion_policy.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_session_storage.h"
-#include "content/browser/conversions/conversion_storage.h"
-#include "content/browser/conversions/rate_limit_table.h"
-#include "content/browser/conversions/sent_report_info.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_manager.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_policy.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_session_storage.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
+#include "content/browser/attribution_reporting/rate_limit_table.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/test/test_content_browser_client.h"
 #include "net/base/schemeful_site.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -354,4 +354,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_TEST_UTILS_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_TEST_UTILS_H_
diff --git a/content/browser/conversions/conversion_utils.cc b/content/browser/attribution_reporting/conversion_utils.cc
similarity index 95%
rename from content/browser/conversions/conversion_utils.cc
rename to content/browser/attribution_reporting/conversion_utils.cc
index b26e446..755f6ba 100644
--- a/content/browser/conversions/conversion_utils.cc
+++ b/content/browser/attribution_reporting/conversion_utils.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/conversion_utils.h"
+#include "content/browser/attribution_reporting/conversion_utils.h"
 
 #include <vector>
 
 #include "base/check.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 
 namespace content {
 
diff --git a/content/browser/conversions/conversion_utils.h b/content/browser/attribution_reporting/conversion_utils.h
similarity index 73%
rename from content/browser/conversions/conversion_utils.h
rename to content/browser/attribution_reporting/conversion_utils.h
index 5a0c44b..05919b8 100644
--- a/content/browser/conversions/conversion_utils.h
+++ b/content/browser/attribution_reporting/conversion_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_UTILS_H_
-#define CONTENT_BROWSER_CONVERSIONS_CONVERSION_UTILS_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_UTILS_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_UTILS_H_
 
 #include "base/compiler_specific.h"
 
@@ -21,4 +21,4 @@
                              base::Time conversion_time) WARN_UNUSED_RESULT;
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_CONVERSION_UTILS_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_CONVERSION_UTILS_H_
diff --git a/content/browser/conversions/conversions_browsertest.cc b/content/browser/attribution_reporting/conversions_browsertest.cc
similarity index 98%
rename from content/browser/conversions/conversions_browsertest.cc
rename to content/browser/attribution_reporting/conversions_browsertest.cc
index 4ced861..a565b290 100644
--- a/content/browser/conversions/conversions_browsertest.cc
+++ b/content/browser/attribution_reporting/conversions_browsertest.cc
@@ -8,8 +8,8 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/strcat.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
-#include "content/browser/conversions/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -88,9 +88,7 @@
 
 class ConversionsBrowserTest : public ContentBrowserTest {
  public:
-  ConversionsBrowserTest() {
-    ConversionManagerImpl::RunInMemoryForTesting();
-  }
+  ConversionsBrowserTest() { ConversionManagerImpl::RunInMemoryForTesting(); }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(switches::kConversionsDebugMode);
diff --git a/content/browser/conversions/conversions_origin_trial_browsertest.cc b/content/browser/attribution_reporting/conversions_origin_trial_browsertest.cc
similarity index 93%
rename from content/browser/conversions/conversions_origin_trial_browsertest.cc
rename to content/browser/attribution_reporting/conversions_origin_trial_browsertest.cc
index 0ce6d13..d5d79b7 100644
--- a/content/browser/conversions/conversions_origin_trial_browsertest.cc
+++ b/content/browser/attribution_reporting/conversions_origin_trial_browsertest.cc
@@ -4,12 +4,12 @@
 
 #include <vector>
 
-#include "build/build_config.h"
 #include "base/strings/strcat.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "build/build_config.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_handle.h"
@@ -90,9 +90,11 @@
 
 #if defined(OS_LINUX)
 // TODO(https://crbug.com/1121464): Flaky on linux.
-#define MAYBE_OriginTrialEnabled_ImpressionRegistered DISABLED_OriginTrialEnabled_ImpressionRegistered
+#define MAYBE_OriginTrialEnabled_ImpressionRegistered \
+  DISABLED_OriginTrialEnabled_ImpressionRegistered
 #else
-#define MAYBE_OriginTrialEnabled_ImpressionRegistered OriginTrialEnabled_ImpressionRegistered
+#define MAYBE_OriginTrialEnabled_ImpressionRegistered \
+  OriginTrialEnabled_ImpressionRegistered
 #endif
 
 IN_PROC_BROWSER_TEST_F(ConversionsOriginTrialBrowserTest,
diff --git a/content/browser/conversions/impression_declaration_browsertest.cc b/content/browser/attribution_reporting/impression_declaration_browsertest.cc
similarity index 99%
rename from content/browser/conversions/impression_declaration_browsertest.cc
rename to content/browser/attribution_reporting/impression_declaration_browsertest.cc
index 8f82aaf..b66d62e 100644
--- a/content/browser/conversions/impression_declaration_browsertest.cc
+++ b/content/browser/attribution_reporting/impression_declaration_browsertest.cc
@@ -10,8 +10,8 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "content/browser/conversions/conversion_host.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/common/content_switches.h"
diff --git a/content/browser/conversions/rate_limit_table.cc b/content/browser/attribution_reporting/rate_limit_table.cc
similarity index 98%
rename from content/browser/conversions/rate_limit_table.cc
rename to content/browser/attribution_reporting/rate_limit_table.cc
index 4027dc1..6b580f652 100644
--- a/content/browser/conversions/rate_limit_table.cc
+++ b/content/browser/attribution_reporting/rate_limit_table.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/rate_limit_table.h"
+#include "content/browser/attribution_reporting/rate_limit_table.h"
 
 #include "base/check.h"
 #include "base/time/clock.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/sql_utils.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/sql_utils.h"
 #include "net/base/schemeful_site.h"
 #include "sql/database.h"
 #include "sql/statement.h"
diff --git a/content/browser/conversions/rate_limit_table.h b/content/browser/attribution_reporting/rate_limit_table.h
similarity index 93%
rename from content/browser/conversions/rate_limit_table.h
rename to content/browser/attribution_reporting/rate_limit_table.h
index d75a1a6..9c9bc05d 100644
--- a/content/browser/conversions/rate_limit_table.h
+++ b/content/browser/attribution_reporting/rate_limit_table.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_RATE_LIMIT_TABLE_H_
-#define CONTENT_BROWSER_CONVERSIONS_RATE_LIMIT_TABLE_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_RATE_LIMIT_TABLE_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_RATE_LIMIT_TABLE_H_
 
 #include <string>
 #include <vector>
@@ -13,8 +13,8 @@
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_storage.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_storage.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "content/common/content_export.h"
 
 namespace base {
@@ -149,4 +149,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_RATE_LIMIT_TABLE_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_RATE_LIMIT_TABLE_H_
diff --git a/content/browser/conversions/rate_limit_table_unittest.cc b/content/browser/attribution_reporting/rate_limit_table_unittest.cc
similarity index 98%
rename from content/browser/conversions/rate_limit_table_unittest.cc
rename to content/browser/attribution_reporting/rate_limit_table_unittest.cc
index f3744a4d..b3343d3 100644
--- a/content/browser/conversions/rate_limit_table_unittest.cc
+++ b/content/browser/attribution_reporting/rate_limit_table_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/rate_limit_table.h"
+#include "content/browser/attribution_reporting/rate_limit_table.h"
 
 #include <memory>
 
@@ -11,9 +11,9 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/test/simple_test_clock.h"
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_report.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 #include "sql/database.h"
 #include "sql/statement.h"
 #include "sql/test/test_helpers.h"
diff --git a/content/browser/conversions/sent_report_info.cc b/content/browser/attribution_reporting/sent_report_info.cc
similarity index 92%
rename from content/browser/conversions/sent_report_info.cc
rename to content/browser/attribution_reporting/sent_report_info.cc
index 4c04d3b..3c38ab2 100644
--- a/content/browser/conversions/sent_report_info.cc
+++ b/content/browser/attribution_reporting/sent_report_info.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/sent_report_info.h"
+#include "content/browser/attribution_reporting/sent_report_info.h"
 
 namespace content {
 
diff --git a/content/browser/conversions/sent_report_info.h b/content/browser/attribution_reporting/sent_report_info.h
similarity index 83%
rename from content/browser/conversions/sent_report_info.h
rename to content/browser/attribution_reporting/sent_report_info.h
index a17832f..bb253ef 100644
--- a/content/browser/conversions/sent_report_info.h
+++ b/content/browser/attribution_reporting/sent_report_info.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_SENT_REPORT_INFO_H_
-#define CONTENT_BROWSER_CONVERSIONS_SENT_REPORT_INFO_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_SENT_REPORT_INFO_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_SENT_REPORT_INFO_H_
 
 #include "base/time/time.h"
-#include "content/browser/conversions/conversion_report.h"
+#include "content/browser/attribution_reporting/conversion_report.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -48,4 +48,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_SENT_REPORT_INFO_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_SENT_REPORT_INFO_H_
diff --git a/content/browser/conversions/sql_utils.cc b/content/browser/attribution_reporting/sql_utils.cc
similarity index 95%
rename from content/browser/conversions/sql_utils.cc
rename to content/browser/attribution_reporting/sql_utils.cc
index 661a4f2c..379cd29 100644
--- a/content/browser/conversions/sql_utils.cc
+++ b/content/browser/attribution_reporting/sql_utils.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/sql_utils.h"
+#include "content/browser/attribution_reporting/sql_utils.h"
 
 #include "base/check.h"
 #include "url/gurl.h"
diff --git a/content/browser/conversions/sql_utils.h b/content/browser/attribution_reporting/sql_utils.h
similarity index 89%
rename from content/browser/conversions/sql_utils.h
rename to content/browser/attribution_reporting/sql_utils.h
index 5b03f1b..3788053 100644
--- a/content/browser/conversions/sql_utils.h
+++ b/content/browser/attribution_reporting/sql_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_SQL_UTILS_H_
-#define CONTENT_BROWSER_CONVERSIONS_SQL_UTILS_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_SQL_UTILS_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_SQL_UTILS_H_
 
 #include <stdint.h>
 
@@ -47,4 +47,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_SQL_UTILS_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_SQL_UTILS_H_
diff --git a/content/browser/conversions/storable_conversion.cc b/content/browser/attribution_reporting/storable_conversion.cc
similarity index 94%
rename from content/browser/conversions/storable_conversion.cc
rename to content/browser/attribution_reporting/storable_conversion.cc
index 8e02c4f..2e44fa1 100644
--- a/content/browser/conversions/storable_conversion.cc
+++ b/content/browser/attribution_reporting/storable_conversion.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/storable_conversion.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
 
 #include <utility>
 
diff --git a/content/browser/conversions/storable_conversion.h b/content/browser/attribution_reporting/storable_conversion.h
similarity index 93%
rename from content/browser/conversions/storable_conversion.h
rename to content/browser/attribution_reporting/storable_conversion.h
index e015342..ea6a314 100644
--- a/content/browser/conversions/storable_conversion.h
+++ b/content/browser/attribution_reporting/storable_conversion.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_STORABLE_CONVERSION_H_
-#define CONTENT_BROWSER_CONVERSIONS_STORABLE_CONVERSION_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_STORABLE_CONVERSION_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_STORABLE_CONVERSION_H_
 
 #include <stdint.h>
 
@@ -84,4 +84,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_STORABLE_CONVERSION_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_STORABLE_CONVERSION_H_
diff --git a/content/browser/conversions/storable_impression.cc b/content/browser/attribution_reporting/storable_impression.cc
similarity index 96%
rename from content/browser/conversions/storable_impression.cc
rename to content/browser/attribution_reporting/storable_impression.cc
index 6dcead5d..c56027dc 100644
--- a/content/browser/conversions/storable_impression.cc
+++ b/content/browser/attribution_reporting/storable_impression.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/conversions/storable_impression.h"
+#include "content/browser/attribution_reporting/storable_impression.h"
 
 #include "base/check_op.h"
 #include "net/base/schemeful_site.h"
diff --git a/content/browser/conversions/storable_impression.h b/content/browser/attribution_reporting/storable_impression.h
similarity index 95%
rename from content/browser/conversions/storable_impression.h
rename to content/browser/attribution_reporting/storable_impression.h
index 808e35a..c4e4f0a 100644
--- a/content/browser/conversions/storable_impression.h
+++ b/content/browser/attribution_reporting/storable_impression.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_CONVERSIONS_STORABLE_IMPRESSION_H_
-#define CONTENT_BROWSER_CONVERSIONS_STORABLE_IMPRESSION_H_
+#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_STORABLE_IMPRESSION_H_
+#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_STORABLE_IMPRESSION_H_
 
 #include <stdint.h>
 
@@ -145,4 +145,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_CONVERSIONS_STORABLE_IMPRESSION_H_
+#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_STORABLE_IMPRESSION_H_
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 6e80ed2..cd89fc3 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -11945,8 +11945,8 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
-    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache, "",
-                              "");
+    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache,
+                              "level", "store-and-evict");
     BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
   }
 };
@@ -12513,11 +12513,8 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
-    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache, "",
-                              "");
-    EnableFeatureAndSetParams(
-        kCacheControlNoStoreRestoreFromBackForwardCacheUnlessCookieChange, "",
-        "");
+    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache,
+                              "level", "restore-unless-cookie-change");
     BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
   }
 };
@@ -12628,6 +12625,309 @@
                     {}, {}, {}, {}, FROM_HERE);
 }
 
+// TODO(https://crbug.com/1231849): flaky on Cast Linux.
+#if defined(OS_LINUX)
+#define MAYBE_PagesWithCacheControlNoStoreEvictedWithBothCookieReasons \
+  DISABLED_PagesWithCacheControlNoStoreEvictedWithBothCookieReasons
+#else
+#define MAYBE_PagesWithCacheControlNoStoreEvictedWithBothCookieReasons \
+  PagesWithCacheControlNoStoreEvictedWithBothCookieReasons
+#endif
+
+// Test that a page with cache-control:no-store enters bfcache with the flag on,
+// and gets evicted with both JavaScript and HTTPOnly cookie changes. Only
+// HTTPOnly cookie reason should be recorded.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange,
+    MAYBE_PagesWithCacheControlNoStoreEvictedWithBothCookieReasons) {
+  CreateHttpsServer();
+  net::test_server::ControllableHttpResponse response(https_server(),
+                                                      "/main_document");
+  net::test_server::ControllableHttpResponse response2(https_server(),
+                                                       "/main_document2");
+  net::test_server::ControllableHttpResponse response3(https_server(),
+                                                       "/main_document");
+  ASSERT_TRUE(https_server()->Start());
+
+  GURL url_a(https_server()->GetURL("a.com", "/main_document"));
+  GURL url_a_2(https_server()->GetURL("a.com", "/main_document2"));
+  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
+
+  Shell* tab_to_be_bfcached = shell();
+  Shell* tab_to_modify_cookie = CreateBrowser();
+
+  // 1) Load the document and specify no-store for the main resource.
+  TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
+  tab_to_be_bfcached->LoadURL(url_a);
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  response.WaitForRequest();
+  response.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
+  response.Done();
+  observer.Wait();
+
+  // 2) Navigate away. |rfh_a| should enter bfcache.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  // Modify cookie from JavaScript as well.
+  EXPECT_TRUE(ExecJs(tab_to_be_bfcached, "document.cookie='foo=quz'"));
+
+  // 3) Navigate to a.com in |tab_to_modify_cookie| and modify HTTPOnly cookie
+  // from the response.
+  TestNavigationObserver observer2(tab_to_modify_cookie->web_contents());
+  tab_to_modify_cookie->LoadURL(url_a_2);
+  response2.WaitForRequest();
+  response2.Send(kResponseWithNoCacheWithHTTPOnlyCookie2);
+  response2.Done();
+  observer2.Wait();
+
+  // 4) Go back. |rfh_a| should be evicted upon restoration.
+  TestNavigationObserver observer3(tab_to_be_bfcached->web_contents());
+  tab_to_be_bfcached->web_contents()->GetController().GoBack();
+  response3.WaitForRequest();
+  response3.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
+  response3.Done();
+  observer3.Wait();
+  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
+                         kCacheControlNoStoreHTTPOnlyCookieModified},
+                    {}, {}, {}, {}, FROM_HERE);
+}
+
+class BackForwardCacheBrowserTestRestoreUnlessHTTPOnlyCookieChange
+    : public BackForwardCacheBrowserTest {
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
+    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache,
+                              "level",
+                              "restore-unless-http-only-cookie-change");
+    BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
+  }
+};
+
+// TODO(https://crbug.com/1231849): flaky on Cast Linux.
+#if defined(OS_LINUX)
+#define MAYBE_NoCacheControlNoStoreButHTTPOnlyCookieChange \
+  DISABLED_NoCacheControlNoStoreButHTTPOnlyCookieChange
+#else
+#define MAYBE_NoCacheControlNoStoreButHTTPOnlyCookieChange \
+  NoCacheControlNoStoreButHTTPOnlyCookieChange
+#endif
+
+// Test that a page without cache-control:no-store can enter BackForwardCache
+// and gets restored if HTTPOnly Cookie changes.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestRestoreUnlessHTTPOnlyCookieChange,
+    MAYBE_NoCacheControlNoStoreButHTTPOnlyCookieChange) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/set-header?Set-Cookie: foo=bar; Secure; HttpOnly;"));
+  GURL url_a_2(embedded_test_server()->GetURL(
+      "a.com", "/set-header?Set-Cookie: foo=baz; Secure; HttpOnly;"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  Shell* tab_to_be_bfcached = shell();
+  Shell* tab_to_modify_cookie = CreateBrowser();
+
+  // 1) Load the document without cache-control:no-store.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_a));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+
+  // 2) Navigate away. |rfh_a| should enter bfcache.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 3) Navigate to a.com in |tab_to_modify_cookie| and modify HTTPOnly cookie
+  // from the header.
+  EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_a_2));
+
+  // 4) Go back. |rfh_a| should be restored from bfcache.
+  tab_to_be_bfcached->web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(tab_to_be_bfcached->web_contents()));
+
+  ExpectRestored(FROM_HERE);
+}
+
+// TODO(https://crbug.com/1231849): flaky on Cast Linux.
+#if defined(OS_LINUX)
+#define MAYBE_PagesWithCacheControlNoStoreNotEvictedIfNormalCookieChange \
+  DISABLED_PagesWithCacheControlNoStoreNotEvictedIfNormalCookieChange
+#else
+#define MAYBE_PagesWithCacheControlNoStoreNotEvictedIfNormalCookieChange \
+  PagesWithCacheControlNoStoreNotEvictedIfNormalCookieChange
+#endif
+
+// Test that a page with cache-control:no-store enters bfcache with the flag on,
+// and does not get evicted if normal cookies change.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestRestoreUnlessHTTPOnlyCookieChange,
+    MAYBE_PagesWithCacheControlNoStoreNotEvictedIfNormalCookieChange) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/set-header?Cache-Control: no-store"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  Shell* tab_to_be_bfcached = shell();
+  Shell* tab_to_modify_cookie = CreateBrowser();
+
+  // 1) Load the document and specify no-store for the main resource.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_a));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+
+  // 2) Set a normal cookie from JavaScript.
+  EXPECT_TRUE(ExecJs(tab_to_be_bfcached, "document.cookie='foo=bar'"));
+  EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
+
+  // 3) Navigate away. |rfh_a| should enter bfcache.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 4) Navigate to a.com in |tab_to_modify_cookie| and modify cookie from
+  // JavaScript.
+  EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_a));
+  EXPECT_EQ("foo=bar", EvalJs(tab_to_modify_cookie, "document.cookie"));
+  EXPECT_TRUE(ExecJs(tab_to_modify_cookie, "document.cookie='foo=baz'"));
+  EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
+
+  // 5) Go back. |rfh_a| should be restored from bfcache.
+  tab_to_be_bfcached->web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(tab_to_be_bfcached->web_contents()));
+
+  EXPECT_EQ("foo=baz", EvalJs(tab_to_be_bfcached, "document.cookie"));
+  ExpectRestored(FROM_HERE);
+}
+
+// TODO(https://crbug.com/1231849): flaky on Cast Linux.
+#if defined(OS_LINUX)
+#define MAYBE_PagesWithCacheControlNoStoreEvictedIfHTTPOnlyCookieChange \
+  DISABLED_PagesWithCacheControlNoStoreEvictedIfHTTPOnlyCookieChange
+#else
+#define MAYBE_PagesWithCacheControlNoStoreEvictedIfHTTPOnlyCookieChange \
+  PagesWithCacheControlNoStoreEvictedIfHTTPOnlyCookieChange
+#endif
+
+// Test that a page with cache-control:no-store enters bfcache with the flag on,
+// and gets evicted if HTTPOnly cookie changes.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange,
+    MAYBE_PagesWithCacheControlNoStoreEvictedIfHTTPOnlyCookieChange) {
+  CreateHttpsServer();
+  net::test_server::ControllableHttpResponse response(https_server(),
+                                                      "/main_document");
+  net::test_server::ControllableHttpResponse response2(https_server(),
+                                                       "/main_document2");
+  net::test_server::ControllableHttpResponse response3(https_server(),
+                                                       "/main_document");
+  ASSERT_TRUE(https_server()->Start());
+
+  GURL url_a(https_server()->GetURL("a.com", "/main_document"));
+  GURL url_a_2(https_server()->GetURL("a.com", "/main_document2"));
+  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
+
+  Shell* tab_to_be_bfcached = shell();
+  Shell* tab_to_modify_cookie = CreateBrowser();
+
+  // 1) Load the document and specify no-store for the main resource.
+  TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
+  tab_to_be_bfcached->LoadURL(url_a);
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  response.WaitForRequest();
+  response.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
+  response.Done();
+  observer.Wait();
+
+  // 2) Navigate away. |rfh_a| should enter bfcache.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 3) Navigate to a.com in |tab_to_modify_cookie| and modify HTTPOnly cookie
+  // from the response.
+  TestNavigationObserver observer2(tab_to_modify_cookie->web_contents());
+  tab_to_modify_cookie->LoadURL(url_a_2);
+  response2.WaitForRequest();
+  response2.Send(kResponseWithNoCacheWithHTTPOnlyCookie2);
+  response2.Done();
+  observer2.Wait();
+
+  // 4) Go back. |rfh_a| should be evicted upon restoration.
+  TestNavigationObserver observer3(tab_to_be_bfcached->web_contents());
+  tab_to_be_bfcached->web_contents()->GetController().GoBack();
+  response3.WaitForRequest();
+  response3.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
+  response3.Done();
+  observer3.Wait();
+  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
+                         kCacheControlNoStoreHTTPOnlyCookieModified},
+                    {}, {}, {}, {}, FROM_HERE);
+}
+
+// TODO(https://crbug.com/1231849): flaky on Cast Linux.
+#if defined(OS_LINUX)
+#define MAYBE_PagesWithCacheControlNoStoreEvictedIfJSAndHTTPOnlyCookieChange \
+  DISABLED_PagesWithCacheControlNoStoreEvictedIfJSAndHTTPOnlyCookieChange
+#else
+#define MAYBE_PagesWithCacheControlNoStoreEvictedIfJSAndHTTPOnlyCookieChange \
+  PagesWithCacheControlNoStoreEvictedIfJSAndHTTPOnlyCookieChange
+#endif
+
+// Test that a page with cache-control:no-store enters bfcache with the flag on,
+// and gets evicted if HTTPOnly cookie changes.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange,
+    MAYBE_PagesWithCacheControlNoStoreEvictedIfJSAndHTTPOnlyCookieChange) {
+  CreateHttpsServer();
+  net::test_server::ControllableHttpResponse response(https_server(),
+                                                      "/main_document");
+  net::test_server::ControllableHttpResponse response2(https_server(),
+                                                       "/main_document2");
+  net::test_server::ControllableHttpResponse response3(https_server(),
+                                                       "/main_document");
+  ASSERT_TRUE(https_server()->Start());
+
+  GURL url_a(https_server()->GetURL("a.com", "/main_document"));
+  GURL url_a_2(https_server()->GetURL("a.com", "/main_document2"));
+  GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
+
+  Shell* tab_to_be_bfcached = shell();
+  Shell* tab_to_modify_cookie = CreateBrowser();
+
+  // 1) Load the document and specify no-store for the main resource.
+  TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
+  tab_to_be_bfcached->LoadURL(url_a);
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  response.WaitForRequest();
+  response.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
+  response.Done();
+  observer.Wait();
+
+  // 2) Navigate away. |rfh_a| should enter bfcache.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  // Modify cookie from JavaScript as well.
+  EXPECT_TRUE(ExecJs(tab_to_be_bfcached, "document.cookie='foo=quz'"));
+
+  // 3) Navigate to a.com in |tab_to_modify_cookie| and modify HTTPOnly cookie
+  // from the response.
+  TestNavigationObserver observer2(tab_to_modify_cookie->web_contents());
+  tab_to_modify_cookie->LoadURL(url_a_2);
+  response2.WaitForRequest();
+  response2.Send(kResponseWithNoCacheWithHTTPOnlyCookie2);
+  response2.Done();
+  observer2.Wait();
+
+  // 4) Go back. |rfh_a| should be evicted upon restoration.
+  TestNavigationObserver observer3(tab_to_be_bfcached->web_contents());
+  tab_to_be_bfcached->web_contents()->GetController().GoBack();
+  response3.WaitForRequest();
+  response3.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
+  response3.Done();
+  observer3.Wait();
+  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
+                         kCacheControlNoStoreHTTPOnlyCookieModified},
+                    {}, {}, {}, {}, FROM_HERE);
+}
+
 namespace {
 enum class SubframeType { SameSite, CrossSite };
 }
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 7545c5e..7e1d178 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -13,12 +13,12 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "cc/base/switches.h"
+#include "content/browser/attribution_reporting/conversion_internals.mojom.h"
+#include "content/browser/attribution_reporting/conversion_internals_ui.h"
 #include "content/browser/background_fetch/background_fetch_service_impl.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/content_index/content_index_service_impl.h"
-#include "content/browser/conversions/conversion_internals.mojom.h"
-#include "content/browser/conversions/conversion_internals_ui.h"
 #include "content/browser/cookie_store/cookie_store_manager.h"
 #include "content/browser/eye_dropper_chooser_impl.h"
 #include "content/browser/federated_learning/floc_service_impl.h"
diff --git a/content/browser/devtools/devtools_conversion_browsertest.cc b/content/browser/devtools/devtools_conversion_browsertest.cc
index 2b6c612..c3d774e 100644
--- a/content/browser/devtools/devtools_conversion_browsertest.cc
+++ b/content/browser/devtools/devtools_conversion_browsertest.cc
@@ -4,7 +4,7 @@
 
 #include <iostream>
 
-#include "content/browser/conversions/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
 #include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index f37b189..cf57dbb 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -2164,6 +2164,9 @@
 
     case network::mojom::CorsError::kInsecurePrivateNetwork:
       return protocol::Network::CorsErrorEnum::InsecurePrivateNetwork;
+
+    case network::mojom::CorsError::kInvalidPrivateNetworkAccess:
+      return protocol::Network::CorsErrorEnum::InvalidPrivateNetworkAccess;
   }
 }
 }  // namespace
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
index 074b9664..5ab0e638 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -1410,14 +1410,7 @@
   loop6.Run();
 }
 
-// Flaky on Mac and Linux ASAN builds. See: crbug.com/1189512.
-#if defined(OS_MAC) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
-    (defined(OS_LINUX) && (defined(ADDRESS_SANITIZER) || defined(UBSAN)))
-#define MAYBE_DatabaseOperationSequencing DISABLED_DatabaseOperationSequencing
-#else
-#define MAYBE_DatabaseOperationSequencing DatabaseOperationSequencing
-#endif
-TEST_F(IndexedDBDispatcherHostTest, MAYBE_DatabaseOperationSequencing) {
+TEST_F(IndexedDBDispatcherHostTest, DISABLED_DatabaseOperationSequencing) {
   const int64_t kDBVersion = 1;
   const int64_t kTransactionId = 1;
   const std::u16string kObjectStoreName1 = u"os1";
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index c00757e8..671c992 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -779,7 +779,6 @@
 void NavigationURLLoaderImpl::OnReceiveEarlyHints(
     network::mojom::EarlyHintsPtr early_hints) {
   // Early Hints should not come after actual response.
-  DCHECK(on_receive_response_time_.is_null());
   DCHECK(!received_response_);
   DCHECK_NE(early_hints->ip_address_space,
             network::mojom::IPAddressSpace::kUnknown);
@@ -809,19 +808,12 @@
   LogQueueTimeHistogram("Navigation.QueueTime.OnReceiveResponse",
                         resource_request_->is_main_frame);
   head_ = std::move(head);
-  on_receive_response_time_ = base::TimeTicks::Now();
 }
 
 void NavigationURLLoaderImpl::OnStartLoadingResponseBody(
     mojo::ScopedDataPipeConsumerHandle response_body) {
   LogQueueTimeHistogram("Navigation.QueueTime.OnStartLoadingResponseBody",
                         resource_request_->is_main_frame);
-  if (!on_receive_response_time_.is_null()) {
-    UMA_HISTOGRAM_TIMES(
-        "Navigation.OnReceiveResponseToOnStartLoadingResponseBody",
-        base::TimeTicks::Now() - on_receive_response_time_);
-  }
-
   response_body_ = std::move(response_body);
   received_response_ = true;
 
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index e9161bd..d18623b 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -262,9 +262,6 @@
   // URLLoaderClient::OnStartLoadingResponseBody() is called.
   bool received_response_ = false;
 
-  // When URLLoaderClient::OnReceiveResponse() is called. For UMA.
-  base::TimeTicks on_receive_response_time_;
-
   bool started_ = false;
 
   // The completion status if it has been received. This is needed to handle
diff --git a/content/browser/prerender/prerender_host_registry_unittest.cc b/content/browser/prerender/prerender_host_registry_unittest.cc
index d1b34da..e588dda 100644
--- a/content/browser/prerender/prerender_host_registry_unittest.cc
+++ b/content/browser/prerender/prerender_host_registry_unittest.cc
@@ -252,9 +252,20 @@
     ActivatePrerenderedPage(kPrerenderingUrl, *wc);
   }
 
+  void ExpectUniqueSampleOfFinalStatus(PrerenderHost::FinalStatus status) {
+    histogram_tester_.ExpectUniqueSample(
+        "Prerender.Experimental.PrerenderHostFinalStatus", status, 1);
+  }
+
+  void ExpectBucketCountOfFinalStatus(PrerenderHost::FinalStatus status) {
+    histogram_tester_.ExpectBucketCount(
+        "Prerender.Experimental.PrerenderHostFinalStatus", status, 1);
+  }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   PrerenderWebContentsDelegate web_contents_delegate_;
+  base::HistogramTester histogram_tester_;
 };
 
 TEST_F(PrerenderHostRegistryTest, CreateAndStartHost) {
@@ -314,7 +325,6 @@
 // Tests that PrerenderHostRegistry limits the number of started prerenders
 // to 1.
 TEST_F(PrerenderHostRegistryTest, NumberLimit_Activation) {
-  base::HistogramTester histogram_tester;
   const GURL kOriginalUrl("https://example.com/");
   std::unique_ptr<TestWebContents> web_contents =
       CreateWebContents(kOriginalUrl);
@@ -335,9 +345,8 @@
       registry->CreateAndStartHost(attributes1, *render_frame_host);
   int frame_tree_node_id2 =
       registry->CreateAndStartHost(attributes2, *render_frame_host);
-  histogram_tester.ExpectUniqueSample(
-      "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded, 1);
+  ExpectUniqueSampleOfFinalStatus(
+      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
 
   // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1.
   EXPECT_NE(frame_tree_node_id1, kNoFrameTreeNodeId);
@@ -354,16 +363,14 @@
   frame_tree_node_id2 =
       registry->CreateAndStartHost(attributes2, *render_frame_host);
   EXPECT_NE(frame_tree_node_id2, kNoFrameTreeNodeId);
-  histogram_tester.ExpectBucketCount(
-      "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded, 1);
+  ExpectBucketCountOfFinalStatus(
+      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
 }
 
 // Tests that PrerenderHostRegistry limits the number of started prerenders
 // to 1, and new candidates can be processed after the initiator page navigates
 // to a new same-origin page.
 TEST_F(PrerenderHostRegistryTest, NumberLimit_SameOriginNavigateAway) {
-  base::HistogramTester histogram_tester;
   const GURL kOriginalUrl("https://example.com/");
   std::unique_ptr<TestWebContents> web_contents =
       CreateWebContents(kOriginalUrl);
@@ -383,9 +390,8 @@
   // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1.
   ASSERT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);
   ASSERT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
-  histogram_tester.ExpectUniqueSample(
-      "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded, 1);
+  ExpectUniqueSampleOfFinalStatus(
+      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
 
   // The initiator document navigates away.
   render_frame_host = NavigatePrimaryPage(
@@ -400,16 +406,14 @@
   SendCandidate(kPrerenderingUrl2, remote2);
 
   EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
-  histogram_tester.ExpectBucketCount(
-      "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded, 1);
+  ExpectBucketCountOfFinalStatus(
+      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
 }
 
 // Tests that PrerenderHostRegistry limits the number of started prerenders
 // to 1, and new candidates can be processed after the initiator page navigates
 // to a new cross-origin page.
 TEST_F(PrerenderHostRegistryTest, NumberLimit_CrossOriginNavigateAway) {
-  base::HistogramTester histogram_tester;
   const GURL kOriginalUrl("https://example.com/");
 
   std::unique_ptr<TestWebContents> web_contents =
@@ -430,9 +434,8 @@
   // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1.
   ASSERT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);
   ASSERT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
-  histogram_tester.ExpectUniqueSample(
-      "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded, 1);
+  ExpectUniqueSampleOfFinalStatus(
+      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
 
   // The initiator document navigates away to a cross-origin page.
   render_frame_host =
@@ -447,9 +450,8 @@
   const GURL kPrerenderingUrl3("https://example.org/next1");
   SendCandidate(kPrerenderingUrl3, remote2);
   EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl3), nullptr);
-  histogram_tester.ExpectBucketCount(
-      "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded, 1);
+  ExpectBucketCountOfFinalStatus(
+      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
 }
 
 TEST_F(PrerenderHostRegistryTest,
@@ -681,7 +683,6 @@
 
 TEST_F(PrerenderHostRegistryTest,
        DontStartPrerenderWhenTriggerIsAlreadyHidden) {
-  base::HistogramTester histogram_tester;
   std::unique_ptr<TestWebContents> web_contents =
       CreateWebContents(GURL("https://example.com/"));
   // The visibility state to be HIDDEN will cause prerendering not started.
@@ -698,9 +699,8 @@
   PrerenderHost* prerender_host =
       registry->FindNonReservedHostById(prerender_frame_tree_node_id);
   EXPECT_EQ(prerender_host, nullptr);
-  histogram_tester.ExpectUniqueSample(
-      "Prerender.Experimental.PrerenderHostFinalStatus",
-      PrerenderHost::FinalStatus::kTriggerBackgrounded, 1);
+  ExpectUniqueSampleOfFinalStatus(
+      PrerenderHost::FinalStatus::kTriggerBackgrounded);
 }
 
 // -------------------------------------------------
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc
index 6442748..39afcec 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -388,6 +388,46 @@
   return true;
 }
 
+// Behavior on pages with cache-control:no-store specified by flags.
+enum class CacheControlNoStoreExperimentLevel {
+  // No experiments for cache-control:no-store are running.
+  kDoNotStore = 1,
+  // Only the metrics gathering experiment is on.
+  kStoreAndEvictUponRestore = 2,
+  // Restore the entry only when cookies have not changed while in cache.
+  kStoreAndRestoreUnlessCookieChange = 3,
+  // Restore the entry only when HTTP Only cookies have not changed while in
+  // cache.
+  kStoreAndRestoreUnlessHTTPOnlyCookieChange = 4,
+};
+
+const char kCacheControlNoStoreExperimentLevelName[] = "level";
+
+static constexpr base::FeatureParam<CacheControlNoStoreExperimentLevel>::Option
+    cache_control_levels[] = {
+        {CacheControlNoStoreExperimentLevel::kStoreAndEvictUponRestore,
+         "store-and-evict"},
+        {CacheControlNoStoreExperimentLevel::kStoreAndRestoreUnlessCookieChange,
+         "restore-unless-cookie-change"},
+        {CacheControlNoStoreExperimentLevel::
+             kStoreAndRestoreUnlessHTTPOnlyCookieChange,
+         "restore-unless-http-only-cookie-change"},
+};
+const base::FeatureParam<CacheControlNoStoreExperimentLevel>
+    cache_control_level{&kCacheControlNoStoreEnterBackForwardCache,
+                        kCacheControlNoStoreExperimentLevelName,
+                        CacheControlNoStoreExperimentLevel::kDoNotStore,
+                        &cache_control_levels};
+
+CacheControlNoStoreExperimentLevel GetCacheControlNoStoreLevel() {
+  if (!IsBackForwardCacheEnabled() ||
+      !base::FeatureList::IsEnabled(
+          kCacheControlNoStoreEnterBackForwardCache)) {
+    return CacheControlNoStoreExperimentLevel::kDoNotStore;
+  }
+  return cache_control_level.Get();
+}
+
 }  // namespace
 
 // static
@@ -549,19 +589,25 @@
   if (!matching_entry)
     return;
 
+  // Note that kCacheControlNoStoreHTTPOnlyCookieModified,
+  // kCacheControlNoStoreCookieModified and kCacheControlNoStore are mutually
+  // exclusive.
   if (matching_entry->cookie_modified_->http_only_cookie_modified) {
     result->No(BackForwardCacheMetrics::NotRestoredReason::
                    kCacheControlNoStoreHTTPOnlyCookieModified);
   } else if (matching_entry->cookie_modified_->cookie_modified) {
-    result->No(BackForwardCacheMetrics::NotRestoredReason::
-                   kCacheControlNoStoreCookieModified);
-  } else {
-    // Cookies did not change, but if the restore flag is not onm we may still
-    // block bfcache.
-    if (!AllowRestoringPagesWithCacheControlNoStore()) {
-      result->No(
-          BackForwardCacheMetrics::NotRestoredReason::kCacheControlNoStore);
+    // JavaScript cookies are modified but not HTTP cookies. Only restore based
+    // on the experiment level.
+    if (GetCacheControlNoStoreLevel() <=
+        CacheControlNoStoreExperimentLevel::
+            kStoreAndRestoreUnlessCookieChange) {
+      result->No(BackForwardCacheMetrics::NotRestoredReason::
+                     kCacheControlNoStoreCookieModified);
     }
+  } else if (GetCacheControlNoStoreLevel() ==
+             CacheControlNoStoreExperimentLevel::kStoreAndEvictUponRestore) {
+    result->No(
+        BackForwardCacheMetrics::NotRestoredReason::kCacheControlNoStore);
   }
 }
 
@@ -1222,20 +1268,8 @@
 }
 
 bool BackForwardCacheImpl::AllowStoringPagesWithCacheControlNoStore() {
-  if (!IsBackForwardCacheEnabled())
-    return false;
-
-  return base::FeatureList::IsEnabled(
-      kCacheControlNoStoreEnterBackForwardCache);
-}
-
-bool BackForwardCacheImpl::AllowRestoringPagesWithCacheControlNoStore() {
-  if (!IsBackForwardCacheEnabled() ||
-      !AllowStoringPagesWithCacheControlNoStore())
-    return false;
-
-  return base::FeatureList::IsEnabled(
-      kCacheControlNoStoreRestoreFromBackForwardCacheUnlessCookieChange);
+  return GetCacheControlNoStoreLevel() >
+         CacheControlNoStoreExperimentLevel::kDoNotStore;
 }
 
 bool BackForwardCacheImpl::IsBrowsingInstanceInBackForwardCacheForDebugging(
diff --git a/content/browser/renderer_host/back_forward_cache_impl.h b/content/browser/renderer_host/back_forward_cache_impl.h
index 70207920..c9350938 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.h
+++ b/content/browser/renderer_host/back_forward_cache_impl.h
@@ -54,19 +54,13 @@
     "BackForwardCacheNoTimeEviction", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Allows pages with cache-control:no-store to enter the back/forward cache.
+// Feature params can specify whether pages with cache-control:no-store can be
+// restored if cookies change / if HTTPOnly cookies change.
 // TODO(crbug.com/1228611): Enable this feature.
 const base::Feature kCacheControlNoStoreEnterBackForwardCache{
     "CacheControlNoStoreEnterBackForwardCache",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Restore pages with cache-control:no-store from back/forward cache if there is
-// no cookie change while the page is in cache.
-// TODO(crbug.com/1228611): Enable this feature.
-const base::Feature
-    kCacheControlNoStoreRestoreFromBackForwardCacheUnlessCookieChange{
-        "CacheControlNoStoreRestoreFromBackForwardCache",
-        base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Allows pages with MediaSession's playback state change to stay eligible for
 // the back/forward cache.
 const base::Feature kBackForwardCacheMediaSessionPlaybackStateChange{
@@ -365,10 +359,6 @@
   // get restored from back/forward cache unless cookies change.
   static bool AllowStoringPagesWithCacheControlNoStore();
 
-  // Returns true if the flag is on for pages with cache-control:no-store to
-  // temporarily enter back/forward cache.
-  static bool AllowRestoringPagesWithCacheControlNoStore();
-
   // Contains the set of stored Entries.
   // Invariant:
   // - Ordered from the most recently used to the last recently used.
diff --git a/content/browser/renderer_host/back_forward_cache_metrics_unittest.cc b/content/browser/renderer_host/back_forward_cache_metrics_unittest.cc
index 6915362e..5ff06d4 100644
--- a/content/browser/renderer_host/back_forward_cache_metrics_unittest.cc
+++ b/content/browser/renderer_host/back_forward_cache_metrics_unittest.cc
@@ -164,8 +164,8 @@
   clock_.Advance(base::TimeDelta::FromMilliseconds(0b1000));
 
   {
-    auto simulator = NavigationSimulator::CreateHistoryNavigation(
-        -1, contents(), false /* is_renderer_initiated */);
+    auto simulator =
+        NavigationSimulator::CreateHistoryNavigation(-1, contents());
     simulator->Start();
     clock_.Advance(base::TimeDelta::FromMilliseconds(0b10000));
     simulator->Commit();
diff --git a/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc b/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc
index a4dd43166..3bdadb0 100644
--- a/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc
+++ b/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc
@@ -10,7 +10,6 @@
 #include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/navigation_request.h"
-#include "content/common/navigation_params_utils.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/common/content_features.h"
@@ -52,20 +51,14 @@
 std::unique_ptr<NavigationThrottle>
 BlockedSchemeNavigationThrottle::CreateThrottleForNavigation(
     NavigationHandle* navigation_handle) {
-  NavigationRequest* request = NavigationRequest::From(navigation_handle);
-  // Create throttles when going to blocked schemes via renderer-initiated
-  // navigations (which are cross-document in the main frame). Note that history
-  // navigations can bypass this, because the blocked scheme must have
-  // originally committed in a permitted case (e.g., omnibox navigation).
-  if (request->IsInMainFrame() && request->IsRendererInitiated() &&
-      !request->IsSameDocument() &&
-      !NavigationTypeUtils::IsHistory(
-          request->common_params().navigation_type) &&
-      (request->GetURL().SchemeIs(url::kDataScheme) ||
-       request->GetURL().SchemeIs(url::kFileSystemScheme)) &&
+  if (navigation_handle->IsInMainFrame() &&
+      navigation_handle->IsRendererInitiated() &&
+      !navigation_handle->IsSameDocument() &&
+      (navigation_handle->GetURL().SchemeIs(url::kDataScheme) ||
+       navigation_handle->GetURL().SchemeIs(url::kFileSystemScheme)) &&
       !base::FeatureList::IsEnabled(
           features::kAllowContentInitiatedDataUrlNavigations)) {
-    return std::make_unique<BlockedSchemeNavigationThrottle>(request);
+    return std::make_unique<BlockedSchemeNavigationThrottle>(navigation_handle);
   }
   return nullptr;
 }
diff --git a/content/browser/renderer_host/navigation_controller_android.cc b/content/browser/renderer_host/navigation_controller_android.cc
index 88de47e..1fd96f8 100644
--- a/content/browser/renderer_host/navigation_controller_android.cc
+++ b/content/browser/renderer_host/navigation_controller_android.cc
@@ -13,7 +13,7 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/containers/flat_map.h"
-#include "content/browser/conversions/conversion_host_utils.h"
+#include "content/browser/attribution_reporting/conversion_host_utils.h"
 #include "content/browser/renderer_host/navigation_controller_impl.h"
 #include "content/browser/renderer_host/navigation_entry_impl.h"
 #include "content/common/url_utils.h"
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 10da3fa6..4df4cd27 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -731,11 +731,8 @@
   pending_entry_index_ = current_index;
   pending_entry_->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
 
-  // location.reload() goes through BeginNavigation, so all reloads triggered
-  // via this codepath are browser initiated.
   NavigateToExistingPendingEntry(reload_type,
-                                 FrameTreeNode::kFrameTreeNodeInvalidId,
-                                 true /* is_browser_initiated */);
+                                 FrameTreeNode::kFrameTreeNodeInvalidId);
 }
 
 void NavigationControllerImpl::CancelPendingReload() {
@@ -964,15 +961,11 @@
 }
 
 void NavigationControllerImpl::GoToIndex(int index) {
-  GoToIndex(index, FrameTreeNode::kFrameTreeNodeInvalidId,
-            true /* is_browser_initiated */);
+  GoToIndex(index, FrameTreeNode::kFrameTreeNodeInvalidId);
 }
 
 void NavigationControllerImpl::GoToIndex(int index,
-                                         int sandbox_frame_tree_node_id,
-                                         bool is_browser_initiated) {
-  DCHECK(sandbox_frame_tree_node_id == FrameTreeNode::kFrameTreeNodeInvalidId ||
-         !is_browser_initiated);
+                                         int sandbox_frame_tree_node_id) {
   TRACE_EVENT0("browser,navigation,benchmark",
                "NavigationControllerImpl::GoToIndex");
   if (index < 0 || index >= static_cast<int>(entries_.size())) {
@@ -988,8 +981,7 @@
   pending_entry_index_ = index;
   pending_entry_->SetTransitionType(ui::PageTransitionFromInt(
       pending_entry_->GetTransitionType() | ui::PAGE_TRANSITION_FORWARD_BACK));
-  NavigateToExistingPendingEntry(ReloadType::NONE, sandbox_frame_tree_node_id,
-                                 is_browser_initiated);
+  NavigateToExistingPendingEntry(ReloadType::NONE, sandbox_frame_tree_node_id);
 }
 
 void NavigationControllerImpl::GoToOffset(int offset) {
@@ -1000,15 +992,6 @@
   GoToIndex(GetIndexForOffset(offset));
 }
 
-void NavigationControllerImpl::GoToOffsetFromRenderer(int offset) {
-  // Note: This is actually reached in unit tests.
-  if (!CanGoToOffset(offset))
-    return;
-
-  GoToIndex(GetIndexForOffset(offset), FrameTreeNode::kFrameTreeNodeInvalidId,
-            false /* is_browser_initiated */);
-}
-
 #if defined(OS_ANDROID)
 void NavigationControllerImpl::GoToOffsetWithSkipping(int offset) {
   // Note: This is actually reached in unit tests.
@@ -2392,14 +2375,10 @@
   if (!frame_entry)
     return false;
 
-  // |is_browser_initiated| is false here because a navigation in a new subframe
-  // always begins with renderer action (i.e., an HTML element being inserted
-  // into the DOM), so it is always renderer-initiated.
   std::unique_ptr<NavigationRequest> request = CreateNavigationRequestFromEntry(
       render_frame_host->frame_tree_node(), entry, frame_entry,
       ReloadType::NONE, false /* is_same_document_history_load */,
-      true /* is_history_navigation_in_new_child */,
-      false /* is_browser_initiated */);
+      true /* is_history_navigation_in_new_child */);
 
   if (!request)
     return false;
@@ -2424,8 +2403,7 @@
   std::unique_ptr<NavigationRequest> request = CreateNavigationRequestFromEntry(
       frame_tree_node, entry, frame_entry, reload_type,
       false /* is_same_document_history_load */,
-      false /* is_history_navigation_in_new_child */,
-      true /* is_browser_initiated */);
+      false /* is_history_navigation_in_new_child */);
   if (!request)
     return false;
   frame_tree_node->navigator().Navigate(std::move(request), reload_type);
@@ -2437,8 +2415,7 @@
     int sandbox_frame_tree_node_id) {
   if (!CanGoToOffset(offset))
     return;
-  GoToIndex(GetIndexForOffset(offset), sandbox_frame_tree_node_id,
-            false /* is_browser_initiated */);
+  GoToIndex(GetIndexForOffset(offset), sandbox_frame_tree_node_id);
 }
 
 void NavigationControllerImpl::NavigateFromFrameProxy(
@@ -2796,8 +2773,7 @@
 
 void NavigationControllerImpl::NavigateToExistingPendingEntry(
     ReloadType reload_type,
-    int sandboxed_source_frame_tree_node_id,
-    bool is_browser_initiated) {
+    int sandboxed_source_frame_tree_node_id) {
   TRACE_EVENT0("navigation",
                "NavigationControllerImpl::NavigateToExistingPendingEntry");
   DCHECK(pending_entry_);
@@ -2833,8 +2809,8 @@
   // navigated.
   std::vector<std::unique_ptr<NavigationRequest>> same_document_loads;
   std::vector<std::unique_ptr<NavigationRequest>> different_document_loads;
-  FindFramesToNavigate(root, reload_type, is_browser_initiated,
-                       &same_document_loads, &different_document_loads);
+  FindFramesToNavigate(root, reload_type, &same_document_loads,
+                       &different_document_loads);
 
   if (same_document_loads.empty() && different_document_loads.empty()) {
     // We were unable to match any frames to navigate.  This can happen if a
@@ -2859,8 +2835,7 @@
             root, pending_entry_, pending_entry_->GetFrameEntry(root),
             ReloadType::NONE /* reload_type */,
             true /* is_same_document_history_load */,
-            false /* is_history_navigation_in_new_child */,
-            is_browser_initiated);
+            false /* is_history_navigation_in_new_child */);
     if (!navigation_request) {
       // If this navigation cannot start, delete the pending NavigationEntry.
       DiscardPendingEntry(false);
@@ -2917,7 +2892,7 @@
     auto navigation_request = CreateNavigationRequestFromEntry(
         root, pending_entry_, pending_entry_->GetFrameEntry(root),
         ReloadType::NONE, false /* is_same_document_history_load */,
-        false /* is_history_navigation_in_new_child */, is_browser_initiated);
+        false /* is_history_navigation_in_new_child */);
     root->navigator().Navigate(std::move(navigation_request), ReloadType::NONE);
 
     return;
@@ -3090,7 +3065,6 @@
 void NavigationControllerImpl::FindFramesToNavigate(
     FrameTreeNode* frame,
     ReloadType reload_type,
-    bool is_browser_initiated,
     std::vector<std::unique_ptr<NavigationRequest>>* same_document_loads,
     std::vector<std::unique_ptr<NavigationRequest>>* different_document_loads) {
   DCHECK(pending_entry_);
@@ -3103,8 +3077,7 @@
         CreateNavigationRequestFromEntry(
             frame, pending_entry_, new_item, reload_type,
             true /* is_same_document_history_load */,
-            false /* is_history_navigation_in_new_child */,
-            is_browser_initiated);
+            false /* is_history_navigation_in_new_child */);
     if (navigation_request) {
       // Only add the request if was properly created. It's possible for the
       // creation to fail in certain cases, e.g. when the URL is invalid.
@@ -3115,8 +3088,7 @@
         CreateNavigationRequestFromEntry(
             frame, pending_entry_, new_item, reload_type,
             false /* is_same_document_history_load */,
-            false /* is_history_navigation_in_new_child */,
-            is_browser_initiated);
+            false /* is_history_navigation_in_new_child */);
     if (navigation_request) {
       // Only add the request if was properly created. It's possible for the
       // creation to fail in certain cases, e.g. when the URL is invalid.
@@ -3130,8 +3102,8 @@
   }
 
   for (size_t i = 0; i < frame->child_count(); i++) {
-    FindFramesToNavigate(frame->child_at(i), reload_type, is_browser_initiated,
-                         same_document_loads, different_document_loads);
+    FindFramesToNavigate(frame->child_at(i), reload_type, same_document_loads,
+                         different_document_loads);
   }
 }
 
@@ -3623,8 +3595,7 @@
     FrameNavigationEntry* frame_entry,
     ReloadType reload_type,
     bool is_same_document_history_load,
-    bool is_history_navigation_in_new_child_frame,
-    bool is_browser_initiated) {
+    bool is_history_navigation_in_new_child_frame) {
   DCHECK(frame_entry);
   GURL dest_url = frame_entry->url();
   absl::optional<url::Origin> origin_to_commit =
@@ -3729,7 +3700,7 @@
 
   return NavigationRequest::CreateBrowserInitiated(
       frame_tree_node, std::move(common_params), std::move(commit_params),
-      is_browser_initiated, false /* was_opener_suppressed */,
+      !entry->is_renderer_initiated(), false /* was_opener_suppressed */,
       nullptr /* initiator_frame_token */,
       ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
       entry->extra_headers(), frame_entry, entry, request_body,
@@ -3781,14 +3752,12 @@
   // cached state.
   if (pending_entry_) {
     NavigateToExistingPendingEntry(ReloadType::NONE,
-                                   FrameTreeNode::kFrameTreeNodeInvalidId,
-                                   true /* is_browser_initiated */);
+                                   FrameTreeNode::kFrameTreeNodeInvalidId);
   } else if (last_committed_entry_index_ != -1) {
     pending_entry_ = entries_[last_committed_entry_index_].get();
     pending_entry_index_ = last_committed_entry_index_;
     NavigateToExistingPendingEntry(ReloadType::NONE,
-                                   FrameTreeNode::kFrameTreeNodeInvalidId,
-                                   true /* is_browser_initiated */);
+                                   FrameTreeNode::kFrameTreeNodeInvalidId);
   } else {
     // If there is something to reload, the successful reload will clear the
     // |needs_reload_| flag. Otherwise, just do it here.
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index 4da3a8b..cfa40fbf 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -163,20 +163,12 @@
   // Navigates to a specified offset from the "current entry". Currently records
   // a histogram indicating whether the session history navigation would only
   // affect frames within the subtree of |sandbox_frame_tree_node_id|, which
-  // initiated the navigation. Navigating via this function is considered
-  // renderer-initiated, since it is only invoked when the renderer requests a
-  // history traversal.
+  // initiated the navigation.
   void GoToOffsetInSandboxedFrame(int offset, int sandbox_frame_tree_node_id);
-
-  // Navigates to the specified offset from the "current entry" and marks the
-  // navigations as initiated by the renderer.
-  void GoToOffsetFromRenderer(int offset);
-
 #if defined(OS_ANDROID)
-  // The difference between (Can)GoToOffsetWithSkipping and
-  // (Can)GoToOffset/(Can)GoToOffsetInSandboxedFrame is that this respects the
-  // history manipulation intervention and will exclude skippable entries.
-  // These should only be used for browser-initiated navigaitons.
+  // The difference with (Can)GoToOffset/(Can)GoToOffsetInSandboxedFrame is that
+  // this respect the history manipulation intervention and will excludes the
+  // skippable entries.
   bool CanGoToOffsetWithSkipping(int offset);
   void GoToOffsetWithSkipping(int offset);
 #endif
@@ -451,17 +443,14 @@
   // |sandbox_frame_tree_node_id| is valid, then this request came
   // from a sandboxed iframe with top level navigation disallowed. This
   // is currently only used for tracking metrics.
-  void GoToIndex(int index,
-                 int sandbox_frame_tree_node_id,
-                 bool is_browser_initiated);
+  void GoToIndex(int index, int sandbox_frame_tree_node_id);
 
   // Starts a navigation to an already existing pending NavigationEntry.
   // Currently records a histogram indicating whether the session history
   // navigation would only affect frames within the subtree of
   // |sandbox_frame_tree_node_id|, which initiated the navigation.
   void NavigateToExistingPendingEntry(ReloadType reload_type,
-                                      int sandboxed_source_frame_tree_node_id,
-                                      bool is_browser_initiated);
+                                      int sandboxed_source_frame_tree_node_id);
 
   // Helper function used by FindFramesToNavigate to determine the appropriate
   // action to take for a particular frame while navigating to
@@ -477,7 +466,6 @@
   void FindFramesToNavigate(
       FrameTreeNode* frame,
       ReloadType reload_type,
-      bool is_browser_initiated,
       std::vector<std::unique_ptr<NavigationRequest>>* same_document_loads,
       std::vector<std::unique_ptr<NavigationRequest>>*
           different_document_loads);
@@ -533,8 +521,7 @@
       FrameNavigationEntry* frame_entry,
       ReloadType reload_type,
       bool is_same_document_history_load,
-      bool is_history_navigation_in_new_child_frame,
-      bool is_browser_initiated);
+      bool is_history_navigation_in_new_child_frame);
 
   // Returns whether there is a pending NavigationEntry whose unique ID matches
   // the given NavigationRequest's pending_nav_entry_id.
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index fe26988..ec90b02 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -1545,7 +1545,7 @@
 
   EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
 
-  // Navigate twice more.
+  // Navigate twice more more.
   for (int url_index = kMaxEntryCount; url_index < kMaxEntryCount + 2;
        ++url_index) {
     GURL url(base::StringPrintf("data:text/html,page%d", url_index));
@@ -1567,54 +1567,6 @@
             controller.GetLastCommittedEntry()->GetURL());
 }
 
-IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       DontIgnoreRendererInitiatedBackAfterNavEntryLimit) {
-  NavigationController& controller = shell()->web_contents()->GetController();
-
-  // The default (50) makes this test too slow and leads to flakes
-  // (https://crbug.com/1167300).
-  NavigationControllerImpl::set_max_entry_count_for_testing(10);
-
-  const int kMaxEntryCount =
-      static_cast<int>(NavigationControllerImpl::max_entry_count());
-
-  // Load up to the max count, all entries should be there.
-  for (int url_index = 0; url_index < kMaxEntryCount; ++url_index) {
-    GURL url(base::StringPrintf("data:text/html,page%d", url_index));
-    EXPECT_TRUE(NavigateToURL(shell(), url));
-  }
-
-  EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
-
-  // Navigate twice more.
-  for (int url_index = kMaxEntryCount; url_index < kMaxEntryCount + 2;
-       ++url_index) {
-    GURL url(base::StringPrintf("data:text/html,page%d", url_index));
-    EXPECT_TRUE(NavigateToURL(shell(), url));
-  }
-
-  // We expect page0 and page1 to be gone.
-  EXPECT_EQ(kMaxEntryCount, controller.GetEntryCount());
-  EXPECT_EQ(GURL("data:text/html,page2"),
-            controller.GetEntryAtIndex(0)->GetURL());
-
-  // Now try to go back. This should not hang.
-  ASSERT_TRUE(controller.CanGoBack());
-  {
-    // Renderer-initiated-back.
-    FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                              ->GetFrameTree()
-                              ->root();
-    FrameNavigateParamsCapturer capturer(root);
-    EXPECT_TRUE(ExecJs(root, "history.back()"));
-    capturer.Wait();
-  }
-
-  // This should have successfully gone back.
-  EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount)),
-            controller.GetLastCommittedEntry()->GetURL());
-}
-
 namespace {
 
 // Does a renderer-initiated location.replace navigation to |url|, replacing the
@@ -18563,151 +18515,6 @@
   EXPECT_EQ(base_url, EvalJs(shell(), "document.URL"));
 }
 
-// Checks that a browser-initiated same-document navigation on a page which has
-// a valid base URL preserves the base URL.
-// See https://crbug.com/1082141.
-IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       RendererInitiatedBackToLoadDataWithBaseURL) {
-  // LoadDataWithBaseURL is never subject to --site-per-process policy today
-  // (this API is only used by Android WebView [where OOPIFs have not shipped
-  // yet] and GuestView cases [which always hosts guests inside a renderer
-  // without an origin lock]).  Therefore, skip the test in --site-per-process
-  // mode to avoid renderer kills which won't happen in practice as described
-  // above.
-  //
-  // TODO(https://crbug.com/962643): Consider enabling this test once Android
-  // Webview or WebView guests support OOPIFs and/or origin locks.
-  if (AreAllSitesIsolatedForTesting())
-    return;
-
-  const GURL base_url("http://baseurl");
-  const GURL history_url("http://history");
-  const std::string data = "<html><title>One</title><body>foo</body></html>";
-  const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
-
-  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
-      shell()->web_contents()->GetController());
-
-  {
-    TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
-    shell()->LoadDataWithBaseURL(history_url, data, base_url);
-    same_tab_observer.Wait();
-  }
-
-  // Verify the last committed NavigationEntry.
-  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
-  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
-  EXPECT_EQ(history_url, entry->GetVirtualURL());
-  EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
-  EXPECT_EQ(data_url, entry->GetURL());
-
-  {
-    // Make a same-document navigation via history.pushState.
-    TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
-    EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#')"));
-    same_tab_observer.Wait();
-  }
-
-  // Verify the last committed NavigationEntry.
-  entry = controller.GetLastCommittedEntry();
-  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
-  EXPECT_EQ(history_url, entry->GetVirtualURL());
-  EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
-  EXPECT_EQ(data_url, entry->GetURL());
-
-  {
-    // Renderer-initiated-back.
-    FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                              ->GetFrameTree()
-                              ->root();
-    FrameNavigateParamsCapturer capturer(root);
-    EXPECT_TRUE(ExecJs(root, "history.back()"));
-    capturer.Wait();
-  }
-
-  // Verify the last committed NavigationEntry.
-  entry = controller.GetLastCommittedEntry();
-  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
-  EXPECT_EQ(history_url, entry->GetVirtualURL());
-  EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
-  EXPECT_EQ(data_url, entry->GetURL());
-  EXPECT_EQ(base_url, EvalJs(shell(), "document.URL"));
-}
-
-IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       HistoryNavigationInNewSubframe) {
-  // This test specifically observes behavior of creating a new frame during a
-  // history navigation, so disable the back forward cache.
-  DisableBackForwardCacheForTesting(contents(),
-                                    BackForwardCache::TEST_ASSUMES_NO_CACHING);
-
-  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
-      shell()->web_contents()->GetController());
-  RenderFrameHostImpl* main_frame =
-      static_cast<WebContentsImpl*>(shell()->web_contents())->GetMainFrame();
-
-  // Navigate to a page with an iframe.
-  GURL url1 =
-      embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html");
-  ASSERT_TRUE(NavigateToURL(shell(), url1));
-  GURL iframe_url = main_frame->child_at(0)->current_url();
-
-  // Navigate away so the iframe is destroyed.
-  GURL url2(embedded_test_server()->GetURL(
-      "/navigation_controller/simple_page_1.html"));
-  ASSERT_TRUE(NavigateToURL(shell(), url2));
-
-  // Go back (browser-initiated).
-  ASSERT_TRUE(controller.CanGoBack());
-  TestNavigationManager observer(shell()->web_contents(), iframe_url);
-  controller.GoBack();
-  EXPECT_TRUE(observer.WaitForRequestStart());
-
-  // Check the initial navigation for the new iframe.
-  NavigationRequest* navigation = main_frame->child_at(0)->navigation_request();
-  ASSERT_TRUE(navigation);
-  EXPECT_TRUE(navigation->IsRendererInitiated());
-}
-
-IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       HistoryNavigationInNewSubframeRendererInitiated) {
-  // This test specifically observes behavior of creating a new frame during a
-  // history navigation, so disable the back forward cache.
-  DisableBackForwardCacheForTesting(contents(),
-                                    BackForwardCache::TEST_ASSUMES_NO_CACHING);
-
-  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
-      shell()->web_contents()->GetController());
-  RenderFrameHostImpl* main_frame =
-      static_cast<WebContentsImpl*>(shell()->web_contents())->GetMainFrame();
-
-  // Navigate to a page with an iframe.
-  GURL url1 =
-      embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html");
-  ASSERT_TRUE(NavigateToURL(shell(), url1));
-  GURL iframe_url = main_frame->child_at(0)->current_url();
-
-  // Navigate away so the iframe is destroyed.
-  GURL url2(embedded_test_server()->GetURL(
-      "/navigation_controller/simple_page_1.html"));
-  ASSERT_TRUE(NavigateToURL(shell(), url2));
-
-  // Go back (renderer-initiated).
-  ASSERT_TRUE(controller.CanGoBack());
-  TestNavigationManager observer(shell()->web_contents(), iframe_url);
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  FrameNavigateParamsCapturer capturer(root);
-  EXPECT_TRUE(ExecJs(root, "history.back()"));
-  EXPECT_TRUE(observer.WaitForRequestStart());
-
-  // Check the initial navigation for the new iframe.
-  NavigationRequest* navigation = main_frame->child_at(0)->navigation_request();
-  ASSERT_TRUE(navigation);
-  EXPECT_TRUE(navigation->IsRendererInitiated());
-}
-
 // Navigate an iframe, then reload it. Check the navigation and the
 // FrameNavigationEntry are the same in both cases.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, ReloadFrame) {
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index 8c739e9..ea2d38d8 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -427,8 +427,8 @@
 
   for (int test = 0; test < NUM_TESTS; ++test) {
     int offset = test_offsets[test];
-    auto navigation = NavigationSimulator::CreateHistoryNavigation(
-        offset, contents(), false /* is_renderer_initiated */);
+    auto navigation =
+        NavigationSimulator::CreateHistoryNavigation(offset, contents());
     navigation->Start();
     url_index += offset;
     // Check that the GoToOffset will land on the expected page.
@@ -959,8 +959,8 @@
 
   // Now make a pending back/forward navigation to a privileged entry.
   // The zeroth entry should be pending.
-  auto back_navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation->ReadyToCommit();
   EXPECT_EQ(0U, navigation_entry_changed_counter_);
   EXPECT_EQ(0U, navigation_list_pruned_counter_);
@@ -1008,8 +1008,8 @@
   navigation_entry_committed_counter_ = 0;
 
   // A back navigation comes in from the renderer...
-  auto back_navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation->ReadyToCommit();
 
   // ...while the user tries to navigate to a new page...
@@ -1473,8 +1473,8 @@
   int change_counter = 0;
   contents()->set_web_preferences_changed_counter(&change_counter);
 
-  auto back_navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation->Start();
   EXPECT_FALSE(controller.GetPendingEntry()->GetIsOverridingUserAgent());
   back_navigation->Commit();
@@ -1496,8 +1496,8 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
-  auto back_navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation->Start();
   EXPECT_EQ(0U, navigation_entry_changed_counter_);
   EXPECT_EQ(0U, navigation_list_pruned_counter_);
@@ -1561,8 +1561,8 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
-  auto navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   navigation->Start();
   EXPECT_EQ(0U, navigation_entry_changed_counter_);
   EXPECT_EQ(0U, navigation_list_pruned_counter_);
@@ -1653,8 +1653,8 @@
       blink::mojom::UserActivationUpdateType::kNotifyActivation,
       blink::mojom::UserActivationNotificationType::kTest);
 
-  auto forward_navigation = NavigationSimulator::CreateHistoryNavigation(
-      1, contents(), false /* is_renderer_initiated */);
+  auto forward_navigation =
+      NavigationSimulator::CreateHistoryNavigation(1, contents());
   forward_navigation->Start();
   // We should now have a pending navigation to go forward.
   EXPECT_EQ(controller.GetEntryCount(), 2);
@@ -1722,8 +1722,8 @@
       blink::mojom::UserActivationUpdateType::kNotifyActivation,
       blink::mojom::UserActivationNotificationType::kTest);
 
-  auto forward_navigation = NavigationSimulator::CreateHistoryNavigation(
-      1, contents(), false /* is_renderer_initiated */);
+  auto forward_navigation =
+      NavigationSimulator::CreateHistoryNavigation(1, contents());
   forward_navigation->Start();
   EXPECT_EQ(0U, navigation_list_pruned_counter_);
 
@@ -2473,8 +2473,8 @@
 
   // Go back, but don't commit yet. Check that we can't delete the current
   // and pending entries.
-  auto back_navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation->Start();
   EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
   EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2));
@@ -2514,8 +2514,8 @@
 
   // Go back, but don't commit yet. Check that we can't delete the current
   // and pending entries.
-  auto back_navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation->Start();
   EXPECT_FALSE(controller.RemoveEntryAtIndex(2));
   EXPECT_FALSE(controller.RemoveEntryAtIndex(1));
@@ -4029,8 +4029,8 @@
   EXPECT_EQ(0, controller.GetCurrentEntryIndex());
 
   // Start going forward to page B.
-  auto forward_navigation = NavigationSimulator::CreateHistoryNavigation(
-      1, contents(), false /* is_renderer_initiated */);
+  auto forward_navigation =
+      NavigationSimulator::CreateHistoryNavigation(1, contents());
   forward_navigation->ReadyToCommit();
 
   // But the renderer unilaterally navigates to page C, pruning B.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index e53ad0b..0cf13e14 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -729,14 +729,7 @@
     // for all renderer-initiated navigations (e.g. see
     // VerifyBeginNavigationCommonParams), but as a defense-in-depth this is
     // also asserted below.
-    // History navigations are exempt from this rule because, although they can
-    // be renderer-initaited via the js history API, the renderer does not
-    // choose the url being navigated to. A renderer-initiated history
-    // navigation may therefore navigate back to a previous browser-initiated
-    // loadDataWithBaseUrl.
-    CHECK(navigation_request->browser_initiated() ||
-          NavigationTypeUtils::IsHistory(
-              navigation_request->common_params().navigation_type));
+    CHECK(navigation_request->browser_initiated());
 
     // loadDataWithBaseUrl submits a data: |common_params.url| (which has a
     // opaque origin), but commits that URL as if it came from
@@ -1319,6 +1312,7 @@
       previous_page_ukm_source_id_(
           frame_tree_node_->current_frame_host()->GetPageUkmSourceId()),
       is_pdf_(is_pdf) {
+  DCHECK(browser_initiated || common_params_->initiator_origin.has_value());
   DCHECK(!blink::IsRendererDebugURL(common_params_->url));
   DCHECK(common_params_->method == "POST" || !common_params_->post_data);
   DCHECK_EQ(common_params_->url, commit_params_->original_url);
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc
index 034aaf1..30633dc 100644
--- a/content/browser/renderer_host/navigator.cc
+++ b/content/browser/renderer_host/navigator.cc
@@ -340,20 +340,14 @@
 }
 
 // A renderer-initiated navigation should be ignored iff a) there is an ongoing
-// request b) which is browser initiated or a history traversal and c) the
-// renderer request is not user-initiated.
-// Renderer-initiated history traversals cause navigations to be ignored for
-// compatibility reasons - this behavior is asserted by several web platform
-// tests.
+// request b) which is browser initiated and c) the renderer request is not
+// user-initiated.
 // static
 bool Navigator::ShouldIgnoreIncomingRendererRequest(
     const NavigationRequest* ongoing_navigation_request,
     bool has_user_gesture) {
   return ongoing_navigation_request &&
-         (ongoing_navigation_request->browser_initiated() ||
-          NavigationTypeUtils::IsHistory(
-              ongoing_navigation_request->common_params().navigation_type)) &&
-         !has_user_gesture;
+         ongoing_navigation_request->browser_initiated() && !has_user_gesture;
 }
 
 NavigatorDelegate* Navigator::GetDelegate() {
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 1a09a6e..4efb2f5 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -45,6 +45,7 @@
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/render_accessibility_host.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/bluetooth/web_bluetooth_service_impl.h"
 #include "content/browser/browser_main_loop.h"
@@ -52,7 +53,6 @@
 #include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/compute_pressure/compute_pressure_manager.h"
 #include "content/browser/contacts/contacts_manager_impl.h"
-#include "content/browser/conversions/conversion_host.h"
 #include "content/browser/data_url_loader_factory.h"
 #include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
@@ -5601,7 +5601,7 @@
       frame_tree_->controller().GoToOffsetInSandboxedFrame(
           offset, GetFrameTreeNodeId());
     } else {
-      frame_tree_->controller().GoToOffsetFromRenderer(offset);
+      frame_tree_->controller().GoToOffset(offset);
     }
   }
 }
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
index a078a2cf..d7081501 100644
--- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -1139,8 +1139,8 @@
   // mojo::AgentSchedulingGroupHost::DidUnloadRenderFrame isn't received.  This
   // shouldn't happen, but we have seen it when going back quickly across many
   // entries (http://crbug.com/93427).
-  auto back_navigation1 = NavigationSimulatorImpl::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation1 =
+      NavigationSimulatorImpl::CreateHistoryNavigation(-1, contents());
   back_navigation1->ReadyToCommit();
   EXPECT_FALSE(rfh2->is_waiting_for_beforeunload_completion());
 
diff --git a/content/browser/resources/conversions/BUILD.gn b/content/browser/resources/conversions/BUILD.gn
index 5d1b9d5..40950f0 100644
--- a/content/browser/resources/conversions/BUILD.gn
+++ b/content/browser/resources/conversions/BUILD.gn
@@ -5,19 +5,18 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  closure_flags =
-      default_closure_args + mojom_js_args + [
-        "js_module_root=" + rebase_path(".", root_build_dir),
-        "js_module_root=" +
-            rebase_path("$root_gen_dir/mojom-webui/content/browser/conversions",
-                        root_build_dir),
-      ]
+  closure_flags = default_closure_args + mojom_js_args + [
+                    "js_module_root=" + rebase_path(".", root_build_dir),
+                    "js_module_root=" + rebase_path(
+                            "$root_gen_dir/mojom-webui/content/browser/attribution_reporting",
+                            root_build_dir),
+                  ]
   deps = [ ":conversion_internals" ]
 }
 
 js_library("conversion_internals") {
   deps = [
-    "//content/browser/conversions:mojo_bindings_webui_js",
+    "//content/browser/attribution_reporting:mojo_bindings_webui_js",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:util.m",
   ]
diff --git a/content/browser/resources/conversions/OWNERS b/content/browser/resources/conversions/OWNERS
index 8b8a4832..6a3b4dd 100644
--- a/content/browser/resources/conversions/OWNERS
+++ b/content/browser/resources/conversions/OWNERS
@@ -1 +1 @@
-file://content/browser/conversions/OWNERS
+file://content/browser/attribution_reporting/OWNERS
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 5df7797..2e75de982 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -746,25 +746,15 @@
                "document_url", document_url.spec());
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  auto callback_with_recording_metrics = base::BindOnce(
-      [](StartServiceWorkerForNavigationHintCallback callback,
-         StartServiceWorkerForNavigationHintResult result) {
-        ServiceWorkerMetrics::RecordStartServiceWorkerForNavigationHintResult(
-            result);
-        std::move(callback).Run(result);
-      },
-      std::move(callback));
-
   if (!context_core_) {
-    std::move(callback_with_recording_metrics)
-        .Run(StartServiceWorkerForNavigationHintResult::FAILED);
+    std::move(callback).Run(StartServiceWorkerForNavigationHintResult::FAILED);
     return;
   }
   context_core_->registry()->FindRegistrationForClientUrl(
       net::SimplifyUrlForRequest(document_url), key,
       base::BindOnce(
           &ServiceWorkerContextWrapper::DidFindRegistrationForNavigationHint,
-          this, std::move(callback_with_recording_metrics)));
+          this, std::move(callback)));
 }
 
 void ServiceWorkerContextWrapper::StopAllServiceWorkersForStorageKey(
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc
index 01e3668..dfa540d 100644
--- a/content/browser/service_worker/service_worker_metrics.cc
+++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -254,10 +254,6 @@
   }
 }
 
-void ServiceWorkerMetrics::RecordWorkerStopped(StopStatus status) {
-  UMA_HISTOGRAM_ENUMERATION("ServiceWorker.WorkerStopped", status);
-}
-
 void ServiceWorkerMetrics::RecordStopWorkerTime(base::TimeDelta time) {
   UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StopWorker.Time", time);
 }
@@ -507,12 +503,6 @@
                              kBucketCount);
 }
 
-void ServiceWorkerMetrics::RecordStartServiceWorkerForNavigationHintResult(
-    StartServiceWorkerForNavigationHintResult result) {
-  UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartForNavigationHint.Result",
-                            result);
-}
-
 void ServiceWorkerMetrics::RecordOfflineCapableReason(
     blink::ServiceWorkerStatusCode status,
     int status_code) {
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h
index 704c3be..c1bb8336 100644
--- a/content/browser/service_worker/service_worker_metrics.h
+++ b/content/browser/service_worker/service_worker_metrics.h
@@ -34,15 +34,6 @@
   };
 
   // Used for UMA. Append-only.
-  enum class StopStatus {
-    NORMAL,
-    DETACH_BY_REGISTRY,
-    TIMEOUT,
-    // Add new types here.
-    kMaxValue = TIMEOUT,
-  };
-
-  // Used for UMA. Append-only.
   // This class is used to indicate which event is fired/finished. Most events
   // have only one request that starts the event and one response that finishes
   // the event, but the fetch event has two responses, so there are two types of
@@ -173,9 +164,6 @@
                                     StartSituation start_situation,
                                     EventType purpose);
 
-  // Records the result of trying to stop a worker.
-  static void RecordWorkerStopped(StopStatus status);
-
   // Records the time taken to successfully stop a worker.
   static void RecordStopWorkerTime(base::TimeDelta time);
 
@@ -211,10 +199,6 @@
 
   static void RecordRuntime(base::TimeDelta time);
 
-  // Records the result of starting service worker for a navigation hint.
-  static void RecordStartServiceWorkerForNavigationHintResult(
-      StartServiceWorkerForNavigationHintResult result);
-
   // Records the reason a service worker was deemed to be offline capable. The
   // reason may be that the service worker responded with 2xx..., 3xx..., or the
   // check timed out.
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index ce1e7664..c818639 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -1256,10 +1256,6 @@
 }
 
 void ServiceWorkerVersion::OnStopped(EmbeddedWorkerStatus old_status) {
-  if (IsInstalled(status())) {
-    ServiceWorkerMetrics::RecordWorkerStopped(
-        ServiceWorkerMetrics::StopStatus::NORMAL);
-  }
   if (!stop_time_.is_null())
     ServiceWorkerMetrics::RecordStopWorkerTime(GetTickDuration(stop_time_));
 
@@ -1267,10 +1263,6 @@
 }
 
 void ServiceWorkerVersion::OnDetached(EmbeddedWorkerStatus old_status) {
-  if (IsInstalled(status())) {
-    ServiceWorkerMetrics::RecordWorkerStopped(
-        ServiceWorkerMetrics::StopStatus::DETACH_BY_REGISTRY);
-  }
   OnStoppedInternal(old_status);
 }
 
@@ -2002,10 +1994,6 @@
   // Stopping the worker hasn't finished within a certain period.
   if (GetTickDuration(stop_time_) > kStopWorkerTimeout) {
     DCHECK_EQ(EmbeddedWorkerStatus::STOPPING, running_status());
-    if (IsInstalled(status())) {
-      ServiceWorkerMetrics::RecordWorkerStopped(
-          ServiceWorkerMetrics::StopStatus::TIMEOUT);
-    }
     ReportError(blink::ServiceWorkerStatusCode::kErrorTimeout,
                 "DETACH_STALLED_IN_STOPPING");
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index a68267ca..057e5bf 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -39,6 +39,7 @@
 #include "components/services/storage/public/mojom/storage_service.mojom.h"
 #include "components/services/storage/storage_service_impl.h"
 #include "components/variations/net/variations_http_headers.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
 #include "content/browser/background_fetch/background_fetch_context.h"
 #include "content/browser/blob_storage/blob_registry_wrapper.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
@@ -51,7 +52,6 @@
 #include "content/browser/code_cache/generated_code_cache.h"
 #include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/compute_pressure/compute_pressure_manager.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
 #include "content/browser/cookie_store/cookie_store_manager.h"
 #include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/devtools/devtools_url_loader_interceptor.h"
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index 08d54fd..847a3dd 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -30,11 +30,11 @@
 #include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "components/services/storage/dom_storage/local_storage_database.pb.h"
 #include "components/services/storage/public/cpp/constants.h"
+#include "content/browser/attribution_reporting/conversion_manager_impl.h"
+#include "content/browser/attribution_reporting/conversion_test_utils.h"
+#include "content/browser/attribution_reporting/storable_conversion.h"
 #include "content/browser/code_cache/generated_code_cache.h"
 #include "content/browser/code_cache/generated_code_cache_context.h"
-#include "content/browser/conversions/conversion_manager_impl.h"
-#include "content/browser/conversions/conversion_test_utils.h"
-#include "content/browser/conversions/storable_conversion.h"
 #include "content/browser/gpu/shader_cache_factory.h"
 #include "content/browser/interest_group/interest_group_manager.h"
 #include "content/browser/storage_partition_impl.h"
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 6b077ac..98a2617 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -50,12 +50,12 @@
 #include "components/url_formatter/url_formatter.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/attribution_reporting/conversion_host.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/conversions/conversion_host.h"
 #include "content/browser/devtools/protocol/page_handler.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
 #include "content/browser/display_cutout/display_cutout_host_impl.h"
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index b628e11..ebd9b10 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -641,8 +641,8 @@
   // Going back should switch SiteInstances again.  The first SiteInstance is
   // stored in the NavigationEntry, so it should be the same as at the start.
   // We should use the same RFH as before, swapping it back in.
-  auto back_navigation = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation->ReadyToCommit();
   TestRenderFrameHost* goback_rfh =
       contents()->GetSpeculativePrimaryMainFrame();
@@ -1227,8 +1227,8 @@
             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
 
   // Go back within the site.
-  auto back_navigation1 = NavigationSimulatorImpl::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation1 =
+      NavigationSimulatorImpl::CreateHistoryNavigation(-1, contents());
   back_navigation1->Start();
 
   auto* first_pending_rfh = contents()->GetSpeculativePrimaryMainFrame();
@@ -1245,8 +1245,8 @@
 
   // Before that commits, go back again.
   back_navigation1->ReadyToCommit();
-  auto back_navigation2 = NavigationSimulatorImpl::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation2 =
+      NavigationSimulatorImpl::CreateHistoryNavigation(-1, contents());
   back_navigation2->Start();
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
   EXPECT_TRUE(contents()->GetSpeculativePrimaryMainFrame());
@@ -1366,8 +1366,8 @@
             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
 
   // Go back within the site.
-  auto back_navigation1 = NavigationSimulator::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation1 =
+      NavigationSimulator::CreateHistoryNavigation(-1, contents());
   back_navigation1->ReadyToCommit();
   if (will_change_site_instance) {
     EXPECT_TRUE(contents()->CrossProcessNavigationPending());
@@ -1377,8 +1377,8 @@
   EXPECT_EQ(entry2, controller().GetPendingEntry());
 
   // Before that commits, go back again.
-  auto back_navigation2 = NavigationSimulatorImpl::CreateHistoryNavigation(
-      -1, contents(), false /* is_renderer_initiated */);
+  auto back_navigation2 =
+      NavigationSimulatorImpl::CreateHistoryNavigation(-1, contents());
   back_navigation2->set_drop_unload_ack(true);
   back_navigation2->ReadyToCommit();
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
diff --git a/content/browser/webui/content_web_ui_controller_factory.cc b/content/browser/webui/content_web_ui_controller_factory.cc
index 5908ab2e..daf6c25 100644
--- a/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/content/browser/webui/content_web_ui_controller_factory.cc
@@ -6,7 +6,7 @@
 
 #include "build/build_config.h"
 #include "content/browser/appcache/appcache_internals_ui.h"
-#include "content/browser/conversions/conversion_internals_ui.h"
+#include "content/browser/attribution_reporting/conversion_internals_ui.h"
 #include "content/browser/gpu/gpu_internals_ui.h"
 #include "content/browser/indexed_db/indexed_db_internals_ui.h"
 #include "content/browser/media/media_internals_ui.h"
diff --git a/content/common/partition_alloc_support.cc b/content/common/partition_alloc_support.cc
index c0bd53e..be1dbf6 100644
--- a/content/common/partition_alloc_support.cc
+++ b/content/common/partition_alloc_support.cc
@@ -217,8 +217,8 @@
         base::features::BackupRefPtrEnabledProcesses::kBrowserAndRenderer) {
       enable_brp |= process_type == switches::kRendererProcess;
     }
-    base::allocator::ConfigurePartitionBackupRefPtrSupport(enable_brp);
   }
+  base::allocator::ConfigurePartitionBackupRefPtrSupport(enable_brp);
 #endif
 
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
diff --git a/content/dev_ui_content_resources.grd b/content/dev_ui_content_resources.grd
index ffea433..044ea1b9 100644
--- a/content/dev_ui_content_resources.grd
+++ b/content/dev_ui_content_resources.grd
@@ -21,7 +21,7 @@
       <include name="IDR_CONVERSION_INTERNALS_HTML" file="browser/resources/conversions/conversion_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_CONVERSION_INTERNALS_JS" file="browser/resources/conversions/conversion_internals.js" type="BINDATA" />
       <include name="IDR_CONVERSION_INTERNALS_CSS" file="browser/resources/conversions/conversion_internals.css" type="BINDATA" />
-      <include name="IDR_CONVERSION_INTERNALS_MOJOM_JS" file="${root_gen_dir}/mojom-webui/content/browser/conversions/conversion_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" />
+      <include name="IDR_CONVERSION_INTERNALS_MOJOM_JS" file="${root_gen_dir}/mojom-webui/content/browser/attribution_reporting/conversion_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_GPU_BROWSER_BRIDGE_JS" file="browser/resources/gpu/browser_bridge.js" type="BINDATA" />
       <include name="IDR_GPU_INFO_VIEW_JS" file="browser/resources/gpu/info_view.js" type="BINDATA" />
       <include name="IDR_GPU_INTERNALS_HTML" file="browser/resources/gpu/gpu_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h
index 7b6b69c..b97cdce9 100644
--- a/content/public/browser/navigation_controller.h
+++ b/content/public/browser/navigation_controller.h
@@ -436,8 +436,7 @@
   virtual void GoBack() = 0;
   virtual void GoForward() = 0;
 
-  // Navigates to the specified absolute index. Should only be used for
-  // browser-initiated navigations.
+  // Navigates to the specified absolute index.
   virtual void GoToIndex(int index) = 0;
 
   // Navigates to the specified offset from the "current entry". Does nothing if
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index 7185c8a..92f1a855 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -125,13 +125,13 @@
   //  * <a> link click
   //  * changing window.location.href
   //  * redirect via the <meta http-equiv="refresh"> tag
-  //  * using window.history.pushState() or window.history.replaceState()
-  //  * using window.history.forward() or window.history.back()
+  //  * using window.history.pushState
   //
   // This method returns false for browser-initiated navigations, including:
   //  * any navigation initiated from the omnibox
   //  * navigations via suggestions in browser UI
   //  * navigations via browser UI: Ctrl-R, refresh/forward/back/home buttons
+  //  * using window.history.forward() or window.history.back()
   //  * any other "explicit" URL navigations, e.g. bookmarks
   virtual bool IsRendererInitiated() = 0;
 
@@ -425,12 +425,6 @@
 
   // Returns, if available, the origin of the document that has initiated the
   // navigation for this NavigationHandle.
-  // NOTE: If this is a history navigation, the initiator origin will be the
-  // origin that initiated the *original* navigation, not the history
-  // navigation. This means that if there was no initiator origin for the
-  // original navigation, but the history navigation was initiated by
-  // javascript, the initiator origin will be null even though
-  // IsRendererInitiated() returns true.
   virtual const absl::optional<url::Origin>& GetInitiatorOrigin() = 0;
 
   // Retrieves any DNS aliases for the requested URL. The alias chain order
diff --git a/content/public/common/url_utils.cc b/content/public/common/url_utils.cc
index 2818573..7a275487 100644
--- a/content/public/common/url_utils.cc
+++ b/content/public/common/url_utils.cc
@@ -8,9 +8,8 @@
 #include <string>
 
 #include "base/check_op.h"
-#include "base/containers/flat_set.h"
+#include "base/containers/fixed_flat_set.h"
 #include "base/feature_list.h"
-#include "base/no_destructor.h"
 #include "base/strings/string_piece.h"
 #include "content/common/url_schemes.h"
 #include "content/public/common/content_features.h"
@@ -65,8 +64,8 @@
 }
 
 bool IsSafeRedirectTarget(const GURL& from_url, const GURL& to_url) {
-  static const base::NoDestructor<base::flat_set<base::StringPiece>>
-      kUnsafeSchemes(base::flat_set<base::StringPiece>({
+  static const auto kUnsafeSchemes =
+      base::MakeFixedFlatSet<base::StringPiece>({
         url::kAboutScheme, url::kFileScheme,
             url::kFileSystemScheme, url::kBlobScheme,
 #if !defined(CHROMECAST_BUILD)
@@ -75,10 +74,10 @@
 #if defined(OS_ANDROID)
             url::kContentScheme,
 #endif
-      }));
+      });
   if (HasWebUIScheme(to_url))
     return false;
-  if (!kUnsafeSchemes->contains(to_url.scheme_piece()))
+  if (!kUnsafeSchemes.contains(to_url.scheme_piece()))
     return true;
   if (from_url.is_empty())
     return false;
diff --git a/content/public/test/navigation_simulator.h b/content/public/test/navigation_simulator.h
index ee384a7..b13caff 100644
--- a/content/public/test/navigation_simulator.h
+++ b/content/public/test/navigation_simulator.h
@@ -119,13 +119,10 @@
 
   // Creates a NavigationSimulator that will be used to simulate a history
   // navigation to one of the |web_contents|'s navigation controller |offset|.
-  // E.g. offset -1 for back navigations and 1 for forward navigations. If
-  // |is_renderer_initiated| is true, the navigation will simulate a history
-  // navigation initiated via JS.
+  // E.g. offset -1 for back navigations and 1 for forward navigations.
   static std::unique_ptr<NavigationSimulator> CreateHistoryNavigation(
       int offset,
-      WebContents* web_contents,
-      bool is_renderer_initiated);
+      WebContents* web_contents);
 
   // Creates a NavigationSimulator that will be used to simulate a
   // renderer-initiated navigation to |original_url| started by
diff --git a/content/public/test/web_contents_tester.h b/content/public/test/web_contents_tester.h
index 4e1a28d..40c8d10f 100644
--- a/content/public/test/web_contents_tester.h
+++ b/content/public/test/web_contents_tester.h
@@ -25,6 +25,7 @@
 namespace content {
 
 class BrowserContext;
+class NavigationSimulator;
 
 // This interface allows embedders of content/ to write tests that depend on a
 // test version of WebContents.  This interface can be retrieved from any
@@ -171,6 +172,10 @@
   // frame and returns the main frame of the page after the navigation is
   // complete.
   virtual RenderFrameHost* AddPrerenderAndCommitNavigation(const GURL& url) = 0;
+  // Starts prerendering a page, simulates a navigation to |url| in the main
+  // frame and returns the simulator after the navigation is started.
+  virtual std::unique_ptr<NavigationSimulator> AddPrerenderAndStartNavigation(
+      const GURL& url) = 0;
 };
 
 }  // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 339ce58..b682882 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -46,6 +46,8 @@
     "../browser/accessibility/test_browser_accessibility_delegate.h",
     "../browser/aggregation_service/aggregation_service_test_utils.cc",
     "../browser/aggregation_service/aggregation_service_test_utils.h",
+    "../browser/attribution_reporting/conversion_test_utils.cc",
+    "../browser/attribution_reporting/conversion_test_utils.h",
     "../browser/background_fetch/background_fetch_test_base.cc",
     "../browser/background_fetch/background_fetch_test_base.h",
     "../browser/background_fetch/background_fetch_test_browser_context.cc",
@@ -58,8 +60,6 @@
     "../browser/background_fetch/mock_background_fetch_delegate.h",
     "../browser/browsing_data/browsing_data_test_utils.cc",
     "../browser/browsing_data/browsing_data_test_utils.h",
-    "../browser/conversions/conversion_test_utils.cc",
-    "../browser/conversions/conversion_test_utils.h",
     "../browser/file_system_access/fake_file_system_access_permission_context.cc",
     "../browser/file_system_access/fake_file_system_access_permission_context.h",
     "../browser/file_system_access/file_system_chooser_test_helpers.cc",
@@ -1073,6 +1073,11 @@
     "../browser/accessibility/site_per_process_accessibility_browsertest.cc",
     "../browser/accessibility/snapshot_ax_tree_browsertest.cc",
     "../browser/accessibility/touch_accessibility_aura_browsertest.cc",
+    "../browser/attribution_reporting/conversion_internals_browsertest.cc",
+    "../browser/attribution_reporting/conversion_registration_browsertest.cc",
+    "../browser/attribution_reporting/conversions_browsertest.cc",
+    "../browser/attribution_reporting/conversions_origin_trial_browsertest.cc",
+    "../browser/attribution_reporting/impression_declaration_browsertest.cc",
     "../browser/back_forward_cache_browsertest.cc",
     "../browser/background_sync/background_sync_base_browsertest.cc",
     "../browser/background_sync/background_sync_base_browsertest.h",
@@ -1093,11 +1098,6 @@
     "../browser/compute_pressure/compute_pressure_origin_trial_browsertest.cc",
     "../browser/content_index/content_index_browsertest.cc",
     "../browser/content_security_policy_browsertest.cc",
-    "../browser/conversions/conversion_internals_browsertest.cc",
-    "../browser/conversions/conversion_registration_browsertest.cc",
-    "../browser/conversions/conversions_browsertest.cc",
-    "../browser/conversions/conversions_origin_trial_browsertest.cc",
-    "../browser/conversions/impression_declaration_browsertest.cc",
     "../browser/cross_origin_opener_policy_browsertest.cc",
     "../browser/cross_site_transfer_browsertest.cc",
     "../browser/data_decoder_browsertest.cc",
@@ -1872,6 +1872,17 @@
     "../browser/aggregation_service/aggregation_service_network_fetcher_impl_unittest.cc",
     "../browser/aggregation_service/aggregation_service_storage_sql_unittest.cc",
     "../browser/aggregation_service/public_key_parsing_utils_unittest.cc",
+    "../browser/attribution_reporting/conversion_host_unittest.cc",
+    "../browser/attribution_reporting/conversion_host_utils_unittest.cc",
+    "../browser/attribution_reporting/conversion_manager_impl_unittest.cc",
+    "../browser/attribution_reporting/conversion_network_sender_impl_unittest.cc",
+    "../browser/attribution_reporting/conversion_policy_unittest.cc",
+    "../browser/attribution_reporting/conversion_reporter_impl_unittest.cc",
+    "../browser/attribution_reporting/conversion_storage_delegate_impl_unittest.cc",
+    "../browser/attribution_reporting/conversion_storage_sql_migrations_unittest.cc",
+    "../browser/attribution_reporting/conversion_storage_sql_unittest.cc",
+    "../browser/attribution_reporting/conversion_storage_unittest.cc",
+    "../browser/attribution_reporting/rate_limit_table_unittest.cc",
     "../browser/background_fetch/background_fetch_cross_origin_filter_unittest.cc",
     "../browser/background_fetch/background_fetch_data_manager_unittest.cc",
     "../browser/background_fetch/background_fetch_delegate_proxy_unittest.cc",
@@ -1928,17 +1939,6 @@
     "../browser/compute_pressure/cpuid_base_frequency_parser_unittest.cc",
     "../browser/content_index/content_index_database_unittest.cc",
     "../browser/content_index/content_index_service_impl_unittest.cc",
-    "../browser/conversions/conversion_host_unittest.cc",
-    "../browser/conversions/conversion_host_utils_unittest.cc",
-    "../browser/conversions/conversion_manager_impl_unittest.cc",
-    "../browser/conversions/conversion_network_sender_impl_unittest.cc",
-    "../browser/conversions/conversion_policy_unittest.cc",
-    "../browser/conversions/conversion_reporter_impl_unittest.cc",
-    "../browser/conversions/conversion_storage_delegate_impl_unittest.cc",
-    "../browser/conversions/conversion_storage_sql_migrations_unittest.cc",
-    "../browser/conversions/conversion_storage_sql_unittest.cc",
-    "../browser/conversions/conversion_storage_unittest.cc",
-    "../browser/conversions/rate_limit_table_unittest.cc",
     "../browser/cookie_store/cookie_store_manager_unittest.cc",
     "../browser/devtools/devtools_background_services_context_impl_unittest.cc",
     "../browser/devtools/devtools_http_handler_unittest.cc",
@@ -2326,7 +2326,7 @@
     sources += [
       "../browser/accessibility/browser_accessibility_android_unittest.cc",
       "../browser/android/nfc_host_unittest.cc",
-      "../browser/conversions/attribution_reporter_android_unittest.cc",
+      "../browser/attribution_reporting/attribution_reporter_android_unittest.cc",
       "../browser/renderer_host/input/web_input_event_builders_android_unittest.cc",
       "../browser/tracing/background_reached_code_tracing_observer_android_unittest.cc",
       "../browser/web_contents/color_chooser_unittest.cc",
diff --git a/content/test/data/conversions/databases/README.md b/content/test/data/conversions/databases/README.md
index 75dadaa..20c78ee 100644
--- a/content/test/data/conversions/databases/README.md
+++ b/content/test/data/conversions/databases/README.md
@@ -7,4 +7,4 @@
 schema.
 
 For more info, please see the migration steps located at the top of
-`content/browser/conversions/conversion_storage_sql_migrations.h`.
+`content/browser/attribution_reporting/conversion_storage_sql_migrations.h`.
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index 9c3d86e8..7762d80 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -131,8 +131,8 @@
 // static
 RenderFrameHost* NavigationSimulator::GoToOffset(WebContents* web_contents,
                                                  int offset) {
-  auto simulator = NavigationSimulatorImpl::CreateHistoryNavigation(
-      offset, web_contents, false /* is_renderer_initiated */);
+  auto simulator =
+      NavigationSimulatorImpl::CreateHistoryNavigation(offset, web_contents);
   simulator->Commit();
   return simulator->GetFinalRenderFrameHost();
 }
@@ -188,8 +188,8 @@
     WebContents* web_contents,
     int offset,
     int net_error_code) {
-  auto simulator = NavigationSimulator::CreateHistoryNavigation(
-      offset, web_contents, false /* is_renderer_initiated */);
+  auto simulator =
+      NavigationSimulator::CreateHistoryNavigation(offset, web_contents);
   simulator->Fail(net_error_code);
   if (net_error_code == net::ERR_ABORTED)
     return nullptr;
@@ -231,25 +231,16 @@
 // static
 std::unique_ptr<NavigationSimulator>
 NavigationSimulator::CreateHistoryNavigation(int offset,
-                                             WebContents* web_contents,
-                                             bool is_renderer_initiated) {
-  return NavigationSimulatorImpl::CreateHistoryNavigation(
-      offset, web_contents, is_renderer_initiated);
+                                             WebContents* web_contents) {
+  return NavigationSimulatorImpl::CreateHistoryNavigation(offset, web_contents);
 }
 
 // static
 std::unique_ptr<NavigationSimulatorImpl>
 NavigationSimulatorImpl::CreateHistoryNavigation(int offset,
-                                                 WebContents* web_contents,
-                                                 bool is_renderer_initiated) {
-  std::unique_ptr<NavigationSimulatorImpl> simulator = nullptr;
-  if (is_renderer_initiated) {
-    simulator = NavigationSimulatorImpl::CreateRendererInitiated(
-        GURL(), web_contents->GetMainFrame());
-  } else {
-    simulator =
-        NavigationSimulatorImpl::CreateBrowserInitiated(GURL(), web_contents);
-  }
+                                                 WebContents* web_contents) {
+  auto simulator =
+      NavigationSimulatorImpl::CreateBrowserInitiated(GURL(), web_contents);
   simulator->SetSessionHistoryOffset(offset);
   return simulator;
 }
@@ -443,8 +434,6 @@
   CHECK(request_);
   if (blink::IsRendererDebugURL(navigation_url_))
     return;
-  if (session_history_offset_)
-    return;
 
   if (!NeedsThrottleChecks())
     return;
@@ -1243,13 +1232,6 @@
 }
 
 bool NavigationSimulatorImpl::SimulateRendererInitiatedStart() {
-  if (session_history_offset_) {
-    static_cast<NavigationControllerImpl&>(web_contents_->GetController())
-        .GoToOffsetFromRenderer(session_history_offset_);
-    request_ = render_frame_host_->frame_tree_node()->navigation_request();
-    return true;
-  }
-
   blink::mojom::BeginNavigationParamsPtr begin_params =
       blink::mojom::BeginNavigationParams::New(
           initiator_frame_host_
diff --git a/content/test/navigation_simulator_impl.h b/content/test/navigation_simulator_impl.h
index 22be401..e357974 100644
--- a/content/test/navigation_simulator_impl.h
+++ b/content/test/navigation_simulator_impl.h
@@ -50,8 +50,7 @@
 
   static std::unique_ptr<NavigationSimulatorImpl> CreateHistoryNavigation(
       int offset,
-      WebContents* web_contents,
-      bool is_renderer_initiated);
+      WebContents* web_contents);
 
   // TODO(https://crbug.com/1131832): Remove |original_url| as it's not used.
   static std::unique_ptr<NavigationSimulatorImpl> CreateRendererInitiated(
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 981542dd..81f410e3 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -431,4 +431,16 @@
   }
   return static_cast<TestRenderFrameHost*>(host->GetPrerenderedMainFrameHost());
 }
+
+std::unique_ptr<NavigationSimulator>
+TestWebContents::AddPrerenderAndStartNavigation(const GURL& url) {
+  int host_id = AddPrerender(url);
+  PrerenderHost* host =
+      GetPrerenderHostRegistry()->FindNonReservedHostById(host_id);
+  DCHECK(host);
+
+  return NavigationSimulatorImpl::CreateFromPendingInFrame(
+      FrameTreeNode::GloballyFindByID(host->frame_tree_node_id()));
+}
+
 }  // namespace content
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index d9a47346..25b21ce7 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -147,6 +147,8 @@
   int AddPrerender(const GURL& url) override;
   TestRenderFrameHost* AddPrerenderAndCommitNavigation(
       const GURL& url) override;
+  std::unique_ptr<NavigationSimulator> AddPrerenderAndStartNavigation(
+      const GURL& url) override;
 
  protected:
   // The deprecated WebContentsTester still needs to subclass this.
diff --git a/docs/commit_checklist.md b/docs/commit_checklist.md
index 6a0857d2..3633a1c 100644
--- a/docs/commit_checklist.md
+++ b/docs/commit_checklist.md
@@ -276,7 +276,7 @@
 
 After your CL is landed, you can use `git rebase-update` or `git cl archive` to
 clean up your local branches. These commands will automatically delete merged
-branches. Mark the associated crbug as "fixed".
+branches. Please mark the associated crbug as "fixed".
 
 [//]: # (the reference link section should be alphabetically sorted)
 [build-instructions]: https://chromium.googlesource.com/chromium/src.git/+/main/docs/#Checking-Out-and-Building
diff --git a/extensions/browser/extension_navigation_throttle.cc b/extensions/browser/extension_navigation_throttle.cc
index 8b1d0d0..aa7607c 100644
--- a/extensions/browser/extension_navigation_throttle.cc
+++ b/extensions/browser/extension_navigation_throttle.cc
@@ -244,17 +244,18 @@
     return content::NavigationThrottle::BLOCK_REQUEST;
   }
 
-  // A browser-initiated navigation is always considered trusted, and thus
-  // allowed.
-  if (!navigation_handle()->IsRendererInitiated())
+  // Navigations with no initiator (e.g. browser-initiated requests) are always
+  // considered trusted, and thus allowed.
+  //
+  // Note that GuestView navigations initiated by the embedder also count as a
+  // browser-initiated navigation.
+  if (!navigation_handle()->GetInitiatorOrigin().has_value()) {
+    DCHECK(!navigation_handle()->IsRendererInitiated());
     return content::NavigationThrottle::PROCEED;
+  }
 
-  // A renderer-initiated request without an initiator origin is a history
-  // traversal to an entry that was originally loaded in a browser-initiated
-  // navigation. Those are trusted, too.
-  if (!navigation_handle()->GetInitiatorOrigin().has_value())
-    return content::NavigationThrottle::PROCEED;
-
+  // All renderer-initiated navigations must have an initiator.
+  DCHECK(navigation_handle()->GetInitiatorOrigin().has_value());
   const url::Origin& initiator_origin =
       navigation_handle()->GetInitiatorOrigin().value();
 
diff --git a/extensions/renderer/messaging_util.h b/extensions/renderer/messaging_util.h
index 8c30d8d0..525ff1db 100644
--- a/extensions/renderer/messaging_util.h
+++ b/extensions/renderer/messaging_util.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "v8/include/v8-forward.h"
 
diff --git a/extensions/renderer/resource_bundle_source_map.h b/extensions/renderer/resource_bundle_source_map.h
index 4e368c5..dd98ad7 100644
--- a/extensions/renderer/resource_bundle_source_map.h
+++ b/extensions/renderer/resource_bundle_source_map.h
@@ -6,6 +6,7 @@
 #define EXTENSIONS_RENDERER_RESOURCE_BUNDLE_SOURCE_MAP_H_
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
diff --git a/gin/gin_features.cc b/gin/gin_features.cc
index 36dd4dc6..24b1446b 100644
--- a/gin/gin_features.cc
+++ b/gin/gin_features.cc
@@ -47,6 +47,12 @@
 const base::Feature kV8NoReclaimUnmodifiedWrappers{
     "V8NoReclaimUnmodifiedWrappers", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables W^X code memory protection in V8.
+// This is enabled in V8 by default. To test the performance impact, we are
+// going to disable this feature in a finch experiment.
+const base::Feature kV8CodeMemoryWriteProtection{
+    "V8CodeMemoryWriteProtection", base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Enables fallback to a breadth-first regexp engine on excessive backtracking.
 const base::Feature kV8ExperimentalRegexpEngine{
     "V8ExperimentalRegexpEngine", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/gin/gin_features.h b/gin/gin_features.h
index 32f96a27..9a7c63e 100644
--- a/gin/gin_features.h
+++ b/gin/gin_features.h
@@ -18,6 +18,7 @@
 GIN_EXPORT extern const base::Feature kV8FlushEmbeddedBlobICache;
 GIN_EXPORT extern const base::Feature kV8LazyFeedbackAllocation;
 GIN_EXPORT extern const base::Feature kV8NoReclaimUnmodifiedWrappers;
+GIN_EXPORT extern const base::Feature kV8CodeMemoryWriteProtection;
 GIN_EXPORT extern const base::Feature kV8OffThreadFinalization;
 GIN_EXPORT extern const base::Feature kV8OptimizeJavascript;
 GIN_EXPORT extern const base::Feature kV8PerContextMarkingWorklist;
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index 0dc972a..4b1bf58 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -302,6 +302,9 @@
                          "--no-sparkplug-needs-short-builtins");
   SetV8FlagsIfOverridden(features::kV8ShortBuiltinCalls,
                          "--short-builtin-calls", "--no-short-builtin-calls");
+  SetV8FlagsIfOverridden(features::kV8CodeMemoryWriteProtection,
+                         "--write-protect-code-memory",
+                         "--no-write-protect-code-memory");
   SetV8FlagsIfOverridden(features::kV8SlowHistograms, "--slow-histograms",
                          "--no-slow-histograms");
 
diff --git a/ios/chrome/app/application_delegate/user_activity_handler.mm b/ios/chrome/app/application_delegate/user_activity_handler.mm
index f11d6d52..2381ef3 100644
--- a/ios/chrome/app/application_delegate/user_activity_handler.mm
+++ b/ios/chrome/app/application_delegate/user_activity_handler.mm
@@ -540,7 +540,7 @@
       NSData* imageData =
           connectionInformation.startupParameters.imageSearchData;
       web::NavigationManager::WebLoadParams webLoadParams =
-          ImageSearchParamGenerator::LoadParamsForImageData(imageData,
+          ImageSearchParamGenerator::LoadParamsForImageData(imageData, GURL(),
                                                             templateURLService);
 
       params.web_params = webLoadParams;
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
index 7abf4173..73ac8501 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
@@ -51,7 +51,7 @@
   // web::WebStatePolicyDecider implementation
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const web::WebStatePolicyDecider::RequestInfo& request_info,
+      web::WebStatePolicyDecider::RequestInfo request_info,
       web::WebStatePolicyDecider::PolicyDecisionCallback callback) override;
 
  private:
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
index 1b29d92..f0435fd 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
@@ -163,7 +163,7 @@
 
 void AppLauncherTabHelper::ShouldAllowRequest(
     NSURLRequest* request,
-    const web::WebStatePolicyDecider::RequestInfo& request_info,
+    web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   GURL request_url = net::GURLWithNSURL(request.URL);
   if (!IsAppUrl(request_url)) {
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
index e3bd0a6..642f08b 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
@@ -123,7 +123,7 @@
                                   ui::PageTransition::PAGE_TRANSITION_LINK)
       WARN_UNUSED_RESULT {
     NSURL* url = [NSURL URLWithString:url_string];
-    web::WebStatePolicyDecider::RequestInfo request_info(
+    const web::WebStatePolicyDecider::RequestInfo request_info(
         transition_type, target_frame_is_main, target_frame_is_cross_origin,
         has_user_gesture);
     __block bool callback_called = false;
@@ -181,7 +181,7 @@
 
     NSURL* url = [NSURL
         URLWithString:@"itms-apps://itunes.apple.com/us/app/appname/id123"];
-    web::WebStatePolicyDecider::RequestInfo request_info(
+    const web::WebStatePolicyDecider::RequestInfo request_info(
         transition_type,
         /*target_frame_is_main=*/true, /*target_frame_is_cross_origin=*/false,
         /*has_user_gesture=*/true);
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service.h b/ios/chrome/browser/credential_provider/credential_provider_service.h
index e02a77c4..ecde9d8 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service.h
+++ b/ios/chrome/browser/credential_provider/credential_provider_service.h
@@ -16,6 +16,10 @@
 
 @protocol MutableCredentialStore;
 
+namespace password_manager {
+class AffiliationService;
+}
+
 namespace syncer {
 class SyncService;
 }
@@ -36,7 +40,8 @@
       AuthenticationService* authentication_service,
       id<MutableCredentialStore> credential_store,
       signin::IdentityManager* identity_manager,
-      syncer::SyncService* sync_service);
+      syncer::SyncService* sync_service,
+      password_manager::AffiliationService* affiliation_service);
 
   CredentialProviderService(const CredentialProviderService&) = delete;
   CredentialProviderService& operator=(const CredentialProviderService&) =
@@ -120,6 +125,9 @@
   // Sync Service to observe.
   syncer::SyncService* sync_service_ = nullptr;
 
+  // Affiliation service to provide affiliations.
+  password_manager::AffiliationService* affiliation_service_ = nullptr;
+
   // The interface for saving and updating credentials.
   id<MutableCredentialStore> credential_store_ = nil;
 
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service.mm b/ios/chrome/browser/credential_provider/credential_provider_service.mm
index c868368c..335800ed 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service.mm
+++ b/ios/chrome/browser/credential_provider/credential_provider_service.mm
@@ -15,8 +15,8 @@
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
-#include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_change.h"
+#include "components/password_manager/core/browser/password_store_interface.h"
 #include "components/password_manager/core/browser/site_affiliation/affiliation_service.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -137,11 +137,13 @@
     AuthenticationService* authentication_service,
     id<MutableCredentialStore> credential_store,
     signin::IdentityManager* identity_manager,
-    syncer::SyncService* sync_service)
+    syncer::SyncService* sync_service,
+    password_manager::AffiliationService* affiliation_service)
     : password_store_(password_store),
       authentication_service_(authentication_service),
       identity_manager_(identity_manager),
       sync_service_(sync_service),
+      affiliation_service_(affiliation_service),
       credential_store_(credential_store) {
   DCHECK(password_store_);
   password_store_->AddObserver(this);
@@ -284,9 +286,8 @@
     std::vector<std::unique_ptr<PasswordForm>> results) {
   auto callback = base::BindOnce(&CredentialProviderService::SyncAllCredentials,
                                  weak_factory_.GetWeakPtr());
-  AffiliatedMatchHelper* matcher = password_store_->affiliated_match_helper();
-  if (matcher) {
-    matcher->InjectAffiliationAndBrandingInformation(
+  if (affiliation_service_) {
+    affiliation_service_->InjectAffiliationAndBrandingInformation(
         std::move(results),
         AffiliationService::StrategyOnCacheMiss::FETCH_OVER_NETWORK,
         std::move(callback));
@@ -343,9 +344,8 @@
       &CredentialProviderService::OnInjectedAffiliationAfterLoginsChanged,
       weak_factory_.GetWeakPtr());
 
-  AffiliatedMatchHelper* matcher = password_store_->affiliated_match_helper();
-  if (matcher) {
-    matcher->InjectAffiliationAndBrandingInformation(
+  if (affiliation_service_) {
+    affiliation_service_->InjectAffiliationAndBrandingInformation(
         std::move(forms_to_add),
         AffiliationService::StrategyOnCacheMiss::FETCH_OVER_NETWORK,
         std::move(callback));
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm b/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm
index da731ea4..d665dfb 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm
+++ b/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm
@@ -6,8 +6,10 @@
 
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/credential_provider/credential_provider_service.h"
+#include "ios/chrome/browser/passwords/ios_chrome_affiliation_service_factory.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
@@ -37,6 +39,7 @@
     : BrowserStateKeyedServiceFactory(
           "CredentialProviderService",
           BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(IOSChromeAffiliationServiceFactory::GetInstance());
   DependsOn(IOSChromePasswordStoreFactory::GetInstance());
   DependsOn(AuthenticationServiceFactory::GetInstance());
   DependsOn(IdentityManagerFactory::GetInstance());
@@ -63,7 +66,12 @@
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForBrowserState(browser_state);
 
+  password_manager::AffiliationService* affiliation_service =
+      base::FeatureList::IsEnabled(
+          password_manager::features::kFillingAcrossAffiliatedWebsites)
+          ? IOSChromeAffiliationServiceFactory::GetForBrowserState(context)
+          : nullptr;
   return std::make_unique<CredentialProviderService>(
       browser_state->GetPrefs(), password_store, authentication_service,
-      credential_store, identity_manager, sync_service);
+      credential_store, identity_manager, sync_service, affiliation_service);
 }
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm b/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm
index cec06af..febbda2 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm
+++ b/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm
@@ -9,7 +9,9 @@
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_store_factory_util.h"
 #include "components/password_manager/core/browser/password_store_impl.h"
+#include "components/password_manager/core/browser/site_affiliation/fake_affiliation_service.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_service.h"
@@ -35,6 +37,7 @@
 
 namespace {
 
+using password_manager::FakeAffiliationService;
 using password_manager::PasswordForm;
 using base::test::ios::WaitUntilConditionOrTimeout;
 using base::test::ios::kWaitForFileOperationTimeout;
@@ -80,7 +83,7 @@
 
     credential_provider_service_ = std::make_unique<CredentialProviderService>(
         &testing_pref_service_, password_store_, auth_service_,
-        credential_store_, nullptr, &sync_service_);
+        credential_store_, nullptr, &sync_service_, &affiliation_service_);
 
     // Fire sync service state changed to simulate sync setup finishing.
     sync_service_.FireStateChanged();
@@ -113,6 +116,7 @@
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
   ChromeAccountManagerService* account_manager_service_;
   syncer::TestSyncService sync_service_;
+  FakeAffiliationService affiliation_service_;
 
   DISALLOW_COPY_AND_ASSIGN(CredentialProviderServiceTest);
 };
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
index fe247f7..834a9a5 100644
--- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
@@ -50,7 +50,7 @@
   // web::WebStatePolicyDecider implementation
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const web::WebStatePolicyDecider::RequestInfo& request_info,
+      web::WebStatePolicyDecider::RequestInfo request_info,
       web::WebStatePolicyDecider::PolicyDecisionCallback callback) override;
 
  private:
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
index edb0282..48cb8538 100644
--- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
@@ -113,7 +113,7 @@
 
 void ITunesUrlsHandlerTabHelper::ShouldAllowRequest(
     NSURLRequest* request,
-    const web::WebStatePolicyDecider::RequestInfo& request_info,
+    web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   // Don't Handle URLS in Off The record mode as this will open StoreKit with
   // Users' iTunes account. Also don't Handle navigations in iframe because they
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
index 9396c460..97d27f2 100644
--- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
@@ -42,7 +42,7 @@
   bool VerifyStoreKitLaunched(NSString* url_string, bool main_frame) {
     fake_launcher_.launchedProductID = nil;
     fake_launcher_.launchedProductParams = nil;
-    web::WebStatePolicyDecider::RequestInfo request_info(
+    const web::WebStatePolicyDecider::RequestInfo request_info(
         ui::PageTransition::PAGE_TRANSITION_LINK, main_frame,
         /*target_frame_is_cross_origin=*/false,
         /*has_user_gesture=*/false);
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h
index cadd8d6..de8e9f3 100644
--- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h
+++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h
@@ -33,7 +33,7 @@
   // web::WebStatePolicyDecider:
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const web::WebStatePolicyDecider::RequestInfo& request_info,
+      web::WebStatePolicyDecider::RequestInfo request_info,
       web::WebStatePolicyDecider::PolicyDecisionCallback callback) override;
   void ShouldAllowResponse(
       NSURLResponse* response,
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm
index ed6badc..1ec4868 100644
--- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm
+++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm
@@ -50,7 +50,7 @@
 
 void WellKnownChangePasswordTabHelper::ShouldAllowRequest(
     NSURLRequest* request,
-    const web::WebStatePolicyDecider::RequestInfo& request_info,
+    web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   GURL request_url = net::GURLWithNSURL(request.URL);
   // The custom behaviour is only used if the .well-known/change-password
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm
index 0d87b2b4..080a891 100644
--- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm
+++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm
@@ -80,6 +80,10 @@
   void CancelPrefetch(const FacetURI& facet_uri,
                       const base::Time& keep_fresh_until) override {}
   void TrimCacheForFacetURI(const FacetURI& facet_uri) override {}
+  void InjectAffiliationAndBrandingInformation(
+      std::vector<std::unique_ptr<password_manager::PasswordForm>> forms,
+      AffiliationService::StrategyOnCacheMiss strategy_on_cache_miss,
+      PasswordFormsCallback result_callback) override {}
 
   void SetOverrideAvailable(bool available) { override_available_ = available; }
 
diff --git a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h
index 8767854..d9952de0 100644
--- a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h
+++ b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h
@@ -19,7 +19,7 @@
   // web::WebStatePolicyDecider
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const web::WebStatePolicyDecider::RequestInfo& request_info,
+      web::WebStatePolicyDecider::RequestInfo request_info,
       web::WebStatePolicyDecider::PolicyDecisionCallback callback) override;
 
  private:
diff --git a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm
index ff0b2f7b..196efa6 100644
--- a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm
+++ b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm
@@ -20,7 +20,7 @@
 
 void PolicyUrlBlockingTabHelper::ShouldAllowRequest(
     NSURLRequest* request,
-    const web::WebStatePolicyDecider::RequestInfo& request_info,
+    web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   GURL gurl = net::GURLWithNSURL(request.URL);
   PolicyBlocklistService* blocklistService =
diff --git a/ios/chrome/browser/prerender/preload_controller.mm b/ios/chrome/browser/prerender/preload_controller.mm
index 2e60d5e..dbc29bd 100644
--- a/ios/chrome/browser/prerender/preload_controller.mm
+++ b/ios/chrome/browser/prerender/preload_controller.mm
@@ -567,8 +567,7 @@
 #pragma mark - CRWWebStatePolicyDecider
 
 - (void)shouldAllowRequest:(NSURLRequest*)request
-               requestInfo:
-                   (const WebStatePolicyDecider::RequestInfo&)requestInfo
+               requestInfo:(WebStatePolicyDecider::RequestInfo)requestInfo
            decisionHandler:(PolicyDecisionHandler)decisionHandler {
   GURL requestURL = net::GURLWithNSURL(request.URL);
   // Don't allow preloading for requests that are handled by opening another
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h
index a8773f85..9cb6d34 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h
@@ -100,7 +100,7 @@
     // web::WebStatePolicyDecider implementation
     void ShouldAllowRequest(
         NSURLRequest* request,
-        const web::WebStatePolicyDecider::RequestInfo& request_info,
+        web::WebStatePolicyDecider::RequestInfo request_info,
         web::WebStatePolicyDecider::PolicyDecisionCallback callback) override;
     void ShouldAllowResponse(
         NSURLResponse* response,
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm
index ce5fb8b..79c0d5a 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm
@@ -134,7 +134,7 @@
 
 void SafeBrowsingTabHelper::PolicyDecider::ShouldAllowRequest(
     NSURLRequest* request,
-    const web::WebStatePolicyDecider::RequestInfo& request_info,
+    web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   // Allow navigations for URLs that cannot be checked by the service.
   GURL request_url = GetCanonicalizedUrl(net::GURLWithNSURL(request.URL));
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm
index 5af00e4..adf93be 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm
@@ -69,7 +69,7 @@
       bool for_main_frame = true,
       ui::PageTransition transition =
           ui::PageTransition::PAGE_TRANSITION_FIRST) {
-    web::WebStatePolicyDecider::RequestInfo request_info(
+    const web::WebStatePolicyDecider::RequestInfo request_info(
         transition, for_main_frame, /*target_frame_is_cross_origin=*/false,
         /*has_user_gesture=*/false);
     __block bool callback_called = false;
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 703b145..395da86f 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -84,7 +84,6 @@
 #import "ios/chrome/browser/ui/commands/help_commands.h"
 #import "ios/chrome/browser/ui/commands/load_query_commands.h"
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
-#import "ios/chrome/browser/ui/commands/search_by_image_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/commands/text_zoom_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
@@ -158,7 +157,6 @@
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h"
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller_factory.h"
 #include "ios/chrome/browser/upgrade/upgrade_center.h"
-#import "ios/chrome/browser/url_loading/image_search_param_generator.h"
 #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_notifier_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_observer_bridge.h"
@@ -172,6 +170,7 @@
 #import "ios/chrome/browser/web/sad_tab_tab_helper.h"
 #import "ios/chrome/browser/web/tab_id_tab_helper.h"
 #import "ios/chrome/browser/web/web_navigation_browser_agent.h"
+#import "ios/chrome/browser/web/web_navigation_util.h"
 #import "ios/chrome/browser/web/web_state_delegate_tab_helper.h"
 #import "ios/chrome/browser/web_state_list/all_web_state_observation_forwarder.h"
 #import "ios/chrome/browser/web_state_list/tab_insertion_browser_agent.h"
@@ -4158,23 +4157,6 @@
   }
 }
 
-- (void)searchByImage:(SearchByImageCommand*)command {
-  web::NavigationManager::WebLoadParams webParams =
-      ImageSearchParamGenerator::LoadParamsForImage(
-          command.image, command.URL,
-          ios::TemplateURLServiceFactory::GetForBrowserState(
-              self.browserState));
-
-  if (command.inNewTab) {
-    UrlLoadParams params = UrlLoadParams::InNewTab(webParams);
-    params.in_incognito = self.isOffTheRecord;
-    UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
-  } else {
-    UrlLoadingBrowserAgent::FromBrowser(self.browser)
-        ->Load(UrlLoadParams::InCurrentTab(webParams));
-  }
-}
-
 - (void)showActivityOverlay:(BOOL)show {
   if (!show) {
     [self.activityOverlayCoordinator stop];
diff --git a/ios/chrome/browser/ui/commands/BUILD.gn b/ios/chrome/browser/ui/commands/BUILD.gn
index feaa202..9b5ed67 100644
--- a/ios/chrome/browser/ui/commands/BUILD.gn
+++ b/ios/chrome/browser/ui/commands/BUILD.gn
@@ -35,8 +35,6 @@
     "qr_scanner_commands.h",
     "reading_list_add_command.h",
     "reading_list_add_command.mm",
-    "search_by_image_command.h",
-    "search_by_image_command.mm",
     "security_alert_commands.h",
     "share_highlight_command.h",
     "share_highlight_command.mm",
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 80a401a..9020138 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -85,9 +85,6 @@
 // omnibox.
 - (void)focusFakebox;
 
-// Searches for an image, using |command| parameters.
-- (void)searchByImage:(SearchByImageCommand*)command;
-
 // Shows/Hides the activity indicator overlay that appears over the view to
 // prevent interaction with the web page.
 - (void)showActivityOverlay:(BOOL)show;
diff --git a/ios/chrome/browser/ui/commands/search_by_image_command.h b/ios/chrome/browser/ui/commands/search_by_image_command.h
deleted file mode 100644
index 85f1ede2..0000000
--- a/ios/chrome/browser/ui/commands/search_by_image_command.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_COMMANDS_SEARCH_BY_IMAGE_COMMAND_H_
-#define IOS_CHROME_BROWSER_UI_COMMANDS_SEARCH_BY_IMAGE_COMMAND_H_
-
-#import <UIKit/UIkit.h>
-
-#include <url/gurl.h>
-
-// An instance of this class contains the data needed to do an image search.
-@interface SearchByImageCommand : NSObject
-
-// Convenience initializer, initializing an command with |image|, an empty URL
-// and in the current tab.
-- (instancetype)initWithImage:(UIImage*)image;
-
-// Initializes to search for |image| located at |URL|, and opens the result
-// |inNewTab|.
-- (instancetype)initWithImage:(UIImage*)image
-                          URL:(const GURL&)URL
-                     inNewTab:(BOOL)inNewTab NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
-@property(nonatomic, strong, readonly) UIImage* image;
-@property(nonatomic, assign, readonly) const GURL& URL;
-@property(nonatomic, assign, readonly) BOOL inNewTab;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_COMMANDS_SEARCH_BY_IMAGE_COMMAND_H_
diff --git a/ios/chrome/browser/ui/commands/search_by_image_command.mm b/ios/chrome/browser/ui/commands/search_by_image_command.mm
deleted file mode 100644
index dac0d039..0000000
--- a/ios/chrome/browser/ui/commands/search_by_image_command.mm
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/commands/search_by_image_command.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface SearchByImageCommand () {
-  GURL _URL;
-}
-@end
-
-@implementation SearchByImageCommand
-
-- (instancetype)initWithImage:(UIImage*)image {
-  return [self initWithImage:image URL:GURL() inNewTab:NO];
-}
-
-- (instancetype)initWithImage:(UIImage*)image
-                          URL:(const GURL&)URL
-                     inNewTab:(BOOL)inNewTab {
-  self = [super init];
-  if (self) {
-    _URL = URL;
-    _image = image;
-    _inNewTab = inNewTab;
-  }
-  return self;
-}
-
-- (const GURL&)URL {
-  return _URL;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/context_menu/context_menu_configuration_provider.mm b/ios/chrome/browser/ui/context_menu/context_menu_configuration_provider.mm
index fe9ff078..b89642e 100644
--- a/ios/chrome/browser/ui/context_menu/context_menu_configuration_provider.mm
+++ b/ios/chrome/browser/ui/context_menu/context_menu_configuration_provider.mm
@@ -20,7 +20,6 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
-#import "ios/chrome/browser/ui/commands/search_by_image_command.h"
 #import "ios/chrome/browser/ui/context_menu/context_menu_utils.h"
 #import "ios/chrome/browser/ui/context_menu/image_preview_view_controller.h"
 #import "ios/chrome/browser/ui/context_menu/link_no_preview_view_controller.h"
@@ -34,6 +33,7 @@
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/pasteboard_util.h"
 #import "ios/chrome/browser/ui/util/url_with_title.h"
+#import "ios/chrome/browser/url_loading/image_search_param_generator.h"
 #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/web/image_fetch/image_fetch_tab_helper.h"
@@ -293,23 +293,8 @@
                                  DCHECK(imageFetcher);
                                  imageFetcher->GetImageData(
                                      imageUrl, referrer, ^(NSData* data) {
-                                       ContextMenuConfigurationProvider*
-                                           strongSelf = weakSelf;
-                                       if (!strongSelf)
-                                         return;
-
-                                       SearchByImageCommand* command =
-                                           [[SearchByImageCommand alloc]
-                                               initWithImage:
-                                                   [UIImage imageWithData:data]
-                                                         URL:imageUrl
-                                                    inNewTab:YES];
-
-                                       id<BrowserCommands> handler =
-                                           static_cast<id<BrowserCommands>>(
-                                               strongSelf.browser
-                                                   ->GetCommandDispatcher());
-                                       [handler searchByImage:command];
+                                       [weakSelf searchByImageData:data
+                                                          imageURL:imageUrl];
                                      });
                                }];
       [menuElements addObject:searchByImage];
@@ -328,6 +313,8 @@
       menuTitle = [[menuTitle substringToIndex:kContextMenuMaxURLTitleLength]
           stringByAppendingString:kContextMenuEllipsis];
     }
+  } else if (!isLink) {
+    menuTitle = GetContextMenuTitle(params);
   }
 
   UIContextMenuActionProvider actionProvider =
@@ -673,18 +660,7 @@
             ImageFetchTabHelper::FromWebState(self.currentWebState);
         DCHECK(imageFetcher);
         imageFetcher->GetImageData(imageUrl, referrer, ^(NSData* data) {
-          ContextMenuConfigurationProvider* strongSelf = weakSelf;
-          if (!strongSelf)
-            return;
-
-          SearchByImageCommand* command = [[SearchByImageCommand alloc]
-              initWithImage:[UIImage imageWithData:data]
-                        URL:imageUrl
-                   inNewTab:YES];
-
-          id<BrowserCommands> handler = static_cast<id<BrowserCommands>>(
-              strongSelf.browser->GetCommandDispatcher());
-          [handler searchByImage:command];
+          [weakSelf searchByImageData:data imageURL:imageUrl];
         });
       };
       [self.legacyContextMenuCoordinator
@@ -708,4 +684,20 @@
                       : nullptr;
 }
 
+#pragma mark - Private
+
+// Starts a reverse image search based on |imageData| and |imageURL| in a new
+// tab.
+- (void)searchByImageData:(NSData*)imageData imageURL:(const GURL&)URL {
+  web::NavigationManager::WebLoadParams webParams =
+      ImageSearchParamGenerator::LoadParamsForImageData(
+          imageData, URL,
+          ios::TemplateURLServiceFactory::GetForBrowserState(
+              self.browser->GetBrowserState()));
+
+  UrlLoadParams params = UrlLoadParams::InNewTab(webParams);
+  params.in_incognito = self.browser->GetBrowserState()->IsOffTheRecord();
+  UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
+}
+
 @end
diff --git a/ios/chrome/browser/ui/context_menu/link_preview/BUILD.gn b/ios/chrome/browser/ui/context_menu/link_preview/BUILD.gn
new file mode 100644
index 0000000..9b27c64
--- /dev/null
+++ b/ios/chrome/browser/ui/context_menu/link_preview/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("link_preview") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "link_preview_delegate.h" ]
+
+  public_deps = [ "//ios/chrome/browser/ui/ntp/discover_feed_preview" ]
+}
diff --git a/ios/chrome/browser/ui/context_menu/link_preview/link_preview_delegate.h b/ios/chrome/browser/ui/context_menu/link_preview/link_preview_delegate.h
new file mode 100644
index 0000000..f9fa3eff
--- /dev/null
+++ b/ios/chrome/browser/ui/context_menu/link_preview/link_preview_delegate.h
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_CONTEXT_MENU_LINK_PREVIEW_LINK_PREVIEW_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_CONTEXT_MENU_LINK_PREVIEW_LINK_PREVIEW_DELEGATE_H_
+
+#import "ios/chrome/browser/ui/ntp/discover_feed_preview/discover_feed_preview_delegate.h"
+
+#endif  // IOS_CHROME_BROWSER_UI_CONTEXT_MENU_LINK_PREVIEW_LINK_PREVIEW_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 1b4046c..170a1a0 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -12,6 +12,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
+#include "components/open_from_clipboard/clipboard_recent_content.h"
 #include "components/profile_metrics/browser_profile_type.h"
 #include "components/search_engines/util.h"
 #include "components/strings/grit/components_strings.h"
@@ -55,6 +56,7 @@
 #include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/util/pasteboard_util.h"
+#import "ios/chrome/browser/url_loading/image_search_param_generator.h"
 #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/url_loading/url_loading_util.h"
@@ -408,6 +410,25 @@
   [agent.nonModalScheduler logUserPastedInOmnibox];
 }
 
+- (void)searchCopiedImage {
+  ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
+      base::BindOnce(^(absl::optional<gfx::Image> optionalImage) {
+        if (!optionalImage) {
+          return;
+        }
+        UIImage* image = optionalImage.value().ToUIImage();
+        web::NavigationManager::WebLoadParams webParams =
+            ImageSearchParamGenerator::LoadParamsForImage(
+                image, ios::TemplateURLServiceFactory::GetForBrowserState(
+                           self.browser->GetBrowserState()));
+        UrlLoadParams params = UrlLoadParams::InCurrentTab(webParams);
+
+        UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
+
+        [self cancelOmniboxEdit];
+      }));
+}
+
 #pragma mark - LocationBarConsumer
 
 - (void)defocusOmnibox {
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
index 278b240..1a9decf 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
@@ -42,6 +42,9 @@
 // action.
 - (void)locationBarVisitCopyLinkTapped;
 
+// Starts a reverse image search for the image currently in the pasteboard.
+- (void)searchCopiedImage;
+
 @end
 
 // The view controller displaying the location bar. Manages the two states of
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
index 238ff141..baca2f0f 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
@@ -18,7 +18,6 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/infobar_commands.h"
 #import "ios/chrome/browser/ui/commands/load_query_commands.h"
-#import "ios/chrome/browser/ui/commands/search_by_image_command.h"
 #import "ios/chrome/browser/ui/default_promo/default_browser_utils.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
 #import "ios/chrome/browser/ui/location_bar/location_bar_constants.h"
@@ -648,19 +647,7 @@
 - (void)searchCopiedImage:(id)sender {
   RecordAction(
       UserMetricsAction("Mobile.OmniboxContextMenu.SearchCopiedImage"));
-  ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
-      base::BindOnce(^(absl::optional<gfx::Image> optionalImage) {
-        if (!optionalImage) {
-          return;
-        }
-        UIImage* image = optionalImage.value().ToUIImage();
-        dispatch_async(dispatch_get_main_queue(), ^{
-          SearchByImageCommand* command =
-              [[SearchByImageCommand alloc] initWithImage:image];
-          [self.dispatcher searchByImage:command];
-          [self.dispatcher cancelOmniboxEdit];
-        });
-      }));
+  [self.delegate searchCopiedImage];
 }
 
 - (void)visitCopiedLink:(id)sender {
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn
index 36d887d..4ae942b 100644
--- a/ios/chrome/browser/ui/omnibox/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -160,6 +160,7 @@
     "//ios/chrome/browser/ui/orchestrator:orchestrator",
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/common",
     "//ios/chrome/common/intents",
     "//ios/chrome/common/ui/colors",
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
index 2784cfe..4e4f158b 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -11,6 +11,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/common/omnibox_focus_state.h"
+#include "components/open_from_clipboard/clipboard_recent_content.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
@@ -34,6 +35,10 @@
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h"
 #include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
+#import "ios/chrome/browser/url_loading/image_search_param_generator.h"
+#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
+#import "ios/chrome/browser/url_loading/url_loading_params.h"
+#import "ios/web/public/navigation/navigation_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -233,6 +238,24 @@
   [agent.nonModalScheduler logUserPastedInOmnibox];
 }
 
+- (void)omniboxViewControllerSearchCopiedImage:
+    (OmniboxViewController*)omniboxViewController {
+  ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
+      base::BindOnce(^(absl::optional<gfx::Image> optionalImage) {
+        if (!optionalImage) {
+          return;
+        }
+        UIImage* image = optionalImage.value().ToUIImage();
+        web::NavigationManager::WebLoadParams webParams =
+            ImageSearchParamGenerator::LoadParamsForImage(
+                image, ios::TemplateURLServiceFactory::GetForBrowserState(
+                           self.browser->GetBrowserState()));
+        UrlLoadParams params = UrlLoadParams::InCurrentTab(webParams);
+
+        UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
+      }));
+}
+
 #pragma mark - private
 
 // Convenience accessor.
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
index 0a917f2..a6d4c4d 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
@@ -29,6 +29,10 @@
 - (void)omniboxViewControllerUserDidVisitCopiedLink:
     (OmniboxViewController*)omniboxViewController;
 
+// Starts a reverse image search for the image currently in the pasteboard.
+- (void)omniboxViewControllerSearchCopiedImage:
+    (OmniboxViewController*)omniboxViewController;
+
 @end
 
 @interface OmniboxViewController : UIViewController<EditViewAnimatee,
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
index afbbf0e..a1f1dec 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -14,7 +14,6 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/load_query_commands.h"
 #import "ios/chrome/browser/ui/commands/omnibox_commands.h"
-#import "ios/chrome/browser/ui/commands/search_by_image_command.h"
 #import "ios/chrome/browser/ui/default_promo/default_browser_utils.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_constants.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_container_view.h"
@@ -617,18 +616,7 @@
   RecordAction(
       UserMetricsAction("Mobile.OmniboxContextMenu.SearchCopiedImage"));
   self.omniboxInteractedWhileFocused = YES;
-  ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
-      base::BindOnce(^(absl::optional<gfx::Image> optionalImage) {
-        if (!optionalImage) {
-          return;
-        }
-        UIImage* image = optionalImage.value().ToUIImage();
-        dispatch_async(dispatch_get_main_queue(), ^{
-          SearchByImageCommand* command =
-              [[SearchByImageCommand alloc] initWithImage:image];
-          [self.dispatcher searchByImage:command];
-        });
-      }));
+  [self.delegate omniboxViewControllerSearchCopiedImage:self];
 }
 
 - (void)visitCopiedLink:(id)sender {
diff --git a/ios/chrome/browser/ui/popup_menu/BUILD.gn b/ios/chrome/browser/ui/popup_menu/BUILD.gn
index ca19a988..edeab75 100644
--- a/ios/chrome/browser/ui/popup_menu/BUILD.gn
+++ b/ios/chrome/browser/ui/popup_menu/BUILD.gn
@@ -87,6 +87,7 @@
     "//ios/chrome/browser/ui/presenters",
     "//ios/chrome/browser/ui/reading_list",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web:feature_flags",
     "//ios/chrome/browser/web/font_size",
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
index e3414c3..16294a8 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
@@ -183,18 +183,7 @@
       break;
     case PopupMenuActionSearchCopiedImage: {
       RecordAction(UserMetricsAction("MobileMenuSearchCopiedImage"));
-      ClipboardRecentContent* clipboardRecentContent =
-          ClipboardRecentContent::GetInstance();
-      clipboardRecentContent->GetRecentImageFromClipboard(
-          base::BindOnce(^(absl::optional<gfx::Image> image) {
-            // Sometimes, the image can be nil even though the clipboard said it
-            // had an image. This most likely a UIKit issue, but practice
-            // defensive coding.
-            if (!image) {
-              return;
-            }
-            [self.dispatcher searchByImage:[image.value().ToUIImage() copy]];
-          }));
+      [self.delegate searchCopiedImage];
       break;
     }
     case PopupMenuActionSearchCopiedText: {
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler_delegate.h b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler_delegate.h
index 7258561a..0607b39 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler_delegate.h
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler_delegate.h
@@ -20,6 +20,8 @@
 - (void)recordSettingsMetricsPerProfile;
 // Records open downloads metric per profile type.
 - (void)recordDownloadsMetricsPerProfile;
+// Starts a reverse image search for the image currently in the pasteboard.
+- (void)searchCopiedImage;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_POPUP_MENU_POPUP_MENU_ACTION_HANDLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
index 2831993..be1cca41 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
@@ -31,6 +31,7 @@
 #import "ios/chrome/browser/ui/popup_menu/public/popup_menu_table_view_controller.h"
 #import "ios/chrome/browser/ui/presenters/contained_presenter_delegate.h"
 #import "ios/chrome/browser/ui/util/layout_guide_names.h"
+#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/web/web_navigation_browser_agent.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -250,6 +251,8 @@
   OverlayPresenter* overlayPresenter = OverlayPresenter::FromBrowser(
       self.browser, OverlayModality::kWebContentArea);
   self.mediator.webContentAreaOverlayPresenter = overlayPresenter;
+  self.mediator.URLLoadingBrowserAgent =
+      UrlLoadingBrowserAgent::FromBrowser(self.browser);
 
   self.contentBlockerMediator = [[BrowserContainerMediator alloc]
                 initWithWebStateList:self.browser->GetWebStateList()
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h
index 3c6c232..82b55989 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h
@@ -23,6 +23,7 @@
 class PrefService;
 class ReadingListModel;
 class TemplateURLService;
+class UrlLoadingBrowserAgent;
 class WebStateList;
 class BrowserPolicyConnectorIOS;
 
@@ -65,6 +66,8 @@
 // The template url service to use for checking whether search by image is
 // available.
 @property(nonatomic, assign) TemplateURLService* templateURLService;
+// The URL loading service, used to load the reverse image search.
+@property(nonatomic, assign) UrlLoadingBrowserAgent* URLLoadingBrowserAgent;
 
 // Disconnect the mediator.
 - (void)disconnect;
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
index 0b5bca2..b633ab9 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -36,6 +36,7 @@
 #include "ios/chrome/browser/policy/policy_features.h"
 #import "ios/chrome/browser/policy/policy_util.h"
 #import "ios/chrome/browser/search_engines/search_engines_util.h"
+#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #import "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/browser/ui/activity_services/canonical_url_retriever.h"
 #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
@@ -53,6 +54,9 @@
 #import "ios/chrome/browser/ui/reading_list/reading_list_menu_notifier.h"
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/browser/url_loading/image_search_param_generator.h"
+#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
+#import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/web/font_size/font_size_tab_helper.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
@@ -582,6 +586,24 @@
                                 type);
 }
 
+- (void)searchCopiedImage {
+  ClipboardRecentContent* clipboardRecentContent =
+      ClipboardRecentContent::GetInstance();
+  clipboardRecentContent->GetRecentImageFromClipboard(
+      base::BindOnce(^(absl::optional<gfx::Image> optionalImage) {
+        if (!optionalImage) {
+          return;
+        }
+        UIImage* image = [optionalImage.value().ToUIImage() copy];
+        web::NavigationManager::WebLoadParams webParams =
+            ImageSearchParamGenerator::LoadParamsForImage(
+                image, self.templateURLService);
+        UrlLoadParams params = UrlLoadParams::InCurrentTab(webParams);
+
+        self.URLLoadingBrowserAgent->Load(params);
+      }));
+}
+
 #pragma mark - IOSLanguageDetectionTabHelperObserving
 
 - (void)iOSLanguageDetectionTabHelper:
diff --git a/ios/chrome/browser/ui/safe_mode/safe_mode_egtest.mm b/ios/chrome/browser/ui/safe_mode/safe_mode_egtest.mm
index 0581204..4bc18fe 100644
--- a/ios/chrome/browser/ui/safe_mode/safe_mode_egtest.mm
+++ b/ios/chrome/browser/ui/safe_mode/safe_mode_egtest.mm
@@ -66,7 +66,6 @@
 - (void)testSafeModeSendingCrashReport {
   // Mocks the +hasReportToUpload method by swizzling to return positively that
   // there are crash reports to upload.
-  // TODO(crbug.com/1015272): Consider moving from swizzling to a delegate.
   EarlGreyScopedBlockSwizzler hasReport(@"SafeModeViewController",
                                         @"hasReportToUpload", ^{
                                           return YES;
@@ -87,7 +86,6 @@
 - (void)testSafeModeDetectedThirdPartyMods {
   // Mocks the +detectedThirdPartyMods method by swizzling to return positively
   // that device appears to be jailbroken and contains third party mods.
-  // TODO(crbug.com/1015272): Consider moving from swizzling to a delegate.
   EarlGreyScopedBlockSwizzler thirdParty(@"SafeModeViewController",
                                          @"detectedThirdPartyMods", ^{
                                            return YES;
@@ -114,7 +112,6 @@
 - (void)testSafeModeBothThirdPartyModsAndHasReport {
   // Mocks the +detectedThirdPartyMods method by swizzling to return positively
   // that device appears to be jailbroken and contains third party mods.
-  // TODO(crbug.com/1015272): Consider moving from swizzling to a delegate.
   EarlGreyScopedBlockSwizzler thirdParty(@"SafeModeViewController",
                                          @"detectedThirdPartyMods", ^{
                                            return YES;
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm
index df681421..6d6e972 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm
@@ -28,7 +28,7 @@
       : web::WebStatePolicyDecider(web_state) {}
 
   void ShouldAllowRequest(NSURLRequest* request,
-                          const RequestInfo& request_info,
+                          RequestInfo request_info,
                           PolicyDecisionCallback callback) override {
     std::move(callback).Run(PolicyDecision::Cancel());
   }
diff --git a/ios/chrome/browser/url_loading/image_search_param_generator.h b/ios/chrome/browser/url_loading/image_search_param_generator.h
index 945264d..75e982ea 100644
--- a/ios/chrome/browser/url_loading/image_search_param_generator.h
+++ b/ios/chrome/browser/url_loading/image_search_param_generator.h
@@ -15,17 +15,16 @@
 class ImageSearchParamGenerator {
  public:
   // Create loading parameters using the given |data|, which should represent
-  // an image.
+  // an image and |url|, the web url the image came from. If the image data
+  // didn't come from a url, use an empty GURL to indicate that.
   static web::NavigationManager::WebLoadParams LoadParamsForImageData(
       NSData* data,
+      const GURL& url,
       TemplateURLService* template_url_service);
 
-  // Create loading parameters using the given |image| and |url|, the web url
-  // the image came from. If the image data didn't come from a url, use an empty
-  // GURL to indicate that.
+  // Create loading parameters using the given |image|.
   static web::NavigationManager::WebLoadParams LoadParamsForImage(
       UIImage* image,
-      const GURL& url,
       TemplateURLService* template_url_service);
 
  private:
diff --git a/ios/chrome/browser/url_loading/image_search_param_generator.mm b/ios/chrome/browser/url_loading/image_search_param_generator.mm
index 2f86484..4f97c4cc 100644
--- a/ios/chrome/browser/url_loading/image_search_param_generator.mm
+++ b/ios/chrome/browser/url_loading/image_search_param_generator.mm
@@ -16,6 +16,7 @@
 web::NavigationManager::WebLoadParams
 ImageSearchParamGenerator::LoadParamsForImageData(
     NSData* data,
+    const GURL& url,
     TemplateURLService* template_url_service) {
   NSData* image_data = data;
   UIImage* image = [UIImage imageWithData:image_data];
@@ -24,8 +25,7 @@
   // we still want to do the image search with nil data because that gives
   // the user the best error experience.
   if (gfx_image.IsEmpty()) {
-    return LoadParamsForResizedImageData(image_data, GURL(),
-                                         template_url_service);
+    return LoadParamsForResizedImageData(image_data, url, template_url_service);
   }
   UIImage* resized_image =
       gfx::ResizedImageForSearchByImage(gfx_image).ToUIImage();
@@ -33,26 +33,24 @@
     image_data = UIImageJPEGRepresentation(resized_image, 1.0);
   }
 
-  return LoadParamsForResizedImageData(image_data, GURL(),
-                                       template_url_service);
+  return LoadParamsForResizedImageData(image_data, url, template_url_service);
 }
 
 web::NavigationManager::WebLoadParams
 ImageSearchParamGenerator::LoadParamsForImage(
     UIImage* image,
-    const GURL& url,
     TemplateURLService* template_url_service) {
   gfx::Image gfx_image(image);
   // Converting to gfx::Image creates an empty image if UIImage is nil. However,
   // we still want to do the image search with nil data because that gives
   // the user the best error experience.
   if (gfx_image.IsEmpty()) {
-    return LoadParamsForResizedImageData(nil, url, template_url_service);
+    return LoadParamsForResizedImageData(nil, GURL(), template_url_service);
   }
   UIImage* resized_image =
       gfx::ResizedImageForSearchByImage(gfx_image).ToUIImage();
   NSData* data = UIImageJPEGRepresentation(resized_image, 1.0);
-  return LoadParamsForResizedImageData(data, url, template_url_service);
+  return LoadParamsForResizedImageData(data, GURL(), template_url_service);
 }
 
 // This method does all the work of constructing the parameters. Internally,
diff --git a/ios/chrome/browser/url_loading/image_search_param_generator_unittest.mm b/ios/chrome/browser/url_loading/image_search_param_generator_unittest.mm
index 9ed4708e..8381864 100644
--- a/ios/chrome/browser/url_loading/image_search_param_generator_unittest.mm
+++ b/ios/chrome/browser/url_loading/image_search_param_generator_unittest.mm
@@ -38,7 +38,7 @@
       ios::TemplateURLServiceFactory::GetForBrowserState(
           chrome_browser_state_.get());
   web::NavigationManager::WebLoadParams load_params =
-      ImageSearchParamGenerator::LoadParamsForImageData(nil,
+      ImageSearchParamGenerator::LoadParamsForImageData(nil, GURL(),
                                                         template_url_service);
   ASSERT_EQ(load_params.url,
             GURL("https://www.google.com/searchbyimage/upload"));
diff --git a/ios/chrome/browser/web/invalid_url_tab_helper.h b/ios/chrome/browser/web/invalid_url_tab_helper.h
index 8f4e822..d8a5b8444 100644
--- a/ios/chrome/browser/web/invalid_url_tab_helper.h
+++ b/ios/chrome/browser/web/invalid_url_tab_helper.h
@@ -25,7 +25,7 @@
   explicit InvalidUrlTabHelper(web::WebState* web_state);
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const web::WebStatePolicyDecider::RequestInfo& request_info,
+      web::WebStatePolicyDecider::RequestInfo request_info,
       web::WebStatePolicyDecider::PolicyDecisionCallback callback) override;
 
   friend class web::WebStateUserData<InvalidUrlTabHelper>;
diff --git a/ios/chrome/browser/web/invalid_url_tab_helper.mm b/ios/chrome/browser/web/invalid_url_tab_helper.mm
index 2d2d6c9..ab2b7f82 100644
--- a/ios/chrome/browser/web/invalid_url_tab_helper.mm
+++ b/ios/chrome/browser/web/invalid_url_tab_helper.mm
@@ -49,7 +49,7 @@
 
 void InvalidUrlTabHelper::ShouldAllowRequest(
     NSURLRequest* request,
-    const web::WebStatePolicyDecider::RequestInfo& request_info,
+    web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
   if (IsUrlRequestValid(request)) {
     return std::move(callback).Run(PolicyDecision::Allow());
diff --git a/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm b/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm
index 6b5b15e..80073be 100644
--- a/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm
+++ b/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm
@@ -30,7 +30,7 @@
       ui::PageTransition transition) {
     NSURL* url = [NSURL URLWithString:spec];
     NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url];
-    web::WebStatePolicyDecider::RequestInfo info(
+    const web::WebStatePolicyDecider::RequestInfo info(
         transition,
         /*target_frame_is_main=*/true,
         /*target_frame_is_cross_origin=*/false,
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 dcff6dc9..fa054a6 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 @@
-f557829398b13a521864133870ebc1002aa07aac
\ No newline at end of file
+264db6b195bf828db7d80ac70f391506de105dac
\ 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 00a5a636..c95954c6 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 @@
-223ec94e216a33da1200791037bf5ff8de57f76d
\ No newline at end of file
+00512236b065b4db93e8f0b3c3973970c43a8dd2
\ 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 fbffbc5..cc2f611 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 @@
-998c5281cc3dc2c6ace696b2084b845817399e01
\ No newline at end of file
+bd3398ce9f0a311a0f7153e4c5ff8598dbe0834e
\ 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 81074e6..eeb3b12 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 @@
-1bd443a00daeda794da3878ee9941090edd3b670
\ No newline at end of file
+373f77272f2796ef42b4d4f60bbb47ff4f62bd0d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index 9f90cc0..d3e7aa0 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-1010b0fae6decf3141eec33b833c800778a3c08a
\ No newline at end of file
+74e8741462a5676bb22e8965079cc818eb4de35e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 63d61df..305abf9 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-343aaf20da235fc0293a0d567f4da70c454fdfe8
\ No newline at end of file
+8baa216aabdc2d34944eafe5518c3076dbab3639
\ 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 06659bd..7c9ae6a87 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 @@
-3fa2f16ca598785ec3aef452ff89f6410b047cb0
\ No newline at end of file
+deb4311113bd83f1fc41c43d9175da42dfba3bfd
\ 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 6d6329c4..ed8b0eb 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 @@
-3f32bde0a12a7f906956da9b10b2fc5e5ea40315
\ No newline at end of file
+93b5dde4d75fe73511e0ded6683c7c1fb61d4f44
\ 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 a3e1380..326a35f 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 @@
-13d17f4a8c877f2c4f28f7239117f2c6fba45ec5
\ No newline at end of file
+8dd32b949519e14bb41e08c27a349111974216b1
\ 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 a9adea7a..1710ede 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 @@
-42799392161914a46739e29e3952a8661cb3c0be
\ No newline at end of file
+4a71a48f7bf98b6e5e09a2a062314744fb3d283f
\ No newline at end of file
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 06ae269..100b11e 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -402,6 +402,7 @@
     "//ios/web/web_state",
     "//ios/web/web_state:page_viewport_state",
     "//ios/web/web_state:policy_decision_state_tracker",
+    "//ios/web/web_state:test_util",
     "//ios/web/web_state:web_view_internal_creation_util",
     "//net:test_support",
     "//testing/gmock",
@@ -580,6 +581,7 @@
     "//ios/web/test:test_constants",
     "//ios/web/test:test_support",
     "//ios/web/web_state",
+    "//ios/web/web_state:test_util",
     "//ios/web/web_state/ui:crw_context_menu_controller",
     "//mojo/core/embedder",
     "//net:test_support",
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index bf9bf3a..634adc8 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -436,7 +436,7 @@
         web::GURLOriginWithWKSecurityOrigin(action.targetFrame.securityOrigin));
     isCrossOriginTargetFrame = !sourceOrigin.IsSameOriginWith(targetOrigin);
   }
-  web::WebStatePolicyDecider::RequestInfo requestInfo(
+  const web::WebStatePolicyDecider::RequestInfo requestInfo(
       transition, isMainFrameNavigationAction, isCrossOriginTargetFrame,
       userInteractedWithRequestMainFrame);
 
diff --git a/ios/web/public/navigation/web_state_policy_decider.h b/ios/web/public/navigation/web_state_policy_decider.h
index 1125318..07d37d5 100644
--- a/ios/web/public/navigation/web_state_policy_decider.h
+++ b/ios/web/public/navigation/web_state_policy_decider.h
@@ -111,7 +111,7 @@
   // |callback| with the decision. Never called in the following cases:
   //  - same-document back-forward and state change navigations
   virtual void ShouldAllowRequest(NSURLRequest* request,
-                                  const RequestInfo& request_info,
+                                  RequestInfo request_info,
                                   PolicyDecisionCallback callback);
 
   // Asks the decider whether the navigation corresponding to |response| should
diff --git a/ios/web/public/navigation/web_state_policy_decider_bridge.h b/ios/web/public/navigation/web_state_policy_decider_bridge.h
index 358a7fd..e124a32 100644
--- a/ios/web/public/navigation/web_state_policy_decider_bridge.h
+++ b/ios/web/public/navigation/web_state_policy_decider_bridge.h
@@ -18,8 +18,7 @@
 
 // Invoked by |WebStatePolicyDeciderBridge::ShouldAllowRequest|.
 - (void)shouldAllowRequest:(NSURLRequest*)request
-               requestInfo:
-                   (const web::WebStatePolicyDecider::RequestInfo&)requestInfo
+               requestInfo:(web::WebStatePolicyDecider::RequestInfo)requestInfo
            decisionHandler:(PolicyDecisionHandler)decisionHandler;
 
 // Invoked by |WebStatePolicyDeciderBridge::ShouldAllowRequest|.
@@ -50,7 +49,7 @@
 
   // web::WebStatePolicyDecider methods.
   void ShouldAllowRequest(NSURLRequest* request,
-                          const RequestInfo& request_info,
+                          RequestInfo request_info,
                           PolicyDecisionCallback callback) override;
 
   void ShouldAllowResponse(NSURLResponse* response,
diff --git a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h
index 65037695..5c9c82b 100644
--- a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h
+++ b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.h
@@ -18,7 +18,8 @@
 
 // Arguments passed to |shouldAllowRequest:requestInfo:|.
 struct FakeShouldAllowRequestInfo {
-  FakeShouldAllowRequestInfo();
+  FakeShouldAllowRequestInfo(NSURLRequest* request,
+                             WebStatePolicyDecider::RequestInfo request_info);
   ~FakeShouldAllowRequestInfo();
   NSURLRequest* request = nil;
   WebStatePolicyDecider::RequestInfo request_info;
@@ -27,6 +28,9 @@
 // Arguments passed to
 // |decidePolicyForNavigationResponse:forMainFrame:completionHandler:|.
 struct FakeDecidePolicyForNavigationResponseInfo {
+  FakeDecidePolicyForNavigationResponseInfo(NSURLResponse* response,
+                                            BOOL for_main_frame);
+  ~FakeDecidePolicyForNavigationResponseInfo();
   NSURLResponse* response = nil;
   BOOL for_main_frame = NO;
 };
@@ -37,11 +41,12 @@
 @interface CRWFakeWebStatePolicyDecider : NSObject<CRWWebStatePolicyDecider>
 // Arguments passed to |shouldAllowRequest:requestInfo:|.
 @property(nonatomic, readonly)
-    web::FakeShouldAllowRequestInfo* shouldAllowRequestInfo;
+    const web::FakeShouldAllowRequestInfo* shouldAllowRequestInfo;
 // Arguments passed to
 // |decidePolicyForNavigationResponse:forMainFrame:completionHandler:|.
-@property(nonatomic, readonly) web::FakeDecidePolicyForNavigationResponseInfo*
-    decidePolicyForNavigationResponseInfo;
+@property(nonatomic, readonly)
+    const web::FakeDecidePolicyForNavigationResponseInfo*
+        decidePolicyForNavigationResponseInfo;
 
 @end
 
diff --git a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm
index ad568b3..7fd912f7 100644
--- a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm
+++ b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm
@@ -12,13 +12,21 @@
 
 namespace web {
 
-FakeShouldAllowRequestInfo::FakeShouldAllowRequestInfo()
-    : request_info(ui::PageTransition::PAGE_TRANSITION_FIRST,
-                   /*target_frame_is_main=*/false,
-                   /*target_frame_is_cross_origin=*/false,
-                   /*has_user_gesture=*/false) {}
+FakeShouldAllowRequestInfo::FakeShouldAllowRequestInfo(
+    NSURLRequest* request,
+    WebStatePolicyDecider::RequestInfo request_info)
+    : request(request), request_info(request_info) {}
+
 FakeShouldAllowRequestInfo::~FakeShouldAllowRequestInfo() = default;
 
+FakeDecidePolicyForNavigationResponseInfo::
+    FakeDecidePolicyForNavigationResponseInfo(NSURLResponse* response,
+                                              BOOL for_main_frame)
+    : response(response), for_main_frame(for_main_frame) {}
+
+FakeDecidePolicyForNavigationResponseInfo::
+    ~FakeDecidePolicyForNavigationResponseInfo() = default;
+
 }  // namespace web
 
 @implementation CRWFakeWebStatePolicyDecider {
@@ -30,11 +38,11 @@
       _decidePolicyForNavigationResponseInfo;
 }
 
-- (web::FakeShouldAllowRequestInfo*)shouldAllowRequestInfo {
+- (const web::FakeShouldAllowRequestInfo*)shouldAllowRequestInfo {
   return _shouldAllowRequestInfo.get();
 }
 
-- (web::FakeDecidePolicyForNavigationResponseInfo*)
+- (const web::FakeDecidePolicyForNavigationResponseInfo*)
     decidePolicyForNavigationResponseInfo {
   return _decidePolicyForNavigationResponseInfo.get();
 }
@@ -42,12 +50,10 @@
 #pragma mark CRWWebStatePolicyDecider methods -
 
 - (void)shouldAllowRequest:(NSURLRequest*)request
-               requestInfo:
-                   (const web::WebStatePolicyDecider::RequestInfo&)requestInfo
+               requestInfo:(web::WebStatePolicyDecider::RequestInfo)requestInfo
            decisionHandler:(PolicyDecisionHandler)decisionHandler {
-  _shouldAllowRequestInfo = std::make_unique<web::FakeShouldAllowRequestInfo>();
-  _shouldAllowRequestInfo->request = request;
-  _shouldAllowRequestInfo->request_info = requestInfo;
+  _shouldAllowRequestInfo =
+      std::make_unique<web::FakeShouldAllowRequestInfo>(request, requestInfo);
   decisionHandler(web::WebStatePolicyDecider::PolicyDecision::Allow());
 }
 
@@ -56,9 +62,8 @@
                           decisionHandler:
                               (PolicyDecisionHandler)decisionHandler {
   _decidePolicyForNavigationResponseInfo =
-      std::make_unique<web::FakeDecidePolicyForNavigationResponseInfo>();
-  _decidePolicyForNavigationResponseInfo->response = response;
-  _decidePolicyForNavigationResponseInfo->for_main_frame = forMainFrame;
+      std::make_unique<web::FakeDecidePolicyForNavigationResponseInfo>(
+          response, forMainFrame);
   decisionHandler(web::WebStatePolicyDecider::PolicyDecision::Allow());
 }
 
diff --git a/ios/web/public/test/fakes/fake_web_state.h b/ios/web/public/test/fakes/fake_web_state.h
index ff1b3baa..e88081d 100644
--- a/ios/web/public/test/fakes/fake_web_state.h
+++ b/ios/web/public/test/fakes/fake_web_state.h
@@ -124,7 +124,7 @@
   // to PolicyDecision::Allow().
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const WebStatePolicyDecider::RequestInfo& request_info,
+      WebStatePolicyDecider::RequestInfo request_info,
       WebStatePolicyDecider::PolicyDecisionCallback callback);
   // Uses |policy_deciders| to determine whether the navigation corresponding to
   // |response| should be allowed. Calls |callback| with the decision. Defaults
diff --git a/ios/web/public/test/fakes/fake_web_state.mm b/ios/web/public/test/fakes/fake_web_state.mm
index ee00f3c..e438790 100644
--- a/ios/web/public/test/fakes/fake_web_state.mm
+++ b/ios/web/public/test/fakes/fake_web_state.mm
@@ -357,7 +357,7 @@
 
 void FakeWebState::ShouldAllowRequest(
     NSURLRequest* request,
-    const WebStatePolicyDecider::RequestInfo& request_info,
+    WebStatePolicyDecider::RequestInfo request_info,
     WebStatePolicyDecider::PolicyDecisionCallback callback) {
   auto request_state_tracker =
       std::make_unique<PolicyDecisionStateTracker>(std::move(callback));
diff --git a/ios/web/public/test/fakes/fake_web_state_policy_decider.h b/ios/web/public/test/fakes/fake_web_state_policy_decider.h
index 4df20d1..654c001 100644
--- a/ios/web/public/test/fakes/fake_web_state_policy_decider.h
+++ b/ios/web/public/test/fakes/fake_web_state_policy_decider.h
@@ -26,7 +26,7 @@
   // WebStatePolicyDecider overrides
   // Always calls |callback| with PolicyDecision::Allow().
   void ShouldAllowRequest(NSURLRequest* request,
-                          const RequestInfo& request_info,
+                          RequestInfo request_info,
                           PolicyDecisionCallback callback) override;
   // Always calls |callback| with PolicyDecision::Allow().
   void ShouldAllowResponse(NSURLResponse* response,
diff --git a/ios/web/public/test/fakes/fake_web_state_policy_decider.mm b/ios/web/public/test/fakes/fake_web_state_policy_decider.mm
index 3df6b75..271c8f05 100644
--- a/ios/web/public/test/fakes/fake_web_state_policy_decider.mm
+++ b/ios/web/public/test/fakes/fake_web_state_policy_decider.mm
@@ -20,7 +20,7 @@
 
 void FakeWebStatePolicyDecider::ShouldAllowRequest(
     NSURLRequest* request,
-    const RequestInfo& request_info,
+    RequestInfo request_info,
     PolicyDecisionCallback callback) {
   std::move(callback).Run(should_allow_request_);
 }
diff --git a/ios/web/web_state/BUILD.gn b/ios/web/web_state/BUILD.gn
index 6d4bc68..f901d331 100644
--- a/ios/web/web_state/BUILD.gn
+++ b/ios/web/web_state/BUILD.gn
@@ -125,3 +125,16 @@
 
   configs += [ "//build/config/compiler:enable_arc" ]
 }
+
+source_set("test_util") {
+  testonly = true
+
+  sources = [
+    "web_state_policy_decider_test_util.h",
+    "web_state_policy_decider_test_util.mm",
+  ]
+
+  deps = [ "//ios/web/public/navigation" ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm
index ebbdfbd..62591aab 100644
--- a/ios/web/web_state/error_page_inttest.mm
+++ b/ios/web/web_state/error_page_inttest.mm
@@ -93,7 +93,7 @@
 
   // WebStatePolicyDecider overrides
   void ShouldAllowRequest(NSURLRequest* request,
-                          const RequestInfo& request_info,
+                          RequestInfo request_info,
                           PolicyDecisionCallback callback) override {
     PolicyDecision decision = PolicyDecision::Allow();
     GURL URL = net::GURLWithNSURL(request.URL);
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 3c335d3e..4bae3da2 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -973,7 +973,7 @@
 
     // WebStatePolicyDecider overrides
     void ShouldAllowRequest(NSURLRequest* request,
-                            const RequestInfo& request_info,
+                            RequestInfo request_info,
                             PolicyDecisionCallback callback) override {
       test_fixture->DestroyWebState();
       std::move(callback).Run(PolicyDecision::Allow());
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index 0de3e46b..8a062ee 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -147,7 +147,7 @@
   // the first PolicyDecision::CancelAndDisplayError() result that was received.
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const WebStatePolicyDecider::RequestInfo& request_info,
+      WebStatePolicyDecider::RequestInfo request_info,
       WebStatePolicyDecider::PolicyDecisionCallback callback);
 
   // Decides whether the navigation corresponding to |response| should
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index f023aaa..4efbda9 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -465,7 +465,7 @@
 
 void WebStateImpl::ShouldAllowRequest(
     NSURLRequest* request,
-    const WebStatePolicyDecider::RequestInfo& request_info,
+    WebStatePolicyDecider::RequestInfo request_info,
     WebStatePolicyDecider::PolicyDecisionCallback callback) {
   auto request_state_tracker =
       std::make_unique<PolicyDecisionStateTracker>(std::move(callback));
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm
index 7c3b8674..a47be5f 100644
--- a/ios/web/web_state/web_state_impl_unittest.mm
+++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -43,6 +43,7 @@
 #include "ios/web/public/web_state_observer.h"
 #import "ios/web/web_state/global_web_state_event_tracker.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
+#include "ios/web/web_state/web_state_policy_decider_test_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -121,7 +122,7 @@
 
   MOCK_METHOD3(ShouldAllowRequest,
                void(NSURLRequest* request,
-                    const WebStatePolicyDecider::RequestInfo& request_info,
+                    WebStatePolicyDecider::RequestInfo request_info,
                     WebStatePolicyDecider::PolicyDecisionCallback callback));
 
   MOCK_METHOD2(ShouldAllowErrorPageToBeDisplayed,
@@ -537,11 +538,7 @@
 // This is needed because WebStatePolicyDecider::RequestInfo doesn't support
 // operator==.
 MATCHER_P(RequestInfoMatch, expected_request_info, /* argument_name = */ "") {
-  return ui::PageTransitionTypeIncludingQualifiersIs(
-             arg.transition_type, expected_request_info.transition_type) &&
-         arg.target_frame_is_main ==
-             expected_request_info.target_frame_is_main &&
-         arg.has_user_gesture == expected_request_info.has_user_gesture;
+  return ::web::RequestInfoMatch(expected_request_info, arg);
 }
 
 // Verifies that policy deciders are correctly called by the web state.
@@ -558,7 +555,7 @@
                                               textEncodingName:nil];
 
   // Test that ShouldAllowRequest() is called for the same parameters.
-  WebStatePolicyDecider::RequestInfo request_info_main_frame(
+  const WebStatePolicyDecider::RequestInfo request_info_main_frame(
       ui::PageTransition::PAGE_TRANSITION_LINK,
       /*target_main_frame=*/true,
       /*target_frame_is_cross_origin=*/false,
@@ -588,7 +585,7 @@
   EXPECT_TRUE(policy_decision.ShouldAllowNavigation());
   EXPECT_FALSE(policy_decision.ShouldCancelNavigation());
 
-  WebStatePolicyDecider::RequestInfo request_info_iframe(
+  const WebStatePolicyDecider::RequestInfo request_info_iframe(
       ui::PageTransition::PAGE_TRANSITION_LINK,
       /*target_main_frame=*/false,
       /*target_frame_is_cross_origin=*/false,
@@ -668,7 +665,7 @@
                    expectedContentLength:0
                         textEncodingName:nil];
 
-  WebStatePolicyDecider::RequestInfo error_request_info_main_frame(
+  const WebStatePolicyDecider::RequestInfo error_request_info_main_frame(
       ui::PageTransition::PAGE_TRANSITION_LINK,
       /*target_main_frame=*/true,
       /*target_frame_is_cross_origin=*/false,
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm
index efcab240..cacf300 100644
--- a/ios/web/web_state/web_state_observer_inttest.mm
+++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -41,6 +41,7 @@
 #import "ios/web/test/web_int_test.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #import "ios/web/web_state/web_state_impl.h"
+#include "ios/web/web_state/web_state_policy_decider_test_util.h"
 #import "net/base/mac/url_conversions.h"
 #import "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
@@ -703,28 +704,11 @@
   EXPECT_EQ(url, item->GetURL());
 }
 
-// A Google Mock matcher which matches |target_frame_is_main| member of
-// WebStatePolicyDecider::RequestInfo. This is needed because
-// WebStatePolicyDecider::RequestInfo doesn't support operator==.
+// A Google Mock matcher which matches WebStatePolicyDecider::RequestInfo.
+// This is needed because WebStatePolicyDecider::RequestInfo doesn't
+// support operator==.
 MATCHER_P(RequestInfoMatch, expected_request_info, /*description=*/"") {
-  bool transition_type_match = ui::PageTransitionTypeIncludingQualifiersIs(
-      arg.transition_type, expected_request_info.transition_type);
-  EXPECT_TRUE(transition_type_match)
-      << "expected transition type: "
-      << PageTransitionGetCoreTransitionString(
-             expected_request_info.transition_type)
-      << " actual transition type: "
-      << PageTransitionGetCoreTransitionString(arg.transition_type);
-  EXPECT_EQ(expected_request_info.target_frame_is_main,
-            arg.target_frame_is_main);
-  EXPECT_EQ(expected_request_info.target_frame_is_cross_origin,
-            arg.target_frame_is_cross_origin);
-  EXPECT_EQ(expected_request_info.has_user_gesture, arg.has_user_gesture);
-
-  return transition_type_match &&
-         arg.target_frame_is_main ==
-             expected_request_info.target_frame_is_main &&
-         arg.has_user_gesture == expected_request_info.has_user_gesture;
+  return ::web::RequestInfoMatch(expected_request_info, arg);
 }
 
 // A GMock matcher that matches |URL| member of |arg| with |expected_url|. |arg|
@@ -777,13 +761,13 @@
 
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const WebStatePolicyDecider::RequestInfo& request_info,
+      WebStatePolicyDecider::RequestInfo request_info,
       WebStatePolicyDecider::PolicyDecisionCallback callback) override {
     MockShouldAllowRequest(request, request_info, callback);
   }
   MOCK_METHOD3(MockShouldAllowRequest,
                void(NSURLRequest*,
-                    const WebStatePolicyDecider::RequestInfo& request_info,
+                    WebStatePolicyDecider::RequestInfo request_info,
                     WebStatePolicyDecider::PolicyDecisionCallback& callback));
   MOCK_METHOD3(ShouldAllowResponse,
                void(NSURLResponse*,
@@ -871,7 +855,7 @@
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()))
       .InSequence(callbacks_sequence);
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -923,7 +907,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -968,7 +952,7 @@
   EXPECT_CALL(observer_, DidStopLoading(web_state()));
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
 
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1038,7 +1022,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1074,7 +1058,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1127,7 +1111,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1173,7 +1157,7 @@
 
   if (@available(iOS 13, *)) {
     // Starting from iOS 13 WebKit, does not rewrite URL.
-    WebStatePolicyDecider::RequestInfo expected_request_info(
+    const WebStatePolicyDecider::RequestInfo expected_request_info(
         ui::PageTransition::PAGE_TRANSITION_TYPED,
         /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
         /*has_user_gesture=*/false);
@@ -1208,7 +1192,7 @@
     webkit_rewritten_url_spec.replace(url.spec().size() - kBadSuffix.size(),
                                       kBadSuffix.size(), ";/");
 
-    WebStatePolicyDecider::RequestInfo expected_request_info(
+    const WebStatePolicyDecider::RequestInfo expected_request_info(
         // Can't match NavigationContext and determine navigation type prior to
         // iOS 13, because context is matched by URL, which is rewritten by
         // WebKit.
@@ -1253,7 +1237,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1297,7 +1281,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1340,7 +1324,7 @@
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
   // ShouldAllowRequest is called to give embedder a chance to handle
   // this unsupported URL scheme.
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1363,7 +1347,7 @@
 
   // Perform new page navigation.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1385,7 +1369,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo reload_request_info(
+  const WebStatePolicyDecider::RequestInfo reload_request_info(
       ui::PageTransition::PAGE_TRANSITION_RELOAD,
       /*target_main_frame=*/true,
       /*target_frame_is_cross_origin=*/false,
@@ -1419,7 +1403,7 @@
 
   // Perform new page navigation.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1441,7 +1425,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_reload_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_reload_request_info(
       ui::PageTransition::PAGE_TRANSITION_RELOAD,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1476,7 +1460,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1502,7 +1486,7 @@
 
   // Perform same-document navigation.
   const GURL hash_url = test_server_->GetURL("/echoall#1");
-  WebStatePolicyDecider::RequestInfo hash_url_expected_request_info(
+  const WebStatePolicyDecider::RequestInfo hash_url_expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1571,7 +1555,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1597,7 +1581,7 @@
 
   // Perform same-page navigation using JavaScript.
   const GURL hash_url = test_server_->GetURL("/echoall#1");
-  WebStatePolicyDecider::RequestInfo expected_hash_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_hash_request_info(
       ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1633,7 +1617,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1701,7 +1685,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_GENERATED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1740,7 +1724,7 @@
 
   // Perform new page navigation.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1763,7 +1747,7 @@
   // Submit the form using JavaScript.
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
-  WebStatePolicyDecider::RequestInfo form_request_info(
+  const WebStatePolicyDecider::RequestInfo form_request_info(
       ui::PageTransition::PAGE_TRANSITION_FORM_SUBMIT,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1800,7 +1784,7 @@
 
   // Perform new page navigation.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1821,7 +1805,7 @@
       WaitForWebViewContainingText(web_state(), ::testing::kTestFormPage));
 
   // Submit the form using JavaScript.
-  WebStatePolicyDecider::RequestInfo form_request_info(
+  const WebStatePolicyDecider::RequestInfo form_request_info(
       ui::PageTransition::PAGE_TRANSITION_FORM_SUBMIT,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1849,7 +1833,7 @@
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
 
-  WebStatePolicyDecider::RequestInfo form_reload_request_info(
+  const WebStatePolicyDecider::RequestInfo form_reload_request_info(
       ui::PageTransition::PAGE_TRANSITION_RELOAD,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1890,7 +1874,7 @@
 
   // Perform new page navigation.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1911,7 +1895,7 @@
       WaitForWebViewContainingText(web_state(), ::testing::kTestFormPage));
 
   // Submit the form using JavaScript.
-  WebStatePolicyDecider::RequestInfo form_request_info(
+  const WebStatePolicyDecider::RequestInfo form_request_info(
       ui::PageTransition::PAGE_TRANSITION_FORM_SUBMIT,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -1935,7 +1919,7 @@
                                            ::testing::kTestFormFieldValue));
 
   // Go Back.
-  WebStatePolicyDecider::RequestInfo back_request_info(
+  const WebStatePolicyDecider::RequestInfo back_request_info(
       static_cast<ui::PageTransition>(
           ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK |
           ui::PageTransition::PAGE_TRANSITION_TYPED),
@@ -1958,7 +1942,7 @@
   }));
 
   // Go forward.
-  WebStatePolicyDecider::RequestInfo forward_request_info(
+  const WebStatePolicyDecider::RequestInfo forward_request_info(
       static_cast<ui::PageTransition>(
           ui::PageTransition::PAGE_TRANSITION_FORM_SUBMIT |
           ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK),
@@ -2011,7 +1995,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2025,7 +2009,7 @@
           &nav_id));
 
   // 5 calls on ShouldAllowRequest and DidRedirectNavigation for redirections.
-  WebStatePolicyDecider::RequestInfo expected_redirect_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_redirect_request_info(
       ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2081,7 +2065,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2113,7 +2097,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2159,7 +2143,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo request_info(
+  const WebStatePolicyDecider::RequestInfo request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2190,7 +2174,7 @@
 // stop, but no other callbacks are called.
 TEST_F(WebStateObserverTest, DisallowRequest) {
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2211,7 +2195,7 @@
 TEST_F(WebStateObserverTest, DisallowRequestAndShowError) {
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
 
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2250,7 +2234,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2294,7 +2278,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2328,7 +2312,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2365,7 +2349,7 @@
 TEST_F(WebStateObserverTest, ImmediatelyStopNavigation) {
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
   EXPECT_CALL(observer_, DidStopLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2396,7 +2380,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2429,7 +2413,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2487,7 +2471,7 @@
 
   // Callbacks due to loading of the main frame.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2502,7 +2486,7 @@
   EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
 
   // Callbacks due to initial loading of iframe.
-  WebStatePolicyDecider::RequestInfo iframe_request_info(
+  const WebStatePolicyDecider::RequestInfo iframe_request_info(
       ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
       /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2521,7 +2505,7 @@
   ASSERT_TRUE(test::WaitForPageToFinishLoading(web_state()));
 
   // Trigger different-document load in iframe.
-  WebStatePolicyDecider::RequestInfo link_clicked_request_info(
+  const WebStatePolicyDecider::RequestInfo link_clicked_request_info(
       ui::PageTransition::PAGE_TRANSITION_LINK,
       /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/true);
@@ -2548,7 +2532,7 @@
 
   // Go back to top.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo forward_back_request_info(
+  const WebStatePolicyDecider::RequestInfo forward_back_request_info(
       ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK,
       /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/true);
@@ -2600,7 +2584,7 @@
 
   // Callbacks due to loading of the main frame.
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2615,7 +2599,7 @@
   EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _));
 
   // Callbacks due to initial loading of iframe.
-  WebStatePolicyDecider::RequestInfo iframe_request_info(
+  const WebStatePolicyDecider::RequestInfo iframe_request_info(
       ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
       /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2637,7 +2621,7 @@
   // same-origin since the currently-loaded URL in the iframe is same-origin
   // with respect to the main frame.
   GURL cross_origin_url = cross_origin_server.GetURL("/echo");
-  WebStatePolicyDecider::RequestInfo iframe_request_info2(
+  const WebStatePolicyDecider::RequestInfo iframe_request_info2(
       ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
       /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2659,7 +2643,7 @@
   // Now load another URL in the iframe. The iframe (that is, the target frame)
   // is now cross-origin with respect to the main frame.
   GURL url2 = test_server_->GetURL("/pony.html");
-  WebStatePolicyDecider::RequestInfo iframe_request_info3(
+  const WebStatePolicyDecider::RequestInfo iframe_request_info3(
       ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT,
       /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/true,
       /*has_user_gesture=*/false);
@@ -2929,7 +2913,7 @@
   NavigationContext* context = nullptr;
   int32_t nav_id = 0;
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
@@ -2962,7 +2946,7 @@
   // Perform first navigation.
   const GURL first_url = test_server_->GetURL("/echoall");
   EXPECT_CALL(observer_, DidStartLoading(web_state()));
-  WebStatePolicyDecider::RequestInfo expected_request_info(
+  const WebStatePolicyDecider::RequestInfo expected_request_info(
       ui::PageTransition::PAGE_TRANSITION_TYPED,
       /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false,
       /*has_user_gesture=*/false);
diff --git a/ios/web/web_state/web_state_policy_decider.mm b/ios/web/web_state/web_state_policy_decider.mm
index c33216ee..583267d 100644
--- a/ios/web/web_state/web_state_policy_decider.mm
+++ b/ios/web/web_state/web_state_policy_decider.mm
@@ -66,7 +66,7 @@
 
 void WebStatePolicyDecider::ShouldAllowRequest(
     NSURLRequest* request,
-    const RequestInfo& request_info,
+    RequestInfo request_info,
     PolicyDecisionCallback callback) {
   std::move(callback).Run(PolicyDecision::Allow());
 }
diff --git a/ios/web/web_state/web_state_policy_decider_bridge.mm b/ios/web/web_state/web_state_policy_decider_bridge.mm
index fbf3adf..5fc1c7ae 100644
--- a/ios/web/web_state/web_state_policy_decider_bridge.mm
+++ b/ios/web/web_state/web_state_policy_decider_bridge.mm
@@ -19,7 +19,7 @@
 
 void WebStatePolicyDeciderBridge::ShouldAllowRequest(
     NSURLRequest* request,
-    const RequestInfo& request_info,
+    RequestInfo request_info,
     PolicyDecisionCallback callback) {
   if ([decider_ respondsToSelector:@selector
                 (shouldAllowRequest:requestInfo:decisionHandler:)]) {
diff --git a/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm b/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm
index c11705d..8cf447f 100644
--- a/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm
+++ b/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm
@@ -33,15 +33,16 @@
   ASSERT_FALSE([decider_ shouldAllowRequestInfo]);
   NSURL* url = [NSURL URLWithString:@"http://test.url"];
   NSURLRequest* request = [NSURLRequest requestWithURL:url];
-  ui::PageTransition transition_type = ui::PageTransition::PAGE_TRANSITION_LINK;
-  bool target_frame_is_main = true;
-  bool target_frame_is_cross_origin = false;
-  bool has_user_gesture = false;
-  WebStatePolicyDecider::RequestInfo request_info(
+  const ui::PageTransition transition_type =
+      ui::PageTransition::PAGE_TRANSITION_LINK;
+  const bool target_frame_is_main = true;
+  const bool target_frame_is_cross_origin = false;
+  const bool has_user_gesture = false;
+  const WebStatePolicyDecider::RequestInfo request_info(
       transition_type, target_frame_is_main, target_frame_is_cross_origin,
       has_user_gesture);
   decider_bridge_.ShouldAllowRequest(request, request_info, base::DoNothing());
-  FakeShouldAllowRequestInfo* should_allow_request_info =
+  const FakeShouldAllowRequestInfo* should_allow_request_info =
       [decider_ shouldAllowRequestInfo];
   ASSERT_TRUE(should_allow_request_info);
   EXPECT_EQ(request, should_allow_request_info->request);
@@ -66,7 +67,7 @@
   bool for_main_frame = true;
   decider_bridge_.ShouldAllowResponse(response, for_main_frame,
                                       base::DoNothing());
-  FakeDecidePolicyForNavigationResponseInfo*
+  const FakeDecidePolicyForNavigationResponseInfo*
       decide_policy_for_navigation_response_info =
           [decider_ decidePolicyForNavigationResponseInfo];
   ASSERT_TRUE(decide_policy_for_navigation_response_info);
diff --git a/ios/web/web_state/web_state_policy_decider_test_util.h b/ios/web/web_state/web_state_policy_decider_test_util.h
new file mode 100644
index 0000000..0213972
--- /dev/null
+++ b/ios/web/web_state/web_state_policy_decider_test_util.h
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_WEB_STATE_WEB_STATE_POLICY_DECIDER_TEST_UTIL_H_
+#define IOS_WEB_WEB_STATE_WEB_STATE_POLICY_DECIDER_TEST_UTIL_H_
+
+#include "ios/web/public/navigation/web_state_policy_decider.h"
+
+namespace web {
+
+// Compares two web::WebStatePolicyDecider::RequestInfo. Used to implement
+// Google Mock matcher for tests. This is needed because operator== is not
+// implemented for web::WebStatePolicyDecider::RequestInfo.
+bool RequestInfoMatch(WebStatePolicyDecider::RequestInfo expected,
+                      WebStatePolicyDecider::RequestInfo got);
+
+}  // namespace web
+
+#endif  // IOS_WEB_WEB_STATE_WEB_STATE_POLICY_DECIDER_TEST_UTIL_H_
diff --git a/ios/web/web_state/web_state_policy_decider_test_util.mm b/ios/web/web_state/web_state_policy_decider_test_util.mm
new file mode 100644
index 0000000..583c212
--- /dev/null
+++ b/ios/web/web_state/web_state_policy_decider_test_util.mm
@@ -0,0 +1,23 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/web_state/web_state_policy_decider_test_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+bool RequestInfoMatch(WebStatePolicyDecider::RequestInfo expected,
+                      WebStatePolicyDecider::RequestInfo got) {
+  return ui::PageTransitionTypeIncludingQualifiersIs(
+             got.transition_type, expected.transition_type) &&
+         (got.target_frame_is_main == expected.target_frame_is_main) &&
+         (got.target_frame_is_cross_origin ==
+          expected.target_frame_is_cross_origin) &&
+         (got.has_user_gesture == expected.has_user_gesture);
+}
+
+}  // namespace web
diff --git a/ios/web_view/internal/web_view_web_state_policy_decider.h b/ios/web_view/internal/web_view_web_state_policy_decider.h
index 43c478b..5081d85 100644
--- a/ios/web_view/internal/web_view_web_state_policy_decider.h
+++ b/ios/web_view/internal/web_view_web_state_policy_decider.h
@@ -27,7 +27,7 @@
   // web::WebStatePolicyDecider overrides:
   void ShouldAllowRequest(
       NSURLRequest* request,
-      const WebStatePolicyDecider::RequestInfo& request_info,
+      WebStatePolicyDecider::RequestInfo request_info,
       WebStatePolicyDecider::PolicyDecisionCallback callback) override;
   void ShouldAllowResponse(
       NSURLResponse* response,
diff --git a/ios/web_view/internal/web_view_web_state_policy_decider.mm b/ios/web_view/internal/web_view_web_state_policy_decider.mm
index 37722d44..bbae64c 100644
--- a/ios/web_view/internal/web_view_web_state_policy_decider.mm
+++ b/ios/web_view/internal/web_view_web_state_policy_decider.mm
@@ -21,7 +21,7 @@
 
 void WebViewWebStatePolicyDecider::ShouldAllowRequest(
     NSURLRequest* request,
-    const WebStatePolicyDecider::RequestInfo& request_info,
+    WebStatePolicyDecider::RequestInfo request_info,
     WebStatePolicyDecider::PolicyDecisionCallback callback) {
   id<CWVNavigationDelegate> delegate = web_view_.navigationDelegate;
   if ([delegate respondsToSelector:@selector
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index b3b7cefd..b648d22a 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -513,6 +513,12 @@
         "CorsURLLoaderFactory: net_log_params field is not expected.");
   }
 
+  if (request.target_ip_address_space != mojom::IPAddressSpace::kUnknown) {
+    mojo::ReportBadMessage(
+        "CorsURLLoaderFactory: target_ip_address_space field is set");
+    return false;
+  }
+
   // TODO(yhirano): If the request mode is "no-cors", the redirect mode should
   // be "follow".
   return true;
diff --git a/services/network/private_network_access_check.cc b/services/network/private_network_access_check.cc
index 1a8e7a98..07cae92 100644
--- a/services/network/private_network_access_check.cc
+++ b/services/network/private_network_access_check.cc
@@ -15,6 +15,7 @@
 
 PrivateNetworkAccessCheckResult PrivateNetworkAccessCheckInternal(
     const network::mojom::ClientSecurityState* client_security_state,
+    mojom::IPAddressSpace target_address_space,
     int32_t url_load_options,
     mojom::IPAddressSpace resource_address_space) {
   if (url_load_options & mojom::kURLLoadOptionBlockLocalRequest &&
@@ -23,6 +24,13 @@
     return PrivateNetworkAccessCheckResult::kBlockedByLoadOption;
   }
 
+  if (target_address_space != mojom::IPAddressSpace::kUnknown) {
+    return resource_address_space == target_address_space
+               ? PrivateNetworkAccessCheckResult::kAllowedByTargetIpAddressSpace
+               : PrivateNetworkAccessCheckResult::
+                     kBlockedByTargetIpAddressSpace;
+  }
+
   if (!client_security_state) {
     return PrivateNetworkAccessCheckResult::kAllowedMissingClientSecurityState;
   }
@@ -48,10 +56,12 @@
 
 PrivateNetworkAccessCheckResult PrivateNetworkAccessCheck(
     const network::mojom::ClientSecurityState* client_security_state,
+    mojom::IPAddressSpace target_address_space,
     int32_t url_load_options,
     mojom::IPAddressSpace resource_address_space) {
   PrivateNetworkAccessCheckResult result = PrivateNetworkAccessCheckInternal(
-      client_security_state, url_load_options, resource_address_space);
+      client_security_state, target_address_space, url_load_options,
+      resource_address_space);
   base::UmaHistogramEnumeration("Security.PrivateNetworkAccess.CheckResult",
                                 result);
   return result;
diff --git a/services/network/private_network_access_check.h b/services/network/private_network_access_check.h
index e56c9ac6..93e67694 100644
--- a/services/network/private_network_access_check.h
+++ b/services/network/private_network_access_check.h
@@ -17,15 +17,19 @@
 
 }  // namespace mojom
 
-// Returns whether a request client with the given `client_security_state`
-// should be allowed to make requests to an endpoint in `resource_address_space`
-// with a `URLLoader` configured with the given `url_load_options`.
+// Returns whether a request client with the given `client_security_state`,
+// expecting a resource in `target_address_space`, should be allowed to make
+// requests to an endpoint in `resource_address_space` with a `URLLoader`
+// configured with the given `url_load_options`.
+//
+// `target_address_space` is ignored if set to `kUnknown`.
 //
 // Implements the following spec:
 // https://wicg.github.io/private-network-access/#private-network-access-check
 PrivateNetworkAccessCheckResult COMPONENT_EXPORT(NETWORK_SERVICE)
     PrivateNetworkAccessCheck(
         const network::mojom::ClientSecurityState* client_security_state,
+        mojom::IPAddressSpace target_address_space,
         int32_t url_load_options,
         mojom::IPAddressSpace resource_address_space);
 
diff --git a/services/network/private_network_access_check_unittest.cc b/services/network/private_network_access_check_unittest.cc
index 5717ef9..a0ac549 100644
--- a/services/network/private_network_access_check_unittest.cc
+++ b/services/network/private_network_access_check_unittest.cc
@@ -22,10 +22,10 @@
 TEST(PrivateNetworkAccessCheckTest, BlockedByLoadOption) {
   base::HistogramTester histogram_tester;
 
-  EXPECT_EQ(
-      PrivateNetworkAccessCheck(nullptr, mojom::kURLLoadOptionBlockLocalRequest,
-                                mojom::IPAddressSpace::kPrivate),
-      Result::kBlockedByLoadOption);
+  EXPECT_EQ(PrivateNetworkAccessCheck(nullptr, mojom::IPAddressSpace::kUnknown,
+                                      mojom::kURLLoadOptionBlockLocalRequest,
+                                      mojom::IPAddressSpace::kPrivate),
+            Result::kBlockedByLoadOption);
 
   histogram_tester.ExpectUniqueSample(kHistogramName,
                                       Result::kBlockedByLoadOption, 1);
@@ -34,7 +34,8 @@
 TEST(PrivateNetworkAccessCheckTest, AllowedMissingClientSecurityState) {
   base::HistogramTester histogram_tester;
 
-  EXPECT_EQ(PrivateNetworkAccessCheck(nullptr, mojom::kURLLoadOptionNone,
+  EXPECT_EQ(PrivateNetworkAccessCheck(nullptr, mojom::IPAddressSpace::kUnknown,
+                                      mojom::kURLLoadOptionNone,
                                       mojom::IPAddressSpace::kLocal),
             Result::kAllowedMissingClientSecurityState);
 
@@ -48,7 +49,8 @@
   mojom::ClientSecurityState state;
   state.ip_address_space = mojom::IPAddressSpace::kPrivate;
 
-  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::kURLLoadOptionNone,
+  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::IPAddressSpace::kUnknown,
+                                      mojom::kURLLoadOptionNone,
                                       mojom::IPAddressSpace::kPrivate),
             Result::kAllowedNoLessPublic);
 
@@ -64,7 +66,8 @@
   state.private_network_request_policy =
       mojom::PrivateNetworkRequestPolicy::kAllow;
 
-  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::kURLLoadOptionNone,
+  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::IPAddressSpace::kUnknown,
+                                      mojom::kURLLoadOptionNone,
                                       mojom::IPAddressSpace::kPrivate),
             Result::kAllowedByPolicyAllow);
 
@@ -80,7 +83,8 @@
   state.private_network_request_policy =
       mojom::PrivateNetworkRequestPolicy::kWarn;
 
-  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::kURLLoadOptionNone,
+  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::IPAddressSpace::kUnknown,
+                                      mojom::kURLLoadOptionNone,
                                       mojom::IPAddressSpace::kPrivate),
             Result::kAllowedByPolicyWarn);
 
@@ -96,7 +100,8 @@
   state.private_network_request_policy =
       mojom::PrivateNetworkRequestPolicy::kBlock;
 
-  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::kURLLoadOptionNone,
+  EXPECT_EQ(PrivateNetworkAccessCheck(&state, mojom::IPAddressSpace::kUnknown,
+                                      mojom::kURLLoadOptionNone,
                                       mojom::IPAddressSpace::kPrivate),
             Result::kBlockedByPolicyBlock);
 
@@ -104,5 +109,29 @@
                                       Result::kBlockedByPolicyBlock, 1);
 }
 
+TEST(PrivateNetworkAccessCheckTest, BlockedByTargetIpAddressSpace) {
+  base::HistogramTester histogram_tester;
+
+  EXPECT_EQ(PrivateNetworkAccessCheck(nullptr, mojom::IPAddressSpace::kPublic,
+                                      mojom::kURLLoadOptionNone,
+                                      mojom::IPAddressSpace::kPrivate),
+            Result::kBlockedByTargetIpAddressSpace);
+
+  histogram_tester.ExpectUniqueSample(
+      kHistogramName, Result::kBlockedByTargetIpAddressSpace, 1);
+}
+
+TEST(PrivateNetworkAccessCheckTest, AllowedByTargetIpAddressSpace) {
+  base::HistogramTester histogram_tester;
+
+  EXPECT_EQ(PrivateNetworkAccessCheck(nullptr, mojom::IPAddressSpace::kPrivate,
+                                      mojom::kURLLoadOptionNone,
+                                      mojom::IPAddressSpace::kPrivate),
+            Result::kAllowedByTargetIpAddressSpace);
+
+  histogram_tester.ExpectUniqueSample(
+      kHistogramName, Result::kAllowedByTargetIpAddressSpace, 1);
+}
+
 }  // namespace
 }  // namespace network
diff --git a/services/network/public/cpp/cors/cors_error_status.cc b/services/network/public/cpp/cors/cors_error_status.cc
index a886799..582253c2 100644
--- a/services/network/public/cpp/cors/cors_error_status.cc
+++ b/services/network/public/cpp/cors/cors_error_status.cc
@@ -26,8 +26,11 @@
                                  const std::string& failed_parameter)
     : cors_error(cors_error), failed_parameter(failed_parameter) {}
 
-CorsErrorStatus::CorsErrorStatus(mojom::IPAddressSpace resource_address_space)
-    : cors_error(mojom::CorsError::kInsecurePrivateNetwork),
+CorsErrorStatus::CorsErrorStatus(mojom::CorsError cors_error,
+                                 mojom::IPAddressSpace target_address_space,
+                                 mojom::IPAddressSpace resource_address_space)
+    : cors_error(cors_error),
+      target_address_space(target_address_space),
       resource_address_space(resource_address_space) {}
 
 CorsErrorStatus::~CorsErrorStatus() = default;
@@ -36,12 +39,14 @@
   // The `issue_id` is not relevant for equality.
   return cors_error == rhs.cors_error &&
          failed_parameter == rhs.failed_parameter &&
+         target_address_space == rhs.target_address_space &&
          resource_address_space == rhs.resource_address_space;
 }
 
 std::ostream& operator<<(std::ostream& os, const CorsErrorStatus& status) {
   return os << "CorsErrorStatus{ cors_error = " << status.cors_error
             << ", failed_parameter = " << status.failed_parameter
+            << ", target_address_space = " << status.target_address_space
             << ", resource_address_space = " << status.resource_address_space
             << ", issue_id = " << status.issue_id << " }";
 }
diff --git a/services/network/public/cpp/cors/cors_error_status.h b/services/network/public/cpp/cors/cors_error_status.h
index dcb757f..e6e99636 100644
--- a/services/network/public/cpp/cors/cors_error_status.h
+++ b/services/network/public/cpp/cors/cors_error_status.h
@@ -36,9 +36,10 @@
   CorsErrorStatus(mojom::CorsError cors_error,
                   const std::string& failed_parameter);
 
-  // Constructor for CORS-RFC1918 errors.
-  // Sets `cors_error` to `kInsecurePrivateNetwork`.
-  explicit CorsErrorStatus(mojom::IPAddressSpace resource_address_space);
+  // Constructor for Private Network Access errors.
+  CorsErrorStatus(mojom::CorsError cors_error,
+                  mojom::IPAddressSpace target_address_space,
+                  mojom::IPAddressSpace resource_address_space);
 
   ~CorsErrorStatus();
 
@@ -52,9 +53,17 @@
   // Contains request method name, or header name that didn't pass a CORS check.
   std::string failed_parameter;
 
+  // The target IP address space set on the URL request.
+  // See `ResourceRequest::target_ip_address_space`.
+  // Set if (but not only if) `cors_error == kInvalidPrivateNetworkAccess`.
+  mojom::IPAddressSpace target_address_space = mojom::IPAddressSpace::kUnknown;
+
   // The address space of the requested resource.
+  // Set iff `cors_error` is one of:
   //
-  // Only set if `cors_error == kInsecurePrivateNetwork`.
+  // - `kInvalidPrivateNetworkAccess`
+  // - `kInsecurePrivateNetwork`
+  //
   mojom::IPAddressSpace resource_address_space =
       mojom::IPAddressSpace::kUnknown;
 
diff --git a/services/network/public/cpp/network_ipc_param_traits.h b/services/network/public/cpp/network_ipc_param_traits.h
index 5fd6ce3..eb164e1 100644
--- a/services/network/public/cpp/network_ipc_param_traits.h
+++ b/services/network/public/cpp/network_ipc_param_traits.h
@@ -64,6 +64,7 @@
 IPC_STRUCT_TRAITS_BEGIN(network::CorsErrorStatus)
   IPC_STRUCT_TRAITS_MEMBER(cors_error)
   IPC_STRUCT_TRAITS_MEMBER(failed_parameter)
+  IPC_STRUCT_TRAITS_MEMBER(target_address_space)
   IPC_STRUCT_TRAITS_MEMBER(resource_address_space)
   IPC_STRUCT_TRAITS_MEMBER(issue_id)
 IPC_STRUCT_TRAITS_END()
diff --git a/services/network/public/cpp/private_network_access_check_result.cc b/services/network/public/cpp/private_network_access_check_result.cc
index 17a451f..a792f08 100644
--- a/services/network/public/cpp/private_network_access_check_result.cc
+++ b/services/network/public/cpp/private_network_access_check_result.cc
@@ -4,19 +4,24 @@
 
 #include "services/network/public/cpp/private_network_access_check_result.h"
 
+#include "services/network/public/mojom/cors.mojom-shared.h"
+
 namespace network {
 
-bool PrivateNetworkAccessCheckResultIsAllowed(
+absl::optional<mojom::CorsError> PrivateNetworkAccessCheckResultToCorsError(
     PrivateNetworkAccessCheckResult result) {
   switch (result) {
     case PrivateNetworkAccessCheckResult::kAllowedMissingClientSecurityState:
     case PrivateNetworkAccessCheckResult::kAllowedNoLessPublic:
     case PrivateNetworkAccessCheckResult::kAllowedByPolicyAllow:
     case PrivateNetworkAccessCheckResult::kAllowedByPolicyWarn:
-      return true;
+    case PrivateNetworkAccessCheckResult::kAllowedByTargetIpAddressSpace:
+      return absl::nullopt;
     case PrivateNetworkAccessCheckResult::kBlockedByLoadOption:
     case PrivateNetworkAccessCheckResult::kBlockedByPolicyBlock:
-      return false;
+      return mojom::CorsError::kInsecurePrivateNetwork;
+    case PrivateNetworkAccessCheckResult::kBlockedByTargetIpAddressSpace:
+      return mojom::CorsError::kInvalidPrivateNetworkAccess;
   }
 }
 
diff --git a/services/network/public/cpp/private_network_access_check_result.h b/services/network/public/cpp/private_network_access_check_result.h
index 7c5ae0e..bfea2ea 100644
--- a/services/network/public/cpp/private_network_access_check_result.h
+++ b/services/network/public/cpp/private_network_access_check_result.h
@@ -6,6 +6,8 @@
 #define SERVICES_NETWORK_PUBLIC_CPP_PRIVATE_NETWORK_ACCESS_CHECK_RESULT_H_
 
 #include "base/component_export.h"
+#include "services/network/public/mojom/cors.mojom-forward.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace network {
 
@@ -32,13 +34,23 @@
   // Private network request: blocked because policy is `kBlock`.
   kBlockedByPolicyBlock = 5,
 
+  // Request carries a `target_ip_address_space` that matches the resource
+  // address space.
+  kAllowedByTargetIpAddressSpace = 6,
+
+  // Request carries a `target_ip_address_space` that differs from the actual
+  // resource address space. This may be indicative of a DNS rebinding attack.
+  kBlockedByTargetIpAddressSpace = 7,
+
   // Required for UMA histogram logging.
-  kMaxValue = kBlockedByPolicyBlock,
+  kMaxValue = kBlockedByTargetIpAddressSpace,
 };
 
-// Returns whether `result` indicates the request should be allowed.
-bool COMPONENT_EXPORT(NETWORK_CPP) PrivateNetworkAccessCheckResultIsAllowed(
-    PrivateNetworkAccessCheckResult result);
+// If `result` indicates that the request should be blocked, returns the
+// corresponding `CorsError` enum value. Otherwise returns `nullopt`.
+absl::optional<mojom::CorsError> COMPONENT_EXPORT(NETWORK_CPP)
+    PrivateNetworkAccessCheckResultToCorsError(
+        PrivateNetworkAccessCheckResult result);
 
 }  // namespace network
 
diff --git a/services/network/public/cpp/resource_request.cc b/services/network/public/cpp/resource_request.cc
index b405a82fd2..a24972b 100644
--- a/services/network/public/cpp/resource_request.cc
+++ b/services/network/public/cpp/resource_request.cc
@@ -253,7 +253,8 @@
              request.devtools_accepted_stream_types &&
          trust_token_params == request.trust_token_params &&
          OptionalWebBundleTokenParamsEqualsForTesting(  // IN-TEST
-             web_bundle_token_params, request.web_bundle_token_params);
+             web_bundle_token_params, request.web_bundle_token_params) &&
+         target_ip_address_space == request.target_ip_address_space;
 }
 
 bool ResourceRequest::SendsCookies() const {
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index 2b7832d..2857fb52 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -27,6 +27,7 @@
 #include "services/network/public/mojom/cors.mojom-shared.h"
 #include "services/network/public/mojom/devtools_observer.mojom-forward.h"
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
 #include "services/network/public/mojom/trust_tokens.mojom.h"
 #include "services/network/public/mojom/url_loader_network_service_observer.mojom.h"
@@ -186,6 +187,8 @@
   absl::optional<std::vector<net::SourceStream::SourceType>>
       devtools_accepted_stream_types;
   absl::optional<NetLogParams> net_log_params;
+  mojom::IPAddressSpace target_ip_address_space =
+      mojom::IPAddressSpace::kUnknown;
 };
 
 // This does not accept |kDefault| referrer policy.
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index 0bcf923..6bd3913 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -22,6 +22,7 @@
 #include "services/network/public/mojom/cookie_access_observer.mojom.h"
 #include "services/network/public/mojom/data_pipe_getter.mojom.h"
 #include "services/network/public/mojom/devtools_observer.mojom.h"
+#include "services/network/public/mojom/ip_address_space.mojom.h"
 #include "services/network/public/mojom/trust_tokens.mojom.h"
 #include "services/network/public/mojom/url_loader.mojom-shared.h"
 #include "services/network/public/mojom/url_request.mojom.h"
@@ -205,6 +206,7 @@
   out->is_fetch_like_api = data.is_fetch_like_api();
   out->is_favicon = data.is_favicon();
   out->obey_origin_policy = data.obey_origin_policy();
+  out->target_ip_address_space = data.target_ip_address_space();
   return true;
 }
 
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 2ad64095..86e6558f 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -30,6 +30,7 @@
 #include "services/network/public/mojom/cookie_access_observer.mojom-forward.h"
 #include "services/network/public/mojom/data_pipe_getter.mojom.h"
 #include "services/network/public/mojom/devtools_observer.mojom-forward.h"
+#include "services/network/public/mojom/ip_address_space.mojom-forward.h"
 #include "services/network/public/mojom/trust_tokens.mojom-forward.h"
 #include "services/network/public/mojom/url_loader.mojom-forward.h"
 #include "services/network/public/mojom/url_loader_network_service_observer.mojom-forward.h"
@@ -336,6 +337,10 @@
   net_log_params(const network::ResourceRequest& request) {
     return request.net_log_params;
   }
+  static network::mojom::IPAddressSpace target_ip_address_space(
+      const network::ResourceRequest& request) {
+    return request.target_ip_address_space;
+  }
 
   static bool Read(network::mojom::URLRequestDataView data,
                    network::ResourceRequest* out);
diff --git a/services/network/public/cpp/url_request_mojom_traits_unittest.cc b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
index 5cad5196..5d140eb 100644
--- a/services/network/public/cpp/url_request_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
@@ -89,6 +89,18 @@
   original.is_revalidating = false;
   original.throttling_profile_id = base::UnguessableToken::Create();
   original.fetch_window_id = base::UnguessableToken::Create();
+  original.web_bundle_token_params =
+      absl::make_optional(ResourceRequest::WebBundleTokenParams(
+          GURL("https://bundle.test/"), base::UnguessableToken::Create(),
+          mojo::PendingRemote<network::mojom::WebBundleHandle>()));
+  original.net_log_params =
+      absl::make_optional(ResourceRequest::NetLogParams());
+  original.devtools_accepted_stream_types =
+      std::vector<net::SourceStream::SourceType>(
+          {net::SourceStream::SourceType::TYPE_BROTLI,
+           net::SourceStream::SourceType::TYPE_GZIP,
+           net::SourceStream::SourceType::TYPE_DEFLATE});
+  original.target_ip_address_space = mojom::IPAddressSpace::kPrivate;
 
   original.trusted_params = ResourceRequest::TrustedParams();
   original.trusted_params->isolation_info = net::IsolationInfo::Create(
@@ -107,17 +119,6 @@
       mojom::TrustTokenSignRequestData::kInclude;
   original.trust_token_params->additional_signed_headers.push_back(
       "some_header");
-  original.web_bundle_token_params =
-      absl::make_optional(ResourceRequest::WebBundleTokenParams(
-          GURL("https://bundle.test/"), base::UnguessableToken::Create(),
-          mojo::PendingRemote<network::mojom::WebBundleHandle>()));
-  original.net_log_params =
-      absl::make_optional(ResourceRequest::NetLogParams());
-  original.devtools_accepted_stream_types =
-      std::vector<net::SourceStream::SourceType>(
-          {net::SourceStream::SourceType::TYPE_BROTLI,
-           net::SourceStream::SourceType::TYPE_GZIP,
-           net::SourceStream::SourceType::TYPE_DEFLATE});
 
   network::ResourceRequest copied;
   EXPECT_TRUE(
diff --git a/services/network/public/mojom/cors.mojom b/services/network/public/mojom/cors.mojom
index d8acb80..5f9ea9b 100644
--- a/services/network/public/mojom/cors.mojom
+++ b/services/network/public/mojom/cors.mojom
@@ -76,6 +76,9 @@
   // "Access-Control-Allow-External:"
   // ( https://wicg.github.io/cors-rfc1918/#headers ) specific error
   // conditions:
+  //
+  // TODO(https://crbug.com/1252295): Rename these to reflect the evolution of
+  // the spec. See https://wicg.github.io/private-network-access/#headers.
   kPreflightMissingAllowExternal,
   kPreflightInvalidAllowExternal,
 
@@ -97,8 +100,13 @@
   kRedirectContainsCredentials,
 
   // Request client is not secure and less private than the request target.
-  // See: https://wicg.github.io/cors-rfc1918.
+  // See: https://wicg.github.io/private-network-access/#secure-context-restriction
   kInsecurePrivateNetwork,
+
+  // The request carried a `target_ip_address_space` which turned out to
+  // be different from the IP address space of the remote endpoint.
+  // See: https://wicg.github.io/private-network-access/#request-target-ip-address-space
+  kInvalidPrivateNetworkAccess,
 };
 
 [Native]
diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom
index 8ad56cb2..6ad6136 100644
--- a/services/network/public/mojom/url_request.mojom
+++ b/services/network/public/mojom/url_request.mojom
@@ -440,6 +440,14 @@
   // (which happens in CorsURLLoader). See the comment of NetLogParams for
   // details.
   NetLogParams? net_log_params;
+
+  // The IP address space to which the target endpoint of this request should
+  // belong, or `kUnknown` if there is no such requirement.
+  // If the target endpoint of the network socket does not belong to this
+  // address space, the request is failed with a CORS error.
+  // Clients outside the network service must not set this field to a value
+  // other than `kUnknown`.
+  IPAddressSpace target_ip_address_space;
 };
 
 // URLRequestBody represents body (i.e. upload data) of a HTTP request.
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 12302ad..92547477 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -500,6 +500,7 @@
       custom_proxy_pre_cache_headers_(request.custom_proxy_pre_cache_headers),
       custom_proxy_post_cache_headers_(request.custom_proxy_post_cache_headers),
       fetch_window_id_(request.fetch_window_id),
+      target_ip_address_space_(request.target_ip_address_space),
       trust_token_helper_factory_(std::move(trust_token_helper_factory)),
       origin_access_list_(origin_access_list),
       cookie_observer_(std::move(cookie_observer)),
@@ -1025,7 +1026,8 @@
   // Fully-qualify function name to disambiguate it, otherwise it resolves to
   // `URLLoader::PrivateNetworkAccessCheck()` and fails to compile.
   PrivateNetworkAccessCheckResult result = network::PrivateNetworkAccessCheck(
-      security_state.get(), options_, resource_address_space);
+      security_state.get(), target_ip_address_space_, options_,
+      resource_address_space);
 
   bool is_warning = false;
   switch (result) {
@@ -1040,8 +1042,8 @@
       return result;
   }
 
-  // If `security_state` was nullptr, then `result` should have been
-  // `kAllowedMissingClientSecurityState`.
+  // If `security_state` was nullptr, then `result` should not have mentioned
+  // the policy set in `security_state->private_network_request_policy`.
   DCHECK(security_state);
 
   if (auto* devtools_observer = GetDevToolsObserver()) {
@@ -1065,12 +1067,16 @@
   // this request should be blocked per Private Network Access.
   mojom::IPAddressSpace resource_address_space =
       IPEndPointToIPAddressSpace(info.endpoint);
-  if (!PrivateNetworkAccessCheckResultIsAllowed(
-          PrivateNetworkAccessCheck(resource_address_space))) {
+
+  absl::optional<mojom::CorsError> cors_error =
+      PrivateNetworkAccessCheckResultToCorsError(
+          PrivateNetworkAccessCheck(resource_address_space));
+  if (cors_error.has_value()) {
     // Remember the CORS error so we can annotate the URLLoaderCompletionStatus
     // with it later, then fail the request with the same net error code as
     // other CORS errors.
-    cors_error_status_ = CorsErrorStatus(resource_address_space);
+    cors_error_status_ = CorsErrorStatus(*cors_error, target_ip_address_space_,
+                                         resource_address_space);
     return net::ERR_FAILED;
   }
 
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index 93dfe6f..d7f278d 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -532,6 +532,10 @@
   // network::ResourceRequest::fetch_window_id for details.
   absl::optional<base::UnguessableToken> fetch_window_id_;
 
+  // See |ResourceRequest::target_ip_address_space_|.
+  mojom::IPAddressSpace target_ip_address_space_ =
+      mojom::IPAddressSpace::kUnknown;
+
   mojo::Remote<mojom::TrustedHeaderClient> header_client_;
 
   std::unique_ptr<FileOpenerForUpload> file_opener_for_upload_;
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 9a9c986..9bdd656 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -489,6 +489,13 @@
   return result;
 }
 
+CorsErrorStatus InsecurePrivateNetworkCorsErrorStatus(
+    mojom::IPAddressSpace resource_address_space) {
+  return CorsErrorStatus(mojom::CorsError::kInsecurePrivateNetwork,
+                         mojom::IPAddressSpace::kUnknown,
+                         resource_address_space);
+}
+
 // Returns whether monitoring was successfully set up.
 // |*output_sample| needs to stay valid until monitoring is stopped.
 std::unique_ptr<base::StatisticsRecorder::ScopedHistogramSampleObserver>
@@ -645,6 +652,8 @@
 
     request.headers.MergeFrom(additional_headers_);
 
+    request.target_ip_address_space = target_ip_address_space_;
+
     return LoadRequest(request, body);
   }
 
@@ -886,6 +895,9 @@
   void set_additional_headers(const net::HttpRequestHeaders& headers) {
     additional_headers_ = headers;
   }
+  void set_target_ip_address_space(mojom::IPAddressSpace address_space) {
+    target_ip_address_space_ = address_space;
+  }
   void set_accept_ch_frame_observer_for_next_request(
       MockAcceptCHFrameObserver* observer) {
     accept_ch_frame_observer_ = observer;
@@ -1019,6 +1031,8 @@
   MockDevToolsObserver* devtools_observer_ = nullptr;
   scoped_refptr<ResourceRequestBody> request_body_;
   net::HttpRequestHeaders additional_headers_;
+  mojom::IPAddressSpace target_ip_address_space_ =
+      mojom::IPAddressSpace::kUnknown;
 
   bool corb_enabled_ = false;
 
@@ -1091,6 +1105,22 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
 
+TEST_F(URLLoaderTest, MatchingTargetIPAddressSpaceIsOk) {
+  set_target_ip_address_space(mojom::IPAddressSpace::kLocal);
+  EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
+TEST_F(URLLoaderTest, MismatchingTargetIPAddressSpaceIsBlocked) {
+  set_target_ip_address_space(mojom::IPAddressSpace::kPrivate);
+  EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
+              IsError(net::ERR_FAILED));
+  EXPECT_THAT(
+      client()->completion_status().cors_error_status,
+      Optional(CorsErrorStatus(mojom::CorsError::kInvalidPrivateNetworkAccess,
+                               mojom::IPAddressSpace::kPrivate,
+                               mojom::IPAddressSpace::kLocal)));
+}
+
 // These tests verify that requests from both secure and non-secure contexts to
 // an IP in the `kLocal` address space are only blocked when the policy is
 // `kBlock` and the initiator's address space is not `kLocal`.
@@ -1110,7 +1140,8 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_FAILED));
   EXPECT_THAT(client()->completion_status().cors_error_status,
-              Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
+              Optional(InsecurePrivateNetworkCorsErrorStatus(
+                  mojom::IPAddressSpace::kLocal)));
 }
 
 TEST_F(URLLoaderTest, SecureUnknownToLocalWarn) {
@@ -1143,7 +1174,8 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_FAILED));
   EXPECT_THAT(client()->completion_status().cors_error_status,
-              Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
+              Optional(InsecurePrivateNetworkCorsErrorStatus(
+                  mojom::IPAddressSpace::kLocal)));
 }
 
 TEST_F(URLLoaderTest, NonSecureUnknownToLocalWarn) {
@@ -1175,7 +1207,8 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_FAILED));
   EXPECT_THAT(client()->completion_status().cors_error_status,
-              Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
+              Optional(InsecurePrivateNetworkCorsErrorStatus(
+                  mojom::IPAddressSpace::kLocal)));
 }
 
 TEST_F(URLLoaderTest, SecurePublicToLocalWarn) {
@@ -1208,7 +1241,8 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_FAILED));
   EXPECT_THAT(client()->completion_status().cors_error_status,
-              Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
+              Optional(InsecurePrivateNetworkCorsErrorStatus(
+                  mojom::IPAddressSpace::kLocal)));
 }
 
 TEST_F(URLLoaderTest, NonSecurePublicToLocalWarn) {
@@ -1240,7 +1274,8 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_FAILED));
   EXPECT_THAT(client()->completion_status().cors_error_status,
-              Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
+              Optional(InsecurePrivateNetworkCorsErrorStatus(
+                  mojom::IPAddressSpace::kLocal)));
 }
 
 TEST_F(URLLoaderTest, SecurePrivateToLocalWarn) {
@@ -1273,7 +1308,8 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_FAILED));
   EXPECT_THAT(client()->completion_status().cors_error_status,
-              Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
+              Optional(InsecurePrivateNetworkCorsErrorStatus(
+                  mojom::IPAddressSpace::kLocal)));
 }
 
 TEST_F(URLLoaderTest, NonSecurePrivateToLocalWarn) {
@@ -1367,7 +1403,8 @@
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_FAILED));
   EXPECT_THAT(client()->completion_status().cors_error_status,
-              Optional(CorsErrorStatus(mojom::IPAddressSpace::kLocal)));
+              Optional(InsecurePrivateNetworkCorsErrorStatus(
+                  mojom::IPAddressSpace::kLocal)));
 }
 
 // Bundles together the inputs to a parameterized private network request test.
@@ -1442,7 +1479,8 @@
   EXPECT_THAT(Load(url), IsError(params.expected_result));
   if (params.expected_result != net::OK) {
     EXPECT_THAT(client()->completion_status().cors_error_status,
-                Optional(CorsErrorStatus(params.endpoint_address_space)));
+                Optional(InsecurePrivateNetworkCorsErrorStatus(
+                    params.endpoint_address_space)));
   }
 }
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8e18b35..72269a1 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5898,21 +5898,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "dimension_sets": [
@@ -6006,21 +6006,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 075bc8cc..3d98214 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -83471,7 +83471,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -83479,14 +83479,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -83563,7 +83563,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -83571,14 +83571,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -84947,21 +84947,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "dimension_sets": [
@@ -85059,21 +85059,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "dimension_sets": [
@@ -86614,21 +86614,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "dimension_sets": [
@@ -86726,21 +86726,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "dimension_sets": [
@@ -87483,21 +87483,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -87579,21 +87579,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4654.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4654.0",
-              "revision": "version:96.0.4654.0"
+              "location": "lacros_version_skew_tests_v96.0.4655.0",
+              "revision": "version:96.0.4655.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index c1e92b18..d3f96c5 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -52,16 +52,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4654.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.0/test_ash_chrome',
       '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter',
     ],
-    'identifier': 'Lacros version skew testing ash 96.0.4654.0',
+    'identifier': 'Lacros version skew testing ash 96.0.4655.0',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v96.0.4654.0',
-          'revision': 'version:96.0.4654.0',
+          'location': 'lacros_version_skew_tests_v96.0.4655.0',
+          'revision': 'version:96.0.4655.0',
         },
       ],
     },
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 973a78c..7433eb7 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -4917,6 +4917,7 @@
       HeaderDisallowedByPreflightResponse
       RedirectContainsCredentials
       InsecurePrivateNetwork
+      InvalidPrivateNetworkAccess
       NoCorsRedirectModeNotFollow
 
   type CorsErrorStatus extends object
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index b2e3f365..1c2ff3ea 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3359,6 +3359,7 @@
   kClientHintsViewportWidth = 4049,
   kInlineBoxIgnoringContinuation = 4050,
   kOffsetWidthOrHeightIgnoringContinuation = 4051,
+  kConditionalFocus = 4052,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_url_loader_client.h b/third_party/blink/public/platform/web_url_loader_client.h
index 6c6e3ef..d89b7db9 100644
--- a/third_party/blink/public/platform/web_url_loader_client.h
+++ b/third_party/blink/public/platform/web_url_loader_client.h
@@ -71,7 +71,8 @@
       const WebString& new_method,
       const WebURLResponse& passed_redirect_response,
       bool& report_raw_headers,
-      std::vector<std::string>* removed_headers) {
+      std::vector<std::string>* removed_headers,
+      bool insecure_scheme_was_upgraded) {
     return true;
   }
 
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
index 91dcbaaf..7ef6d72 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
@@ -48,7 +48,6 @@
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
-#include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 625e828..77ba7871 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2685,6 +2685,11 @@
   if (HasRareData()) {
     ElementRareData* data = GetElementRareData();
 
+    if (data->GetEditContext()) {
+      data->GetEditContext()->DetachElement(this);
+      data->SetEditContext(nullptr);
+    }
+
     data->ClearRestyleFlags();
 
     if (ElementAnimations* element_animations = data->GetElementAnimations())
@@ -3529,16 +3534,25 @@
 }
 
 void Element::setEditContext(EditContext* edit_context) {
+  if (!InActiveDocument())
+    return;
+
   // If an element is in focus when being attached to a new EditContext,
   // its old EditContext, if it has any, will get blurred,
   // and the new EditContext will automatically get focused.
   if (edit_context && IsFocusedElementInDocument()) {
     if (auto* old_edit_context = editContext())
-      old_edit_context->blur();
+      old_edit_context->Blur();
 
-    edit_context->focus();
+    edit_context->Focus();
   }
 
+  if (auto* old_edit_context = editContext())
+    old_edit_context->DetachElement(this);
+
+  if (edit_context)
+    edit_context->AttachElement(this);
+
   EnsureElementRareData().SetEditContext(edit_context);
 
   // An element is ready to receive text input if there is an EditContext
diff --git a/third_party/blink/renderer/core/editing/ime/edit_context.cc b/third_party/blink/renderer/core/editing/ime/edit_context.cc
index c30acb7..b37e22d 100644
--- a/third_party/blink/renderer/core/editing/ime/edit_context.cc
+++ b/third_party/blink/renderer/core/editing/ime/edit_context.cc
@@ -176,7 +176,7 @@
   }
 }
 
-void EditContext::focus() {
+void EditContext::Focus() {
   EditContext* current_active_edit_context =
       GetInputMethodController().GetActiveEditContext();
   if (current_active_edit_context && current_active_edit_context != this) {
@@ -188,7 +188,7 @@
   GetInputMethodController().SetActiveEditContext(this);
 }
 
-void EditContext::blur() {
+void EditContext::Blur() {
   if (GetInputMethodController().GetActiveEditContext() != this)
     return;
   // Clean up the state of the |this| EditContext.
@@ -292,6 +292,10 @@
   return "manual";
 }
 
+const HeapVector<Member<Element>>& EditContext::attachedElements() {
+  return attached_elements_;
+}
+
 void EditContext::setInputPanelPolicy(const String& input_policy) {
   if (input_policy == "auto")
     input_panel_policy_ = EditContextInputPanelPolicy::kAuto;
@@ -615,6 +619,26 @@
                           selection_start_, selection_end_);
 }
 
+void EditContext::AttachElement(Element* element_to_attach) {
+  if (std::any_of(attached_elements_.begin(), attached_elements_.end(),
+                  [element_to_attach](const auto& element) {
+                    return element.Get() == element_to_attach;
+                  }))
+    return;
+
+  attached_elements_.push_back(element_to_attach);
+}
+
+void EditContext::DetachElement(Element* element_to_detach) {
+  auto* it = std::find_if(attached_elements_.begin(), attached_elements_.end(),
+                          [element_to_detach](const auto& element) {
+                            return element.Get() == element_to_detach;
+                          });
+
+  if (it != attached_elements_.end())
+    attached_elements_.erase(it);
+}
+
 WebTextInputType EditContext::TextInputType() {
   switch (input_mode_) {
     case WebTextInputMode::kWebTextInputModeText:
@@ -697,6 +721,7 @@
   ActiveScriptWrappable::Trace(visitor);
   ExecutionContextClient::Trace(visitor);
   EventTargetWithInlineData::Trace(visitor);
+  visitor->Trace(attached_elements_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/ime/edit_context.h b/third_party/blink/renderer/core/editing/ime/edit_context.h
index a2fa144..83544f1 100644
--- a/third_party/blink/renderer/core/editing/ime/edit_context.h
+++ b/third_party/blink/renderer/core/editing/ime/edit_context.h
@@ -21,6 +21,7 @@
 class DOMRect;
 class EditContext;
 class EditContextInit;
+class Element;
 class ExceptionState;
 class InputMethodController;
 
@@ -49,17 +50,6 @@
 
   // Public APIs for an EditContext (called from JS).
 
-  // When focus is called on an EditContext, it sets the active EditContext in
-  // the document so it can use the text input state to send info about the
-  // EditContext to text input clients in the browser process which will also
-  // set focus of the text input clients on the corresponding context document.
-  void focus();
-
-  // This API sets the active EditContext to null in the document that results
-  // in a focus change event to the text input clients in the browser process
-  // which will also remove focus from the corresponding context document.
-  void blur();
-
   // This API should be called when the selection has changed.
   // It takes as parameters a start and end character offsets, which are based
   // on the text held by the EditContext. This may be called by the web app when
@@ -90,6 +80,9 @@
                   const String& new_text,
                   ExceptionState& exception_state);
 
+  // Get elements that are associated with this EditContext.
+  const HeapVector<Member<Element>>& attachedElements();
+
   // Returns the text of the EditContext.
   String text() const;
 
@@ -131,6 +124,8 @@
   // Auto raises the VK automatically, Manual suppresses it.
   void setInputPanelPolicy(const String& input_policy);
 
+  // Internal APIs (called from Blink).
+
   // EventTarget overrides
   const AtomicString& InterfaceName() const override;
   ExecutionContext* GetExecutionContext() const override;
@@ -160,6 +155,17 @@
   bool GetCompositionCharacterBounds(WebVector<gfx::Rect>& bounds) override;
   WebRange GetSelectionOffsets() const override;
 
+  // When focus is called on an EditContext, it sets the active EditContext in
+  // the document so it can use the text input state to send info about the
+  // EditContext to text input clients in the browser process which will also
+  // set focus of the text input clients on the corresponding context document.
+  void Focus();
+
+  // This API sets the active EditContext to null in the document that results
+  // in a focus change event to the text input clients in the browser process
+  // which will also remove focus from the corresponding context document.
+  void Blur();
+
   // Populate |control_bounds| and |selection_bounds| with the bounds fetched
   // from the active EditContext.
   void GetLayoutBounds(gfx::Rect* control_bounds,
@@ -195,6 +201,9 @@
   // characters from the buffer.
   void ExtendSelectionAndDelete(int before, int after);
 
+  void AttachElement(Element* element_to_attach);
+  void DetachElement(Element* element_to_detach);
+
  private:
   // Returns the enter key action attribute set in the EditContext.
   ui::TextInputAction GetEditContextEnterKeyHint() const;
@@ -262,6 +271,8 @@
   // It is reset once the composition ends.
   uint32_t composition_range_start_ = 0;
   uint32_t composition_range_end_ = 0;
+  // Elements that are associated with this EditContext.
+  HeapVector<Member<Element>> attached_elements_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/ime/edit_context.idl b/third_party/blink/renderer/core/editing/ime/edit_context.idl
index 214e56d..ffa96e90 100644
--- a/third_party/blink/renderer/core/editing/ime/edit_context.idl
+++ b/third_party/blink/renderer/core/editing/ime/edit_context.idl
@@ -15,6 +15,7 @@
     [RaisesException] void updateSelection(unsigned long start, unsigned long end);
     void updateBounds(DOMRect controlBounds, DOMRect selectionBounds);
     [RaisesException] void updateText(unsigned long start, unsigned long end, DOMString newText);
+    sequence<Element> attachedElements();
 
     attribute DOMString text;
     [RaisesException=Setter] attribute unsigned long selectionStart;
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.cc b/third_party/blink/renderer/core/html/forms/text_control_element.cc
index 37288c6..88611f29 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -533,18 +533,6 @@
   return CreateVisiblePosition(it.EndPosition(), TextAffinity::kUpstream);
 }
 
-// TODO(yosin): We should move |TextControlElement::IndexForVisiblePosition()|
-// to "ax_layout_object.cc" since this function is used only there.
-int TextControlElement::IndexForVisiblePosition(
-    const VisiblePosition& pos) const {
-  Position index_position = pos.DeepEquivalent().ParentAnchoredEquivalent();
-  if (EnclosingTextControl(index_position) != this)
-    return 0;
-  DCHECK(index_position.IsConnected()) << index_position;
-  return TextIterator::RangeLength(Position(InnerEditorElement(), 0),
-                                   index_position);
-}
-
 unsigned TextControlElement::selectionStart() const {
   if (!IsTextControl())
     return 0;
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.h b/third_party/blink/renderer/core/html/forms/text_control_element.h
index b31eba4..79db4a90 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element.h
+++ b/third_party/blink/renderer/core/html/forms/text_control_element.h
@@ -77,7 +77,6 @@
   void UpdatePlaceholderVisibility();
 
   VisiblePosition VisiblePositionForIndex(int) const;
-  int IndexForVisiblePosition(const VisiblePosition&) const;
   unsigned selectionStart() const;
   unsigned selectionEnd() const;
   const AtomicString& selectionDirection() const;
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index d62b005..ffbda64 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -502,6 +502,9 @@
 
     case network::mojom::CorsError::kInsecurePrivateNetwork:
       return protocol::Network::CorsErrorEnum::InsecurePrivateNetwork;
+
+    case network::mojom::CorsError::kInvalidPrivateNetworkAccess:
+      return protocol::Network::CorsErrorEnum::InvalidPrivateNetworkAccess;
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index 9e5cf34..e9f3ae83 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -783,6 +783,7 @@
   "geometry/writing_mode_converter_test.cc",
   "grid_test.cc",
   "hit_testing_test.cc",
+  "layout_block_flow_test.cc",
   "layout_block_test.cc",
   "layout_box_model_object_test.cc",
   "layout_box_test.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index d6c41f84..389ff19 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -4647,7 +4647,7 @@
 
   // TODO(crbug.com/1144203): This code path should be switch to
   // |RecalcFragmentsVisualOverflow|.
-  if (PhysicalFragmentCount()) {
+  if (CanUseFragmentsForVisualOverflow()) {
     for (const NGPhysicalBoxFragment& fragment : PhysicalFragments()) {
       if (const NGFragmentItems* items = fragment.Items()) {
         NGInlineCursor cursor(fragment, *items);
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow_test.cc b/third_party/blink/renderer/core/layout/layout_block_flow_test.cc
new file mode 100644
index 0000000..01f6412
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/layout_block_flow_test.cc
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
+
+namespace blink {
+
+class LayoutBlockFlowTest : public NGLayoutTest {};
+
+// crbug.com/1253159.  We had a bug that a legacy IFC LayoutBlockFlow didn't
+// call RecalcVisualOverflow() for children.
+TEST_F(LayoutBlockFlowTest, RecalcInlineChildrenLayoutOverflow) {
+  SetBodyInnerHTML(R"HTML(
+<style>
+kbd { float: right; }
+var { column-count: 17179869184; }
+</style>
+<kbd id="kbd">
+<var>
+<svg>
+<text id="text">B B
+)HTML");
+  LayoutBlockFlow* kbd = To<LayoutBlockFlow>(GetLayoutObjectByElementId("kbd"));
+  // The parent should be NG.
+  ASSERT_TRUE(kbd->Parent()->IsLayoutNGBlockFlow());
+  ASSERT_FALSE(kbd->IsLayoutNGBlockFlow());  // Should be legacy.
+  ASSERT_TRUE(kbd->CreatesNewFormattingContext());
+  UpdateAllLifecyclePhasesForTest();
+  GetElementById("text")->setAttribute("font-size", "100");
+  UpdateAllLifecyclePhasesForTest();
+  // The test passes if no DCHECK failure in ng_ink_overflow.cc.
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/page/focus_controller.cc b/third_party/blink/renderer/core/page/focus_controller.cc
index d0c59cc41..9328a7c 100644
--- a/third_party/blink/renderer/core/page/focus_controller.cc
+++ b/third_party/blink/renderer/core/page/focus_controller.cc
@@ -1317,11 +1317,11 @@
     // is deactivated. If getting focus, the EditContext is activated.
     if (old_focused_element) {
       if (auto* old_editContext = old_focused_element->editContext())
-        old_editContext->blur();
+        old_editContext->Blur();
     }
     if (element) {
       if (auto* editContext = element->editContext())
-        editContext->focus();
+        editContext->Focus();
     }
   }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 2a62433..0928c02 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -817,6 +817,7 @@
 }
 
 void NGBoxFragmentPainter::PaintFloatingItems(const PaintInfo& paint_info,
+                                              const PaintInfo& float_paint_info,
                                               NGInlineCursor* cursor) {
   while (*cursor) {
     const NGFragmentItem* item = cursor->Current().Item();
@@ -832,14 +833,14 @@
     }
     if (child_fragment->IsFloating()) {
       if (child_fragment->CanTraverse()) {
-        NGBoxFragmentPainter(*child_fragment).Paint(paint_info);
+        NGBoxFragmentPainter(*child_fragment).Paint(float_paint_info);
       } else {
         ObjectPainter(*child_fragment->GetLayoutObject())
-            .PaintAllPhasesAtomically(paint_info);
+            .PaintAllPhasesAtomically(float_paint_info);
       }
     } else if (child_fragment->IsBlockInInline() &&
                child_fragment->HasFloatingDescendantsForPaint()) {
-      PaintFloatingChildren(*child_fragment, paint_info);
+      NGBoxFragmentPainter(*child_fragment).Paint(paint_info);
     }
     DCHECK(child_fragment->IsInlineBox() || !cursor->Current().HasChildren());
     cursor->MoveToNext();
@@ -947,13 +948,13 @@
           DynamicTo<NGPhysicalBoxFragment>(&container)) {
     if (const NGFragmentItems* items = box->Items()) {
       NGInlineCursor cursor(*box, *items);
-      PaintFloatingItems(float_paint_info, &cursor);
+      PaintFloatingItems(paint_info, float_paint_info, &cursor);
       return;
     }
     if (inline_box_cursor_) {
       DCHECK(box->IsInlineBox());
       NGInlineCursor descendants = inline_box_cursor_->CursorForDescendants();
-      PaintFloatingItems(float_paint_info, &descendants);
+      PaintFloatingItems(paint_info, float_paint_info, &descendants);
       return;
     }
     DCHECK(!box->IsInlineBox());
@@ -2192,9 +2193,23 @@
     }
 
     if (fragment.IsBlockInInline()) {
-      // "label-contains-other-interactive-content.html" reaches here.
-      return NGBoxFragmentPainter(fragment).NodeAtPoint(hit_test,
-                                                        physical_offset);
+      if (NGBoxFragmentPainter(fragment).NodeAtPoint(hit_test,
+                                                     physical_offset)) {
+        return true;
+      }
+      if (!box_fragment_.IsInlineBox()) {
+        // fast/events/pointerevents/mouse-pointer-transition-events.html
+        // requires this.
+        return false;
+      }
+      // [1] and [2] reach here for hit test on empty <div> with size.
+      // [1] label-contains-other-interactive-content.html
+      // [2] svg/custom/use-event-retargeting.html
+      if (hit_test.action != kHitTestForeground)
+        return false;
+      return NGBoxFragmentPainter(fragment).NodeAtPoint(
+          *hit_test.result, hit_test.location, physical_offset,
+          kHitTestChildBlockBackgrounds);
     }
 
     // When traversing into a different inline formatting context,
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index 49d7e09..242f6bd 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -166,7 +166,9 @@
                     const PaintInfo& paint_info,
                     const PhysicalOffset& paint_offset,
                     const PhysicalOffset& parent_offset);
-  void PaintFloatingItems(const PaintInfo&, NGInlineCursor* cursor);
+  void PaintFloatingItems(const PaintInfo& paint_info,
+                          const PaintInfo& float_paint_info,
+                          NGInlineCursor* cursor);
   void PaintFloatingChildren(const NGPhysicalFragment&,
                              const PaintInfo& paint_info);
   void PaintFloatingChildren(const NGPhysicalFragment&,
diff --git a/third_party/blink/renderer/core/style/applied_text_decoration.h b/third_party/blink/renderer/core/style/applied_text_decoration.h
index b79dc4d..cc050ff 100644
--- a/third_party/blink/renderer/core/style/applied_text_decoration.h
+++ b/third_party/blink/renderer/core/style/applied_text_decoration.h
@@ -5,6 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_APPLIED_TEXT_DECORATION_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_APPLIED_TEXT_DECORATION_H_
 
+#include <memory>
+
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/core/style/text_decoration_thickness.h"
 #include "third_party/blink/renderer/platform/geometry/length.h"
diff --git a/third_party/blink/renderer/modules/mediastream/capture_handle.idl b/third_party/blink/renderer/modules/mediastream/capture_handle.idl
index 00d65f2d..a989c0b 100644
--- a/third_party/blink/renderer/modules/mediastream/capture_handle.idl
+++ b/third_party/blink/renderer/modules/mediastream/capture_handle.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(crbug.com/1208868): Link to the spec once it's published.
+// https://wicg.github.io/capture-handle/
 dictionary CaptureHandle {
   DOMString origin;
   DOMString handle;
diff --git a/third_party/blink/renderer/modules/mediastream/capture_handle_change_event.idl b/third_party/blink/renderer/modules/mediastream/capture_handle_change_event.idl
index e0d0fe4e..c82b135 100644
--- a/third_party/blink/renderer/modules/mediastream/capture_handle_change_event.idl
+++ b/third_party/blink/renderer/modules/mediastream/capture_handle_change_event.idl
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BST-style license that can be
 // found in the LICENSE file.
 
-// TODO(crbug.com:1208868): Link to the spec once it's produced.
-
+// https://wicg.github.io/capture-handle/
 [
     Exposed = Window, RuntimeEnabled = CaptureHandle
 ] interface CaptureHandleChangeEvent : Event {
diff --git a/third_party/blink/renderer/modules/mediastream/capture_handle_change_event_init.idl b/third_party/blink/renderer/modules/mediastream/capture_handle_change_event_init.idl
index 939efdf..b76e937 100644
--- a/third_party/blink/renderer/modules/mediastream/capture_handle_change_event_init.idl
+++ b/third_party/blink/renderer/modules/mediastream/capture_handle_change_event_init.idl
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BST-style license that can be
 // found in the LICENSE file.
 
-// TODO(crbug.com:1208868): Link to the spec once it's produced.
-
+// https://wicg.github.io/capture-handle/
 dictionary CaptureHandleChangeEventInit : EventInit {
     required CaptureHandle captureHandle;
 };
diff --git a/third_party/blink/renderer/modules/mediastream/capture_handle_config.idl b/third_party/blink/renderer/modules/mediastream/capture_handle_config.idl
index 4503728e..2bb20d1 100644
--- a/third_party/blink/renderer/modules/mediastream/capture_handle_config.idl
+++ b/third_party/blink/renderer/modules/mediastream/capture_handle_config.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(crbug.com/1208868): Link to the spec once it's published.
+// https://wicg.github.io/capture-handle/
 dictionary CaptureHandleConfig {
   boolean exposeOrigin = false;
   DOMString handle = "";
diff --git a/third_party/blink/renderer/modules/mediastream/focusable_media_stream_track.idl b/third_party/blink/renderer/modules/mediastream/focusable_media_stream_track.idl
index ce69ada9..a1df9953 100644
--- a/third_party/blink/renderer/modules/mediastream/focusable_media_stream_track.idl
+++ b/third_party/blink/renderer/modules/mediastream/focusable_media_stream_track.idl
@@ -23,6 +23,6 @@
   // Promise<MediaStream> is resolved, or if the call comes too late due
   // to processing delays, the user agent assumes an implicit call with |focus|
   // set to a value decided by the user agent itself.
-  [CallWith = ExecutionContext, RaisesException]
+  [CallWith = ExecutionContext, RaisesException, MeasureAs = ConditionalFocus]
   void focus(CaptureStartFocusBehavior focus_behavior);
 };
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.idl b/third_party/blink/renderer/modules/mediastream/media_devices.idl
index f600177..f776230 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.idl
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.idl
@@ -29,9 +29,9 @@
     ] Promise<MediaStream>
     getDisplayMedia(optional MediaStreamConstraints constraints = {});
 
+    // https://wicg.github.io/capture-handle/
     // Allows an application APP to opt-in to exposing certain information to
     // applications which end up capturing APP.
-    // TODO(crbug.com/1208868): Link to the spec once it's published.
     [
       RuntimeEnabled = CaptureHandle, CallWith = ScriptState, RaisesException
     ] void
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track.idl b/third_party/blink/renderer/modules/mediastream/media_stream_track.idl
index 2ccb060..405939d 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_track.idl
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_track.idl
@@ -44,6 +44,7 @@
     attribute EventHandler onunmute;
     readonly attribute MediaStreamTrackState readyState;
     attribute EventHandler onended;
+    // https://wicg.github.io/capture-handle/
     [RuntimeEnabled = CaptureHandle] attribute EventHandler oncapturehandlechange;
 
     [CallWith=ScriptState] MediaStreamTrack clone();
@@ -52,6 +53,7 @@
     MediaTrackCapabilities getCapabilities();
     MediaTrackConstraints getConstraints();
     MediaTrackSettings getSettings();
+    // https://wicg.github.io/capture-handle/
     [RuntimeEnabled=CaptureHandle, MeasureAs=CaptureHandle] CaptureHandle? getCaptureHandle();
 
     [CallWith=ScriptState] Promise<void> applyConstraints(optional MediaTrackConstraints constraints = {});
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 9c2cff1..7008d08 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -361,60 +361,11 @@
   return installed_scripts_manager_.get();
 }
 
-void ServiceWorkerGlobalScope::CountWorkerScript(size_t script_size,
-                                                 size_t cached_metadata_size) {
-  DCHECK_EQ(GetScriptType(), mojom::blink::ScriptType::kClassic);
-  base::UmaHistogramCustomCounts(
-      "ServiceWorker.ScriptSize",
-      base::saturated_cast<base::Histogram::Sample>(script_size), 1000, 5000000,
-      50);
-
-  if (cached_metadata_size) {
-    base::UmaHistogramCustomCounts(
-        "ServiceWorker.ScriptCachedMetadataSize",
-        base::saturated_cast<base::Histogram::Sample>(cached_metadata_size),
-        1000, 50000000, 50);
-  }
-
-  CountScriptInternal(script_size, cached_metadata_size);
-}
-
-void ServiceWorkerGlobalScope::CountImportedScript(
-    size_t script_size,
-    size_t cached_metadata_size) {
-  DCHECK_EQ(GetScriptType(), mojom::blink::ScriptType::kClassic);
-  CountScriptInternal(script_size, cached_metadata_size);
-}
-
 void ServiceWorkerGlobalScope::DidEvaluateScript() {
   DCHECK(!did_evaluate_script_);
   did_evaluate_script_ = true;
 
   event_queue_->Start();
-
-  // Skip recording UMAs for module scripts because there're no ways to get the
-  // number of static-imported scripts and the total size of the imported
-  // scripts.
-  if (GetScriptType() == mojom::blink::ScriptType::kModule) {
-    return;
-  }
-
-  // TODO(asamidoi,nhiroki): Record the UMAs for module scripts, or remove them
-  // if they're no longer used.
-  base::UmaHistogramCounts1000(
-      "ServiceWorker.ScriptCount",
-      base::saturated_cast<base::Histogram::Sample>(script_count_));
-  base::UmaHistogramCustomCounts(
-      "ServiceWorker.ScriptTotalSize",
-      base::saturated_cast<base::Histogram::Sample>(script_total_size_), 1000,
-      5000000, 50);
-  if (script_cached_metadata_total_size_) {
-    base::UmaHistogramCustomCounts(
-        "ServiceWorker.ScriptCachedMetadataTotalSize",
-        base::saturated_cast<base::Histogram::Sample>(
-            script_cached_metadata_total_size_),
-        1000, 50000000, 50);
-  }
 }
 
 void ServiceWorkerGlobalScope::DidReceiveResponseForClassicScript(
@@ -591,14 +542,6 @@
                         stack_id);
 }
 
-void ServiceWorkerGlobalScope::CountScriptInternal(
-    size_t script_size,
-    size_t cached_metadata_size) {
-  ++script_count_;
-  script_total_size_ += script_size;
-  script_cached_metadata_total_size_ += cached_metadata_size;
-}
-
 ServiceWorkerClients* ServiceWorkerGlobalScope::clients() {
   if (!clients_)
     clients_ = ServiceWorkerClients::Create();
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index a780546..f4ce2a53 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -138,13 +138,6 @@
   void Dispose() override;
   InstalledScriptsManager* GetInstalledScriptsManager() override;
 
-  // Counts an evaluated script and its size. Called for the main worker script.
-  void CountWorkerScript(size_t script_size, size_t cached_metadata_size);
-
-  // Counts an evaluated script and its size. Called for each of imported
-  // scripts.
-  void CountImportedScript(size_t script_size, size_t cached_metadata_size);
-
   // Called when the main worker script is evaluated.
   void DidEvaluateScript();
 
@@ -579,9 +572,6 @@
               WTF::UnsignedWithZeroKeyHashTraits<int64_t>>
       service_worker_objects_;
   bool did_evaluate_script_ = false;
-  size_t script_count_ = 0;
-  size_t script_total_size_ = 0;
-  size_t script_cached_metadata_total_size_ = 0;
   bool is_installing_ = false;
   size_t cache_storage_installed_script_count_ = 0;
   uint64_t cache_storage_installed_script_total_size_ = 0;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index b2efbea..8339af90 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -176,11 +176,8 @@
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
       "ServiceWorker", "ServiceWorkerGlobalScopeProxy::EvaluateTopLevelScript",
       TRACE_ID_LOCAL(this));
-  // TODO(asamidoi): Remove CountWorkerScript which is called for recording
-  // metrics if the metrics are no longer referenced, and then merge
-  // WillEvaluateClassicScript and WillEvaluateModuleScript for cleanup.
-  worker_global_scope_->CountWorkerScript(script_size, cached_metadata_size);
-
+  // TODO(https://crbug.com/1253218): Merge WillEvaluateClassicScript and
+  // WillEvaluateModuleScript for cleanup.
   ScriptState::Scope scope(
       WorkerGlobalScope()->ScriptController()->GetScriptState());
   Client().WillEvaluateScript(
@@ -191,7 +188,7 @@
     size_t script_size,
     size_t cached_metadata_size) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  worker_global_scope_->CountImportedScript(script_size, cached_metadata_size);
+  // TODO(https://crbug.com/1253218): Remove this empty function.
 }
 
 void ServiceWorkerGlobalScopeProxy::WillEvaluateModuleScript() {
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index 3110172..3188371 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -19,31 +19,9 @@
   ]
 }
 
-source_set("heap_unsanitized") {
-  if (is_asan) {
-    configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ]
-  }
-  configs +=
-      [ "//third_party/blink/renderer/platform:blink_platform_implementation" ]
-
-  # std::atomic<>:: functions must be inlined.
-  configs -= [ "//build/config/compiler:default_optimization" ]
-  configs += [ "//build/config/compiler:optimize_max" ]
-  if (using_mismatched_sample_profile) {
-    configs -= [ "//build/config/compiler:afdo_optimize_size" ]
-  }
-
-  sources = []
-
-  deps = [
-    "//base",
-    "//third_party/blink/renderer/platform/wtf",
-  ]
-  public_deps = [ "//third_party/blink/renderer/platform:platform_export" ]
-}
-
 blink_platform_sources("heap") {
   sources = [
+    "blink_gc_memory_dump_provider.cc",
     "blink_gc_memory_dump_provider.h",
     "collection_support/clear_collection_scope.h",
     "collection_support/heap_deque.h",
@@ -55,6 +33,7 @@
     "collection_support/heap_linked_stack.h",
     "collection_support/heap_vector.h",
     "collection_support/heap_vector_backing.h",
+    "custom_spaces.cc",
     "custom_spaces.h",
     "disallow_new_wrapper.h",
     "forward.h",
@@ -64,55 +43,27 @@
     "heap.h",
     "heap_allocator.h",
     "heap_allocator_impl.h",
-    "heap_stats_collector.h",
     "heap_traits.h",
     "member.h",
     "persistent.h",
     "process_heap.h",
     "self_keep_alive.h",
+    "thread_local.h",
+    "thread_state.cc",
     "thread_state.h",
     "thread_state_scopes.h",
     "trace_traits.h",
-    "unified_heap_controller.h",
     "unified_heap_marking_visitor.h",
     "visitor.h",
+    "write_barrier.h",
   ]
 
   deps = [
     ":blink_heap_buildflags",
     "//base",
-    "//third_party/blink/renderer/platform:make_platform_generated",
-    "//third_party/blink/renderer/platform/heap:heap_unsanitized",
-    "//third_party/icu",
-    "//v8",
-  ]
-
-  sources += [
-    "v8_wrapper/blink_gc.h",
-    "v8_wrapper/blink_gc_memory_dump_provider.cc",
-    "v8_wrapper/blink_gc_memory_dump_provider.h",
-    "v8_wrapper/collection_support/heap_hash_table_backing.h",
-    "v8_wrapper/collection_support/heap_vector_backing.h",
-    "v8_wrapper/custom_spaces.cc",
-    "v8_wrapper/custom_spaces.h",
-    "v8_wrapper/garbage_collected.h",
-    "v8_wrapper/heap.h",
-    "v8_wrapper/heap_allocator_impl.h",
-    "v8_wrapper/member.h",
-    "v8_wrapper/persistent.h",
-    "v8_wrapper/process_heap.h",
-    "v8_wrapper/thread_local.h",
-    "v8_wrapper/thread_state.cc",
-    "v8_wrapper/thread_state.h",
-    "v8_wrapper/thread_state_scopes.h",
-    "v8_wrapper/trace_traits.h",
-    "v8_wrapper/unified_heap_marking_visitor.h",
-    "v8_wrapper/visitor.h",
-    "v8_wrapper/write_barrier.h",
-  ]
-
-  deps += [
     "//gin:gin",
+    "//third_party/blink/renderer/platform:make_platform_generated",
+    "//third_party/icu",
 
     # Dependency on V8 which transitively depends on cppgc but exposes
     # JS-related C++ heap through V8's Isolate.
@@ -141,14 +92,10 @@
     "heap_test_objects.cc",
     "heap_test_objects.h",
     "heap_test_platform.h",
+    "heap_test_utilities.cc",
     "heap_test_utilities.h",
   ]
 
-  sources += [
-    "v8_wrapper/heap_test_utilities.cc",
-    "v8_wrapper/heap_test_utilities.h",
-  ]
-
   deps = [
     ":blink_heap_buildflags",
     "//testing/gtest",
diff --git a/third_party/blink/renderer/platform/heap/blink_gc.h b/third_party/blink/renderer/platform/heap/blink_gc.h
index 28a94f0..74169bb 100644
--- a/third_party/blink/renderer/platform/heap/blink_gc.h
+++ b/third_party/blink/renderer/platform/heap/blink_gc.h
@@ -5,6 +5,30 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h"
+#include "third_party/blink/renderer/platform/heap/forward.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/cppgc/liveness-broker.h"
+#include "v8/include/cppgc/trace-trait.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT BlinkGC final {
+  STATIC_ONLY(BlinkGC);
+
+ public:
+  // When garbage collecting we need to know whether or not there can be
+  // pointers to Oilpan-managed objects on the stack for each thread. When
+  // threads reach a safe point they record whether or not they have pointers on
+  // the stack.
+  enum StackState { kNoHeapPointersOnStack, kHeapPointersOnStack };
+};
+
+using Address = uint8_t*;
+using ConstAddress = const uint8_t*;
+
+using TraceCallback = cppgc::TraceCallback;
+using WeakCallback = void (*)(const cppgc::LivenessBroker&, const void*);
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.cc b/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc
similarity index 97%
rename from third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.cc
rename to third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc
index e31f772..d5010898 100644
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.cc
+++ b/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h"
+#include "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h"
 
 #include <inttypes.h>
 #include <ios>
@@ -13,7 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_manager.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "v8/include/cppgc/heap-statistics.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h b/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
index 9ae4b7d..8e47674 100644
--- a/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
+++ b/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h
@@ -5,6 +5,40 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace blink {
+
+class ThreadState;
+
+class PLATFORM_EXPORT BlinkGCMemoryDumpProvider final
+    : public base::trace_event::MemoryDumpProvider {
+  USING_FAST_MALLOC(BlinkGCMemoryDumpProvider);
+
+ public:
+  enum class HeapType { kBlinkMainThread, kBlinkWorkerThread };
+
+  ~BlinkGCMemoryDumpProvider() final;
+  BlinkGCMemoryDumpProvider(ThreadState*,
+                            scoped_refptr<base::SingleThreadTaskRunner>,
+                            HeapType);
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
+                    base::trace_event::ProcessMemoryDump*) final;
+
+ private:
+  ThreadState* const thread_state_;
+  const HeapType heap_type_;
+  const std::string dump_base_name_;
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
index d21c4780..9ce79b8 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
@@ -5,13 +5,105 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
 
+#include <type_traits>
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/heap/trace_traits.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
-
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h"
+#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
+#include "third_party/blink/renderer/platform/wtf/hash_table.h"
+#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
+#include "v8/include/cppgc/custom-space.h"
+#include "v8/include/cppgc/explicit-management.h"
+#include "v8/include/cppgc/object-size-trait.h"
 
 namespace blink {
 
+template <typename Table>
+class HeapHashTableBacking final
+    : public GarbageCollected<HeapHashTableBacking<Table>>,
+      public WTF::ConditionalDestructor<
+          HeapHashTableBacking<Table>,
+          std::is_trivially_destructible<typename Table::ValueType>::value> {
+  using ClassType = HeapHashTableBacking<Table>;
+  using ValueType = typename Table::ValueType;
+
+ public:
+  // Although the HeapHashTableBacking is fully constructed, the array resulting
+  // from ToArray may not be fully constructed as the elements of the array are
+  // not initialized and may have null vtable pointers. Null vtable pointer
+  // violates CFI for polymorphic types.
+  NO_SANITIZE_UNRELATED_CAST ALWAYS_INLINE static ValueType* ToArray(
+      ClassType* backing) {
+    return reinterpret_cast<ValueType*>(backing);
+  }
+
+  ALWAYS_INLINE static ClassType* FromArray(ValueType* array) {
+    return reinterpret_cast<ClassType*>(array);
+  }
+
+  void Free(cppgc::HeapHandle& heap_handle) {
+    cppgc::subtle::FreeUnreferencedObject(heap_handle, *this);
+  }
+
+  bool Resize(size_t new_size) {
+    return cppgc::subtle::Resize(*this, GetAdditionalBytes(new_size));
+  }
+
+  // Conditionally invoked via destructor.
+  void Finalize();
+
+ private:
+  static cppgc::AdditionalBytes GetAdditionalBytes(size_t wanted_array_size) {
+    // HHTB is an empty class that's purely used with inline storage. Since its
+    // sizeof(HHTB) == 1, we need to subtract its size to avoid wasting storage.
+    static_assert(sizeof(ClassType) == 1, "Class declaration changed");
+    DCHECK_GE(wanted_array_size, sizeof(ClassType));
+    return cppgc::AdditionalBytes{wanted_array_size - sizeof(ClassType)};
+  }
+};
+
+template <typename Table>
+void HeapHashTableBacking<Table>::Finalize() {
+  using Value = typename Table::ValueType;
+  static_assert(
+      !std::is_trivially_destructible<Value>::value,
+      "Finalization of trivially destructible classes should not happen.");
+  const size_t object_size =
+      cppgc::subtle::ObjectSizeTrait<HeapHashTableBacking<Table>>::GetSize(
+          *this);
+  const size_t length = object_size / sizeof(Value);
+  Value* table = reinterpret_cast<Value*>(this);
+  for (unsigned i = 0; i < length; ++i) {
+    if (!Table::IsEmptyOrDeletedBucket(table[i]))
+      table[i].~Value();
+  }
+}
+
+template <typename Table>
+struct ThreadingTrait<HeapHashTableBacking<Table>> {
+  STATIC_ONLY(ThreadingTrait);
+  using Key = typename Table::KeyType;
+  using Value = typename Table::ValueType;
+  static constexpr ThreadAffinity kAffinity =
+      (ThreadingTrait<Key>::kAffinity == kMainThreadOnly) &&
+              (ThreadingTrait<Value>::kAffinity == kMainThreadOnly)
+          ? kMainThreadOnly
+          : kAnyThread;
+};
+
+template <typename First, typename Second>
+struct ThreadingTrait<WTF::KeyValuePair<First, Second>> {
+  STATIC_ONLY(ThreadingTrait);
+  static constexpr ThreadAffinity kAffinity =
+      (ThreadingTrait<First>::kAffinity == kMainThreadOnly) &&
+              (ThreadingTrait<Second>::kAffinity == kMainThreadOnly)
+          ? kMainThreadOnly
+          : kAnyThread;
+};
+
 // Helper for processing ephemerons represented as KeyValuePair. Reorders
 // parameters if needed so that KeyType is always weak.
 template <typename _KeyType,
@@ -66,6 +158,94 @@
 
 namespace WTF {
 
+namespace internal {
+
+// ConcurrentBucket is a wrapper for HashTable buckets for concurrent marking.
+// It is used to provide a snapshot view of the bucket key and guarantee
+// that the same key is used for checking empty/deleted buckets and tracing.
+template <typename T>
+class ConcurrentBucket {
+  using KeyExtractionCallback = void (*)(const T&, void*);
+
+ public:
+  using BucketType = T;
+
+  ConcurrentBucket(const T& t, KeyExtractionCallback extract_key) {
+    extract_key(t, &buf_);
+  }
+
+  // for HashTable that don't use KeyValuePair (i.e. *HashSets), the key
+  // and the value are the same.
+  const T* key() const { return reinterpret_cast<const T*>(&buf_); }
+  const T* value() const { return key(); }
+  const T* bucket() const { return key(); }
+
+ private:
+  // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
+  // can be accessed the same as objects of type T
+  static constexpr size_t boundary = std::max(alignof(T), sizeof(size_t));
+  alignas(boundary) char buf_[sizeof(T)];
+};
+
+template <typename Key, typename Value>
+class ConcurrentBucket<KeyValuePair<Key, Value>> {
+  using KeyExtractionCallback = void (*)(const KeyValuePair<Key, Value>&,
+                                         void*);
+
+ public:
+  using BucketType = ConcurrentBucket;
+
+  ConcurrentBucket(const KeyValuePair<Key, Value>& pair,
+                   KeyExtractionCallback extract_key)
+      : value_(&pair.value) {
+    extract_key(pair, &buf_);
+  }
+
+  const Key* key() const { return reinterpret_cast<const Key*>(&buf_); }
+  const Value* value() const { return value_; }
+  const ConcurrentBucket* bucket() const { return this; }
+
+ private:
+  // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
+  // can be accessed the same as objects of type Key
+  static constexpr size_t boundary = std::max(alignof(Key), sizeof(size_t));
+  alignas(boundary) char buf_[sizeof(Key)];
+  const Value* value_;
+};
+
+}  // namespace internal
+
+template <WTF::WeakHandlingFlag weak_handling, typename Table>
+struct TraceHashTableBackingInCollectionTrait {
+  using Value = typename Table::ValueType;
+  using Traits = typename Table::ValueTraits;
+  using Extractor = typename Table::ExtractorType;
+
+  static void Trace(blink::Visitor* visitor, const void* self) {
+    static_assert(IsTraceableInCollectionTrait<Traits>::value ||
+                      WTF::IsWeak<Value>::value,
+                  "Table should not be traced");
+    const Value* array = reinterpret_cast<const Value*>(self);
+    const size_t length =
+        cppgc::subtle::
+            ObjectSizeTrait<const blink::HeapHashTableBacking<Table>>::GetSize(
+                *reinterpret_cast<const blink::HeapHashTableBacking<Table>*>(
+                    self)) /
+        sizeof(Value);
+    for (size_t i = 0; i < length; ++i) {
+      internal::ConcurrentBucket<Value> concurrent_bucket(
+          array[i], Extractor::ExtractSafe);
+      if (!HashTableHelper<Value, Extractor, typename Table::KeyTraitsType>::
+              IsEmptyOrDeletedBucketForKey(*concurrent_bucket.key())) {
+        blink::TraceCollectionIfEnabled<
+            weak_handling,
+            typename internal::ConcurrentBucket<Value>::BucketType,
+            Traits>::Trace(visitor, concurrent_bucket.bucket());
+      }
+    }
+  }
+};
+
 template <typename Table>
 struct TraceInCollectionTrait<kNoWeakHandling,
                               blink::HeapHashTableBacking<Table>,
@@ -226,4 +406,113 @@
 
 }  // namespace WTF
 
+namespace cppgc {
+
+// Assign HeapVector to the custom HeapVectorBackingSpace.
+template <typename Table>
+struct SpaceTrait<blink::HeapHashTableBacking<Table>> {
+  using Space = blink::HeapHashTableBackingSpace;
+};
+
+// Custom allocation accounts for inlined storage of the actual elements of the
+// backing table.
+template <typename Table>
+class MakeGarbageCollectedTrait<blink::HeapHashTableBacking<Table>>
+    : public MakeGarbageCollectedTraitBase<blink::HeapHashTableBacking<Table>> {
+ public:
+  using Backing = blink::HeapHashTableBacking<Table>;
+
+  template <typename... Args>
+  static Backing* Call(AllocationHandle& handle, size_t num_elements) {
+    static_assert(
+        !std::is_polymorphic<blink::HeapHashTableBacking<Table>>::value,
+        "HeapHashTableBacking must not be polymorphic as it is converted to a "
+        "raw array of buckets for certain operation");
+    CHECK_GT(num_elements, 0u);
+    // Allocate automatically considers the custom space via SpaceTrait.
+    void* memory = MakeGarbageCollectedTraitBase<Backing>::Allocate(
+        handle, sizeof(typename Table::ValueType) * num_elements);
+    Backing* object = ::new (memory) Backing();
+    MakeGarbageCollectedTraitBase<Backing>::MarkObjectAsFullyConstructed(
+        object);
+    return object;
+  }
+};
+
+template <typename Table>
+struct TraceTrait<blink::HeapHashTableBacking<Table>> {
+  using Backing = blink::HeapHashTableBacking<Table>;
+  using Traits = typename Table::ValueTraits;
+  using ValueType = typename Table::ValueTraits::TraitType;
+
+  static TraceDescriptor GetTraceDescriptor(const void* self) {
+    return {self, Trace<WTF::kNoWeakHandling>};
+  }
+
+  static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
+    return GetWeakTraceDescriptorImpl<ValueType>::GetWeakTraceDescriptor(self);
+  }
+
+  template <WTF::WeakHandlingFlag weak_handling = WTF::kNoWeakHandling>
+  static void Trace(Visitor* visitor, const void* self) {
+    if (!Traits::kCanTraceConcurrently && self) {
+      if (visitor->DeferTraceToMutatorThreadIfConcurrent(
+              self, &Trace<weak_handling>,
+              cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
+                  *reinterpret_cast<const Backing*>(self)))) {
+        return;
+      }
+    }
+
+    static_assert(WTF::IsTraceableInCollectionTrait<Traits>::value ||
+                      WTF::IsWeak<ValueType>::value,
+                  "T should not be traced");
+    WTF::TraceInCollectionTrait<weak_handling, Backing, void>::Trace(visitor,
+                                                                     self);
+  }
+
+ private:
+  // Default setting for HashTable is without weak trace descriptor.
+  template <typename ValueType>
+  struct GetWeakTraceDescriptorImpl {
+    static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
+      return {self, nullptr};
+    }
+  };
+
+  // Specialization for WTF::KeyValuePair, which is default bucket storage type.
+  template <typename K, typename V>
+  struct GetWeakTraceDescriptorImpl<WTF::KeyValuePair<K, V>> {
+    static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+      return GetWeakTraceDescriptorKVPImpl<K, V>::GetWeakTraceDescriptor(
+          backing);
+    }
+
+    // Default setting for KVP without ephemeron semantics.
+    template <typename KeyType,
+              typename ValueType,
+              bool ephemeron_semantics = (WTF::IsWeak<KeyType>::value &&
+                                          !WTF::IsWeak<ValueType>::value &&
+                                          WTF::IsTraceable<ValueType>::value) ||
+                                         (WTF::IsWeak<ValueType>::value &&
+                                          !WTF::IsWeak<KeyType>::value &&
+                                          WTF::IsTraceable<KeyType>::value)>
+    struct GetWeakTraceDescriptorKVPImpl {
+      static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+        return {backing, nullptr};
+      }
+    };
+
+    // Specialization for KVP with ephemeron semantics.
+    template <typename KeyType, typename ValueType>
+    struct GetWeakTraceDescriptorKVPImpl<KeyType, ValueType, true> {
+      static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
+        return {backing, Trace<WTF::kWeakHandling>};
+      }
+    };
+  };
+};
+
+}  // namespace cppgc
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
index 7f7f24a..cb8488c1 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h
@@ -5,6 +5,246 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h"
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/trace_traits.h"
+#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
+#include "third_party/blink/renderer/platform/wtf/container_annotations.h"
+#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
+#include "v8/include/cppgc/allocation.h"
+#include "v8/include/cppgc/custom-space.h"
+#include "v8/include/cppgc/explicit-management.h"
+#include "v8/include/cppgc/object-size-trait.h"
+#include "v8/include/cppgc/trace-trait.h"
+#include "v8/include/cppgc/visitor.h"
+
+namespace blink {
+namespace internal {
+
+inline bool VTableInitialized(const void* object_payload) {
+  return !!(*reinterpret_cast<const size_t*>(object_payload));
+}
+
+}  // namespace internal
+
+template <typename T, typename Traits = WTF::VectorTraits<T>>
+class HeapVectorBacking final
+    : public GarbageCollected<HeapVectorBacking<T, Traits>>,
+      public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
+                                        !Traits::kNeedsDestruction> {
+  using ClassType = HeapVectorBacking<T, Traits>;
+
+ public:
+  // Although the HeapVectorBacking is fully constructed, the array resulting
+  // from ToArray may not be fully constructed as the elements of the array are
+  // not initialized and may have null vtable pointers. Null vtable pointer
+  // violates CFI for polymorphic types.
+  NO_SANITIZE_UNRELATED_CAST ALWAYS_INLINE static T* ToArray(
+      ClassType* backing) {
+    return reinterpret_cast<T*>(backing);
+  }
+
+  ALWAYS_INLINE static ClassType* FromArray(T* payload) {
+    return reinterpret_cast<ClassType*>(payload);
+  }
+
+  void Free(cppgc::HeapHandle& heap_handle) {
+    cppgc::subtle::FreeUnreferencedObject(heap_handle, *this);
+  }
+
+  bool Resize(size_t new_size) {
+    return cppgc::subtle::Resize(*this, GetAdditionalBytes(new_size));
+  }
+
+  // Conditionally invoked via destructor.
+  void Finalize();
+
+ private:
+  static cppgc::AdditionalBytes GetAdditionalBytes(size_t wanted_array_size) {
+    // HVB is an empty class that's purely used with inline storage. Since its
+    // sizeof(HVB) == 1, we need to subtract its size to avoid wasting storage.
+    static_assert(sizeof(ClassType) == 1, "Class declaration changed");
+    DCHECK_GE(wanted_array_size, sizeof(ClassType));
+    return cppgc::AdditionalBytes{wanted_array_size - sizeof(ClassType)};
+  }
+};
+
+template <typename T, typename Traits>
+void HeapVectorBacking<T, Traits>::Finalize() {
+  static_assert(Traits::kNeedsDestruction,
+                "Only vector buffers with items requiring destruction should "
+                "be finalized");
+  static_assert(
+      Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic<T>::value,
+      "HeapVectorBacking doesn't support objects that cannot be cleared as "
+      "unused with memset or don't have a vtable");
+  static_assert(
+      !std::is_trivially_destructible<T>::value,
+      "Finalization of trivially destructible classes should not happen.");
+  const size_t object_size =
+      cppgc::subtle::ObjectSizeTrait<HeapVectorBacking<T, Traits>>::GetSize(
+          *this);
+  const size_t length = object_size / sizeof(T);
+  Address payload = reinterpret_cast<Address>(this);
+#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
+  ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T));
+#endif  // ANNOTATE_CONTIGUOUS_CONTAINER
+  // HeapVectorBacking calls finalizers for unused slots and expects them to be
+  // no-ops.
+  if (std::is_polymorphic<T>::value) {
+    for (size_t i = 0; i < length; ++i) {
+      Address element = payload + i * sizeof(T);
+      if (internal::VTableInitialized(element))
+        reinterpret_cast<T*>(element)->~T();
+    }
+  } else {
+    T* buffer = reinterpret_cast<T*>(payload);
+    for (size_t i = 0; i < length; ++i)
+      buffer[i].~T();
+  }
+}
+
+template <typename T, typename Traits>
+struct ThreadingTrait<HeapVectorBacking<T, Traits>> {
+  STATIC_ONLY(ThreadingTrait);
+  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
+}  // namespace blink
+
+namespace WTF {
+
+// This trace method is used for all HeapVectorBacking objects. On-stack objects
+// are found and dispatched using conservative stack scanning. HeapVector (i.e.
+// Vector) dispatches all regular on-heap backings to this method.
+template <typename T, typename Traits>
+struct TraceInCollectionTrait<kNoWeakHandling,
+                              blink::HeapVectorBacking<T, Traits>,
+                              void> {
+  using Backing = blink::HeapVectorBacking<T, Traits>;
+
+  static void Trace(blink::Visitor* visitor, const void* self) {
+    // HeapVectorBacking does not know the exact size of the vector
+    // and just knows the capacity of the vector. Due to the constraint,
+    // HeapVectorBacking can support only the following objects:
+    //
+    // - An object that has a vtable. In this case, HeapVectorBacking
+    //   traces only slots that are not zeroed out. This is because if
+    //   the object has a vtable, the zeroed slot means that it is
+    //   an unused slot (Remember that the unused slots are guaranteed
+    //   to be zeroed out by VectorUnusedSlotClearer).
+    //
+    // - An object that can be initialized with memset. In this case,
+    //   HeapVectorBacking traces all slots including unused slots.
+    //   This is fine because the fact that the object can be initialized
+    //   with memset indicates that it is safe to treat the zerod slot
+    //   as a valid object.
+    static_assert(!IsTraceableInCollectionTrait<Traits>::value ||
+                      Traits::kCanClearUnusedSlotsWithMemset ||
+                      std::is_polymorphic<T>::value,
+                  "HeapVectorBacking doesn't support objects that cannot be "
+                  "cleared as unused with memset.");
+
+    // This trace method is instantiated for vectors where
+    // IsTraceableInCollectionTrait<Traits>::value is false, but the trace
+    // method should not be called. Thus we cannot static-assert
+    // IsTraceableInCollectionTrait<Traits>::value but should runtime-assert it.
+    DCHECK(IsTraceableInCollectionTrait<Traits>::value);
+
+    const T* array = reinterpret_cast<const T*>(self);
+    const size_t length =
+        cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
+            *reinterpret_cast<const Backing*>(self)) /
+        sizeof(T);
+#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
+    // As commented above, HeapVectorBacking can trace unused slots (which are
+    // already zeroed out).
+    ANNOTATE_CHANGE_SIZE(array, length, 0, length);
+#endif  // ANNOTATE_CONTIGUOUS_CONTAINER
+    if (std::is_polymorphic<T>::value) {
+      for (unsigned i = 0; i < length; ++i) {
+        if (blink::internal::VTableInitialized(&array[i])) {
+          blink::TraceIfNeeded<
+              T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
+                                                                     array[i]);
+        }
+      }
+    } else {
+      for (size_t i = 0; i < length; ++i) {
+        blink::TraceIfNeeded<
+            T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
+                                                                   array[i]);
+      }
+    }
+  }
+};
+
+}  // namespace WTF
+
+namespace cppgc {
+
+// Assign HeapVector to the custom HeapVectorBackingSpace.
+template <typename T>
+struct SpaceTrait<blink::HeapVectorBacking<T>> {
+  using Space = blink::HeapVectorBackingSpace;
+};
+
+// Custom allocation accounts for inlined storage of the actual elements of the
+// backing array.
+template <typename T>
+class MakeGarbageCollectedTrait<blink::HeapVectorBacking<T>>
+    : public MakeGarbageCollectedTraitBase<blink::HeapVectorBacking<T>> {
+  using Backing = blink::HeapVectorBacking<T>;
+
+ public:
+  template <typename... Args>
+  static Backing* Call(AllocationHandle& handle, size_t num_elements) {
+    static_assert(!std::is_polymorphic<blink::HeapVectorBacking<T>>::value,
+                  "HeapVectorBacking must not be polymorphic as it is "
+                  "converted to a raw array of buckets for certain operation");
+    CHECK_GT(num_elements, 0u);
+    // Allocate automatically considers the custom space via SpaceTrait.
+    void* memory = MakeGarbageCollectedTraitBase<Backing>::Allocate(
+        handle, sizeof(T) * num_elements);
+    Backing* object = ::new (memory) Backing();
+    MakeGarbageCollectedTraitBase<Backing>::MarkObjectAsFullyConstructed(
+        object);
+    return object;
+  }
+};
+
+template <typename T, typename Traits>
+struct TraceTrait<blink::HeapVectorBacking<T, Traits>> {
+  using Backing = blink::HeapVectorBacking<T, Traits>;
+
+  static TraceDescriptor GetTraceDescriptor(const void* self) {
+    return {self, Trace};
+  }
+
+  static void Trace(Visitor* visitor, const void* self) {
+    if (!Traits::kCanTraceConcurrently && self) {
+      if (visitor->DeferTraceToMutatorThreadIfConcurrent(
+              self, &Trace,
+              cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
+                  *reinterpret_cast<const Backing*>(self)))) {
+        return;
+      }
+    }
+
+    static_assert(!WTF::IsWeak<T>::value,
+                  "Weakness is not supported in HeapVector and HeapDeque");
+    if (WTF::IsTraceableInCollectionTrait<Traits>::value) {
+      WTF::TraceInCollectionTrait<WTF::kNoWeakHandling,
+                                  blink::HeapVectorBacking<T, Traits>,
+                                  void>::Trace(visitor, self);
+    }
+  }
+};
+
+}  // namespace cppgc
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.cc b/third_party/blink/renderer/platform/heap/custom_spaces.cc
similarity index 88%
rename from third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.cc
rename to third_party/blink/renderer/platform/heap/custom_spaces.cc
index fb5eaabb..3847b1a 100644
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.cc
+++ b/third_party/blink/renderer/platform/heap/custom_spaces.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/heap/custom_spaces.h b/third_party/blink/renderer/platform/heap/custom_spaces.h
index 7b98bda..5055e80 100644
--- a/third_party/blink/renderer/platform/heap/custom_spaces.h
+++ b/third_party/blink/renderer/platform/heap/custom_spaces.h
@@ -5,6 +5,63 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_CUSTOM_SPACES_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_CUSTOM_SPACES_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
+#include <memory>
+#include <vector>
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "v8/include/cppgc/custom-space.h"
+
+namespace blink {
+
+// The following defines custom spaces that are used to partition Oilpan's heap.
+// Each custom space is assigned to a type partition using `cppgc::SpaceTrait`.
+// It is expected that `kSpaceIndex` uniquely identifies a space and that the
+// indices of all custom spaces form a sequence starting at 0. See
+// `cppgc::CustomSpace` for details.
+
+class PLATFORM_EXPORT HeapVectorBackingSpace
+    : public cppgc::CustomSpace<HeapVectorBackingSpace> {
+ public:
+  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 0;
+  static constexpr bool kSupportsCompaction = true;
+};
+
+class PLATFORM_EXPORT HeapHashTableBackingSpace
+    : public cppgc::CustomSpace<HeapHashTableBackingSpace> {
+ public:
+  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 1;
+  static constexpr bool kSupportsCompaction = true;
+};
+
+class PLATFORM_EXPORT NodeSpace : public cppgc::CustomSpace<NodeSpace> {
+ public:
+  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 2;
+};
+
+class PLATFORM_EXPORT CSSValueSpace : public cppgc::CustomSpace<CSSValueSpace> {
+ public:
+  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 3;
+};
+
+class PLATFORM_EXPORT LayoutObjectSpace
+    : public cppgc::CustomSpace<LayoutObjectSpace> {
+ public:
+  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 4;
+};
+
+struct CustomSpaces {
+  static std::vector<std::unique_ptr<cppgc::CustomSpaceBase>>
+  CreateCustomSpaces() {
+    std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> spaces;
+    spaces.emplace_back(std::make_unique<HeapVectorBackingSpace>());
+    spaces.emplace_back(std::make_unique<HeapHashTableBackingSpace>());
+    spaces.emplace_back(std::make_unique<NodeSpace>());
+    spaces.emplace_back(std::make_unique<CSSValueSpace>());
+    spaces.emplace_back(std::make_unique<LayoutObjectSpace>());
+    return spaces;
+  }
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_CUSTOM_SPACES_H_
diff --git a/third_party/blink/renderer/platform/heap/garbage_collected.h b/third_party/blink/renderer/platform/heap/garbage_collected.h
index 9b81a6c4..710ef10 100644
--- a/third_party/blink/renderer/platform/heap/garbage_collected.h
+++ b/third_party/blink/renderer/platform/heap/garbage_collected.h
@@ -5,6 +5,30 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h"
+#include "v8/include/cppgc/garbage-collected.h"
+#include "v8/include/cppgc/type-traits.h"
+
+// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or
+// field when checking for proper usage.  When using GC_PLUGIN_IGNORE
+// a bug-number should be provided as an argument where the bug describes
+// what needs to happen to remove the GC_PLUGIN_IGNORE again.
+#if defined(__clang__)
+#define GC_PLUGIN_IGNORE(bug) \
+  __attribute__((annotate("blink_gc_plugin_ignore")))
+#else
+#define GC_PLUGIN_IGNORE(bug)
+#endif
+
+namespace blink {
+
+using GarbageCollectedMixin = cppgc::GarbageCollectedMixin;
+
+template <typename T>
+struct IsGarbageCollectedMixin {
+ public:
+  static const bool value = cppgc::IsGarbageCollectedMixinTypeV<T>;
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h
index cb41e7e6..370ca661 100644
--- a/third_party/blink/renderer/platform/heap/heap.h
+++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -5,6 +5,47 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap.h"
+#include "third_party/blink/renderer/platform/heap/process_heap.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "v8/include/cppgc/allocation.h"
+#include "v8/include/cppgc/garbage-collected.h"
+#include "v8/include/cppgc/internal/pointer-policies.h"
+#include "v8/include/cppgc/liveness-broker.h"
+
+namespace blink {
+
+using LivenessBroker = cppgc::LivenessBroker;
+
+template <typename T>
+using GarbageCollected = cppgc::GarbageCollected<T>;
+
+// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage
+// collected type.
+template <typename T, typename... Args>
+T* MakeGarbageCollected(Args&&... args) {
+  return cppgc::MakeGarbageCollected<T>(
+      ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+          ->allocation_handle(),
+      std::forward<Args>(args)...);
+}
+
+using AdditionalBytes = cppgc::AdditionalBytes;
+
+// Constructs an instance of T, which is a garbage collected type. This special
+// version takes size which enables constructing inline objects.
+template <typename T, typename... Args>
+T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) {
+  return cppgc::MakeGarbageCollected<T>(
+      ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+          ->allocation_handle(),
+      std::forward<AdditionalBytes>(additional_bytes),
+      std::forward<Args>(args)...);
+}
+
+static constexpr bool kBlinkGCHasDebugChecks =
+    !std::is_same<cppgc::internal::DefaultMemberCheckingPolicy,
+                  cppgc::internal::DisabledCheckingPolicy>::value;
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator_impl.h b/third_party/blink/renderer/platform/heap/heap_allocator_impl.h
index b67be25..d0f1e41 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator_impl.h
+++ b/third_party/blink/renderer/platform/heap/heap_allocator_impl.h
@@ -1,10 +1,251 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/heap/write_barrier.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/cppgc/explicit-management.h"
+#include "v8/include/cppgc/heap-consistency.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT HeapAllocator {
+  STATIC_ONLY(HeapAllocator);
+
+ public:
+  using HeapConsistency = cppgc::subtle::HeapConsistency;
+  using LivenessBroker = blink::LivenessBroker;
+
+  static constexpr bool kIsGarbageCollected = true;
+
+  // See wtf/size_t.h for details.
+  static constexpr size_t kMaxHeapObjectSizeLog2 = 27;
+  static constexpr size_t kMaxHeapObjectSize = 1 << kMaxHeapObjectSizeLog2;
+
+  template <typename T>
+  static size_t MaxElementCountInBackingStore() {
+    return kMaxHeapObjectSize / sizeof(T);
+  }
+
+  template <typename T>
+  static size_t QuantizedSize(size_t count) {
+    CHECK_LE(count, MaxElementCountInBackingStore<T>());
+    // Oilpan's internal size is independent of MaxElementCountInBackingStore()
+    // and the required size to match capacity needs.
+    return count * sizeof(T);
+  }
+
+  template <typename T>
+  static T* AllocateVectorBacking(size_t size) {
+    return HeapVectorBacking<T>::ToArray(
+        MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T)));
+  }
+
+  template <typename T>
+  static void FreeVectorBacking(T* array) {
+    if (!array)
+      return;
+
+    HeapVectorBacking<T>::FromArray(array)->Free(
+        ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+            ->heap_handle());
+  }
+
+  template <typename T>
+  static bool ExpandVectorBacking(T* array, size_t new_size) {
+    DCHECK(array);
+    return HeapVectorBacking<T>::FromArray(array)->Resize(new_size);
+  }
+
+  template <typename T>
+  static bool ShrinkVectorBacking(T* array, size_t, size_t new_size) {
+    DCHECK(array);
+    return HeapVectorBacking<T>::FromArray(array)->Resize(new_size);
+  }
+
+  template <typename T, typename HashTable>
+  static T* AllocateHashTableBacking(size_t size) {
+    static_assert(sizeof(T) == sizeof(typename HashTable::ValueType),
+                  "T must match ValueType.");
+    return HeapHashTableBacking<HashTable>::ToArray(
+        MakeGarbageCollected<HeapHashTableBacking<HashTable>>(size /
+                                                              sizeof(T)));
+  }
+
+  template <typename T, typename HashTable>
+  static T* AllocateZeroedHashTableBacking(size_t size) {
+    return AllocateHashTableBacking<T, HashTable>(size);
+  }
+
+  template <typename T, typename HashTable>
+  static void FreeHashTableBacking(T* array) {
+    if (!array)
+      return;
+
+    HeapHashTableBacking<HashTable>::FromArray(array)->Free(
+        ThreadStateFor<ThreadingTrait<
+            HeapHashTableBacking<HashTable>>::kAffinity>::GetState()
+            ->heap_handle());
+  }
+
+  template <typename T, typename HashTable>
+  static bool ExpandHashTableBacking(T* array, size_t new_size) {
+    DCHECK(array);
+    return HeapHashTableBacking<HashTable>::FromArray(array)->Resize(new_size);
+  }
+
+  static bool IsAllocationAllowed() {
+    return cppgc::subtle::DisallowGarbageCollectionScope::
+        IsGarbageCollectionAllowed(ThreadState::Current()->heap_handle());
+  }
+
+  static bool IsIncrementalMarking() {
+    auto& heap_handle = ThreadState::Current()->heap_handle();
+    return cppgc::subtle::HeapState::IsMarking(heap_handle) &&
+           !cppgc::subtle::HeapState::IsInAtomicPause(heap_handle);
+  }
+
+  static void EnterGCForbiddenScope() {
+    cppgc::subtle::NoGarbageCollectionScope::Enter(
+        ThreadState::Current()->cpp_heap().GetHeapHandle());
+  }
+
+  static void LeaveGCForbiddenScope() {
+    cppgc::subtle::NoGarbageCollectionScope::Leave(
+        ThreadState::Current()->cpp_heap().GetHeapHandle());
+  }
+
+  template <typename Traits>
+  static bool CanReuseHashTableDeletedBucket() {
+    if (Traits::kEmptyValueIsZero || !Traits::kCanTraceConcurrently)
+      return true;
+    return !IsIncrementalMarking();
+  }
+
+  template <typename T>
+  static void BackingWriteBarrier(T** slot) {
+    WriteBarrier::DispatchForObject(slot);
+  }
+
+  template <typename T>
+  static void TraceBackingStoreIfMarked(T* object) {
+    HeapConsistency::WriteBarrierParams params;
+    if (HeapConsistency::GetWriteBarrierType(object, params) ==
+        HeapConsistency::WriteBarrierType::kMarking) {
+      HeapConsistency::SteeleWriteBarrier(params, object);
+    }
+  }
+
+  template <typename T, typename Traits>
+  static void NotifyNewObject(T* slot_in_backing) {
+    HeapConsistency::WriteBarrierParams params;
+    // `slot_in_backing` points into a backing store and T is not necessarily a
+    // garbage collected type but may be kept inline.
+    switch (HeapConsistency::GetWriteBarrierType(
+        slot_in_backing, params, []() -> cppgc::HeapHandle& {
+          return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+              ->heap_handle();
+        })) {
+      case HeapConsistency::WriteBarrierType::kMarking:
+        HeapConsistency::DijkstraWriteBarrierRange(
+            params, slot_in_backing, sizeof(T), 1,
+            TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
+        break;
+      case HeapConsistency::WriteBarrierType::kGenerational:
+        HeapConsistency::GenerationalBarrier(params, slot_in_backing);
+        break;
+      case HeapConsistency::WriteBarrierType::kNone:
+        break;
+      default:
+        break;  // TODO(1056170): Remove default case when API is stable.
+    }
+  }
+
+  template <typename T, typename Traits>
+  static void NotifyNewObjects(T* first_element, size_t length) {
+    HeapConsistency::WriteBarrierParams params;
+    // `first_element` points into a backing store and T is not necessarily a
+    // garbage collected type but may be kept inline.
+    switch (HeapConsistency::GetWriteBarrierType(
+        first_element, params, []() -> cppgc::HeapHandle& {
+          return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
+              ->heap_handle();
+        })) {
+      case HeapConsistency::WriteBarrierType::kMarking:
+        HeapConsistency::DijkstraWriteBarrierRange(
+            params, first_element, sizeof(T), length,
+            TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
+        break;
+      case HeapConsistency::WriteBarrierType::kGenerational:
+        HeapConsistency::GenerationalBarrier(params, first_element);
+        break;
+      case HeapConsistency::WriteBarrierType::kNone:
+        break;
+      default:
+        break;  // TODO(1056170): Remove default case when API is stable.
+    }
+  }
+
+  template <typename T, typename Traits>
+  static void Trace(Visitor* visitor, const T& t) {
+    TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T,
+                             Traits>::Trace(visitor, &t);
+  }
+
+  template <typename T>
+  static void TraceVectorBacking(Visitor* visitor,
+                                 const T* backing,
+                                 const T* const* backing_slot) {
+    visitor->RegisterMovableReference(const_cast<const HeapVectorBacking<T>**>(
+        reinterpret_cast<const HeapVectorBacking<T>* const*>(backing_slot)));
+    visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing));
+  }
+
+  template <typename T, typename HashTable>
+  static void TraceHashTableBackingStrongly(Visitor* visitor,
+                                            const T* backing,
+                                            const T* const* backing_slot) {
+    visitor->RegisterMovableReference(
+        const_cast<const HeapHashTableBacking<HashTable>**>(
+            reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
+                backing_slot)));
+    visitor->Trace(
+        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing));
+  }
+
+  template <typename T, typename HashTable>
+  static void TraceHashTableBackingWeakly(Visitor* visitor,
+                                          const T* backing,
+                                          const T* const* backing_slot,
+                                          WeakCallback callback,
+                                          const void* parameter) {
+    visitor->RegisterMovableReference(
+        const_cast<const HeapHashTableBacking<HashTable>**>(
+            reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
+                backing_slot)));
+    visitor->TraceWeakContainer(
+        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing),
+        callback, parameter);
+  }
+
+  static bool DeferTraceToMutatorThreadIfConcurrent(Visitor* visitor,
+                                                    const void* object,
+                                                    TraceCallback callback,
+                                                    size_t deferred_size) {
+    return visitor->DeferTraceToMutatorThreadIfConcurrent(object, callback,
+                                                          deferred_size);
+  }
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
deleted file mode 100644
index 3cda388..0000000
--- a/third_party/blink/renderer/platform/heap/heap_stats_collector.h
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.cc b/third_party/blink/renderer/platform/heap/heap_test_utilities.cc
similarity index 100%
rename from third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.cc
rename to third_party/blink/renderer/platform/heap/heap_test_utilities.cc
diff --git a/third_party/blink/renderer/platform/heap/heap_test_utilities.h b/third_party/blink/renderer/platform/heap/heap_test_utilities.h
index 8461f8af..b7cee4d 100644
--- a/third_party/blink/renderer/platform/heap/heap_test_utilities.h
+++ b/third_party/blink/renderer/platform/heap/heap_test_utilities.h
@@ -5,6 +5,96 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8-cppgc.h"
+#include "v8.h"
+#include "v8/include/cppgc/testing.h"
+
+namespace blink {
+
+// Allows for overriding the stack state for the purpose of testing. Any garbage
+// collection calls scoped with `HeapPointersOnStackScope` will perform
+// conservative stack scanning, even if other (more local) hints indicate that
+// there's no need for it.
+class HeapPointersOnStackScope final {
+  STACK_ALLOCATED();
+
+ public:
+  explicit HeapPointersOnStackScope(const ThreadState* state)
+      : embedder_stack_state_(
+            state->cpp_heap().GetHeapHandle(),
+            cppgc::EmbedderStackState::kMayContainHeapPointers) {}
+
+  HeapPointersOnStackScope(const HeapPointersOnStackScope&) = delete;
+  HeapPointersOnStackScope& operator=(const HeapPointersOnStackScope&) = delete;
+
+ private:
+  cppgc::testing::OverrideEmbedderStackStateScope embedder_stack_state_;
+};
+
+class TestSupportingGC : public testing::Test {
+ public:
+  ~TestSupportingGC() override;
+
+  // Performs a precise garbage collection with eager sweeping.
+  static void PreciselyCollectGarbage();
+
+  // Performs a conservative garbage collection with eager sweeping.
+  static void ConservativelyCollectGarbage();
+
+  // Performs multiple rounds of garbage collections until no more memory can be
+  // freed. This is useful to avoid other garbage collections having to deal
+  // with stale memory.
+  static void ClearOutOldGarbage();
+
+ protected:
+  base::test::TaskEnvironment task_environment_;
+};
+
+// Test driver for compaction.
+class CompactionTestDriver {
+ public:
+  explicit CompactionTestDriver(ThreadState*);
+
+  void ForceCompactionForNextGC();
+
+ protected:
+  cppgc::testing::StandaloneTestingHeap heap_;
+};
+
+// Test driver for incremental marking. Assumes that no stack handling is
+// required.
+class IncrementalMarkingTestDriver {
+ public:
+  explicit IncrementalMarkingTestDriver(ThreadState*);
+  ~IncrementalMarkingTestDriver();
+
+  virtual void StartGC();
+  virtual void TriggerMarkingSteps(
+      BlinkGC::StackState stack_state =
+          BlinkGC::StackState::kNoHeapPointersOnStack);
+  virtual void FinishGC();
+
+ protected:
+  cppgc::testing::StandaloneTestingHeap heap_;
+};
+
+// Test driver for concurrent marking. Assumes that no stack handling is
+// required.
+class ConcurrentMarkingTestDriver : public IncrementalMarkingTestDriver {
+ public:
+  explicit ConcurrentMarkingTestDriver(ThreadState*);
+
+  void StartGC() override;
+  void TriggerMarkingSteps(
+      BlinkGC::StackState stack_state =
+          BlinkGC::StackState::kNoHeapPointersOnStack) override;
+  void FinishGC() override;
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TEST_UTILITIES_H_
diff --git a/third_party/blink/renderer/platform/heap/member.h b/third_party/blink/renderer/platform/heap/member.h
index b8487f1a..3324d5b1 100644
--- a/third_party/blink/renderer/platform/heap/member.h
+++ b/third_party/blink/renderer/platform/heap/member.h
@@ -5,15 +5,52 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
 
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/write_barrier.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
 #include "third_party/blink/renderer/platform/wtf/hash_functions.h"
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
 #include "third_party/blink/renderer/platform/wtf/type_traits.h"
-
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/member.h"
+#include "v8/include/cppgc/member.h"
 
 namespace blink {
 
 template <typename T>
+using Member = cppgc::Member<T>;
+
+template <typename T>
+using WeakMember = cppgc::WeakMember<T>;
+
+template <typename T>
+using UntracedMember = cppgc::UntracedMember<T>;
+
+template <typename T>
+inline bool IsHashTableDeletedValue(const Member<T>& m) {
+  return m == cppgc::kSentinelPointer;
+}
+
+constexpr auto kMemberDeletedValue = cppgc::kSentinelPointer;
+
+template <typename T>
+struct ThreadingTrait<blink::Member<T>> {
+  STATIC_ONLY(ThreadingTrait);
+  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
+template <typename T>
+struct ThreadingTrait<blink::WeakMember<T>> {
+  STATIC_ONLY(ThreadingTrait);
+  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
+template <typename T>
+struct ThreadingTrait<blink::UntracedMember<T>> {
+  STATIC_ONLY(ThreadingTrait);
+  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
+};
+
+template <typename T>
 inline void swap(Member<T>& a, Member<T>& b) {
   a.Swap(b);
 }
@@ -121,6 +158,47 @@
 struct HashTraits<blink::UntracedMember<T>>
     : BaseMemberHashTraits<T, blink::UntracedMember<T>> {};
 
+template <typename T, typename Traits, typename Allocator>
+class MemberConstructTraits {
+  STATIC_ONLY(MemberConstructTraits);
+
+ public:
+  template <typename... Args>
+  static T* Construct(void* location, Args&&... args) {
+    return new (NotNullTag::kNotNull, location) T(std::forward<Args>(args)...);
+  }
+
+  static void NotifyNewElement(T* element) {
+    blink::WriteBarrier::DispatchForObject(element);
+  }
+
+  template <typename... Args>
+  static T* ConstructAndNotifyElement(void* location, Args&&... args) {
+    // ConstructAndNotifyElement updates an existing Member which might
+    // also be comncurrently traced while we update it. The regular ctors
+    // for Member don't use an atomic write which can lead to data races.
+    T* object = Construct(location, std::forward<Args>(args)...,
+                          typename T::AtomicInitializerTag());
+    NotifyNewElement(object);
+    return object;
+  }
+
+  static void NotifyNewElements(T* array, size_t len) {
+    while (len-- > 0) {
+      blink::WriteBarrier::DispatchForObject(array);
+      array++;
+    }
+  }
+};
+
+template <typename T, typename Traits, typename Allocator>
+class ConstructTraits<blink::Member<T>, Traits, Allocator>
+    : public MemberConstructTraits<blink::Member<T>, Traits, Allocator> {};
+
+template <typename T, typename Traits, typename Allocator>
+class ConstructTraits<blink::WeakMember<T>, Traits, Allocator>
+    : public MemberConstructTraits<blink::WeakMember<T>, Traits, Allocator> {};
+
 }  // namespace WTF
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
diff --git a/third_party/blink/renderer/platform/heap/persistent.h b/third_party/blink/renderer/platform/heap/persistent.h
index 8ad0b11..3255718 100644
--- a/third_party/blink/renderer/platform/heap/persistent.h
+++ b/third_party/blink/renderer/platform/heap/persistent.h
@@ -5,15 +5,78 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_
 
+#include "base/bind.h"
+#include "third_party/blink/renderer/platform/bindings/buildflags.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
 #include "third_party/blink/renderer/platform/wtf/type_traits.h"
 #include "third_party/blink/renderer/platform/wtf/vector_traits.h"
-
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h"
+#include "v8/include/cppgc/cross-thread-persistent.h"
+#include "v8/include/cppgc/persistent.h"
+#include "v8/include/cppgc/source-location.h"
 
 namespace blink {
 
+template <typename T>
+using Persistent = cppgc::Persistent<T>;
+
+template <typename T>
+using WeakPersistent = cppgc::WeakPersistent<T>;
+
+template <typename T>
+using CrossThreadPersistent = cppgc::subtle::CrossThreadPersistent<T>;
+
+template <typename T>
+using CrossThreadWeakPersistent = cppgc::subtle::WeakCrossThreadPersistent<T>;
+
+using PersistentLocation = cppgc::SourceLocation;
+
+template <typename T>
+Persistent<T> WrapPersistent(
+    T* value,
+    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+  return Persistent<T>(value, loc);
+}
+
+template <typename T>
+WeakPersistent<T> WrapWeakPersistent(
+    T* value,
+    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+  return WeakPersistent<T>(value, loc);
+}
+
+template <typename T>
+CrossThreadPersistent<T> WrapCrossThreadPersistent(
+    T* value,
+    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+  return CrossThreadPersistent<T>(value, loc);
+}
+
+template <typename T>
+CrossThreadWeakPersistent<T> WrapCrossThreadWeakPersistent(
+    T* value,
+    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
+  return CrossThreadWeakPersistent<T>(value, loc);
+}
+
+#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+#define PERSISTENT_FROM_HERE PersistentLocation::Current()
+#else
+#define PERSISTENT_FROM_HERE PersistentLocation()
+#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
+
+template <typename U, typename T, typename weakness>
+cppgc::internal::BasicPersistent<U, weakness> DownCast(
+    const cppgc::internal::BasicPersistent<T, weakness>& p) {
+  return p.template To<U>();
+}
+
+template <typename U, typename T, typename weakness>
+cppgc::internal::BasicCrossThreadPersistent<U, weakness> DownCast(
+    const cppgc::internal::BasicCrossThreadPersistent<T, weakness>& p) {
+  return p.template To<U>();
+}
+
 template <typename T,
           typename = std::enable_if_t<WTF::IsGarbageCollectedType<T>::value>>
 Persistent<T> WrapPersistentIfNeeded(T* value) {
diff --git a/third_party/blink/renderer/platform/heap/process_heap.h b/third_party/blink/renderer/platform/heap/process_heap.h
index d94b420..8ce02f2 100644
--- a/third_party/blink/renderer/platform/heap/process_heap.h
+++ b/third_party/blink/renderer/platform/heap/process_heap.h
@@ -5,6 +5,30 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h"
+#include "gin/public/cppgc.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/cppgc/platform.h"
+#include "v8/include/cppgc/process-heap-statistics.h"
+
+namespace blink {
+
+// TODO(1056170): Implement wrapper.
+class PLATFORM_EXPORT ProcessHeap {
+  STATIC_ONLY(ProcessHeap);
+
+ public:
+  static void Init() { gin::InitializeCppgcFromV8Platform(); }
+
+  static size_t TotalAllocatedObjectSize() {
+    return cppgc::ProcessHeapStatistics::TotalAllocatedObjectSize();
+  }
+
+  static size_t TotalAllocatedSpace() {
+    return cppgc::ProcessHeapStatistics::TotalAllocatedSpace();
+  }
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/test/blink_gc_memory_dump_provider_test.cc b/third_party/blink/renderer/platform/heap/test/blink_gc_memory_dump_provider_test.cc
index 00d3633..7822a08 100644
--- a/third_party/blink/renderer/platform/heap/test/blink_gc_memory_dump_provider_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/blink_gc_memory_dump_provider_test.cc
@@ -8,9 +8,9 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
 #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_local.h b/third_party/blink/renderer/platform/heap/thread_local.h
similarity index 90%
rename from third_party/blink/renderer/platform/heap/v8_wrapper/thread_local.h
rename to third_party/blink/renderer/platform/heap/thread_local.h
index 1a0c43b0..84ef435 100644
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_local.h
+++ b/third_party/blink/renderer/platform/heap/thread_local.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_LOCAL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_LOCAL_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_LOCAL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_LOCAL_H_
 
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
@@ -60,4 +60,4 @@
 
 #endif  // defined(BLINK_HEAP_HIDE_THREAD_LOCAL_IN_LIBRARY)
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_LOCAL_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_LOCAL_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc
similarity index 98%
rename from third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.cc
rename to third_party/blink/renderer/platform/heap/thread_state.cc
index e5c73a6..ace275d 100644
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.cc
+++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
 
 #include "gin/public/v8_platform.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
+#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "v8/include/cppgc/heap-consistency.h"
diff --git a/third_party/blink/renderer/platform/heap/thread_state.h b/third_party/blink/renderer/platform/heap/thread_state.h
index 0e077f4..b8bdf7e 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.h
+++ b/third_party/blink/renderer/platform/heap/thread_state.h
@@ -5,6 +5,174 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+#include "third_party/blink/renderer/platform/heap/blink_gc.h"
+#include "third_party/blink/renderer/platform/heap/thread_local.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/threading.h"
+#include "v8-profiler.h"
+#include "v8/include/cppgc/heap-consistency.h"
+#include "v8/include/cppgc/prefinalizer.h"
+#include "v8/include/v8-callbacks.h"
+#include "v8/include/v8-cppgc.h"
+
+namespace v8 {
+class CppHeap;
+}  // namespace v8
+
+namespace cppgc {
+class AllocationHandle;
+}  // namespace cppgc
+
+namespace v8 {
+class EmbedderGraph;
+class EmbedderRootsHandler;
+}  // namespace v8
+
+namespace blink {
+
+#define USING_PRE_FINALIZER(Class, PreFinalizer) \
+  CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer)
+
+// ThreadAffinity indicates which threads objects can be used on. We
+// distinguish between objects that can be used on the main thread
+// only and objects that can be used on any thread.
+//
+// For objects that can only be used on the main thread, we avoid going
+// through thread-local storage to get to the thread state. This is
+// important for performance.
+enum ThreadAffinity {
+  kAnyThread,
+  kMainThreadOnly,
+};
+
+template <typename T, typename = void>
+struct ThreadingTrait {
+  STATIC_ONLY(ThreadingTrait);
+  static constexpr ThreadAffinity kAffinity = kAnyThread;
+};
+
+template <ThreadAffinity>
+class ThreadStateFor;
+class ThreadState;
+
+using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*,
+                                              v8::EmbedderGraph*,
+                                              void*);
+
+// Storage for all ThreadState objects. This includes the main-thread
+// ThreadState as well. Keep it outside the class so that PLATFORM_EXPORT
+// doesn't apply to it (otherwise, clang-cl complains).
+extern thread_local ThreadState* g_thread_specific_ CONSTINIT
+    __attribute__((tls_model(BLINK_HEAP_THREAD_LOCAL_MODEL)));
+
+class PLATFORM_EXPORT ThreadState final {
+ public:
+  class NoAllocationScope;
+  class GCForbiddenScope;
+
+  BLINK_HEAP_DECLARE_THREAD_LOCAL_GETTER(Current,
+                                         ThreadState*,
+                                         g_thread_specific_)
+
+  static ALWAYS_INLINE ThreadState* MainThreadState() {
+    return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
+  }
+
+  // Attaches a ThreadState to the main-thread.
+  static ThreadState* AttachMainThread();
+  // Attaches a ThreadState to the currently running thread. Must not be the
+  // main thread and must be called after AttachMainThread().
+  static ThreadState* AttachCurrentThread();
+  static void DetachCurrentThread();
+
+  void AttachToIsolate(v8::Isolate* isolate, V8BuildEmbedderGraphCallback);
+  void DetachFromIsolate();
+
+  ALWAYS_INLINE cppgc::AllocationHandle& allocation_handle() const {
+    return allocation_handle_;
+  }
+  ALWAYS_INLINE cppgc::HeapHandle& heap_handle() const { return heap_handle_; }
+  ALWAYS_INLINE v8::CppHeap& cpp_heap() const { return *cpp_heap_; }
+  ALWAYS_INLINE v8::Isolate* GetIsolate() const { return isolate_; }
+
+  void SafePoint(BlinkGC::StackState);
+
+  bool IsMainThread() const { return this == MainThreadState(); }
+  bool IsCreationThread() const { return thread_id_ == CurrentThread(); }
+
+  void NotifyGarbageCollection(v8::GCType, v8::GCCallbackFlags);
+
+  bool InAtomicSweepingPause() const {
+    auto& heap_handle = cpp_heap().GetHeapHandle();
+    return cppgc::subtle::HeapState::IsInAtomicPause(heap_handle) &&
+           cppgc::subtle::HeapState::IsSweeping(heap_handle);
+  }
+
+  bool IsAllocationAllowed() const {
+    return cppgc::subtle::DisallowGarbageCollectionScope::
+        IsGarbageCollectionAllowed(cpp_heap().GetHeapHandle());
+  }
+
+  // Waits until sweeping is done and invokes the given callback with
+  // the total sizes of live objects in Node and CSS arenas.
+  void CollectNodeAndCssStatistics(
+      base::OnceCallback<void(size_t allocated_node_bytes,
+                              size_t allocated_css_bytes)>);
+
+  bool IsIncrementalMarking();
+
+  // Forced garbage collection for testing:
+  //
+  // Collects garbage as long as live memory decreases (capped at 5).
+  void CollectAllGarbageForTesting(
+      BlinkGC::StackState stack_state =
+          BlinkGC::StackState::kNoHeapPointersOnStack);
+
+  void EnableDetachedGarbageCollectionsForTesting();
+
+  static ThreadState* AttachMainThreadForTesting(v8::Platform*);
+  static ThreadState* AttachCurrentThreadForTesting(v8::Platform*);
+
+ private:
+  // Main-thread ThreadState avoids TLS completely by using a regular global.
+  // The object is manually managed and should not rely on global ctor/dtor.
+  static uint8_t main_thread_state_storage_[];
+
+  explicit ThreadState(v8::Platform*);
+  ~ThreadState();
+
+  std::unique_ptr<v8::CppHeap> cpp_heap_;
+  std::unique_ptr<v8::EmbedderRootsHandler> embedder_roots_handler_;
+  cppgc::AllocationHandle& allocation_handle_;
+  cppgc::HeapHandle& heap_handle_;
+  v8::Isolate* isolate_ = nullptr;
+  base::PlatformThreadId thread_id_;
+  bool forced_scheduled_gc_for_testing_ = false;
+};
+
+template <>
+class ThreadStateFor<kMainThreadOnly> {
+  STATIC_ONLY(ThreadStateFor);
+
+ public:
+  static ALWAYS_INLINE ThreadState* GetState() {
+    return ThreadState::MainThreadState();
+  }
+};
+
+template <>
+class ThreadStateFor<kAnyThread> {
+  STATIC_ONLY(ThreadStateFor);
+
+ public:
+  static ALWAYS_INLINE ThreadState* GetState() {
+    return ThreadState::Current();
+  }
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
diff --git a/third_party/blink/renderer/platform/heap/thread_state_scopes.h b/third_party/blink/renderer/platform/heap/thread_state_scopes.h
index 9a64977..68457f8f 100644
--- a/third_party/blink/renderer/platform/heap/thread_state_scopes.h
+++ b/third_party/blink/renderer/platform/heap/thread_state_scopes.h
@@ -5,12 +5,44 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_
 
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h"
+#include "v8/include/cppgc/heap-consistency.h"
 
 namespace blink {
 
+// The NoAllocationScope class is used in debug mode to catch unwanted
+// allocations. E.g. allocations during GC.
+class ThreadState::NoAllocationScope final {
+  STACK_ALLOCATED();
+
+ public:
+  explicit NoAllocationScope(ThreadState* state)
+      : disallow_gc_(state->cpp_heap().GetHeapHandle()) {}
+
+  NoAllocationScope(const NoAllocationScope&) = delete;
+  NoAllocationScope& operator=(const NoAllocationScope&) = delete;
+
+ private:
+  const cppgc::subtle::DisallowGarbageCollectionScope disallow_gc_;
+};
+
+// The GCForbiddenScope class is used to prevent GC finalization
+// when it is not safe to do so.
+class ThreadState::GCForbiddenScope final {
+  STACK_ALLOCATED();
+
+ public:
+  explicit GCForbiddenScope(ThreadState* state)
+      : no_gc_(state->cpp_heap().GetHeapHandle()) {}
+
+  GCForbiddenScope(const NoAllocationScope&) = delete;
+  GCForbiddenScope& operator=(const NoAllocationScope&) = delete;
+
+ private:
+  const cppgc::subtle::NoGarbageCollectionScope no_gc_;
+};
+
 #if defined(LEAK_SANITIZER)
 class LsanDisabledScope final {
   STACK_ALLOCATED();
diff --git a/third_party/blink/renderer/platform/heap/trace_traits.h b/third_party/blink/renderer/platform/heap/trace_traits.h
index cb66498..91c92a1 100644
--- a/third_party/blink/renderer/platform/heap/trace_traits.h
+++ b/third_party/blink/renderer/platform/heap/trace_traits.h
@@ -5,15 +5,32 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
 
+#include <tuple>
+
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/wtf/hash_table.h"
-
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
+#include "v8/include/cppgc/trace-trait.h"
 
 namespace blink {
 
+template <typename T, bool = WTF::IsTraceable<T>::value>
+struct TraceIfNeeded;
+
+template <typename T>
+struct TraceIfNeeded<T, false> {
+  STATIC_ONLY(TraceIfNeeded);
+  static void Trace(Visitor*, const T&) {}
+};
+
+template <typename T>
+struct TraceIfNeeded<T, true> {
+  STATIC_ONLY(TraceIfNeeded);
+  static void Trace(Visitor* visitor, const T& t) { visitor->Trace(t); }
+};
+
 template <WTF::WeakHandlingFlag weakness,
           typename T,
           typename Traits,
@@ -121,4 +138,26 @@
 
 }  // namespace WTF
 
+namespace cppgc {
+
+// This trace trait for std::pair will null weak members if their referent is
+// collected. If you have a collection that contain weakness it does not remove
+// entries from the collection that contain nulled weak members.
+template <typename T, typename U>
+struct TraceTrait<std::pair<T, U>> {
+  STATIC_ONLY(TraceTrait);
+
+ public:
+  static TraceDescriptor GetTraceDescriptor(const void* self) {
+    return {self, Trace};
+  }
+
+  static void Trace(Visitor* visitor, const std::pair<T, U>* pair) {
+    blink::TraceIfNeeded<U>::Trace(visitor, pair->second);
+    blink::TraceIfNeeded<T>::Trace(visitor, pair->first);
+  }
+};
+
+}  // namespace cppgc
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_controller.h b/third_party/blink/renderer/platform/heap/unified_heap_controller.h
deleted file mode 100644
index 01ab304..0000000
--- a/third_party/blink/renderer/platform/heap/unified_heap_controller.h
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
index 3c1576e..5f6a7e40 100644
--- a/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
+++ b/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h
@@ -5,6 +5,47 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h"
+#include "base/compiler_specific.h"
+#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/v8-cppgc.h"
+#include "v8/include/v8-traced-handle.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT UnifiedHeapMarkingVisitor final {
+  STATIC_ONLY(UnifiedHeapMarkingVisitor);
+
+ public:
+  static ALWAYS_INLINE void WriteBarrier(
+      const v8::TracedReference<v8::Value>& ref) {
+    v8::JSHeapConsistency::WriteBarrierParams params;
+    if (v8::JSHeapConsistency::GetWriteBarrierType(
+            ref, params, []() -> cppgc::HeapHandle& {
+              return ThreadState::Current()->heap_handle();
+            }) == v8::JSHeapConsistency::WriteBarrierType::kMarking) {
+      v8::JSHeapConsistency::DijkstraMarkingBarrier(
+          params, ThreadState::Current()->heap_handle(), ref);
+    }
+  }
+
+  static ALWAYS_INLINE void WriteBarrier(v8::Isolate*,
+                                         v8::Local<v8::Object>& wrapper,
+                                         const WrapperTypeInfo*,
+                                         const void* wrappable) {
+    v8::JSHeapConsistency::WriteBarrierParams params;
+    if (v8::JSHeapConsistency::GetWriteBarrierType(
+            wrapper, kV8DOMWrapperObjectIndex, wrappable, params,
+            []() -> cppgc::HeapHandle& {
+              return ThreadState::Current()->heap_handle();
+            }) == v8::JSHeapConsistency::WriteBarrierType::kMarking) {
+      v8::JSHeapConsistency::DijkstraMarkingBarrier(
+          params, ThreadState::Current()->heap_handle(), wrappable);
+    }
+  }
+};
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h b/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h
deleted file mode 100644
index b5fe0b2..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
-
-#include "third_party/blink/renderer/platform/heap/forward.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8/include/cppgc/liveness-broker.h"
-#include "v8/include/cppgc/trace-trait.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT BlinkGC final {
-  STATIC_ONLY(BlinkGC);
-
- public:
-  // When garbage collecting we need to know whether or not there can be
-  // pointers to Oilpan-managed objects on the stack for each thread. When
-  // threads reach a safe point they record whether or not they have pointers on
-  // the stack.
-  enum StackState { kNoHeapPointersOnStack, kHeapPointersOnStack };
-};
-
-using Address = uint8_t*;
-using ConstAddress = const uint8_t*;
-
-using TraceCallback = cppgc::TraceCallback;
-using WeakCallback = void (*)(const cppgc::LivenessBroker&, const void*);
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h b/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h
deleted file mode 100644
index 0bb476f..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
-
-#include "base/trace_event/memory_dump_provider.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
-
-namespace blink {
-
-class ThreadState;
-
-class PLATFORM_EXPORT BlinkGCMemoryDumpProvider final
-    : public base::trace_event::MemoryDumpProvider {
-  USING_FAST_MALLOC(BlinkGCMemoryDumpProvider);
-
- public:
-  enum class HeapType { kBlinkMainThread, kBlinkWorkerThread };
-
-  ~BlinkGCMemoryDumpProvider() final;
-  BlinkGCMemoryDumpProvider(ThreadState*,
-                            scoped_refptr<base::SingleThreadTaskRunner>,
-                            HeapType);
-
-  // MemoryDumpProvider implementation.
-  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
-                    base::trace_event::ProcessMemoryDump*) final;
-
- private:
-  ThreadState* const thread_state_;
-  const HeapType heap_type_;
-  const std::string dump_base_name_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h b/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h
deleted file mode 100644
index ad05f4a5..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_hash_table_backing.h
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
-
-#include <type_traits>
-#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
-#include "third_party/blink/renderer/platform/wtf/hash_table.h"
-#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
-#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
-#include "v8/include/cppgc/custom-space.h"
-#include "v8/include/cppgc/explicit-management.h"
-#include "v8/include/cppgc/object-size-trait.h"
-
-namespace blink {
-
-template <typename Table>
-class HeapHashTableBacking final
-    : public GarbageCollected<HeapHashTableBacking<Table>>,
-      public WTF::ConditionalDestructor<
-          HeapHashTableBacking<Table>,
-          std::is_trivially_destructible<typename Table::ValueType>::value> {
-  using ClassType = HeapHashTableBacking<Table>;
-  using ValueType = typename Table::ValueType;
-
- public:
-  // Although the HeapHashTableBacking is fully constructed, the array resulting
-  // from ToArray may not be fully constructed as the elements of the array are
-  // not initialized and may have null vtable pointers. Null vtable pointer
-  // violates CFI for polymorphic types.
-  NO_SANITIZE_UNRELATED_CAST ALWAYS_INLINE static ValueType* ToArray(
-      ClassType* backing) {
-    return reinterpret_cast<ValueType*>(backing);
-  }
-
-  ALWAYS_INLINE static ClassType* FromArray(ValueType* array) {
-    return reinterpret_cast<ClassType*>(array);
-  }
-
-  void Free(cppgc::HeapHandle& heap_handle) {
-    cppgc::subtle::FreeUnreferencedObject(heap_handle, *this);
-  }
-
-  bool Resize(size_t new_size) {
-    return cppgc::subtle::Resize(*this, GetAdditionalBytes(new_size));
-  }
-
-  // Conditionally invoked via destructor.
-  void Finalize();
-
- private:
-  static cppgc::AdditionalBytes GetAdditionalBytes(size_t wanted_array_size) {
-    // HHTB is an empty class that's purely used with inline storage. Since its
-    // sizeof(HHTB) == 1, we need to subtract its size to avoid wasting storage.
-    static_assert(sizeof(ClassType) == 1, "Class declaration changed");
-    DCHECK_GE(wanted_array_size, sizeof(ClassType));
-    return cppgc::AdditionalBytes{wanted_array_size - sizeof(ClassType)};
-  }
-};
-
-template <typename Table>
-void HeapHashTableBacking<Table>::Finalize() {
-  using Value = typename Table::ValueType;
-  static_assert(
-      !std::is_trivially_destructible<Value>::value,
-      "Finalization of trivially destructible classes should not happen.");
-  const size_t object_size =
-      cppgc::subtle::ObjectSizeTrait<HeapHashTableBacking<Table>>::GetSize(
-          *this);
-  const size_t length = object_size / sizeof(Value);
-  Value* table = reinterpret_cast<Value*>(this);
-  for (unsigned i = 0; i < length; ++i) {
-    if (!Table::IsEmptyOrDeletedBucket(table[i]))
-      table[i].~Value();
-  }
-}
-
-template <typename Table>
-struct ThreadingTrait<HeapHashTableBacking<Table>> {
-  STATIC_ONLY(ThreadingTrait);
-  using Key = typename Table::KeyType;
-  using Value = typename Table::ValueType;
-  static constexpr ThreadAffinity kAffinity =
-      (ThreadingTrait<Key>::kAffinity == kMainThreadOnly) &&
-              (ThreadingTrait<Value>::kAffinity == kMainThreadOnly)
-          ? kMainThreadOnly
-          : kAnyThread;
-};
-
-template <typename First, typename Second>
-struct ThreadingTrait<WTF::KeyValuePair<First, Second>> {
-  STATIC_ONLY(ThreadingTrait);
-  static constexpr ThreadAffinity kAffinity =
-      (ThreadingTrait<First>::kAffinity == kMainThreadOnly) &&
-              (ThreadingTrait<Second>::kAffinity == kMainThreadOnly)
-          ? kMainThreadOnly
-          : kAnyThread;
-};
-
-}  // namespace blink
-
-namespace WTF {
-
-namespace internal {
-
-// ConcurrentBucket is a wrapper for HashTable buckets for concurrent marking.
-// It is used to provide a snapshot view of the bucket key and guarantee
-// that the same key is used for checking empty/deleted buckets and tracing.
-template <typename T>
-class ConcurrentBucket {
-  using KeyExtractionCallback = void (*)(const T&, void*);
-
- public:
-  using BucketType = T;
-
-  ConcurrentBucket(const T& t, KeyExtractionCallback extract_key) {
-    extract_key(t, &buf_);
-  }
-
-  // for HashTable that don't use KeyValuePair (i.e. *HashSets), the key
-  // and the value are the same.
-  const T* key() const { return reinterpret_cast<const T*>(&buf_); }
-  const T* value() const { return key(); }
-  const T* bucket() const { return key(); }
-
- private:
-  // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
-  // can be accessed the same as objects of type T
-  static constexpr size_t boundary = std::max(alignof(T), sizeof(size_t));
-  alignas(boundary) char buf_[sizeof(T)];
-};
-
-template <typename Key, typename Value>
-class ConcurrentBucket<KeyValuePair<Key, Value>> {
-  using KeyExtractionCallback = void (*)(const KeyValuePair<Key, Value>&,
-                                         void*);
-
- public:
-  using BucketType = ConcurrentBucket;
-
-  ConcurrentBucket(const KeyValuePair<Key, Value>& pair,
-                   KeyExtractionCallback extract_key)
-      : value_(&pair.value) {
-    extract_key(pair, &buf_);
-  }
-
-  const Key* key() const { return reinterpret_cast<const Key*>(&buf_); }
-  const Value* value() const { return value_; }
-  const ConcurrentBucket* bucket() const { return this; }
-
- private:
-  // Alignment is needed for atomic accesses to |buf_| and to assure |buf_|
-  // can be accessed the same as objects of type Key
-  static constexpr size_t boundary = std::max(alignof(Key), sizeof(size_t));
-  alignas(boundary) char buf_[sizeof(Key)];
-  const Value* value_;
-};
-
-}  // namespace internal
-
-template <WTF::WeakHandlingFlag weak_handling, typename Table>
-struct TraceHashTableBackingInCollectionTrait {
-  using Value = typename Table::ValueType;
-  using Traits = typename Table::ValueTraits;
-  using Extractor = typename Table::ExtractorType;
-
-  static void Trace(blink::Visitor* visitor, const void* self) {
-    static_assert(IsTraceableInCollectionTrait<Traits>::value ||
-                      WTF::IsWeak<Value>::value,
-                  "Table should not be traced");
-    const Value* array = reinterpret_cast<const Value*>(self);
-    const size_t length =
-        cppgc::subtle::
-            ObjectSizeTrait<const blink::HeapHashTableBacking<Table>>::GetSize(
-                *reinterpret_cast<const blink::HeapHashTableBacking<Table>*>(
-                    self)) /
-        sizeof(Value);
-    for (size_t i = 0; i < length; ++i) {
-      internal::ConcurrentBucket<Value> concurrent_bucket(
-          array[i], Extractor::ExtractSafe);
-      if (!HashTableHelper<Value, Extractor, typename Table::KeyTraitsType>::
-              IsEmptyOrDeletedBucketForKey(*concurrent_bucket.key())) {
-        blink::TraceCollectionIfEnabled<
-            weak_handling,
-            typename internal::ConcurrentBucket<Value>::BucketType,
-            Traits>::Trace(visitor, concurrent_bucket.bucket());
-      }
-    }
-  }
-};
-
-}  // namespace WTF
-
-namespace cppgc {
-
-// Assign HeapVector to the custom HeapVectorBackingSpace.
-template <typename Table>
-struct SpaceTrait<blink::HeapHashTableBacking<Table>> {
-  using Space = blink::HeapHashTableBackingSpace;
-};
-
-// Custom allocation accounts for inlined storage of the actual elements of the
-// backing table.
-template <typename Table>
-class MakeGarbageCollectedTrait<blink::HeapHashTableBacking<Table>>
-    : public MakeGarbageCollectedTraitBase<blink::HeapHashTableBacking<Table>> {
- public:
-  using Backing = blink::HeapHashTableBacking<Table>;
-
-  template <typename... Args>
-  static Backing* Call(AllocationHandle& handle, size_t num_elements) {
-    static_assert(
-        !std::is_polymorphic<blink::HeapHashTableBacking<Table>>::value,
-        "HeapHashTableBacking must not be polymorphic as it is converted to a "
-        "raw array of buckets for certain operation");
-    CHECK_GT(num_elements, 0u);
-    // Allocate automatically considers the custom space via SpaceTrait.
-    void* memory = MakeGarbageCollectedTraitBase<Backing>::Allocate(
-        handle, sizeof(typename Table::ValueType) * num_elements);
-    Backing* object = ::new (memory) Backing();
-    MakeGarbageCollectedTraitBase<Backing>::MarkObjectAsFullyConstructed(
-        object);
-    return object;
-  }
-};
-
-template <typename Table>
-struct TraceTrait<blink::HeapHashTableBacking<Table>> {
-  using Backing = blink::HeapHashTableBacking<Table>;
-  using Traits = typename Table::ValueTraits;
-  using ValueType = typename Table::ValueTraits::TraitType;
-
-  static TraceDescriptor GetTraceDescriptor(const void* self) {
-    return {self, Trace<WTF::kNoWeakHandling>};
-  }
-
-  static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
-    return GetWeakTraceDescriptorImpl<ValueType>::GetWeakTraceDescriptor(self);
-  }
-
-  template <WTF::WeakHandlingFlag weak_handling = WTF::kNoWeakHandling>
-  static void Trace(Visitor* visitor, const void* self) {
-    if (!Traits::kCanTraceConcurrently && self) {
-      if (visitor->DeferTraceToMutatorThreadIfConcurrent(
-              self, &Trace<weak_handling>,
-              cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
-                  *reinterpret_cast<const Backing*>(self)))) {
-        return;
-      }
-    }
-
-    static_assert(WTF::IsTraceableInCollectionTrait<Traits>::value ||
-                      WTF::IsWeak<ValueType>::value,
-                  "T should not be traced");
-    WTF::TraceInCollectionTrait<weak_handling, Backing, void>::Trace(visitor,
-                                                                     self);
-  }
-
- private:
-  // Default setting for HashTable is without weak trace descriptor.
-  template <typename ValueType>
-  struct GetWeakTraceDescriptorImpl {
-    static TraceDescriptor GetWeakTraceDescriptor(const void* self) {
-      return {self, nullptr};
-    }
-  };
-
-  // Specialization for WTF::KeyValuePair, which is default bucket storage type.
-  template <typename K, typename V>
-  struct GetWeakTraceDescriptorImpl<WTF::KeyValuePair<K, V>> {
-    static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
-      return GetWeakTraceDescriptorKVPImpl<K, V>::GetWeakTraceDescriptor(
-          backing);
-    }
-
-    // Default setting for KVP without ephemeron semantics.
-    template <typename KeyType,
-              typename ValueType,
-              bool ephemeron_semantics = (WTF::IsWeak<KeyType>::value &&
-                                          !WTF::IsWeak<ValueType>::value &&
-                                          WTF::IsTraceable<ValueType>::value) ||
-                                         (WTF::IsWeak<ValueType>::value &&
-                                          !WTF::IsWeak<KeyType>::value &&
-                                          WTF::IsTraceable<KeyType>::value)>
-    struct GetWeakTraceDescriptorKVPImpl {
-      static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
-        return {backing, nullptr};
-      }
-    };
-
-    // Specialization for KVP with ephemeron semantics.
-    template <typename KeyType, typename ValueType>
-    struct GetWeakTraceDescriptorKVPImpl<KeyType, ValueType, true> {
-      static TraceDescriptor GetWeakTraceDescriptor(const void* backing) {
-        return {backing, Trace<WTF::kWeakHandling>};
-      }
-    };
-  };
-};
-
-}  // namespace cppgc
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h b/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h
deleted file mode 100644
index e2db74b9..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/collection_support/heap_vector_backing.h
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
-
-#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/trace_traits.h"
-#include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
-#include "third_party/blink/renderer/platform/wtf/container_annotations.h"
-#include "third_party/blink/renderer/platform/wtf/sanitizers.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
-#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
-#include "v8/include/cppgc/allocation.h"
-#include "v8/include/cppgc/custom-space.h"
-#include "v8/include/cppgc/explicit-management.h"
-#include "v8/include/cppgc/object-size-trait.h"
-#include "v8/include/cppgc/trace-trait.h"
-#include "v8/include/cppgc/visitor.h"
-
-namespace blink {
-namespace internal {
-
-inline bool VTableInitialized(const void* object_payload) {
-  return !!(*reinterpret_cast<const size_t*>(object_payload));
-}
-
-}  // namespace internal
-
-template <typename T, typename Traits = WTF::VectorTraits<T>>
-class HeapVectorBacking final
-    : public GarbageCollected<HeapVectorBacking<T, Traits>>,
-      public WTF::ConditionalDestructor<HeapVectorBacking<T, Traits>,
-                                        !Traits::kNeedsDestruction> {
-  using ClassType = HeapVectorBacking<T, Traits>;
-
- public:
-  // Although the HeapVectorBacking is fully constructed, the array resulting
-  // from ToArray may not be fully constructed as the elements of the array are
-  // not initialized and may have null vtable pointers. Null vtable pointer
-  // violates CFI for polymorphic types.
-  NO_SANITIZE_UNRELATED_CAST ALWAYS_INLINE static T* ToArray(
-      ClassType* backing) {
-    return reinterpret_cast<T*>(backing);
-  }
-
-  ALWAYS_INLINE static ClassType* FromArray(T* payload) {
-    return reinterpret_cast<ClassType*>(payload);
-  }
-
-  void Free(cppgc::HeapHandle& heap_handle) {
-    cppgc::subtle::FreeUnreferencedObject(heap_handle, *this);
-  }
-
-  bool Resize(size_t new_size) {
-    return cppgc::subtle::Resize(*this, GetAdditionalBytes(new_size));
-  }
-
-  // Conditionally invoked via destructor.
-  void Finalize();
-
- private:
-  static cppgc::AdditionalBytes GetAdditionalBytes(size_t wanted_array_size) {
-    // HVB is an empty class that's purely used with inline storage. Since its
-    // sizeof(HVB) == 1, we need to subtract its size to avoid wasting storage.
-    static_assert(sizeof(ClassType) == 1, "Class declaration changed");
-    DCHECK_GE(wanted_array_size, sizeof(ClassType));
-    return cppgc::AdditionalBytes{wanted_array_size - sizeof(ClassType)};
-  }
-};
-
-template <typename T, typename Traits>
-void HeapVectorBacking<T, Traits>::Finalize() {
-  static_assert(Traits::kNeedsDestruction,
-                "Only vector buffers with items requiring destruction should "
-                "be finalized");
-  static_assert(
-      Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic<T>::value,
-      "HeapVectorBacking doesn't support objects that cannot be cleared as "
-      "unused with memset or don't have a vtable");
-  static_assert(
-      !std::is_trivially_destructible<T>::value,
-      "Finalization of trivially destructible classes should not happen.");
-  const size_t object_size =
-      cppgc::subtle::ObjectSizeTrait<HeapVectorBacking<T, Traits>>::GetSize(
-          *this);
-  const size_t length = object_size / sizeof(T);
-  Address payload = reinterpret_cast<Address>(this);
-#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
-  ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T));
-#endif  // ANNOTATE_CONTIGUOUS_CONTAINER
-  // HeapVectorBacking calls finalizers for unused slots and expects them to be
-  // no-ops.
-  if (std::is_polymorphic<T>::value) {
-    for (size_t i = 0; i < length; ++i) {
-      Address element = payload + i * sizeof(T);
-      if (internal::VTableInitialized(element))
-        reinterpret_cast<T*>(element)->~T();
-    }
-  } else {
-    T* buffer = reinterpret_cast<T*>(payload);
-    for (size_t i = 0; i < length; ++i)
-      buffer[i].~T();
-  }
-}
-
-template <typename T, typename Traits>
-struct ThreadingTrait<HeapVectorBacking<T, Traits>> {
-  STATIC_ONLY(ThreadingTrait);
-  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
-};
-
-}  // namespace blink
-
-namespace WTF {
-
-// This trace method is used for all HeapVectorBacking objects. On-stack objects
-// are found and dispatched using conservative stack scanning. HeapVector (i.e.
-// Vector) dispatches all regular on-heap backings to this method.
-template <typename T, typename Traits>
-struct TraceInCollectionTrait<kNoWeakHandling,
-                              blink::HeapVectorBacking<T, Traits>,
-                              void> {
-  using Backing = blink::HeapVectorBacking<T, Traits>;
-
-  static void Trace(blink::Visitor* visitor, const void* self) {
-    // HeapVectorBacking does not know the exact size of the vector
-    // and just knows the capacity of the vector. Due to the constraint,
-    // HeapVectorBacking can support only the following objects:
-    //
-    // - An object that has a vtable. In this case, HeapVectorBacking
-    //   traces only slots that are not zeroed out. This is because if
-    //   the object has a vtable, the zeroed slot means that it is
-    //   an unused slot (Remember that the unused slots are guaranteed
-    //   to be zeroed out by VectorUnusedSlotClearer).
-    //
-    // - An object that can be initialized with memset. In this case,
-    //   HeapVectorBacking traces all slots including unused slots.
-    //   This is fine because the fact that the object can be initialized
-    //   with memset indicates that it is safe to treat the zerod slot
-    //   as a valid object.
-    static_assert(!IsTraceableInCollectionTrait<Traits>::value ||
-                      Traits::kCanClearUnusedSlotsWithMemset ||
-                      std::is_polymorphic<T>::value,
-                  "HeapVectorBacking doesn't support objects that cannot be "
-                  "cleared as unused with memset.");
-
-    // This trace method is instantiated for vectors where
-    // IsTraceableInCollectionTrait<Traits>::value is false, but the trace
-    // method should not be called. Thus we cannot static-assert
-    // IsTraceableInCollectionTrait<Traits>::value but should runtime-assert it.
-    DCHECK(IsTraceableInCollectionTrait<Traits>::value);
-
-    const T* array = reinterpret_cast<const T*>(self);
-    const size_t length =
-        cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
-            *reinterpret_cast<const Backing*>(self)) /
-        sizeof(T);
-#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
-    // As commented above, HeapVectorBacking can trace unused slots (which are
-    // already zeroed out).
-    ANNOTATE_CHANGE_SIZE(array, length, 0, length);
-#endif  // ANNOTATE_CONTIGUOUS_CONTAINER
-    if (std::is_polymorphic<T>::value) {
-      for (unsigned i = 0; i < length; ++i) {
-        if (blink::internal::VTableInitialized(&array[i])) {
-          blink::TraceIfNeeded<
-              T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
-                                                                     array[i]);
-        }
-      }
-    } else {
-      for (size_t i = 0; i < length; ++i) {
-        blink::TraceIfNeeded<
-            T, IsTraceableInCollectionTrait<Traits>::value>::Trace(visitor,
-                                                                   array[i]);
-      }
-    }
-  }
-};
-
-}  // namespace WTF
-
-namespace cppgc {
-
-// Assign HeapVector to the custom HeapVectorBackingSpace.
-template <typename T>
-struct SpaceTrait<blink::HeapVectorBacking<T>> {
-  using Space = blink::HeapVectorBackingSpace;
-};
-
-// Custom allocation accounts for inlined storage of the actual elements of the
-// backing array.
-template <typename T>
-class MakeGarbageCollectedTrait<blink::HeapVectorBacking<T>>
-    : public MakeGarbageCollectedTraitBase<blink::HeapVectorBacking<T>> {
-  using Backing = blink::HeapVectorBacking<T>;
-
- public:
-  template <typename... Args>
-  static Backing* Call(AllocationHandle& handle, size_t num_elements) {
-    static_assert(!std::is_polymorphic<blink::HeapVectorBacking<T>>::value,
-                  "HeapVectorBacking must not be polymorphic as it is "
-                  "converted to a raw array of buckets for certain operation");
-    CHECK_GT(num_elements, 0u);
-    // Allocate automatically considers the custom space via SpaceTrait.
-    void* memory = MakeGarbageCollectedTraitBase<Backing>::Allocate(
-        handle, sizeof(T) * num_elements);
-    Backing* object = ::new (memory) Backing();
-    MakeGarbageCollectedTraitBase<Backing>::MarkObjectAsFullyConstructed(
-        object);
-    return object;
-  }
-};
-
-template <typename T, typename Traits>
-struct TraceTrait<blink::HeapVectorBacking<T, Traits>> {
-  using Backing = blink::HeapVectorBacking<T, Traits>;
-
-  static TraceDescriptor GetTraceDescriptor(const void* self) {
-    return {self, Trace};
-  }
-
-  static void Trace(Visitor* visitor, const void* self) {
-    if (!Traits::kCanTraceConcurrently && self) {
-      if (visitor->DeferTraceToMutatorThreadIfConcurrent(
-              self, &Trace,
-              cppgc::subtle::ObjectSizeTrait<const Backing>::GetSize(
-                  *reinterpret_cast<const Backing*>(self)))) {
-        return;
-      }
-    }
-
-    static_assert(!WTF::IsWeak<T>::value,
-                  "Weakness is not supported in HeapVector and HeapDeque");
-    if (WTF::IsTraceableInCollectionTrait<Traits>::value) {
-      WTF::TraceInCollectionTrait<WTF::kNoWeakHandling,
-                                  blink::HeapVectorBacking<T, Traits>,
-                                  void>::Trace(visitor, self);
-    }
-  }
-};
-
-}  // namespace cppgc
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h b/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h
deleted file mode 100644
index 640cb332..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_CUSTOM_SPACES_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_CUSTOM_SPACES_H_
-
-#include <memory>
-#include <vector>
-
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "v8/include/cppgc/custom-space.h"
-
-namespace blink {
-
-// The following defines custom spaces that are used to partition Oilpan's heap.
-// Each custom space is assigned to a type partition using `cppgc::SpaceTrait`.
-// It is expected that `kSpaceIndex` uniquely identifies a space and that the
-// indices of all custom spaces form a sequence starting at 0. See
-// `cppgc::CustomSpace` for details.
-
-class PLATFORM_EXPORT HeapVectorBackingSpace
-    : public cppgc::CustomSpace<HeapVectorBackingSpace> {
- public:
-  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 0;
-  static constexpr bool kSupportsCompaction = true;
-};
-
-class PLATFORM_EXPORT HeapHashTableBackingSpace
-    : public cppgc::CustomSpace<HeapHashTableBackingSpace> {
- public:
-  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 1;
-  static constexpr bool kSupportsCompaction = true;
-};
-
-class PLATFORM_EXPORT NodeSpace : public cppgc::CustomSpace<NodeSpace> {
- public:
-  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 2;
-};
-
-class PLATFORM_EXPORT CSSValueSpace : public cppgc::CustomSpace<CSSValueSpace> {
- public:
-  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 3;
-};
-
-class PLATFORM_EXPORT LayoutObjectSpace
-    : public cppgc::CustomSpace<LayoutObjectSpace> {
- public:
-  static constexpr cppgc::CustomSpaceIndex kSpaceIndex = 4;
-};
-
-struct CustomSpaces {
-  static std::vector<std::unique_ptr<cppgc::CustomSpaceBase>>
-  CreateCustomSpaces() {
-    std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> spaces;
-    spaces.emplace_back(std::make_unique<HeapVectorBackingSpace>());
-    spaces.emplace_back(std::make_unique<HeapHashTableBackingSpace>());
-    spaces.emplace_back(std::make_unique<NodeSpace>());
-    spaces.emplace_back(std::make_unique<CSSValueSpace>());
-    spaces.emplace_back(std::make_unique<LayoutObjectSpace>());
-    return spaces;
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_CUSTOM_SPACES_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h b/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h
deleted file mode 100644
index a06d0e7..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
-
-#include "v8/include/cppgc/garbage-collected.h"
-#include "v8/include/cppgc/type-traits.h"
-
-// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or
-// field when checking for proper usage.  When using GC_PLUGIN_IGNORE
-// a bug-number should be provided as an argument where the bug describes
-// what needs to happen to remove the GC_PLUGIN_IGNORE again.
-#if defined(__clang__)
-#define GC_PLUGIN_IGNORE(bug) \
-  __attribute__((annotate("blink_gc_plugin_ignore")))
-#else
-#define GC_PLUGIN_IGNORE(bug)
-#endif
-
-namespace blink {
-
-using GarbageCollectedMixin = cppgc::GarbageCollectedMixin;
-
-template <typename T>
-struct IsGarbageCollectedMixin {
- public:
-  static const bool value = cppgc::IsGarbageCollectedMixinTypeV<T>;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h
deleted file mode 100644
index 0b452aa..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
-
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
-#include "v8/include/cppgc/allocation.h"
-#include "v8/include/cppgc/garbage-collected.h"
-#include "v8/include/cppgc/internal/pointer-policies.h"
-#include "v8/include/cppgc/liveness-broker.h"
-
-namespace blink {
-
-using LivenessBroker = cppgc::LivenessBroker;
-
-template <typename T>
-using GarbageCollected = cppgc::GarbageCollected<T>;
-
-// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage
-// collected type.
-template <typename T, typename... Args>
-T* MakeGarbageCollected(Args&&... args) {
-  return cppgc::MakeGarbageCollected<T>(
-      ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
-          ->allocation_handle(),
-      std::forward<Args>(args)...);
-}
-
-using AdditionalBytes = cppgc::AdditionalBytes;
-
-// Constructs an instance of T, which is a garbage collected type. This special
-// version takes size which enables constructing inline objects.
-template <typename T, typename... Args>
-T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) {
-  return cppgc::MakeGarbageCollected<T>(
-      ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
-          ->allocation_handle(),
-      std::forward<AdditionalBytes>(additional_bytes),
-      std::forward<Args>(args)...);
-}
-
-static constexpr bool kBlinkGCHasDebugChecks =
-    !std::is_same<cppgc::internal::DefaultMemberCheckingPolicy,
-                  cppgc::internal::DisabledCheckingPolicy>::value;
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h
deleted file mode 100644
index 4179e550..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator_impl.h
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_IMPL_H_
-
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8/include/cppgc/explicit-management.h"
-#include "v8/include/cppgc/heap-consistency.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT HeapAllocator {
-  STATIC_ONLY(HeapAllocator);
-
- public:
-  using HeapConsistency = cppgc::subtle::HeapConsistency;
-  using LivenessBroker = blink::LivenessBroker;
-
-  static constexpr bool kIsGarbageCollected = true;
-
-  // See wtf/size_t.h for details.
-  static constexpr size_t kMaxHeapObjectSizeLog2 = 27;
-  static constexpr size_t kMaxHeapObjectSize = 1 << kMaxHeapObjectSizeLog2;
-
-  template <typename T>
-  static size_t MaxElementCountInBackingStore() {
-    return kMaxHeapObjectSize / sizeof(T);
-  }
-
-  template <typename T>
-  static size_t QuantizedSize(size_t count) {
-    CHECK_LE(count, MaxElementCountInBackingStore<T>());
-    // Oilpan's internal size is independent of MaxElementCountInBackingStore()
-    // and the required size to match capacity needs.
-    return count * sizeof(T);
-  }
-
-  template <typename T>
-  static T* AllocateVectorBacking(size_t size) {
-    return HeapVectorBacking<T>::ToArray(
-        MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T)));
-  }
-
-  template <typename T>
-  static void FreeVectorBacking(T* array) {
-    if (!array)
-      return;
-
-    HeapVectorBacking<T>::FromArray(array)->Free(
-        ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
-            ->heap_handle());
-  }
-
-  template <typename T>
-  static bool ExpandVectorBacking(T* array, size_t new_size) {
-    DCHECK(array);
-    return HeapVectorBacking<T>::FromArray(array)->Resize(new_size);
-  }
-
-  template <typename T>
-  static bool ShrinkVectorBacking(T* array, size_t, size_t new_size) {
-    DCHECK(array);
-    return HeapVectorBacking<T>::FromArray(array)->Resize(new_size);
-  }
-
-  template <typename T, typename HashTable>
-  static T* AllocateHashTableBacking(size_t size) {
-    static_assert(sizeof(T) == sizeof(typename HashTable::ValueType),
-                  "T must match ValueType.");
-    return HeapHashTableBacking<HashTable>::ToArray(
-        MakeGarbageCollected<HeapHashTableBacking<HashTable>>(size /
-                                                              sizeof(T)));
-  }
-
-  template <typename T, typename HashTable>
-  static T* AllocateZeroedHashTableBacking(size_t size) {
-    return AllocateHashTableBacking<T, HashTable>(size);
-  }
-
-  template <typename T, typename HashTable>
-  static void FreeHashTableBacking(T* array) {
-    if (!array)
-      return;
-
-    HeapHashTableBacking<HashTable>::FromArray(array)->Free(
-        ThreadStateFor<ThreadingTrait<
-            HeapHashTableBacking<HashTable>>::kAffinity>::GetState()
-            ->heap_handle());
-  }
-
-  template <typename T, typename HashTable>
-  static bool ExpandHashTableBacking(T* array, size_t new_size) {
-    DCHECK(array);
-    return HeapHashTableBacking<HashTable>::FromArray(array)->Resize(new_size);
-  }
-
-  static bool IsAllocationAllowed() {
-    return cppgc::subtle::DisallowGarbageCollectionScope::
-        IsGarbageCollectionAllowed(ThreadState::Current()->heap_handle());
-  }
-
-  static bool IsIncrementalMarking() {
-    auto& heap_handle = ThreadState::Current()->heap_handle();
-    return cppgc::subtle::HeapState::IsMarking(heap_handle) &&
-           !cppgc::subtle::HeapState::IsInAtomicPause(heap_handle);
-  }
-
-  static void EnterGCForbiddenScope() {
-    cppgc::subtle::NoGarbageCollectionScope::Enter(
-        ThreadState::Current()->cpp_heap().GetHeapHandle());
-  }
-
-  static void LeaveGCForbiddenScope() {
-    cppgc::subtle::NoGarbageCollectionScope::Leave(
-        ThreadState::Current()->cpp_heap().GetHeapHandle());
-  }
-
-  template <typename Traits>
-  static bool CanReuseHashTableDeletedBucket() {
-    if (Traits::kEmptyValueIsZero || !Traits::kCanTraceConcurrently)
-      return true;
-    return !IsIncrementalMarking();
-  }
-
-  template <typename T>
-  static void BackingWriteBarrier(T** slot) {
-    WriteBarrier::DispatchForObject(slot);
-  }
-
-  template <typename T>
-  static void TraceBackingStoreIfMarked(T* object) {
-    HeapConsistency::WriteBarrierParams params;
-    if (HeapConsistency::GetWriteBarrierType(object, params) ==
-        HeapConsistency::WriteBarrierType::kMarking) {
-      HeapConsistency::SteeleWriteBarrier(params, object);
-    }
-  }
-
-  template <typename T, typename Traits>
-  static void NotifyNewObject(T* slot_in_backing) {
-    HeapConsistency::WriteBarrierParams params;
-    // `slot_in_backing` points into a backing store and T is not necessarily a
-    // garbage collected type but may be kept inline.
-    switch (HeapConsistency::GetWriteBarrierType(
-        slot_in_backing, params, []() -> cppgc::HeapHandle& {
-          return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
-              ->heap_handle();
-        })) {
-      case HeapConsistency::WriteBarrierType::kMarking:
-        HeapConsistency::DijkstraWriteBarrierRange(
-            params, slot_in_backing, sizeof(T), 1,
-            TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
-        break;
-      case HeapConsistency::WriteBarrierType::kGenerational:
-        HeapConsistency::GenerationalBarrier(params, slot_in_backing);
-        break;
-      case HeapConsistency::WriteBarrierType::kNone:
-        break;
-      default:
-        break;  // TODO(1056170): Remove default case when API is stable.
-    }
-  }
-
-  template <typename T, typename Traits>
-  static void NotifyNewObjects(T* first_element, size_t length) {
-    HeapConsistency::WriteBarrierParams params;
-    // `first_element` points into a backing store and T is not necessarily a
-    // garbage collected type but may be kept inline.
-    switch (HeapConsistency::GetWriteBarrierType(
-        first_element, params, []() -> cppgc::HeapHandle& {
-          return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
-              ->heap_handle();
-        })) {
-      case HeapConsistency::WriteBarrierType::kMarking:
-        HeapConsistency::DijkstraWriteBarrierRange(
-            params, first_element, sizeof(T), length,
-            TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace);
-        break;
-      case HeapConsistency::WriteBarrierType::kGenerational:
-        HeapConsistency::GenerationalBarrier(params, first_element);
-        break;
-      case HeapConsistency::WriteBarrierType::kNone:
-        break;
-      default:
-        break;  // TODO(1056170): Remove default case when API is stable.
-    }
-  }
-
-  template <typename T, typename Traits>
-  static void Trace(Visitor* visitor, const T& t) {
-    TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T,
-                             Traits>::Trace(visitor, &t);
-  }
-
-  template <typename T>
-  static void TraceVectorBacking(Visitor* visitor,
-                                 const T* backing,
-                                 const T* const* backing_slot) {
-    visitor->RegisterMovableReference(const_cast<const HeapVectorBacking<T>**>(
-        reinterpret_cast<const HeapVectorBacking<T>* const*>(backing_slot)));
-    visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing));
-  }
-
-  template <typename T, typename HashTable>
-  static void TraceHashTableBackingStrongly(Visitor* visitor,
-                                            const T* backing,
-                                            const T* const* backing_slot) {
-    visitor->RegisterMovableReference(
-        const_cast<const HeapHashTableBacking<HashTable>**>(
-            reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
-                backing_slot)));
-    visitor->Trace(
-        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing));
-  }
-
-  template <typename T, typename HashTable>
-  static void TraceHashTableBackingWeakly(Visitor* visitor,
-                                          const T* backing,
-                                          const T* const* backing_slot,
-                                          WeakCallback callback,
-                                          const void* parameter) {
-    visitor->RegisterMovableReference(
-        const_cast<const HeapHashTableBacking<HashTable>**>(
-            reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>(
-                backing_slot)));
-    visitor->TraceWeakContainer(
-        reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing),
-        callback, parameter);
-  }
-
-  static bool DeferTraceToMutatorThreadIfConcurrent(Visitor* visitor,
-                                                    const void* object,
-                                                    TraceCallback callback,
-                                                    size_t deferred_size) {
-    return visitor->DeferTraceToMutatorThreadIfConcurrent(object, callback,
-                                                          deferred_size);
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_IMPL_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h b/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h
deleted file mode 100644
index 0ac0aa7..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/heap_test_utilities.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TEST_UTILITIES_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TEST_UTILITIES_H_
-
-#include "base/test/task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8-cppgc.h"
-#include "v8.h"
-#include "v8/include/cppgc/testing.h"
-
-namespace blink {
-
-// Allows for overriding the stack state for the purpose of testing. Any garbage
-// collection calls scoped with `HeapPointersOnStackScope` will perform
-// conservative stack scanning, even if other (more local) hints indicate that
-// there's no need for it.
-class HeapPointersOnStackScope final {
-  STACK_ALLOCATED();
-
- public:
-  explicit HeapPointersOnStackScope(const ThreadState* state)
-      : embedder_stack_state_(
-            state->cpp_heap().GetHeapHandle(),
-            cppgc::EmbedderStackState::kMayContainHeapPointers) {}
-
-  HeapPointersOnStackScope(const HeapPointersOnStackScope&) = delete;
-  HeapPointersOnStackScope& operator=(const HeapPointersOnStackScope&) = delete;
-
- private:
-  cppgc::testing::OverrideEmbedderStackStateScope embedder_stack_state_;
-};
-
-class TestSupportingGC : public testing::Test {
- public:
-  ~TestSupportingGC() override;
-
-  // Performs a precise garbage collection with eager sweeping.
-  static void PreciselyCollectGarbage();
-
-  // Performs a conservative garbage collection with eager sweeping.
-  static void ConservativelyCollectGarbage();
-
-  // Performs multiple rounds of garbage collections until no more memory can be
-  // freed. This is useful to avoid other garbage collections having to deal
-  // with stale memory.
-  static void ClearOutOldGarbage();
-
- protected:
-  base::test::TaskEnvironment task_environment_;
-};
-
-// Test driver for compaction.
-class CompactionTestDriver {
- public:
-  explicit CompactionTestDriver(ThreadState*);
-
-  void ForceCompactionForNextGC();
-
- protected:
-  cppgc::testing::StandaloneTestingHeap heap_;
-};
-
-// Test driver for incremental marking. Assumes that no stack handling is
-// required.
-class IncrementalMarkingTestDriver {
- public:
-  explicit IncrementalMarkingTestDriver(ThreadState*);
-  ~IncrementalMarkingTestDriver();
-
-  virtual void StartGC();
-  virtual void TriggerMarkingSteps(
-      BlinkGC::StackState stack_state =
-          BlinkGC::StackState::kNoHeapPointersOnStack);
-  virtual void FinishGC();
-
- protected:
-  cppgc::testing::StandaloneTestingHeap heap_;
-};
-
-// Test driver for concurrent marking. Assumes that no stack handling is
-// required.
-class ConcurrentMarkingTestDriver : public IncrementalMarkingTestDriver {
- public:
-  explicit ConcurrentMarkingTestDriver(ThreadState*);
-
-  void StartGC() override;
-  void TriggerMarkingSteps(
-      BlinkGC::StackState stack_state =
-          BlinkGC::StackState::kNoHeapPointersOnStack) override;
-  void FinishGC() override;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TEST_UTILITIES_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/member.h b/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
deleted file mode 100644
index 3366052..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
-
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
-#include "v8/include/cppgc/member.h"
-
-namespace blink {
-
-template <typename T>
-using Member = cppgc::Member<T>;
-
-template <typename T>
-using WeakMember = cppgc::WeakMember<T>;
-
-template <typename T>
-using UntracedMember = cppgc::UntracedMember<T>;
-
-template <typename T>
-inline bool IsHashTableDeletedValue(const Member<T>& m) {
-  return m == cppgc::kSentinelPointer;
-}
-
-constexpr auto kMemberDeletedValue = cppgc::kSentinelPointer;
-
-template <typename T>
-struct ThreadingTrait<blink::Member<T>> {
-  STATIC_ONLY(ThreadingTrait);
-  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
-};
-
-template <typename T>
-struct ThreadingTrait<blink::WeakMember<T>> {
-  STATIC_ONLY(ThreadingTrait);
-  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
-};
-
-template <typename T>
-struct ThreadingTrait<blink::UntracedMember<T>> {
-  STATIC_ONLY(ThreadingTrait);
-  static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
-};
-
-}  // namespace blink
-
-namespace WTF {
-
-template <typename T, typename Traits, typename Allocator>
-class MemberConstructTraits {
-  STATIC_ONLY(MemberConstructTraits);
-
- public:
-  template <typename... Args>
-  static T* Construct(void* location, Args&&... args) {
-    return new (NotNullTag::kNotNull, location) T(std::forward<Args>(args)...);
-  }
-
-  static void NotifyNewElement(T* element) {
-    blink::WriteBarrier::DispatchForObject(element);
-  }
-
-  template <typename... Args>
-  static T* ConstructAndNotifyElement(void* location, Args&&... args) {
-    // ConstructAndNotifyElement updates an existing Member which might
-    // also be comncurrently traced while we update it. The regular ctors
-    // for Member don't use an atomic write which can lead to data races.
-    T* object = Construct(location, std::forward<Args>(args)...,
-                          typename T::AtomicInitializerTag());
-    NotifyNewElement(object);
-    return object;
-  }
-
-  static void NotifyNewElements(T* array, size_t len) {
-    while (len-- > 0) {
-      blink::WriteBarrier::DispatchForObject(array);
-      array++;
-    }
-  }
-};
-
-template <typename T, typename Traits, typename Allocator>
-class ConstructTraits<blink::Member<T>, Traits, Allocator>
-    : public MemberConstructTraits<blink::Member<T>, Traits, Allocator> {};
-
-template <typename T, typename Traits, typename Allocator>
-class ConstructTraits<blink::WeakMember<T>, Traits, Allocator>
-    : public MemberConstructTraits<blink::WeakMember<T>, Traits, Allocator> {};
-
-}  // namespace WTF
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h b/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h
deleted file mode 100644
index 6ec1e7d..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
-
-#include "base/bind.h"
-#include "third_party/blink/renderer/platform/bindings/buildflags.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
-#include "v8/include/cppgc/cross-thread-persistent.h"
-#include "v8/include/cppgc/persistent.h"
-#include "v8/include/cppgc/source-location.h"
-
-namespace blink {
-
-template <typename T>
-using Persistent = cppgc::Persistent<T>;
-
-template <typename T>
-using WeakPersistent = cppgc::WeakPersistent<T>;
-
-template <typename T>
-using CrossThreadPersistent = cppgc::subtle::CrossThreadPersistent<T>;
-
-template <typename T>
-using CrossThreadWeakPersistent = cppgc::subtle::WeakCrossThreadPersistent<T>;
-
-using PersistentLocation = cppgc::SourceLocation;
-
-template <typename T>
-Persistent<T> WrapPersistent(
-    T* value,
-    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
-  return Persistent<T>(value, loc);
-}
-
-template <typename T>
-WeakPersistent<T> WrapWeakPersistent(
-    T* value,
-    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
-  return WeakPersistent<T>(value, loc);
-}
-
-template <typename T>
-CrossThreadPersistent<T> WrapCrossThreadPersistent(
-    T* value,
-    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
-  return CrossThreadPersistent<T>(value, loc);
-}
-
-template <typename T>
-CrossThreadWeakPersistent<T> WrapCrossThreadWeakPersistent(
-    T* value,
-    const cppgc::SourceLocation& loc = cppgc::SourceLocation::Current()) {
-  return CrossThreadWeakPersistent<T>(value, loc);
-}
-
-#if BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-#define PERSISTENT_FROM_HERE PersistentLocation::Current()
-#else
-#define PERSISTENT_FROM_HERE PersistentLocation()
-#endif  // BUILDFLAG(RAW_HEAP_SNAPSHOTS)
-
-template <typename U, typename T, typename weakness>
-cppgc::internal::BasicPersistent<U, weakness> DownCast(
-    const cppgc::internal::BasicPersistent<T, weakness>& p) {
-  return p.template To<U>();
-}
-
-template <typename U, typename T, typename weakness>
-cppgc::internal::BasicCrossThreadPersistent<U, weakness> DownCast(
-    const cppgc::internal::BasicCrossThreadPersistent<T, weakness>& p) {
-  return p.template To<U>();
-}
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h b/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h
deleted file mode 100644
index e100e4c..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
-
-#include "gin/public/cppgc.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8/include/cppgc/platform.h"
-#include "v8/include/cppgc/process-heap-statistics.h"
-
-namespace blink {
-
-// TODO(1056170): Implement wrapper.
-class PLATFORM_EXPORT ProcessHeap {
-  STATIC_ONLY(ProcessHeap);
-
- public:
-  static void Init() { gin::InitializeCppgcFromV8Platform(); }
-
-  static size_t TotalAllocatedObjectSize() {
-    return cppgc::ProcessHeapStatistics::TotalAllocatedObjectSize();
-  }
-
-  static size_t TotalAllocatedSpace() {
-    return cppgc::ProcessHeapStatistics::TotalAllocatedSpace();
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h b/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h
deleted file mode 100644
index 6b327a2..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
-
-#include "base/compiler_specific.h"
-#include "build/build_config.h"
-#include "third_party/blink/renderer/platform/heap/blink_gc.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_local.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/threading.h"
-#include "v8-profiler.h"
-#include "v8/include/cppgc/heap-consistency.h"
-#include "v8/include/cppgc/prefinalizer.h"
-#include "v8/include/v8-callbacks.h"
-#include "v8/include/v8-cppgc.h"
-
-namespace v8 {
-class CppHeap;
-}  // namespace v8
-
-namespace cppgc {
-class AllocationHandle;
-}  // namespace cppgc
-
-namespace v8 {
-class EmbedderGraph;
-class EmbedderRootsHandler;
-}  // namespace v8
-
-namespace blink {
-
-#define USING_PRE_FINALIZER(Class, PreFinalizer) \
-  CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer)
-
-// ThreadAffinity indicates which threads objects can be used on. We
-// distinguish between objects that can be used on the main thread
-// only and objects that can be used on any thread.
-//
-// For objects that can only be used on the main thread, we avoid going
-// through thread-local storage to get to the thread state. This is
-// important for performance.
-enum ThreadAffinity {
-  kAnyThread,
-  kMainThreadOnly,
-};
-
-template <typename T, typename = void>
-struct ThreadingTrait {
-  STATIC_ONLY(ThreadingTrait);
-  static constexpr ThreadAffinity kAffinity = kAnyThread;
-};
-
-template <ThreadAffinity>
-class ThreadStateFor;
-class ThreadState;
-
-using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*,
-                                              v8::EmbedderGraph*,
-                                              void*);
-
-// Storage for all ThreadState objects. This includes the main-thread
-// ThreadState as well. Keep it outside the class so that PLATFORM_EXPORT
-// doesn't apply to it (otherwise, clang-cl complains).
-extern thread_local ThreadState* g_thread_specific_ CONSTINIT
-    __attribute__((tls_model(BLINK_HEAP_THREAD_LOCAL_MODEL)));
-
-class PLATFORM_EXPORT ThreadState final {
- public:
-  class NoAllocationScope;
-  class GCForbiddenScope;
-
-  BLINK_HEAP_DECLARE_THREAD_LOCAL_GETTER(Current,
-                                         ThreadState*,
-                                         g_thread_specific_)
-
-  static ALWAYS_INLINE ThreadState* MainThreadState() {
-    return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
-  }
-
-  // Attaches a ThreadState to the main-thread.
-  static ThreadState* AttachMainThread();
-  // Attaches a ThreadState to the currently running thread. Must not be the
-  // main thread and must be called after AttachMainThread().
-  static ThreadState* AttachCurrentThread();
-  static void DetachCurrentThread();
-
-  void AttachToIsolate(v8::Isolate* isolate, V8BuildEmbedderGraphCallback);
-  void DetachFromIsolate();
-
-  ALWAYS_INLINE cppgc::AllocationHandle& allocation_handle() const {
-    return allocation_handle_;
-  }
-  ALWAYS_INLINE cppgc::HeapHandle& heap_handle() const { return heap_handle_; }
-  ALWAYS_INLINE v8::CppHeap& cpp_heap() const { return *cpp_heap_; }
-  ALWAYS_INLINE v8::Isolate* GetIsolate() const { return isolate_; }
-
-  void SafePoint(BlinkGC::StackState);
-
-  bool IsMainThread() const { return this == MainThreadState(); }
-  bool IsCreationThread() const { return thread_id_ == CurrentThread(); }
-
-  void NotifyGarbageCollection(v8::GCType, v8::GCCallbackFlags);
-
-  bool InAtomicSweepingPause() const {
-    auto& heap_handle = cpp_heap().GetHeapHandle();
-    return cppgc::subtle::HeapState::IsInAtomicPause(heap_handle) &&
-           cppgc::subtle::HeapState::IsSweeping(heap_handle);
-  }
-
-  bool IsAllocationAllowed() const {
-    return cppgc::subtle::DisallowGarbageCollectionScope::
-        IsGarbageCollectionAllowed(cpp_heap().GetHeapHandle());
-  }
-
-  // Waits until sweeping is done and invokes the given callback with
-  // the total sizes of live objects in Node and CSS arenas.
-  void CollectNodeAndCssStatistics(
-      base::OnceCallback<void(size_t allocated_node_bytes,
-                              size_t allocated_css_bytes)>);
-
-  bool IsIncrementalMarking();
-
-  // Forced garbage collection for testing:
-  //
-  // Collects garbage as long as live memory decreases (capped at 5).
-  void CollectAllGarbageForTesting(
-      BlinkGC::StackState stack_state =
-          BlinkGC::StackState::kNoHeapPointersOnStack);
-
-  void EnableDetachedGarbageCollectionsForTesting();
-
-  static ThreadState* AttachMainThreadForTesting(v8::Platform*);
-  static ThreadState* AttachCurrentThreadForTesting(v8::Platform*);
-
- private:
-  // Main-thread ThreadState avoids TLS completely by using a regular global.
-  // The object is manually managed and should not rely on global ctor/dtor.
-  static uint8_t main_thread_state_storage_[];
-
-  explicit ThreadState(v8::Platform*);
-  ~ThreadState();
-
-  std::unique_ptr<v8::CppHeap> cpp_heap_;
-  std::unique_ptr<v8::EmbedderRootsHandler> embedder_roots_handler_;
-  cppgc::AllocationHandle& allocation_handle_;
-  cppgc::HeapHandle& heap_handle_;
-  v8::Isolate* isolate_ = nullptr;
-  base::PlatformThreadId thread_id_;
-  bool forced_scheduled_gc_for_testing_ = false;
-};
-
-template <>
-class ThreadStateFor<kMainThreadOnly> {
-  STATIC_ONLY(ThreadStateFor);
-
- public:
-  static ALWAYS_INLINE ThreadState* GetState() {
-    return ThreadState::MainThreadState();
-  }
-};
-
-template <>
-class ThreadStateFor<kAnyThread> {
-  STATIC_ONLY(ThreadStateFor);
-
- public:
-  static ALWAYS_INLINE ThreadState* GetState() {
-    return ThreadState::Current();
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h b/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h
deleted file mode 100644
index 82e71e9..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
-
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-#include "v8/include/cppgc/heap-consistency.h"
-
-namespace blink {
-
-// The NoAllocationScope class is used in debug mode to catch unwanted
-// allocations. E.g. allocations during GC.
-class ThreadState::NoAllocationScope final {
-  STACK_ALLOCATED();
-
- public:
-  explicit NoAllocationScope(ThreadState* state)
-      : disallow_gc_(state->cpp_heap().GetHeapHandle()) {}
-
-  NoAllocationScope(const NoAllocationScope&) = delete;
-  NoAllocationScope& operator=(const NoAllocationScope&) = delete;
-
- private:
-  const cppgc::subtle::DisallowGarbageCollectionScope disallow_gc_;
-};
-
-// The GCForbiddenScope class is used to prevent GC finalization
-// when it is not safe to do so.
-class ThreadState::GCForbiddenScope final {
-  STACK_ALLOCATED();
-
- public:
-  explicit GCForbiddenScope(ThreadState* state)
-      : no_gc_(state->cpp_heap().GetHeapHandle()) {}
-
-  GCForbiddenScope(const NoAllocationScope&) = delete;
-  GCForbiddenScope& operator=(const NoAllocationScope&) = delete;
-
- private:
-  const cppgc::subtle::NoGarbageCollectionScope no_gc_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h b/third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h
deleted file mode 100644
index 7503719..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/trace_traits.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_TRACE_TRAITS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_TRACE_TRAITS_H_
-
-#include <tuple>
-
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-#include "third_party/blink/renderer/platform/wtf/type_traits.h"
-#include "v8/include/cppgc/trace-trait.h"
-
-namespace blink {
-
-template <typename T, bool = WTF::IsTraceable<T>::value>
-struct TraceIfNeeded;
-
-template <typename T>
-struct TraceIfNeeded<T, false> {
-  STATIC_ONLY(TraceIfNeeded);
-  static void Trace(Visitor*, const T&) {}
-};
-
-template <typename T>
-struct TraceIfNeeded<T, true> {
-  STATIC_ONLY(TraceIfNeeded);
-  static void Trace(Visitor* visitor, const T& t) { visitor->Trace(t); }
-};
-
-}  // namespace blink
-
-namespace cppgc {
-
-// This trace trait for std::pair will null weak members if their referent is
-// collected. If you have a collection that contain weakness it does not remove
-// entries from the collection that contain nulled weak members.
-template <typename T, typename U>
-struct TraceTrait<std::pair<T, U>> {
-  STATIC_ONLY(TraceTrait);
-
- public:
-  static TraceDescriptor GetTraceDescriptor(const void* self) {
-    return {self, Trace};
-  }
-
-  static void Trace(Visitor* visitor, const std::pair<T, U>* pair) {
-    blink::TraceIfNeeded<U>::Trace(visitor, pair->second);
-    blink::TraceIfNeeded<T>::Trace(visitor, pair->first);
-  }
-};
-
-}  // namespace cppgc
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_TRACE_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h b/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h
deleted file mode 100644
index c49566d4..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
-
-#include "base/compiler_specific.h"
-#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8/include/v8-cppgc.h"
-#include "v8/include/v8-traced-handle.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT UnifiedHeapMarkingVisitor final {
-  STATIC_ONLY(UnifiedHeapMarkingVisitor);
-
- public:
-  static ALWAYS_INLINE void WriteBarrier(
-      const v8::TracedReference<v8::Value>& ref) {
-    v8::JSHeapConsistency::WriteBarrierParams params;
-    if (v8::JSHeapConsistency::GetWriteBarrierType(
-            ref, params, []() -> cppgc::HeapHandle& {
-              return ThreadState::Current()->heap_handle();
-            }) == v8::JSHeapConsistency::WriteBarrierType::kMarking) {
-      v8::JSHeapConsistency::DijkstraMarkingBarrier(
-          params, ThreadState::Current()->heap_handle(), ref);
-    }
-  }
-
-  static ALWAYS_INLINE void WriteBarrier(v8::Isolate*,
-                                         v8::Local<v8::Object>& wrapper,
-                                         const WrapperTypeInfo*,
-                                         const void* wrappable) {
-    v8::JSHeapConsistency::WriteBarrierParams params;
-    if (v8::JSHeapConsistency::GetWriteBarrierType(
-            wrapper, kV8DOMWrapperObjectIndex, wrappable, params,
-            []() -> cppgc::HeapHandle& {
-              return ThreadState::Current()->heap_handle();
-            }) == v8::JSHeapConsistency::WriteBarrierType::kMarking) {
-      v8::JSHeapConsistency::DijkstraMarkingBarrier(
-          params, ThreadState::Current()->heap_handle(), wrappable);
-    }
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h b/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h
deleted file mode 100644
index a7da1cc..0000000
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
-
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "v8/include/cppgc/visitor.h"
-
-namespace blink {
-
-using Visitor = cppgc::Visitor;
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/visitor.h b/third_party/blink/renderer/platform/heap/visitor.h
index 9fb80dc..952d309 100644
--- a/third_party/blink/renderer/platform/heap/visitor.h
+++ b/third_party/blink/renderer/platform/heap/visitor.h
@@ -5,6 +5,13 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
 
-#include "third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "v8/include/cppgc/visitor.h"
+
+namespace blink {
+
+using Visitor = cppgc::Visitor;
+
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h b/third_party/blink/renderer/platform/heap/write_barrier.h
similarity index 82%
rename from third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h
rename to third_party/blink/renderer/platform/heap/write_barrier.h
index 4bfa2a3..adfe0da 100644
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/write_barrier.h
+++ b/third_party/blink/renderer/platform/heap/write_barrier.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_WRITE_BARRIER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_WRITE_BARRIER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WRITE_BARRIER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WRITE_BARRIER_H_
 
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "v8/include/cppgc/heap-consistency.h"
@@ -36,4 +36,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_WRITE_BARRIER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WRITE_BARRIER_H_
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
index 3b989c9e..3a23dd74 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
@@ -227,6 +227,12 @@
                        "' contains a username and password, which is "
                        "disallowed for cross-origin requests."});
       break;
+    case CorsError::kInvalidPrivateNetworkAccess:
+      Append(builder, {"Request had a target IP address space of `",
+                       ShortAddressSpace(status.target_address_space),
+                       "` yet the resource is in address space `",
+                       ShortAddressSpace(status.resource_address_space), "`."});
+      break;
   }
   return builder.ToString();
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 94da0e6..e523f20 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -90,6 +90,7 @@
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "url/url_constants.h"
 
 namespace blink {
 
@@ -773,7 +774,8 @@
     const WebString& new_method,
     const WebURLResponse& passed_redirect_response,
     bool& has_devtools_request_id,
-    std::vector<std::string>* removed_headers) {
+    std::vector<std::string>* removed_headers,
+    bool insecure_scheme_was_upgraded) {
   DCHECK(!passed_redirect_response.IsNull());
 
   if (passed_redirect_response.HasAuthorizationCoveredByWildcardOnPreflight()) {
@@ -836,10 +838,17 @@
         unused_preload ? ReportingDisposition::kSuppressReporting
                        : ReportingDisposition::kReport;
 
+    // The network stack might have upgraded to https an http URL. Report-only
+    // CSP must be checked with the url prior to that upgrade.
+    KURL new_url_prior_upgrade = new_url;
+    if (insecure_scheme_was_upgraded && new_url.ProtocolIs(url::kHttpsScheme)) {
+      new_url_prior_upgrade.SetProtocol(url::kHttpScheme);
+    }
+
     // CanRequest() checks only enforced CSP, so check report-only here to
     // ensure that violations are sent.
     Context().CheckCSPForRequest(
-        request_context, request_destination, new_url, options,
+        request_context, request_destination, new_url_prior_upgrade, options,
         reporting_disposition, url_before_redirects,
         ResourceRequest::RedirectStatus::kFollowedRedirect);
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
index 248ee73..aabb4df 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -134,7 +134,8 @@
                           const WebString& new_method,
                           const WebURLResponse& passed_redirect_response,
                           bool& has_devtools_request_id,
-                          std::vector<std::string>* removed_headers) override;
+                          std::vector<std::string>* removed_headers,
+                          bool insecure_scheme_was_upgraded) override;
   void DidSendData(uint64_t bytes_sent,
                    uint64_t total_bytes_to_be_sent) override;
   void DidReceiveResponse(const WebURLResponse&) override;
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
index ee814fd..82aa7a9 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
@@ -332,7 +332,6 @@
                last_loaded_url_.GetString().Utf8());
 
   has_received_response_head_ = true;
-  on_receive_response_time_ = base::TimeTicks::Now();
 
   if (NeedsStoringMessage()) {
     StoreAndDispatch(
@@ -449,12 +448,6 @@
   DCHECK(!has_received_response_body_);
   has_received_response_body_ = true;
 
-  if (!on_receive_response_time_.is_null()) {
-    UMA_HISTOGRAM_TIMES(
-        "Renderer.OnReceiveResponseToOnStartLoadingResponseBody",
-        base::TimeTicks::Now() - on_receive_response_time_);
-  }
-
   if (!NeedsStoringMessage()) {
     // Send the message immediately.
     resource_request_sender_->OnStartLoadingResponseBody(std::move(body));
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h
index 3832adc..112614d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.h
@@ -115,9 +115,6 @@
   KURL last_loaded_url_;
   WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper_;
 
-  // For UMA.
-  base::TimeTicks on_receive_response_time_;
-
   base::WeakPtrFactory<MojoURLLoaderClient> weak_factory_{this};
 };
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
index 8a2b2c6b..3f3f2a2 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
@@ -642,7 +642,8 @@
       WebString::FromUTF8(redirect_info.new_referrer),
       ReferrerUtils::NetToMojoReferrerPolicy(redirect_info.new_referrer_policy),
       WebString::FromUTF8(redirect_info.new_method), response,
-      has_devtools_request_id_, removed_headers);
+      has_devtools_request_id_, removed_headers,
+      redirect_info.insecure_scheme_was_upgraded);
 }
 
 void WebURLLoader::Context::OnReceivedResponse(
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
index a931609..651fd98 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
@@ -208,7 +208,8 @@
                           const WebString& new_method,
                           const WebURLResponse& passed_redirect_response,
                           bool& report_raw_headers,
-                          std::vector<std::string>*) override {
+                          std::vector<std::string>*,
+                          bool insecure_scheme_was_upgraded) override {
     EXPECT_TRUE(loader_);
 
     // No test currently simulates mutiple redirects.
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
index ac44a4b0..c469dc0 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
@@ -85,7 +85,8 @@
   bool follow = client_->WillFollowRedirect(
       redirect_url, net::SiteForCookies::FromUrl(redirect_url), WebString(),
       network::mojom::ReferrerPolicy::kDefault, method, redirect_response,
-      report_raw_headers, nullptr /* removed_headers */);
+      report_raw_headers, nullptr /* removed_headers */,
+      false /* insecure_scheme_was_upgraded */);
   // |this| might be deleted in willFollowRedirect().
   if (!self)
     return redirect_url;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 876f897..7fd37b4 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -779,6 +779,8 @@
 crbug.com/711807 external/wpt/css/CSS2/normal-flow/replaced-intrinsic-001.xht [ Failure ]
 crbug.com/711807 external/wpt/css/CSS2/normal-flow/replaced-intrinsic-002.xht [ Failure ]
 
+crbug.com/716930 external/wpt/css/CSS2/normal-flow/block-in-inline-float-in-layer-001.html [ Failure ]
+
 #### external/wpt/css/css-sizing
 crbug.com/1251788 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-002.html [ Failure ]
 crbug.com/970201 external/wpt/css/css-sizing/slice-intrinsic-size.html [ Failure ]
@@ -4575,9 +4577,6 @@
 # Flakes 2018-06-02
 crbug.com/841567 fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Pass ]
 
-# Now that upgrade-insecure-requests enforcing is fixed for redirects, this test will fail while reporting is implemented.
-crbug.com/615885 external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html [ Timeout ]
-
 # Flakes 2018-06-04
 
 # Sheriff 2018-06-07
diff --git a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
index ed62d5d..b9031211 100644
--- a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
+++ b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
@@ -806,6 +806,7 @@
 crbug.com/1050754 external/wpt/eventsource/shared-worker/eventsource-url.htm [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html [ Failure ]
+crbug.com/1050754 external/wpt/external/wpt/fetch/api/headers/headers-normalize.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/fetch/api/response/response-stream-disturbed-1.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/fetch/api/response/response-stream-disturbed-2.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/fetch/api/response/response-stream-disturbed-3.any.sharedworker.html [ Failure ]
diff --git a/third_party/blink/web_tests/editing/input/edit-context.html b/third_party/blink/web_tests/editing/input/edit-context.html
index 19bfc12..30d33b5 100644
--- a/third_party/blink/web_tests/editing/input/edit-context.html
+++ b/third_party/blink/web_tests/editing/input/edit-context.html
@@ -58,12 +58,84 @@
 
   const new_div = document.createElement("DIV");
   assert_equals(new_div.editContext, null);
+  document.body.appendChild(new_div);
+
+  new_div.editContext = editContext;
+  assert_equals(new_div.editContext, editContext);
+  new_div.editContext = null;
+  assert_equals(new_div.editContext, null);
+  document.body.removeChild(new_div);
+}, 'Testing Element.editContext');
+
+test(function() {
+  const editContext = new EditContext();
+  assert_not_equals(editContext, null);
+
+  const disconnected_div = document.createElement("DIV");
+  assert_equals(disconnected_div.editContext, null);
+
+  disconnected_div.editContext = editContext;
+  assert_equals(disconnected_div.editContext, null);
+  assert_equals(editContext.attachedElements().length, 0);
+}, 'EditContext can only be associated with an element that is in an active document.');
+
+test(function() {
+  const editContext = new EditContext();
+  assert_not_equals(editContext, null);
+
+  const div = document.createElement("DIV");
+  assert_equals(div.editContext, null);
+
+  document.body.appendChild(div);
+  div.editContext = editContext;
+  assert_equals(div.editContext, editContext);
+  assert_equals(editContext.attachedElements().length, 1);
+  assert_equals(editContext.attachedElements()[0], div);
+
+  document.body.removeChild(div);
+  assert_equals(div.editContext, null);
+  assert_equals(editContext.attachedElements().length, 0);
+}, 'If an element is removed from tree, it will disconnect its associated EditContext.');
+
+test(function() {
+  const editContext = new EditContext();
+
+  const div_parent = document.createElement("DIV");
+  const div_child = document.createElement("DIV");
+  document.body.appendChild(div_parent);
+  div_parent.appendChild(div_child);
+
+  div_child.editContext = editContext;
+  assert_equals(div_child.editContext, editContext);
+  assert_equals(div_parent.editContext, null);
+  assert_equals(editContext.attachedElements().length, 1);
+  assert_equals(editContext.attachedElements()[0], div_child);
+
+  document.body.removeChild(div_parent);
+  assert_equals(div_child.editContext, null);
+  assert_equals(editContext.attachedElements().length, 0);
+}, 'If an element\'s ancestor is removed from tree, the element will disconnect its associated EditContext.');
+
+test(function() {
+  const editContext = new EditContext();
+
+  const test = document.getElementById("test");
+  const test2 = document.getElementById("test2");
 
   test.editContext = editContext;
+  test2.editContext = editContext;
+
   assert_equals(test.editContext, editContext);
+  assert_equals(test2.editContext, editContext);
+  assert_equals(editContext.attachedElements().length, 2);
+  assert_equals(editContext.attachedElements()[0], test);
+  assert_equals(editContext.attachedElements()[1], test2);
+
   test.editContext = null;
-  assert_equals(test.editContext, null);
-}, 'Testing Element.editContext');
+
+  assert_equals(editContext.attachedElements().length, 1);
+  assert_equals(editContext.attachedElements()[0], test2);
+}, '.attachedElements() should return associated elements');
 
 test(function() {
   const editContext = new EditContext();
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 8073eb547..bf29c7d 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -42290,6 +42290,19 @@
         {}
        ]
       ],
+      "block-in-inline-float-in-layer-001.html": [
+       "f177aca160a3735dc0d6e8e3cd9bc29734e6c17b",
+       [
+        null,
+        [
+         [
+          "/css/CSS2/normal-flow/block-in-inline-float-in-layer-001-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "block-in-inline-insert-001-nosplit-ref.xht": [
        "363ed9eefd444d2d8b2779f53367e3f8cccaeb9d",
        [
@@ -222748,6 +222761,10 @@
        "bdb5963e8944bf23cab77b089626e098944bd35f",
        []
       ],
+      "block-in-inline-float-in-layer-001-ref.html": [
+       "cbaf7ccb23f11e5f201620d9dcab0541464c036d",
+       []
+      ],
       "block-in-inline-insert-017-ref.xht": [
        "cc5b6d24560351be10dc17ca6ec48e37d76932b6",
        []
@@ -388368,7 +388385,7 @@
        ]
       ],
       "headers-normalize.any.js": [
-       "621cee0ff0bdaf1a9004a49e3bbaeee213330dde",
+       "68cf5b85f3acb7fcfe6275ffa0c4d37843ac2935",
        [
         "fetch/api/headers/headers-normalize.any.html",
         {
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-in-inline-float-in-layer-001-ref.html b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-in-inline-float-in-layer-001-ref.html
new file mode 100644
index 0000000..cbaf7cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-in-inline-float-in-layer-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+.layer {
+  filter: blur(1px);
+}
+.float {
+  float: left;
+}
+</style>
+<body>
+  <div class="layer">
+    <div>
+      <div class="float">float</div>
+   </div>
+  </div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-in-inline-float-in-layer-001.html b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-in-inline-float-in-layer-001.html
new file mode 100644
index 0000000..f177aca
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/block-in-inline-float-in-layer-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta name="assert" content="Block-in-inline: float in an inline box that has a layer">
+<link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#anonymous-block-level" />
+<link rel="match" href="block-in-inline-float-in-layer-001-ref.html"/>
+<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org" />
+<style>
+.layer {
+  filter: blur(1px);
+}
+.float {
+  float: left;
+}
+</style>
+<body>
+  <span class="layer">
+    <div>
+      <div class="float">float</div>
+   </div>
+  </span>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.any.js
index 621cee0f..68cf5b85 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/headers/headers-normalize.any.js
@@ -3,35 +3,54 @@
 
 "use strict";
 
-var headerDictWS = {"name1": " space ",
-                    "name2": "\ttab\t",
-                    "name3": " spaceAndTab\t",
-                    "name4": "\r\n newLine", //obs-fold cases
-                    "name5": "newLine\r\n ",
-                    "name6": "\r\n\tnewLine",
-                    };
+const expectations = {
+  "name1": [" space ", "space"],
+  "name2": ["\ttab\t", "tab"],
+  "name3": [" spaceAndTab\t", "spaceAndTab"],
+  "name4": ["\r\n newLine", "newLine"], //obs-fold cases
+  "name5": ["newLine\r\n ", "newLine"],
+  "name6": ["\r\n\tnewLine", "newLine"],
+  "name7": ["\t\f\tnewLine\n", "\f\tnewLine"],
+  "name8": ["newLine\xa0", "newLine\xa0"], // \xa0 == non breaking space
+};
 
-test(function() {
-  var headers = new Headers(headerDictWS);
-  for (const name in headerDictWS)
-    assert_equals(headers.get(name), headerDictWS[name].trim(),
-      "name: " + name + " has normalized value: " + headerDictWS[name].trim());
+test(function () {
+  const headerDict = Object.fromEntries(
+    Object.entries(expectations).map(([name, [actual]]) => [name, actual]),
+  );
+  var headers = new Headers(headerDict);
+  for (const name in expectations) {
+    const expected = expectations[name][1];
+    assert_equals(
+      headers.get(name),
+      expected,
+      "name: " + name + " has normalized value: " + expected,
+    );
+  }
 }, "Create headers with not normalized values");
 
-test(function() {
+test(function () {
   var headers = new Headers();
-  for (const name in headerDictWS) {
-    headers.append(name, headerDictWS[name]);
-    assert_equals(headers.get(name), headerDictWS[name].trim(),
-      "name: " + name + " has value: " + headerDictWS[name].trim());
+  for (const name in expectations) {
+    headers.append(name, expectations[name][0]);
+    const expected = expectations[name][1];
+    assert_equals(
+      headers.get(name),
+      expected,
+      "name: " + name + " has value: " + expected,
+    );
   }
 }, "Check append method with not normalized values");
 
-test(function() {
+test(function () {
   var headers = new Headers();
-  for (const name in headerDictWS) {
-    headers.set(name, headerDictWS[name]);
-    assert_equals(headers.get(name), headerDictWS[name].trim(),
-      "name: " + name + " has value: " + headerDictWS[name].trim());
+  for (const name in expectations) {
+    headers.set(name, expectations[name][0]);
+    const expected = expectations[name][1];
+    assert_equals(
+      headers.get(name),
+      expected,
+      "name: " + name + " has value: " + expected,
+    );
   }
 }, "Check set method with not normalized values");
diff --git a/third_party/blink/web_tests/external/wpt/wasm/serialization/module/cross-origin-module-sharing-fails.html b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/cross-origin-module-sharing-fails.html
new file mode 100644
index 0000000..cd3e99b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/cross-origin-module-sharing-fails.html
@@ -0,0 +1,38 @@
+<title>Postmessage of a WebAssembly.Module cross-origin fails with a messageerror</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<script src="resources/test-incrementer.js"></script>
+
+<body>
+<script>
+async function testPostMessageErrorForOrigin(t, remoteOrigin){
+  const iframe = document.createElement('iframe');
+  iframe.src = `${remoteOrigin}${base_path()}resources/incrementer-iframe-failure.html`;
+  const iframeLoaded = new Promise(resolve => iframe.onload = resolve);
+  document.body.appendChild(iframe);
+  t.add_cleanup(() => {
+    iframe.remove();
+  });
+  await iframeLoaded;
+
+  const module = await createWasmModule();
+  const messageErrorReceived =
+    new Promise(resolve => window.onmessage = resolve);
+  iframe.contentWindow.postMessage({message: 'send module', module}, "*");
+  let reply = await messageErrorReceived;
+  assert_equals('messageerror received', reply.data);
+}
+
+promise_test(async t => {
+  const remoteOrigin = get_host_info().OTHER_ORIGIN;
+  await testPostMessageErrorForOrigin(t, remoteOrigin);
+}, "postMessaging a wasm module to an iframe in a different agent cluster fails");
+
+promise_test(async t => {
+  const remoteOrigin = get_host_info().HTTPS_ORIGIN;
+  await testPostMessageErrorForOrigin(t, remoteOrigin);
+}, "postMessaging a wasm module to a cross-origin iframe in the same agent cluster fails");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index fd1255fa..0813cf8f 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -2151,6 +2151,7 @@
     getter selectionEnd
     getter selectionStart
     getter text
+    method attachedElements
     method constructor
     method updateBounds
     method updateSelection
diff --git a/tools/clang/rewrite_raw_ptr_fields/manual-paths-to-ignore.txt b/tools/clang/rewrite_raw_ptr_fields/manual-paths-to-ignore.txt
index 8d65485..5c22e8d 100644
--- a/tools/clang/rewrite_raw_ptr_fields/manual-paths-to-ignore.txt
+++ b/tools/clang/rewrite_raw_ptr_fields/manual-paths-to-ignore.txt
@@ -64,11 +64,26 @@
 base/containers/linked_list.h
 base/containers/circular_deque.h
 
-# Performance related exclusion based on speedometer2 benchmark
-third_party/blink/renderer/core/
-third_party/blink/renderer/platform/bindings/
-third_party/blink/renderer/platform/heap/
-third_party/blink/renderer/platform/wtf/
+# Exclude code that only runs inside a renderer process - renderer
+# processes are excluded for now from the MiraclePtr project scope,
+# because they are sensitive to performance regressions (to a much higher
+# degree than, say, the Browser process).
+#
+# Note that some renderer-only directories are already excluded
+# elsewhere - for example "v8/" is excluded in another part of this
+# file.
+#
+# The common/ directories must be included in the rewrite as they contain code
+# that is also used from the browser process.
+#
+# Also, note that isInThirdPartyLocation AST matcher in
+# RewriteRawPtrFields.cpp explicitly includes third_party/blink
+# (because it is in the same git repository as the rest of Chromium),
+# but we go ahead and exclude it below.
+/renderer/  # (e.g. //content/renderer/ or //components/visitedlink/renderer/).
+third_party/blink/
+!third_party/blink/public/common/
+!third_party/blink/common/
 
 # Exclude paths in separate repositories - i.e. in directories that
 # 1. Contain a ".git" subdirectory
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b22c206..95eb8e67 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3601,6 +3601,25 @@
       label="Shortcut install, menu showed 'Install' (failure mode)"/>
 </enum>
 
+<enum name="AppTypeV2">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="Android app"/>
+  <int value="2" label="Built-in app"/>
+  <int value="3" label="Linux app"/>
+  <int value="4" label="Chrome app opened in a window"/>
+  <int value="5" label="Chrome app opened in a tab"/>
+  <int value="6" label="Web app in a window"/>
+  <int value="7" label="Web app in a tab"/>
+  <int value="8" label="Mac OS app"/>
+  <int value="9" label="Plugin VM"/>
+  <int value="10" label="Standalone browser"/>
+  <int value="11" label="Remote app"/>
+  <int value="12" label="Borealis app"/>
+  <int value="13" label="System web app"/>
+  <int value="14" label="Chrome browser (inc. web/Chrome apps in tabs)"/>
+  <int value="15" label="Chrome app opened in Standalone browser"/>
+</enum>
+
 <enum name="AppWillTerminateReceived">
   <int value="0" label="WasNotReceivedForXte">
     ApplicationWillTerminate notification was not received for this XTE.
@@ -15248,6 +15267,7 @@
   <int value="22" label="kHeaderDisallowedByPreflightResponse"/>
   <int value="23" label="kRedirectContainsCredentials"/>
   <int value="24" label="kInsecurePrivateNetwork"/>
+  <int value="25" label="kInvalidPrivateNetworkAccess"/>
 </enum>
 
 <enum name="CorsAccessCheckResult">
@@ -34666,6 +34686,7 @@
   <int value="4049" label="ClientHintsViewportWidth"/>
   <int value="4050" label="InlineBoxIgnoringContinuation"/>
   <int value="4051" label="OffsetWidthOrHeightIgnoringContinuation"/>
+  <int value="4052" label="ConditionalFocus"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index 6de1268d..01affa5 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -209,7 +209,20 @@
     expires_after="2022-07-01">
   <owner>dominickn@chromium.org</owner>
   <owner>nancylingwang@chromium.org</owner>
-  <summary>Records an app launch grouped by app type.</summary>
+  <summary>
+    Records an app launch grouped by app type. This is recorded when an app is
+    launched.
+  </summary>
+</histogram>
+
+<histogram name="Apps.AppLaunchPerAppTypeV2" enum="AppTypeV2"
+    expires_after="2022-07-01">
+  <owner>nancylingwang@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <summary>
+    Records an app launch grouped by app type V2. This is recorded when an app
+    is launched.
+  </summary>
 </histogram>
 
 <histogram name="Apps.AppLaunchSource" enum="LaunchSource"
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 33d08e0..3ee2060 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1027,7 +1027,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SAML.APILogin" enum="ChromeOSSamlApiUsed"
-    expires_after="2021-10-02">
+    expires_after="2022-04-02">
   <owner>mslus@chromium.org</owner>
   <owner>emaxx@chromium.org</owner>
   <summary>
@@ -1046,7 +1046,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SAML.InSessionPasswordSyncEvent"
-    enum="SamlInSessionPasswordSyncEvent" expires_after="2021-10-30">
+    enum="SamlInSessionPasswordSyncEvent" expires_after="2022-04-30">
   <owner>mslus@chromium.org</owner>
   <owner>mohammedabdon@chromium.org</owner>
   <summary>
@@ -1056,7 +1056,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SAML.Provider" enum="ChromeOSSamlProvider"
-    expires_after="2021-10-17">
+    expires_after="2022-04-17">
   <owner>mslus@chromium.org</owner>
   <owner>mohammedabdon@chromium.org</owner>
   <summary>Records SAML provider when SAML login flow is used.</summary>
diff --git a/tools/metrics/histograms/metadata/login/histograms.xml b/tools/metrics/histograms/metadata/login/histograms.xml
index 2e23c4a..4e0824da 100644
--- a/tools/metrics/histograms/metadata/login/histograms.xml
+++ b/tools/metrics/histograms/metadata/login/histograms.xml
@@ -129,7 +129,7 @@
 </histogram>
 
 <histogram name="Login.OfflineLoginWithHiddenUserPods"
-    enum="ChromeOSHiddenUserPodsOfflineLogin" expires_after="M95">
+    enum="ChromeOSHiddenUserPodsOfflineLogin" expires_after="M105">
   <owner>mslus@chromium.org</owner>
   <owner>chromeos-commercial-identity@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 8e67311..10c480e8 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1039,6 +1039,9 @@
 
 <histogram name="Navigation.OnReceiveResponseToOnStartLoadingResponseBody"
     units="ms" expires_after="M85">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 47af2ad..8fe91e7 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -788,6 +788,9 @@
 
 <histogram name="PageLoad.Clients.ServiceWorker2.PageTransition"
     enum="CorePageTransition" expires_after="M85">
+  <obsolete>
+    Expired in October 2020. Removed from the code in September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <summary>
     The core transition type for main frame page loads controlled by a service
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml
index a902848..beec77e4 100644
--- a/tools/metrics/histograms/metadata/renderer/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -309,6 +309,9 @@
 
 <histogram name="Renderer.OnReceiveResponseToOnStartLoadingResponseBody"
     units="ms" expires_after="M85">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index 3bb28fa4..3eb5842 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -835,6 +835,9 @@
 
 <histogram name="ServiceWorker.ScriptCachedMetadataSize" units="bytes"
     expires_after="2021-12-19">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -847,6 +850,9 @@
 
 <histogram name="ServiceWorker.ScriptCachedMetadataTotalSize" units="bytes"
     expires_after="2021-05-18">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -859,6 +865,9 @@
 
 <histogram name="ServiceWorker.ScriptCount" units="count"
     expires_after="2021-05-18">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -870,6 +879,9 @@
 
 <histogram name="ServiceWorker.ScriptSize" units="bytes"
     expires_after="2021-05-18">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -881,6 +893,9 @@
 
 <histogram name="ServiceWorker.ScriptTotalSize" units="bytes"
     expires_after="2021-05-18">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -909,6 +924,9 @@
 
 <histogram name="ServiceWorker.StartForNavigationHint.Result"
     enum="ServiceWorkerStartForNavigationHintResult" expires_after="2021-02-16">
+  <obsolete>
+    Removed September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -931,6 +949,10 @@
 
 <histogram name="ServiceWorker.StartTiming.BrowserThreadHopTime"
     units="microseconds" expires_after="M80">
+  <obsolete>
+    No longer emitted since ServiceWorkerOnUI shipped in September 2020 (M86):
+    https://crbug.com/824858
+  </obsolete>
   <owner>kinuko@chromium.org</owner>
   <summary>
     The sum of all the times spent posting tasks between the UI and IO threads
@@ -948,8 +970,9 @@
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.ClockConsistency"
-    enum="CrossProcessTimeDelta" expires_after="2020-07-30">
-  <owner>falken@chromium.org</owner>
+    enum="CrossProcessTimeDelta" expires_after="2022-09-01">
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     Recorded on each successful service worker startup.
@@ -961,12 +984,15 @@
 
     If the clocks and timing were inconsistent, ServiceWorker.StartTiming.*
     metrics (other than this one) are not recorded.
+
+    This histogram was expired between roughly 2021-07-30 and 2021-09-31.
   </summary>
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.Duration" units="ms"
-    expires_after="2021-07-30">
-  <owner>falken@chromium.org</owner>
+    expires_after="2022-09-01">
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken to start a service worker that is already installed, from
@@ -975,13 +1001,16 @@
     if DevTools was ever attached to the Service Worker during startup. It does
     not include time, if any, waiting for the service worker to finish stopping
     before asking it to start, if that occurred.
+
+    This histogram was expired between roughly 2021-07-30 and 2021-09-31.
   </summary>
 </histogram>
 
 <histogram
     name="ServiceWorker.StartTiming.ReceivedStartWorkerToScriptEvaluationStart"
     units="ms" expires_after="2021-12-05">
-  <owner>falken@chromium.org</owner>
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) the renderer receiving the start worker IPC message,
@@ -992,7 +1021,8 @@
 
 <histogram name="ServiceWorker.StartTiming.ScriptEvaluationEndToEnd" units="ms"
     expires_after="2021-12-05">
-  <owner>falken@chromium.org</owner>
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) initial JavaScript evaluation finishing on the
@@ -1005,7 +1035,8 @@
 <histogram
     name="ServiceWorker.StartTiming.ScriptEvaluationStartToScriptEvaluationEnd"
     units="ms" expires_after="2021-12-05">
-  <owner>falken@chromium.org</owner>
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) initial JavaScript evaluation starting on the worker
@@ -1017,7 +1048,8 @@
 <histogram
     name="ServiceWorker.StartTiming.SentStartWorkerToReceivedStartWorker"
     units="ms" expires_after="2021-12-05">
-  <owner>falken@chromium.org</owner>
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) the browser sending the start worker IPC message, to
@@ -1027,41 +1059,51 @@
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.StartToReceivedStartWorker"
-    units="ms" expires_after="2021-07-30">
-  <owner>falken@chromium.org</owner>
+    units="ms" expires_after="2022-09-01">
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) the start of service worker startup, to (b) the
     renderer receiving the start worker IPC message. Recorded when
     ServiceWorker.StartTiming.Duration is recorded.
+
+    This histogram was expired between roughly 2021-07-30 and 2021-09-31.
   </summary>
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.StartToScriptEvaluationEnd"
-    units="ms" expires_after="2021-07-30">
-  <owner>falken@chromium.org</owner>
+    units="ms" expires_after="2022-09-01">
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) the start of service worker startup, to (b) initial
     JavaScript evaluation finishing on the worker thread. Recorded when
     ServiceWorker.StartTiming.Duration is recorded.
+
+    This histogram was expired between roughly 2021-07-30 and 2021-09-31.
   </summary>
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.StartToScriptEvaluationStart"
-    units="ms" expires_after="2021-07-30">
-  <owner>falken@chromium.org</owner>
+    units="ms" expires_after="2022-09-01">
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) the start of service worker startup, to (b) initial
     JavaScript evaluation starting on the worker thread. Recorded when
     ServiceWorker.StartTiming.Duration is recorded.
+
+    This histogram was expired between roughly 2021-07-30 and 2021-09-31.
   </summary>
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.StartToSentStartWorker" units="ms"
     expires_after="2021-12-05">
-  <owner>falken@chromium.org</owner>
+  <owner>wanderview@chromium.org</owner>
+  <owner>asamidoi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
     The time taken from (a) the start of service worker startup, to (b) the
@@ -1221,6 +1263,9 @@
 
 <histogram name="ServiceWorker.WorkerStopped" enum="ServiceWorkerStoppedStatus"
     expires_after="2021-08-09">
+  <obsolete>
+    Removed in September 2021.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 24602c9..0157c92 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -64,7 +64,7 @@
  <item id="content_hash_verification_job" added_in_milestone="62" hash_code="64733114" type="0" content_hash_code="127912411" os_list="linux,windows" file_path="extensions/browser/content_hash_fetcher.cc"/>
  <item id="content_resource_fetcher" added_in_milestone="63" hash_code="70796791" type="0" deprecated="2017-09-16" content_hash_code="135648626" file_path=""/>
  <item id="content_suggestion_get_favicon" added_in_milestone="62" hash_code="16653985" type="0" content_hash_code="134280933" os_list="linux,windows" file_path="components/ntp_snippets/content_suggestions_service.cc"/>
- <item id="conversion_measurement_report" added_in_milestone="84" hash_code="113422320" type="0" content_hash_code="102111798" os_list="linux,windows" file_path="content/browser/conversions/conversion_network_sender_impl.cc"/>
+ <item id="conversion_measurement_report" added_in_milestone="84" hash_code="113422320" type="0" content_hash_code="102111798" os_list="linux,windows" file_path="content/browser/attribution_reporting/conversion_network_sender_impl.cc"/>
  <item id="credenential_avatar" added_in_milestone="62" hash_code="53695122" type="0" content_hash_code="113035371" os_list="linux,windows" file_path="chrome/browser/ui/passwords/account_avatar_fetcher.cc"/>
  <item id="cros_recovery_image_download" added_in_milestone="62" hash_code="101725581" type="0" content_hash_code="10999698" os_list="linux,windows" file_path="chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc"/>
  <item id="cryptauth_device_sync_tickle" added_in_milestone="62" hash_code="96565489" type="1" second_id="29188932" deprecated="2018-03-15" content_hash_code="115714668" file_path=""/>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/shared_with_crostini_pluginvm_banner.js b/ui/file_manager/file_manager/foreground/js/ui/banners/shared_with_crostini_pluginvm_banner.js
index 66c6492c..737f583a 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/shared_with_crostini_pluginvm_banner.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/shared_with_crostini_pluginvm_banner.js
@@ -81,12 +81,14 @@
     if (context.type ===
         (constants.DEFAULT_CROSTINI_VM + constants.PLUGIN_VM)) {
       text.innerText = str('MESSAGE_FOLDER_SHARED_WITH_CROSTINI_AND_PLUGIN_VM');
-      button.setAttribute('href', 'chrome://os-settings/pluginVm/sharedPaths');
+      button.setAttribute(
+          'href', 'chrome://os-settings/app-management/pluginVm/sharedPaths');
       return;
     }
     if (context.type === constants.PLUGIN_VM) {
       text.innerText = str('MESSAGE_FOLDER_SHARED_WITH_PLUGIN_VM');
-      button.setAttribute('href', 'chrome://os-settings/pluginVm/sharedPaths');
+      button.setAttribute(
+          'href', 'chrome://os-settings/app-management/pluginVm/sharedPaths');
       return;
     }
     text.innerText = str('MESSAGE_FOLDER_SHARED_WITH_CROSTINI');
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 0942348..f8d75d7 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -54,6 +54,8 @@
     "host/gtk_surface1.h",
     "host/org_kde_kwin_idle.cc",
     "host/org_kde_kwin_idle.h",
+    "host/overlay_prioritizer.cc",
+    "host/overlay_prioritizer.h",
     "host/shell_object_factory.cc",
     "host/shell_object_factory.h",
     "host/shell_popup_wrapper.cc",
@@ -202,6 +204,7 @@
     "//build/config/linux/libdrm",
     "//components/crash/core/common:crash_key",
     "//components/exo/wayland/protocol:aura_shell_protocol",
+    "//components/exo/wayland/protocol:overlay_prioritizer_protocol",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//skia",
@@ -389,6 +392,10 @@
     "test/test_keyboard.h",
     "test/test_output.cc",
     "test/test_output.h",
+    "test/test_overlay_prioritized_surface.cc",
+    "test/test_overlay_prioritized_surface.h",
+    "test/test_overlay_prioritizer.cc",
+    "test/test_overlay_prioritizer.h",
     "test/test_positioner.cc",
     "test/test_positioner.h",
     "test/test_region.cc",
@@ -428,6 +435,7 @@
   ]
 
   public_deps = [
+    "//components/exo/wayland/protocol:overlay_prioritizer_protocol",
     "//skia",
     "//testing/gmock",
     "//third_party/wayland:wayland_server",
diff --git a/ui/ozone/platform/wayland/common/wayland_object.cc b/ui/ozone/platform/wayland/common/wayland_object.cc
index 6b64e6f..1fea999 100644
--- a/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -15,6 +15,7 @@
 #include <keyboard-extension-unstable-v1-client-protocol.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <linux-explicit-synchronization-unstable-v1-client-protocol.h>
+#include <overlay-prioritizer-client-protocol.h>
 #include <pointer-constraints-unstable-v1-client-protocol.h>
 #include <pointer-gestures-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
@@ -107,6 +108,8 @@
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(gtk_surface1)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(org_kde_kwin_idle)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(org_kde_kwin_idle_timeout)
+IMPLEMENT_WAYLAND_OBJECT_TRAITS(overlay_prioritizer)
+IMPLEMENT_WAYLAND_OBJECT_TRAITS(overlay_prioritized_surface)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(wl_buffer)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(wl_callback)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(wl_compositor)
diff --git a/ui/ozone/platform/wayland/common/wayland_object.h b/ui/ozone/platform/wayland/common/wayland_object.h
index 4135627..6aafd59 100644
--- a/ui/ozone/platform/wayland/common/wayland_object.h
+++ b/ui/ozone/platform/wayland/common/wayland_object.h
@@ -25,29 +25,22 @@
 using GlobalObjectFactory = void (*)(ui::WaylandConnection* connection,
                                      wl_registry* registry,
                                      uint32_t name,
+                                     const std::string& interface,
                                      uint32_t version);
 
-// This template forces T to declare two static methods, Register() and
-// Instantiate().  The subclass must implement them as follows:
-//
-// void Register(ui::WaylandConnection* connection)
-// - must call connection->RegisterGlobalObjectFactory() and pass there the name
-//   of the Wayland interface and the address of the subclass's Instantiate()
-//   method.  The connection will use the name of the interface as a key to find
-//   and call the instantiation method when that interface is announced by the
-//   server.
+// This template forces T to declare a static Instantiate() method.  The
+// subclass must implement it as follows:
 //
 // void Instantiate(WaylandConnection* connection,
 //                  wl_registry* registry,
 //                  uint32_t name,
+//                  const std::string& interface,
 //                  uint32_t version)
 // - must bind the Wayland object and store it in the connection.
 template <typename T>
 class GlobalObjectRegistrar {
  public:
   GlobalObjectRegistrar() {
-    void (*Register)(ui::WaylandConnection*) = T::Register;
-    ALLOW_UNUSED_LOCAL(Register);
     GlobalObjectFactory Instantiate = T::Instantiate;
     ALLOW_UNUSED_LOCAL(Instantiate);
   }
@@ -109,6 +102,8 @@
 DECLARE_WAYLAND_OBJECT_TRAITS(gtk_surface1)
 DECLARE_WAYLAND_OBJECT_TRAITS(org_kde_kwin_idle)
 DECLARE_WAYLAND_OBJECT_TRAITS(org_kde_kwin_idle_timeout)
+DECLARE_WAYLAND_OBJECT_TRAITS(overlay_prioritizer)
+DECLARE_WAYLAND_OBJECT_TRAITS(overlay_prioritized_surface)
 DECLARE_WAYLAND_OBJECT_TRAITS(wl_buffer)
 DECLARE_WAYLAND_OBJECT_TRAITS(wl_callback)
 DECLARE_WAYLAND_OBJECT_TRAITS(wl_compositor)
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
index 8822c0a5..af3087d 100644
--- a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
@@ -20,18 +20,17 @@
 }
 
 // static
-void GtkPrimarySelectionDeviceManager::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory(
-      "gtk_primary_selection_device_manager",
-      &GtkPrimarySelectionDeviceManager::Instantiate);
-}
+constexpr char GtkPrimarySelectionDeviceManager::kInterfaceName[];
 
 // static
 void GtkPrimarySelectionDeviceManager::Instantiate(
     WaylandConnection* connection,
     wl_registry* registry,
     uint32_t name,
+    const std::string& interface,
     uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->gtk_primary_selection_device_manager())
     return;
 
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h
index 395f5db..e358408 100644
--- a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h
@@ -21,10 +21,13 @@
   using DataSource = GtkPrimarySelectionSource;
   using DataDevice = GtkPrimarySelectionDevice;
 
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] =
+      "gtk_primary_selection_device_manager";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   GtkPrimarySelectionDeviceManager(
diff --git a/ui/ozone/platform/wayland/host/gtk_shell1.cc b/ui/ozone/platform/wayland/host/gtk_shell1.cc
index 88126d9d..cb3b0c8 100644
--- a/ui/ozone/platform/wayland/host/gtk_shell1.cc
+++ b/ui/ozone/platform/wayland/host/gtk_shell1.cc
@@ -22,16 +22,16 @@
 }  // namespace
 
 // static
-void GtkShell1::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("gtk_shell1",
-                                          &GtkShell1::Instantiate);
-}
+constexpr char GtkShell1::kInterfaceName[];
 
 // static
 void GtkShell1::Instantiate(WaylandConnection* connection,
                             wl_registry* registry,
                             uint32_t name,
+                            const std::string& interface,
                             uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->gtk_shell1_ || version < kMinGtkShell1Version)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/gtk_shell1.h b/ui/ozone/platform/wayland/host/gtk_shell1.h
index ed52a69..8347604 100644
--- a/ui/ozone/platform/wayland/host/gtk_shell1.h
+++ b/ui/ozone/platform/wayland/host/gtk_shell1.h
@@ -15,10 +15,12 @@
 
 class GtkShell1 : public wl::GlobalObjectRegistrar<GtkShell1> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "gtk_shell1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   explicit GtkShell1(gtk_shell1* shell1);
diff --git a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc
index d990c81..7cff69b 100644
--- a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc
+++ b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc
@@ -48,16 +48,16 @@
 };
 
 // static
-void OrgKdeKwinIdle::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("org_kde_kwin_idle",
-                                          &OrgKdeKwinIdle::Instantiate);
-}
+constexpr char OrgKdeKwinIdle::kInterfaceName[];
 
 // static
 void OrgKdeKwinIdle::Instantiate(WaylandConnection* connection,
                                  wl_registry* registry,
                                  uint32_t name,
+                                 const std::string& interface,
                                  uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->org_kde_kwin_idle_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h
index 303f5f2..7be8c268 100644
--- a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h
+++ b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h
@@ -19,10 +19,12 @@
 // org_kde_kwin_idle interface.
 class OrgKdeKwinIdle : public wl::GlobalObjectRegistrar<OrgKdeKwinIdle> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "org_kde_kwin_idle";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   OrgKdeKwinIdle(org_kde_kwin_idle* idle, WaylandConnection* connection);
diff --git a/ui/ozone/platform/wayland/host/overlay_prioritizer.cc b/ui/ozone/platform/wayland/host/overlay_prioritizer.cc
new file mode 100644
index 0000000..e8aaf39
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/overlay_prioritizer.cc
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/overlay_prioritizer.h"
+
+#include <overlay-prioritizer-client-protocol.h>
+
+#include "base/logging.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+
+namespace ui {
+
+namespace {
+constexpr uint32_t kMaxOverlayPrioritizerVersion = 1;
+}
+
+// static
+constexpr char OverlayPrioritizer::kInterfaceName[];
+
+// static
+void OverlayPrioritizer::Instantiate(WaylandConnection* connection,
+                                     wl_registry* registry,
+                                     uint32_t name,
+                                     const std::string& interface,
+                                     uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
+  if (connection->overlay_prioritizer_)
+    return;
+
+  auto prioritizer = wl::Bind<overlay_prioritizer>(
+      registry, name, std::min(version, kMaxOverlayPrioritizerVersion));
+  if (!prioritizer) {
+    LOG(ERROR) << "Failed to bind overlay_prioritizer";
+    return;
+  }
+  connection->overlay_prioritizer_ =
+      std::make_unique<OverlayPrioritizer>(prioritizer.release(), connection);
+}
+
+OverlayPrioritizer::OverlayPrioritizer(overlay_prioritizer* prioritizer,
+                                       WaylandConnection* connection)
+    : prioritizer_(prioritizer) {}
+
+OverlayPrioritizer::~OverlayPrioritizer() = default;
+
+wl::Object<overlay_prioritized_surface>
+OverlayPrioritizer::CreateOverlayPrioritizedSurface(wl_surface* surface) {
+  return wl::Object<overlay_prioritized_surface>(
+      overlay_prioritizer_get_overlay_prioritized_surface(prioritizer_.get(),
+                                                          surface));
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/overlay_prioritizer.h b/ui/ozone/platform/wayland/host/overlay_prioritizer.h
new file mode 100644
index 0000000..81429b9
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/overlay_prioritizer.h
@@ -0,0 +1,43 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_OVERLAY_PRIORITIZER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_OVERLAY_PRIORITIZER_H_
+
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace ui {
+
+class WaylandConnection;
+
+// Wraps the overlay-prioritizer, which is provided via
+// overlay_prioritizer interface.
+class OverlayPrioritizer
+    : public wl::GlobalObjectRegistrar<OverlayPrioritizer> {
+ public:
+  static constexpr char kInterfaceName[] = "overlay_prioritizer";
+
+  static void Instantiate(WaylandConnection* connection,
+                          wl_registry* registry,
+                          uint32_t name,
+                          const std::string& interface,
+                          uint32_t version);
+
+  explicit OverlayPrioritizer(overlay_prioritizer* prioritizer,
+                              WaylandConnection* connection);
+  OverlayPrioritizer(const OverlayPrioritizer&) = delete;
+  OverlayPrioritizer& operator=(const OverlayPrioritizer&) = delete;
+  ~OverlayPrioritizer();
+
+  wl::Object<overlay_prioritized_surface> CreateOverlayPrioritizedSurface(
+      wl_surface* surface);
+
+ private:
+  // Wayland object wrapped by this class.
+  wl::Object<overlay_prioritizer> prioritizer_;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_OVERLAY_PRIORITIZER_H_
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index 2146973f..c93bd97 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -30,6 +30,7 @@
 #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
 #include "ui/ozone/platform/wayland/host/gtk_shell1.h"
 #include "ui/ozone/platform/wayland/host/org_kde_kwin_idle.h"
+#include "ui/ozone/platform/wayland/host/overlay_prioritizer.h"
 #include "ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.h"
 #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
 #include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
@@ -156,22 +157,40 @@
 
   // Register factories for classes that implement wl::GlobalObjectRegistrar<T>.
   // Keep alphabetical order for convenience.
-  GtkPrimarySelectionDeviceManager::Register(this);
-  GtkShell1::Register(this);
-  OrgKdeKwinIdle::Register(this);
-  WaylandDataDeviceManager::Register(this);
-  WaylandDrm::Register(this);
-  WaylandOutput::Register(this);
-  WaylandShm::Register(this);
-  WaylandZAuraShell::Register(this);
-  WaylandZcrCursorShapes::Register(this);
-  WaylandZwpLinuxDmabuf::Register(this);
-  WaylandZwpPointerConstraints::Register(this);
-  WaylandZwpPointerGestures::Register(this);
-  WaylandZwpRelativePointerManager::Register(this);
-  XdgForeignWrapper::Register(this);
-  ZwpIdleInhibitManager::Register(this);
-  ZwpPrimarySelectionDeviceManager::Register(this);
+  RegisterGlobalObjectFactory(GtkPrimarySelectionDeviceManager::kInterfaceName,
+                              &GtkPrimarySelectionDeviceManager::Instantiate);
+  RegisterGlobalObjectFactory(GtkShell1::kInterfaceName,
+                              &GtkShell1::Instantiate);
+  RegisterGlobalObjectFactory(OrgKdeKwinIdle::kInterfaceName,
+                              &OrgKdeKwinIdle::Instantiate);
+  RegisterGlobalObjectFactory(OverlayPrioritizer::kInterfaceName,
+                              &OverlayPrioritizer::Instantiate);
+  RegisterGlobalObjectFactory(WaylandDataDeviceManager::kInterfaceName,
+                              &WaylandDataDeviceManager::Instantiate);
+  RegisterGlobalObjectFactory(WaylandDrm::kInterfaceName,
+                              &WaylandDrm::Instantiate);
+  RegisterGlobalObjectFactory(WaylandOutput::kInterfaceName,
+                              &WaylandOutput::Instantiate);
+  RegisterGlobalObjectFactory(WaylandShm::kInterfaceName,
+                              &WaylandShm::Instantiate);
+  RegisterGlobalObjectFactory(WaylandZAuraShell::kInterfaceName,
+                              &WaylandZAuraShell::Instantiate);
+  RegisterGlobalObjectFactory(WaylandZcrCursorShapes::kInterfaceName,
+                              &WaylandZcrCursorShapes::Instantiate);
+  RegisterGlobalObjectFactory(WaylandZwpLinuxDmabuf::kInterfaceName,
+                              &WaylandZwpLinuxDmabuf::Instantiate);
+  RegisterGlobalObjectFactory(WaylandZwpPointerConstraints::kInterfaceName,
+                              &WaylandZwpPointerConstraints::Instantiate);
+  RegisterGlobalObjectFactory(WaylandZwpPointerGestures::kInterfaceName,
+                              &WaylandZwpPointerGestures::Instantiate);
+  RegisterGlobalObjectFactory(WaylandZwpRelativePointerManager::kInterfaceName,
+                              &WaylandZwpRelativePointerManager::Instantiate);
+  RegisterGlobalObjectFactory(XdgForeignWrapper::kInterfaceName,
+                              &XdgForeignWrapper::Instantiate);
+  RegisterGlobalObjectFactory(ZwpIdleInhibitManager::kInterfaceName,
+                              &ZwpIdleInhibitManager::Instantiate);
+  RegisterGlobalObjectFactory(ZwpPrimarySelectionDeviceManager::kInterfaceName,
+                              &ZwpPrimarySelectionDeviceManager::Instantiate);
 
   static constexpr wl_registry_listener registry_listener = {
       &Global,
@@ -444,7 +463,7 @@
 
   auto factory_it = connection->global_object_factories_.find(interface);
   if (factory_it != connection->global_object_factories_.end()) {
-    (*factory_it->second)(connection, registry, name, version);
+    (*factory_it->second)(connection, registry, name, interface, version);
   } else if (!connection->compositor_ &&
              strcmp(interface, "wl_compositor") == 0) {
     connection->compositor_ = wl::Bind<wl_compositor>(
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index e5a44d2..e148bda 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -60,6 +60,7 @@
 class ZwpIdleInhibitManager;
 class ZwpPrimarySelectionDeviceManager;
 class XdgForeignWrapper;
+class OverlayPrioritizer;
 
 // These values are persisted to logs.  Entries should not be renumbered and
 // numeric values should never be reused.
@@ -236,6 +237,10 @@
     return zwp_idle_inhibit_manager_.get();
   }
 
+  OverlayPrioritizer* overlay_prioritizer() const {
+    return overlay_prioritizer_.get();
+  }
+
   // Returns whether protocols that support setting window geometry are
   // available.
   bool SupportsSetWindowGeometry() const;
@@ -276,6 +281,7 @@
   friend class GtkPrimarySelectionDeviceManager;
   friend class GtkShell1;
   friend class OrgKdeKwinIdle;
+  friend class OverlayPrioritizer;
   friend class WaylandDataDeviceManager;
   friend class WaylandDrm;
   friend class WaylandOutput;
@@ -373,6 +379,7 @@
   std::unique_ptr<WaylandBufferManagerHost> buffer_manager_host_;
   std::unique_ptr<XdgForeignWrapper> xdg_foreign_;
   std::unique_ptr<ZwpIdleInhibitManager> zwp_idle_inhibit_manager_;
+  std::unique_ptr<OverlayPrioritizer> overlay_prioritizer_;
 
   // Clipboard-related objects. |clipboard_| must be declared after all
   // DeviceManager instances it depends on, otherwise tests may crash with
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc b/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
index 036512a..408cb1c7 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
@@ -18,16 +18,16 @@
 }
 
 // static
-void WaylandDataDeviceManager::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory(
-      "wl_data_device_manager", &WaylandDataDeviceManager::Instantiate);
-}
+constexpr char WaylandDataDeviceManager::kInterfaceName[];
 
 // static
 void WaylandDataDeviceManager::Instantiate(WaylandConnection* connection,
                                            wl_registry* registry,
                                            uint32_t name,
+                                           const std::string& interface,
                                            uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->data_device_manager_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device_manager.h b/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
index 76925e8..fa6899c6a 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
@@ -18,10 +18,12 @@
 class WaylandDataDeviceManager
     : public wl::GlobalObjectRegistrar<WaylandDataDeviceManager> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "wl_data_device_manager";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   using DataSource = WaylandDataSource;
diff --git a/ui/ozone/platform/wayland/host/wayland_drm.cc b/ui/ozone/platform/wayland/host/wayland_drm.cc
index e11d58c..d806e8e 100644
--- a/ui/ozone/platform/wayland/host/wayland_drm.cc
+++ b/ui/ozone/platform/wayland/host/wayland_drm.cc
@@ -21,15 +21,16 @@
 }
 
 // static
-void WaylandDrm::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("wl_drm", &WaylandDrm::Instantiate);
-}
+constexpr char WaylandDrm::kInterfaceName[];
 
 // static
 void WaylandDrm::Instantiate(WaylandConnection* connection,
                              wl_registry* registry,
                              uint32_t name,
+                             const std::string& interface,
                              uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->drm_ || version < kMinWlDrmVersion)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_drm.h b/ui/ozone/platform/wayland/host/wayland_drm.h
index b03ae72d..b881264 100644
--- a/ui/ozone/platform/wayland/host/wayland_drm.h
+++ b/ui/ozone/platform/wayland/host/wayland_drm.h
@@ -29,10 +29,12 @@
 // |wl_buffer|s backed by dmabuf prime file descriptors.
 class WaylandDrm : public wl::GlobalObjectRegistrar<WaylandDrm> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "wl_drm";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   WaylandDrm(wl_drm* drm, WaylandConnection* connection);
diff --git a/ui/ozone/platform/wayland/host/wayland_output.cc b/ui/ozone/platform/wayland/host/wayland_output.cc
index 741385b..7f52891 100644
--- a/ui/ozone/platform/wayland/host/wayland_output.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output.cc
@@ -20,16 +20,16 @@
 }
 
 // static
-void WaylandOutput::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("wl_output",
-                                          &WaylandOutput::Instantiate);
-}
+constexpr char WaylandOutput::kInterfaceName[];
 
 // static
 void WaylandOutput::Instantiate(WaylandConnection* connection,
                                 wl_registry* registry,
                                 uint32_t name,
+                                const std::string& interface,
                                 uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (version < kMinWlOutputVersion) {
     LOG(ERROR)
         << "Unable to bind to the unsupported wl_output object with version= "
diff --git a/ui/ozone/platform/wayland/host/wayland_output.h b/ui/ozone/platform/wayland/host/wayland_output.h
index 303793dc..0beb4f4 100644
--- a/ui/ozone/platform/wayland/host/wayland_output.h
+++ b/ui/ozone/platform/wayland/host/wayland_output.h
@@ -20,10 +20,12 @@
 // that are available to the application.
 class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "wl_output";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   class Delegate {
diff --git a/ui/ozone/platform/wayland/host/wayland_shm.cc b/ui/ozone/platform/wayland/host/wayland_shm.cc
index 1b39c82..7c6cd40 100644
--- a/ui/ozone/platform/wayland/host/wayland_shm.cc
+++ b/ui/ozone/platform/wayland/host/wayland_shm.cc
@@ -15,15 +15,16 @@
 }  // namespace
 
 // static
-void WaylandShm::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("wl_shm", &WaylandShm::Instantiate);
-}
+constexpr char WaylandShm::kInterfaceName[];
 
 // static
 void WaylandShm::Instantiate(WaylandConnection* connection,
                              wl_registry* registry,
                              uint32_t name,
+                             const std::string& interface,
                              uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->shm_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_shm.h b/ui/ozone/platform/wayland/host/wayland_shm.h
index 9484dda..23bf03b 100644
--- a/ui/ozone/platform/wayland/host/wayland_shm.h
+++ b/ui/ozone/platform/wayland/host/wayland_shm.h
@@ -20,10 +20,12 @@
 // |wl_buffer|s backed by a fd to a shared memory.
 class WaylandShm : public wl::GlobalObjectRegistrar<WaylandShm> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "wl_shm";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   WaylandShm(wl_shm* shm, WaylandConnection* connection);
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
index 2bd7736..7e38c64 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -6,6 +6,7 @@
 
 #include <alpha-compositing-unstable-v1-client-protocol.h>
 #include <linux-explicit-synchronization-unstable-v1-client-protocol.h>
+#include <overlay-prioritizer-client-protocol.h>
 #include <viewporter-client-protocol.h>
 #include <algorithm>
 
@@ -16,6 +17,7 @@
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/overlay_prioritizer.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_output.h"
 #include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
@@ -23,6 +25,31 @@
 
 namespace ui {
 
+namespace {
+
+uint32_t TranslatePriority(gfx::OverlayPriorityHint priority_hint) {
+  uint32_t priority = OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_NONE;
+  switch (priority_hint) {
+    case gfx::OverlayPriorityHint::kNone:
+      priority = OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_NONE;
+      break;
+    case gfx::OverlayPriorityHint::kRegular:
+      priority = OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_REGULAR;
+      break;
+    case gfx::OverlayPriorityHint::kLowLatencyCanvas:
+      priority =
+          OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_PREFERRED_LOW_LATENCY_CANVAS;
+      break;
+    case gfx::OverlayPriorityHint::kHardwareProtection:
+      priority =
+          OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_REQUIRED_HARDWARE_PROTECTION;
+      break;
+  }
+  return priority;
+}
+
+}  // namespace
+
 WaylandSurface::ExplicitReleaseInfo::ExplicitReleaseInfo(
     wl::Object<zwp_linux_buffer_release_v1>&& linux_buffer_release,
     wl_buffer* buffer)
@@ -86,6 +113,17 @@
     LOG(WARNING) << "Server doesn't support zcr_alpha_compositing_v1.";
   }
 
+  if (auto* overlay_prioritizer = connection_->overlay_prioritizer()) {
+    overlay_priority_surface_ =
+        overlay_prioritizer->CreateOverlayPrioritizedSurface(surface());
+    if (!overlay_priority_surface_) {
+      LOG(ERROR) << "Failed to create overlay_priority_surface";
+      return false;
+    }
+  } else {
+    LOG(WARNING) << "Server doesn't support overlay_prioritizer.";
+  }
+
   return true;
 }
 
@@ -439,7 +477,10 @@
 
 void WaylandSurface::SetOverlayPriority(
     gfx::OverlayPriorityHint priority_hint) {
-  NOTIMPLEMENTED_LOG_ONCE();
+  if (overlay_priority_surface()) {
+    overlay_prioritized_surface_set_overlay_priority(
+        overlay_priority_surface(), TranslatePriority(priority_hint));
+  }
 }
 
 // static
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
index 1668967..9578f42 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -40,6 +40,9 @@
   ~WaylandSurface();
 
   WaylandWindow* root_window() const { return root_window_; }
+  overlay_prioritized_surface* overlay_priority_surface() {
+    return overlay_priority_surface_.get();
+  }
   wl_surface* surface() const { return surface_.get(); }
   wp_viewport* viewport() const { return viewport_.get(); }
   zcr_blending_v1* blending() const { return blending_.get(); }
@@ -176,6 +179,7 @@
   wl::Object<wp_viewport> viewport_;
   wl::Object<zcr_blending_v1> blending_;
   wl::Object<zwp_linux_surface_synchronization_v1> surface_sync_;
+  wl::Object<overlay_prioritized_surface> overlay_priority_surface_;
   base::flat_map<zwp_linux_buffer_release_v1*, ExplicitReleaseInfo>
       linux_buffer_releases_;
   ExplicitReleaseCallback explicit_release_callback_;
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 29f951d3..c5499194 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -279,6 +279,7 @@
 
  private:
   FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetWindowScale);
+  FRIEND_TEST_ALL_PREFIXES(WaylandBufferManagerTest, CanSubmitOverlayPriority);
 
   // Initializes the WaylandWindow with supplied properties.
   bool Initialize(PlatformWindowInitProperties properties);
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc b/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
index 593fb11..a9e72376 100644
--- a/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
@@ -22,16 +22,16 @@
 }
 
 // static
-void WaylandZAuraShell::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("zaura_shell",
-                                          &WaylandZAuraShell::Instantiate);
-}
+constexpr char WaylandZAuraShell::kInterfaceName[];
 
 // static
 void WaylandZAuraShell::Instantiate(WaylandConnection* connection,
                                     wl_registry* registry,
                                     uint32_t name,
+                                    const std::string& interface,
                                     uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->zaura_shell_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_shell.h b/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
index 4d4279b8..19144508 100644
--- a/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
@@ -15,10 +15,12 @@
 // Wraps the zaura_shell object.
 class WaylandZAuraShell : public wl::GlobalObjectRegistrar<WaylandZAuraShell> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zaura_shell";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   WaylandZAuraShell(zaura_shell* aura_shell, WaylandConnection* connection);
diff --git a/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc b/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc
index 651e4f8..094a2f9 100644
--- a/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc
@@ -22,16 +22,16 @@
 using mojom::CursorType;
 
 // static
-void WaylandZcrCursorShapes::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("zcr_cursor_shapes_v1",
-                                          &WaylandZcrCursorShapes::Instantiate);
-}
+constexpr char WaylandZcrCursorShapes::kInterfaceName[];
 
 // static
 void WaylandZcrCursorShapes::Instantiate(WaylandConnection* connection,
                                          wl_registry* registry,
                                          uint32_t name,
+                                         const std::string& interface,
                                          uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->zcr_cursor_shapes_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h b/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h
index 9780c13..29af2085 100644
--- a/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h
+++ b/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h
@@ -19,10 +19,12 @@
 class WaylandZcrCursorShapes
     : public wl::GlobalObjectRegistrar<WaylandZcrCursorShapes> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zcr_cursor_shapes_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   WaylandZcrCursorShapes(zcr_cursor_shapes_v1* zcr_cursor_shapes,
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
index 099c93f..7035dc4 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
@@ -18,16 +18,16 @@
 }
 
 // static
-void WaylandZwpLinuxDmabuf::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("zwp_linux_dmabuf_v1",
-                                          &WaylandZwpLinuxDmabuf::Instantiate);
-}
+constexpr char WaylandZwpLinuxDmabuf::kInterfaceName[];
 
 // static
 void WaylandZwpLinuxDmabuf::Instantiate(WaylandConnection* connection,
                                         wl_registry* registry,
                                         uint32_t name,
+                                        const std::string& interface,
                                         uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->zwp_dmabuf())
     return;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h
index c3ad237..5f3243cf 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h
@@ -30,10 +30,12 @@
 class WaylandZwpLinuxDmabuf
     : public wl::GlobalObjectRegistrar<WaylandZwpLinuxDmabuf> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zwp_linux_dmabuf_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   WaylandZwpLinuxDmabuf(zwp_linux_dmabuf_v1* zwp_linux_dmabuf,
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc
index b0c3544..24e4dac 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc
@@ -19,16 +19,16 @@
 }
 
 // static
-void WaylandZwpPointerConstraints::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory(
-      "zwp_pointer_constraints_v1", &WaylandZwpPointerConstraints::Instantiate);
-}
+constexpr char WaylandZwpPointerConstraints::kInterfaceName[];
 
 // static
 void WaylandZwpPointerConstraints::Instantiate(WaylandConnection* connection,
                                                wl_registry* registry,
                                                uint32_t name,
+                                               const std::string& interface,
                                                uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->wayland_zwp_pointer_constraints_ ||
       version < kMinZwpPointerConstraintsVersion) {
     return;
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h
index 31f1262..3ad33bb 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h
@@ -16,10 +16,12 @@
 class WaylandZwpPointerConstraints
     : public wl::GlobalObjectRegistrar<WaylandZwpPointerConstraints> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zwp_pointer_constraints_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   WaylandZwpPointerConstraints(zwp_pointer_constraints_v1* pointer_constraints,
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc
index 86a0d3a..6f86447f 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc
@@ -23,16 +23,16 @@
 }
 
 // static
-void WaylandZwpPointerGestures::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory(
-      "zwp_pointer_gestures_v1", &WaylandZwpPointerGestures::Instantiate);
-}
+constexpr char WaylandZwpPointerGestures::kInterfaceName[];
 
 // static
 void WaylandZwpPointerGestures::Instantiate(WaylandConnection* connection,
                                             wl_registry* registry,
                                             uint32_t name,
+                                            const std::string& interface,
                                             uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->wayland_zwp_pointer_gestures_ ||
       version < kMinZwpPointerGesturesVersion)
     return;
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h
index ab24678..884deb1 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h
@@ -22,10 +22,12 @@
 class WaylandZwpPointerGestures
     : public wl::GlobalObjectRegistrar<WaylandZwpPointerGestures> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zwp_pointer_gestures_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   class Delegate;
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc b/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc
index 26c9cc38..3a8ef4c 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc
@@ -18,18 +18,17 @@
 }
 
 // static
-void WaylandZwpRelativePointerManager::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory(
-      "zwp_relative_pointer_manager_v1",
-      &WaylandZwpRelativePointerManager::Instantiate);
-}
+constexpr char WaylandZwpRelativePointerManager::kInterfaceName[];
 
 // static
 void WaylandZwpRelativePointerManager::Instantiate(
     WaylandConnection* connection,
     wl_registry* registry,
     uint32_t name,
+    const std::string& interface,
     uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->wayland_zwp_relative_pointer_manager_ ||
       version < kMinZwpRelativePointerManagerVersion)
     return;
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h b/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h
index 48799e8..014829a 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h
@@ -19,10 +19,12 @@
 class WaylandZwpRelativePointerManager
     : public wl::GlobalObjectRegistrar<WaylandZwpRelativePointerManager> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zwp_relative_pointer_manager_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   class Delegate;
diff --git a/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc b/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc
index 43a419c1..811f2d2 100644
--- a/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc
+++ b/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc
@@ -14,16 +14,16 @@
 namespace ui {
 
 // static
-void XdgForeignWrapper::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("zxdg_exporter_v1",
-                                          &XdgForeignWrapper::Instantiate);
-}
+constexpr char XdgForeignWrapper::kInterfaceName[];
 
 // static
 void XdgForeignWrapper::Instantiate(WaylandConnection* connection,
                                     wl_registry* registry,
                                     uint32_t name,
+                                    const std::string& interface,
                                     uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->xdg_foreign_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h b/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h
index 4187d80..2cc1197 100644
--- a/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h
+++ b/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h
@@ -24,10 +24,12 @@
 class XdgForeignWrapper : public wl::GlobalObjectRegistrar<XdgForeignWrapper>,
                           public WaylandWindowObserver {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zxdg_exporter_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   using OnHandleExported = base::OnceCallback<void(const std::string&)>;
diff --git a/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc b/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc
index ef9cf6fd..4712129 100644
--- a/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc
+++ b/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc
@@ -16,16 +16,16 @@
 }
 
 // static
-void ZwpIdleInhibitManager::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory("zwp_idle_inhibit_manager_v1",
-                                          &ZwpIdleInhibitManager::Instantiate);
-}
+constexpr char ZwpIdleInhibitManager::kInterfaceName[];
 
 // static
 void ZwpIdleInhibitManager::Instantiate(WaylandConnection* connection,
                                         wl_registry* registry,
                                         uint32_t name,
+                                        const std::string& interface,
                                         uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->zwp_idle_inhibit_manager_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.h b/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.h
index 796945f..7fda58e9 100644
--- a/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.h
+++ b/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.h
@@ -16,10 +16,12 @@
 class ZwpIdleInhibitManager
     : public wl::GlobalObjectRegistrar<ZwpIdleInhibitManager> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] = "zwp_idle_inhibit_manager_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   explicit ZwpIdleInhibitManager(zwp_idle_inhibit_manager_v1* manager,
diff --git a/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc b/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc
index 0bae867..f6f9fd2 100644
--- a/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc
+++ b/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc
@@ -20,18 +20,17 @@
 }  // namespace
 
 // static
-void ZwpPrimarySelectionDeviceManager::Register(WaylandConnection* connection) {
-  connection->RegisterGlobalObjectFactory(
-      "zwp_primary_selection_device_manager_v1",
-      &ZwpPrimarySelectionDeviceManager::Instantiate);
-}
+constexpr char ZwpPrimarySelectionDeviceManager::kInterfaceName[];
 
 // static
 void ZwpPrimarySelectionDeviceManager::Instantiate(
     WaylandConnection* connection,
     wl_registry* registry,
     uint32_t name,
+    const std::string& interface,
     uint32_t version) {
+  DCHECK_EQ(interface, kInterfaceName);
+
   if (connection->zwp_primary_selection_device_manager_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h b/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
index 5fe8fc8..053105ad 100644
--- a/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
+++ b/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
@@ -18,10 +18,13 @@
 class ZwpPrimarySelectionDeviceManager
     : public wl::GlobalObjectRegistrar<ZwpPrimarySelectionDeviceManager> {
  public:
-  static void Register(WaylandConnection* connection);
+  static constexpr char kInterfaceName[] =
+      "zwp_primary_selection_device_manager_v1";
+
   static void Instantiate(WaylandConnection* connection,
                           wl_registry* registry,
                           uint32_t name,
+                          const std::string& interface,
                           uint32_t version);
 
   using DataSource = ZwpPrimarySelectionSource;
diff --git a/ui/ozone/platform/wayland/test/mock_surface.cc b/ui/ozone/platform/wayland/test/mock_surface.cc
index b6b4a208..8be2148d 100644
--- a/ui/ozone/platform/wayland/test/mock_surface.cc
+++ b/ui/ozone/platform/wayland/test/mock_surface.cc
@@ -124,6 +124,8 @@
     wl_resource_destroy(viewport_->resource());
   if (blending_ && blending_->resource())
     wl_resource_destroy(blending_->resource());
+  if (prioritized_surface_ && prioritized_surface_->resource())
+    wl_resource_destroy(prioritized_surface_->resource());
 }
 
 MockSurface* MockSurface::FromResource(wl_resource* resource) {
diff --git a/ui/ozone/platform/wayland/test/mock_surface.h b/ui/ozone/platform/wayland/test/mock_surface.h
index a302d5e..2c7c4d02 100644
--- a/ui/ozone/platform/wayland/test/mock_surface.h
+++ b/ui/ozone/platform/wayland/test/mock_surface.h
@@ -15,6 +15,7 @@
 #include "ui/ozone/platform/wayland/test/mock_xdg_surface.h"
 #include "ui/ozone/platform/wayland/test/server_object.h"
 #include "ui/ozone/platform/wayland/test/test_alpha_blending.h"
+#include "ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h"
 #include "ui/ozone/platform/wayland/test/test_subsurface.h"
 #include "ui/ozone/platform/wayland/test/test_viewport.h"
 #include "ui/ozone/platform/wayland/test/test_xdg_popup.h"
@@ -63,6 +64,14 @@
   void set_viewport(TestViewport* viewport) { viewport_ = viewport; }
   TestViewport* viewport() { return viewport_; }
 
+  void set_overlay_prioritized_surface(
+      TestOverlayPrioritizedSurface* prioritized_surface) {
+    prioritized_surface_ = prioritized_surface;
+  }
+  TestOverlayPrioritizedSurface* prioritized_surface() {
+    return prioritized_surface_;
+  }
+
   void set_blending(TestAlphaBlending* blending) { blending_ = blending; }
   TestAlphaBlending* blending() { return blending_; }
 
@@ -102,6 +111,7 @@
   TestSubSurface* sub_surface_ = nullptr;
   TestViewport* viewport_ = nullptr;
   TestAlphaBlending* blending_ = nullptr;
+  TestOverlayPrioritizedSurface* prioritized_surface_ = nullptr;
   gfx::Rect opaque_region_ = {-1, -1, 0, 0};
   gfx::Rect input_region_ = {-1, -1, 0, 0};
 
diff --git a/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.cc b/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.cc
new file mode 100644
index 0000000..ce86afa5
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.cc
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h"
+
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+
+namespace wl {
+
+namespace {
+
+void SetOverlayPriority(struct wl_client* client,
+                        struct wl_resource* resource,
+                        uint32_t priority) {
+  GetUserDataAs<TestOverlayPrioritizedSurface>(resource)->set_overlay_priority(
+      priority);
+}
+
+}  // namespace
+
+const struct overlay_prioritized_surface_interface
+    kTestOverlayPrioritizedSurfaceImpl = {
+        DestroyResource,
+        SetOverlayPriority,
+};
+
+TestOverlayPrioritizedSurface::TestOverlayPrioritizedSurface(
+    wl_resource* resource,
+    wl_resource* surface)
+    : ServerObject(resource), surface_(surface) {
+  DCHECK(surface_);
+}
+
+TestOverlayPrioritizedSurface::~TestOverlayPrioritizedSurface() {
+  auto* mock_prioritized_surface = GetUserDataAs<MockSurface>(surface_);
+  if (mock_prioritized_surface)
+    mock_prioritized_surface->set_overlay_prioritized_surface(nullptr);
+}
+
+}  // namespace wl
diff --git a/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h b/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h
new file mode 100644
index 0000000..3d52c8d
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_OVERLAY_PRIORITIZED_SURFACE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_OVERLAY_PRIORITIZED_SURFACE_H_
+
+#include <overlay-prioritizer-server-protocol.h>
+
+#include "ui/ozone/platform/wayland/test/server_object.h"
+
+struct wl_resource;
+
+namespace wl {
+
+extern const struct overlay_prioritized_surface_interface
+    kTestOverlayPrioritizedSurfaceImpl;
+
+class TestOverlayPrioritizedSurface : public ServerObject {
+ public:
+  TestOverlayPrioritizedSurface(wl_resource* resource, wl_resource* surface);
+  ~TestOverlayPrioritizedSurface() override;
+  TestOverlayPrioritizedSurface(const TestOverlayPrioritizedSurface& rhs) =
+      delete;
+  TestOverlayPrioritizedSurface& operator=(
+      const TestOverlayPrioritizedSurface& rhs) = delete;
+
+  void set_overlay_priority(uint32_t priority) { overlay_priority_ = priority; }
+  uint32_t overlay_priority() { return overlay_priority_; }
+
+ private:
+  // Surface resource that is the ground for this prioritized surface.
+  wl_resource* surface_ = nullptr;
+
+  uint32_t overlay_priority_ =
+      OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_NONE;
+};
+
+}  // namespace wl
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_OVERLAY_PRIORITIZED_SURFACE_H_
diff --git a/ui/ozone/platform/wayland/test/test_overlay_prioritizer.cc b/ui/ozone/platform/wayland/test/test_overlay_prioritizer.cc
new file mode 100644
index 0000000..d8b94368
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/test_overlay_prioritizer.cc
@@ -0,0 +1,56 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/test/test_overlay_prioritizer.h"
+
+#include <overlay-prioritizer-server-protocol.h>
+
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/server_object.h"
+#include "ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h"
+
+namespace wl {
+
+namespace {
+
+constexpr uint32_t kOverlayPriortizerProtocolVersion = 1;
+
+void GetOverlayPrioritizedSurface(struct wl_client* client,
+                                  struct wl_resource* resource,
+                                  uint32_t id,
+                                  struct wl_resource* surface) {
+  auto* mock_surface = GetUserDataAs<MockSurface>(surface);
+  if (mock_surface->prioritized_surface()) {
+    wl_resource_post_error(
+        resource, OVERLAY_PRIORITIZER_ERROR_OVERLAY_HINTED_SURFACE_EXISTS,
+        "overlay_prioritizer exists");
+    return;
+  }
+
+  wl_resource* prioritized_surface_resource = CreateResourceWithImpl<
+      ::testing::NiceMock<TestOverlayPrioritizedSurface>>(
+      client, &overlay_prioritized_surface_interface,
+      wl_resource_get_version(resource), &kTestOverlayPrioritizedSurfaceImpl,
+      id, surface);
+  DCHECK(prioritized_surface_resource);
+  mock_surface->set_overlay_prioritized_surface(
+      GetUserDataAs<TestOverlayPrioritizedSurface>(
+          prioritized_surface_resource));
+}
+
+}  // namespace
+
+const struct overlay_prioritizer_interface kTestOverlayPrioritizerImpl = {
+    DestroyResource,
+    GetOverlayPrioritizedSurface,
+};
+
+TestOverlayPrioritizer::TestOverlayPrioritizer()
+    : GlobalObject(&overlay_prioritizer_interface,
+                   &kTestOverlayPrioritizerImpl,
+                   kOverlayPriortizerProtocolVersion) {}
+
+TestOverlayPrioritizer::~TestOverlayPrioritizer() = default;
+
+}  // namespace wl
diff --git a/ui/ozone/platform/wayland/test/test_overlay_prioritizer.h b/ui/ozone/platform/wayland/test/test_overlay_prioritizer.h
new file mode 100644
index 0000000..ed84e983
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/test_overlay_prioritizer.h
@@ -0,0 +1,23 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_OVERLAY_PRIORITIZER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_OVERLAY_PRIORITIZER_H_
+
+#include "ui/ozone/platform/wayland/test/global_object.h"
+
+namespace wl {
+
+// Manage overlay_prioritizer object.
+class TestOverlayPrioritizer : public GlobalObject {
+ public:
+  TestOverlayPrioritizer();
+  ~TestOverlayPrioritizer() override;
+  TestOverlayPrioritizer(const TestOverlayPrioritizer& rhs) = delete;
+  TestOverlayPrioritizer& operator=(const TestOverlayPrioritizer& rhs) = delete;
+};
+
+}  // namespace wl
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_OVERLAY_PRIORITIZER_H_
diff --git a/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc b/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
index 7eaecfe1..7a90ea7 100644
--- a/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
+++ b/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
@@ -92,6 +92,8 @@
     return false;
   if (!zwp_linux_dmabuf_v1_.Initialize(display_.get()))
     return false;
+  if (!overlay_prioritizer_.Initialize(display_.get()))
+    return false;
 
   client_ = wl_client_create(display_.get(), server_fd.release());
   if (!client_)
diff --git a/ui/ozone/platform/wayland/test/test_wayland_server_thread.h b/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
index 5326c02..e8ce95a 100644
--- a/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
+++ b/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
@@ -22,6 +22,7 @@
 #include "ui/ozone/platform/wayland/test/test_compositor.h"
 #include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
 #include "ui/ozone/platform/wayland/test/test_output.h"
+#include "ui/ozone/platform/wayland/test/test_overlay_prioritizer.h"
 #include "ui/ozone/platform/wayland/test/test_seat.h"
 #include "ui/ozone/platform/wayland/test/test_subcompositor.h"
 #include "ui/ozone/platform/wayland/test/test_viewporter.h"
@@ -144,6 +145,7 @@
   TestAlphaCompositing alpha_compositing_;
   TestDataDeviceManager data_device_manager_;
   TestOutput output_;
+  TestOverlayPrioritizer overlay_prioritizer_;
   TestSeat seat_;
   MockXdgShell xdg_shell_;
   MockZxdgShellV6 zxdg_shell_v6_;
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
index dd7c3b64..d53ad948 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/gfx/gpu_fence_handle.h"
-#include "ui/gfx/overlay_priority_hint.h"
-#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
-#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
-
 #include <drm_fourcc.h>
+#include <overlay-prioritizer-client-protocol.h>
+
+#include <cstdint>
 #include <memory>
 
 #include "base/files/file_path.h"
@@ -16,12 +14,18 @@
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/gpu_fence_handle.h"
 #include "ui/gfx/linux/drm_util_linux.h"
+#include "ui/gfx/overlay_priority_hint.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h"
+#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
 #include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.h"
+#include "ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h"
 #include "ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h"
 #include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
@@ -1941,6 +1945,68 @@
   Sync();
 }
 
+TEST_P(WaylandBufferManagerTest, HasOverlayPrioritizer) {
+  EXPECT_TRUE(connection_->overlay_prioritizer());
+}
+
+TEST_P(WaylandBufferManagerTest, CanSubmitOverlayPriority) {
+  std::vector<uint32_t> kBufferIds = {1, 2, 3};
+
+  MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(),
+                                  window_->GetWidget());
+
+  auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
+  EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(3);
+  for (auto id : kBufferIds) {
+    CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, id);
+  }
+
+  Sync();
+
+  for (size_t i = 0; i < kBufferIds.size(); i++) {
+    zwp_linux_buffer_params_v1_send_created(
+        linux_dmabuf->buffer_params()[i]->resource(),
+        linux_dmabuf->buffer_params()[i]->buffer_resource());
+  }
+
+  Sync();
+
+  std::vector<std::pair<gfx::OverlayPriorityHint, uint32_t>> priorities = {
+      {gfx::OverlayPriorityHint::kNone,
+       OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_NONE},
+      {gfx::OverlayPriorityHint::kRegular,
+       OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_REGULAR},
+      {gfx::OverlayPriorityHint::kLowLatencyCanvas,
+       OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_PREFERRED_LOW_LATENCY_CANVAS},
+      {gfx::OverlayPriorityHint::kHardwareProtection,
+       OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_REQUIRED_HARDWARE_PROTECTION}};
+
+  for (const auto& priority : priorities) {
+    std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
+    for (auto id : kBufferIds) {
+      overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+          id == 1 ? INT32_MIN : id,
+          gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, id, kDefaultScale,
+          window_->GetBounds(), gfx::RectF(), window_->GetBounds(), false, 1.0f,
+          gfx::GpuFenceHandle(), priority.first));
+    }
+
+    buffer_manager_gpu_->CommitOverlays(window_->GetWidget(),
+                                        std::move(overlay_configs));
+
+    Sync();
+
+    for (auto& subsurface : window_->wayland_subsurfaces_) {
+      auto* mock_surface_of_subsurface = server_.GetObject<wl::MockSurface>(
+          subsurface->wayland_surface()->GetSurfaceId());
+      EXPECT_TRUE(mock_surface_of_subsurface);
+      EXPECT_EQ(
+          mock_surface_of_subsurface->prioritized_surface()->overlay_priority(),
+          priority.second);
+    }
+  }
+}
+
 INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
                          WaylandBufferManagerTest,
                          Values(wl::ServerConfig{
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc
index 0a94f43..4316480 100644
--- a/weblayer/app/content_main_delegate_impl.cc
+++ b/weblayer/app/content_main_delegate_impl.cc
@@ -193,7 +193,7 @@
     ::features::kDisableDeJelly,
     ::features::kDynamicColorGamut,
 #else
-    // TODO(crbug.com/1131021): Support WebOTP Service on WebLayer.
+    // WebOTP is supported only on Android in WebLayer.
     ::features::kWebOTP,
 #endif
   };