diff --git a/DEPS b/DEPS
index 19838c2..73949da 100644
--- a/DEPS
+++ b/DEPS
@@ -306,7 +306,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd90917a1da6bcf6e40616509664147e9d73b012f',
+  'skia_revision': '160bf907c0eea2b489b4ca5260233958fac6f368',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -314,7 +314,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '01b27a6f17434983235bf963fad63c3ec92c456f',
+  'angle_revision': 'a6fae3fec80902dc810efc44e153bd97e507275d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -385,7 +385,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': 'abf15f342f5ab1a9c466464e6c5cbf38271b2e36',
+  'devtools_frontend_revision': '7f5186963e90f13f0a7be3d102925a96a71afe6d',
   # 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.
@@ -457,7 +457,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'cros_components_revision': '97e45e933f8f9f584a4a8caf59b0e517a0dd5324',
+  'cros_components_revision': 'a39db696dcc3922a53561ab58c8b89ae7eda5f9d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -816,7 +816,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    '27d061f9baf1f94d6cc20747fafb39c7535016ab',
+    '78e33b77f5ed84569adb89598e86f7748b9b73a2',
     'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal',
   },
 
@@ -1000,7 +1000,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'sfkd_7g8xAywUG-eSpRzB7GAqVc2NCrY1kQoBLGRVKkC',
+          'version': 'QywWz1_m6w-DIah4IXQ3I27LDjKgn9kUMTP1SEJgigUC',
       },
     ],
     'condition': 'checkout_android',
@@ -1249,7 +1249,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '6691fef0f2cf96bd56c9305dfd6d6644616226eb',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '5a5aab5420323133d15e69c9f6a4f846f0de8ebc',
     'condition': 'checkout_src_internal',
   },
 
@@ -1664,7 +1664,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a3e39a91c2d5d61394a314c8b042d07660e8743d',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '209aac9ddf6a7bf049ac7c4d847cb4926f65ee81',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1846,7 +1846,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '622cac9c69eb356b1e6a5117b6ddbb0d0e2acbaf',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '992c9a857757ebbebf8aa50f2e05355cfa7b9efd',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '408f0be5c23024a4b88f80b7707f570cd53ca6a6',
@@ -1919,7 +1919,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8170bc1e50a872ea0f736c2aea3290c2c5fde03f',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e9ffd1665c432c9eb5f3fe06ec6dafb0f867a684',
     'condition': 'checkout_src_internal',
   },
 
@@ -1949,7 +1949,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'd-ZhMA6rYoStq9l1o3a2s_290IHycGVmW3JyavxMf34C',
+        'version': 'G92j1-JAZt4csCBN1NQsEufJZQaCyYDtUJFkCmZQNTsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1971,7 +1971,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'pXb22K_ujzsS0b1Z1LMb3VkrhYhP2FlVgV7A4iovusUC',
+        'version': '1W6l_EV9c96k_haPLjYQYFoEuoLiwiYqGdKCU9D4-BsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn
index 9c40d9a..e479e7c 100644
--- a/android_webview/browser/BUILD.gn
+++ b/android_webview/browser/BUILD.gn
@@ -291,6 +291,7 @@
     "//third_party/blink/public/mojom:mojom_core",
     "//third_party/blink/public/mojom:mojom_platform",
     "//third_party/crashpad/crashpad/client",
+    "//third_party/zlib/google:compression_utils",
     "//ui/android",
     "//ui/display/util:util",
     "//ui/gl",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 6410f344..30d9865a 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -110,6 +110,7 @@
   "+third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h",
   "+third_party/crashpad/crashpad/client",
   "+third_party/crashpad/crashpad/util",
+  "+third_party/zlib/google/compression_utils.h",
 
   "+ui/display",
   "+ui/gfx",
diff --git a/android_webview/browser/tracing/aw_background_tracing_metrics_provider.cc b/android_webview/browser/tracing/aw_background_tracing_metrics_provider.cc
index 7332603..a2a804e 100644
--- a/android_webview/browser/tracing/aw_background_tracing_metrics_provider.cc
+++ b/android_webview/browser/tracing/aw_background_tracing_metrics_provider.cc
@@ -7,11 +7,40 @@
 #include "android_webview/browser/metrics/aw_metrics_service_client.h"
 #include "android_webview/browser/tracing/background_tracing_field_trial.h"
 #include "base/strings/string_piece.h"
+#include "base/task/thread_pool.h"
 #include "components/metrics/field_trials_provider.h"
 #include "components/metrics/metrics_service.h"
+#include "third_party/metrics_proto/trace_log.pb.h"
+#include "third_party/zlib/google/compression_utils.h"
 
 namespace tracing {
 
+namespace {
+
+// Compresses |serialized_trace| and returns the result. If the compressed trace
+// does not fit into the upload limit or if there are zlib errors, returns
+// nullopt.
+// TODO(b/247824653): consider truncating the trace so that we have at least
+// some data.
+absl::optional<std::string> Compress(std::string&& serialized_trace) {
+  std::string deflated;
+  deflated.resize(kCompressedUploadLimitBytes);
+  size_t compressed_size;
+
+  if (compression::GzipCompress(serialized_trace,
+                                reinterpret_cast<char*>(deflated.data()),
+                                kCompressedUploadLimitBytes, &compressed_size,
+                                /* malloc_fn= */ nullptr,
+                                /* free_fn= */ nullptr)) {
+    deflated.resize(compressed_size);
+    return deflated;
+  } else {
+    return absl::nullopt;
+  }
+}
+
+}  // namespace
+
 AwBackgroundTracingMetricsProvider::AwBackgroundTracingMetricsProvider() =
     default;
 AwBackgroundTracingMetricsProvider::~AwBackgroundTracingMetricsProvider() =
@@ -31,12 +60,37 @@
 }
 
 void AwBackgroundTracingMetricsProvider::ProvideEmbedderMetrics(
-    metrics::ChromeUserMetricsExtension* uma_proto,
-    base::HistogramSnapshotManager* snapshot_manager) {
+    metrics::ChromeUserMetricsExtension& uma_proto,
+    std::string&& serialized_trace,
+    metrics::TraceLog& log,
+    base::HistogramSnapshotManager* snapshot_manager,
+    base::OnceCallback<void(bool)> done_callback) {
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&Compress, std::move(serialized_trace)),
+      base::BindOnce(&AwBackgroundTracingMetricsProvider::OnTraceCompressed,
+                     weak_factory_.GetWeakPtr(), std::ref(uma_proto),
+                     std::ref(log), std::move(done_callback)));
+}
+
+void AwBackgroundTracingMetricsProvider::OnTraceCompressed(
+    metrics::ChromeUserMetricsExtension& uma_proto,
+    metrics::TraceLog& log,
+    base::OnceCallback<void(bool)> done_callback,
+    absl::optional<std::string> compressed_trace) {
+  if (!compressed_trace) {
+    std::move(done_callback).Run(false);
+    return;
+  }
+
+  SetTrace(log, std::move(*compressed_trace));
+  log.set_compression_type(metrics::TraceLog::COMPRESSION_TYPE_ZLIB);
+
   // Remove the package name according to the privacy requirements.
   // See go/public-webview-trace-collection.
-  auto* system_profile = uma_proto->mutable_system_profile();
+  auto* system_profile = uma_proto.mutable_system_profile();
   system_profile->clear_app_package_name();
+  std::move(done_callback).Run(true);
 }
 
 }  // namespace tracing
diff --git a/android_webview/browser/tracing/aw_background_tracing_metrics_provider.h b/android_webview/browser/tracing/aw_background_tracing_metrics_provider.h
index 0a0ff285..d69b7d58 100644
--- a/android_webview/browser/tracing/aw_background_tracing_metrics_provider.h
+++ b/android_webview/browser/tracing/aw_background_tracing_metrics_provider.h
@@ -7,8 +7,15 @@
 
 #include "components/tracing/common/background_tracing_metrics_provider.h"
 
+#include "base/memory/weak_ptr.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
 namespace tracing {
 
+// Only upload traces under 512 KB to decrease the risk of filling up
+// the app's IPC binder buffer (1 MB) and causing crashes.
+constexpr static int kCompressedUploadLimitBytes = 512 * 1024;
+
 class AwBackgroundTracingMetricsProvider
     : public BackgroundTracingMetricsProvider {
  public:
@@ -27,8 +34,18 @@
  private:
   // BackgroundTracingMetricsProvider:
   void ProvideEmbedderMetrics(
-      metrics::ChromeUserMetricsExtension* uma_proto,
-      base::HistogramSnapshotManager* snapshot_manager) override;
+      metrics::ChromeUserMetricsExtension& uma_proto,
+      std::string&& serialized_trace,
+      metrics::TraceLog& log,
+      base::HistogramSnapshotManager* snapshot_manager,
+      base::OnceCallback<void(bool)> done_callback) override;
+
+  void OnTraceCompressed(metrics::ChromeUserMetricsExtension& uma_proto,
+                         metrics::TraceLog& log,
+                         base::OnceCallback<void(bool)> done_callback,
+                         absl::optional<std::string> serialized_trace);
+
+  base::WeakPtrFactory<AwBackgroundTracingMetricsProvider> weak_factory_{this};
 };
 
 }  // namespace tracing
diff --git a/android_webview/browser/tracing/aw_background_tracing_metrics_provider_unittest.cc b/android_webview/browser/tracing/aw_background_tracing_metrics_provider_unittest.cc
index 1b1cf99..99e5b265 100644
--- a/android_webview/browser/tracing/aw_background_tracing_metrics_provider_unittest.cc
+++ b/android_webview/browser/tracing/aw_background_tracing_metrics_provider_unittest.cc
@@ -7,6 +7,9 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/rand_util.h"
+#include "base/run_loop.h"
+#include "base/test/bind.h"
 #include "components/tracing/common/trace_startup_config.h"
 #include "content/public/browser/background_tracing_config.h"
 #include "content/public/browser/background_tracing_manager.h"
@@ -36,7 +39,6 @@
 
   void SetUp() override {
     base::Value::Dict dict;
-    ;
 
     dict.Set("mode", "REACTIVE_TRACING_MODE");
     dict.Set("custom_categories",
@@ -83,18 +85,66 @@
   metrics::ChromeUserMetricsExtension uma_proto;
   uma_proto.set_client_id(100);
   uma_proto.set_session_id(15);
+
+  base::RunLoop run_loop;
   provider.ProvideIndependentMetrics(
-      base::BindOnce([](bool success) { EXPECT_TRUE(success); }), &uma_proto,
+      base::BindLambdaForTesting([&run_loop](bool success) {
+        EXPECT_TRUE(success);
+        run_loop.Quit();
+      }),
+      &uma_proto,
       /* snapshot_manager=*/nullptr);
+  run_loop.Run();
 
   EXPECT_EQ(100u, uma_proto.client_id());
   EXPECT_EQ(15, uma_proto.session_id());
   ASSERT_EQ(1, uma_proto.trace_log_size());
-  EXPECT_EQ(kDummyTrace, uma_proto.trace_log(0).raw_data());
+  EXPECT_EQ(metrics::TraceLog::COMPRESSION_TYPE_ZLIB,
+            uma_proto.trace_log(0).compression_type());
+  EXPECT_NE(kDummyTrace, uma_proto.trace_log(0).raw_data());
 
   EXPECT_FALSE(provider.HasIndependentMetrics());
 }
 
+TEST_F(AwBackgroundTracingMetricsProviderTest, HandlesOversizeTraceLog) {
+  AwBackgroundTracingMetricsProvider provider;
+  EXPECT_FALSE(provider.HasIndependentMetrics());
+
+  auto trace = std::make_unique<std::string>();
+  constexpr int size = kCompressedUploadLimitBytes * 5;
+  trace->resize(size);
+
+  // Writing a random string to the trace makes it less likely to compress well
+  // and fit into the upload limit.
+  for (int i = 0; i < size; i++) {
+    (*trace)[i] = base::RandInt('a', 'z');
+  }
+
+  content::BackgroundTracingManager::GetInstance().SetTraceToUploadForTesting(
+      std::move(trace));
+
+  EXPECT_TRUE(provider.HasIndependentMetrics());
+  metrics::ChromeUserMetricsExtension uma_proto;
+  uma_proto.set_client_id(100);
+  uma_proto.set_session_id(15);
+
+  base::RunLoop run_loop;
+  provider.ProvideIndependentMetrics(
+      base::BindLambdaForTesting([&run_loop](bool success) {
+        EXPECT_FALSE(success);
+        run_loop.Quit();
+      }),
+      &uma_proto,
+      /* snapshot_manager=*/nullptr);
+  run_loop.Run();
+
+  EXPECT_EQ(100u, uma_proto.client_id());
+  EXPECT_EQ(15, uma_proto.session_id());
+  EXPECT_EQ(1, uma_proto.trace_log_size());
+  EXPECT_TRUE(uma_proto.trace_log(0).raw_data().empty());
+  EXPECT_FALSE(provider.HasIndependentMetrics());
+}
+
 TEST_F(AwBackgroundTracingMetricsProviderTest, ClearsAppPackageName) {
   AwBackgroundTracingMetricsProvider provider;
   EXPECT_FALSE(provider.HasIndependentMetrics());
@@ -106,13 +156,21 @@
   metrics::ChromeUserMetricsExtension uma_proto;
 
   uma_proto.mutable_system_profile()->set_app_package_name("my_app");
+  base::RunLoop run_loop;
   provider.ProvideIndependentMetrics(
-      base::BindOnce([](bool success) { EXPECT_TRUE(success); }), &uma_proto,
+      base::BindLambdaForTesting([&run_loop](bool success) {
+        EXPECT_TRUE(success);
+        run_loop.Quit();
+      }),
+      &uma_proto,
       /* snapshot_manager=*/nullptr);
+  run_loop.Run();
 
   EXPECT_TRUE(uma_proto.system_profile().app_package_name().empty());
   ASSERT_EQ(1, uma_proto.trace_log_size());
-  EXPECT_EQ(kDummyTrace, uma_proto.trace_log(0).raw_data());
+  EXPECT_EQ(metrics::TraceLog::COMPRESSION_TYPE_ZLIB,
+            uma_proto.trace_log(0).compression_type());
+  EXPECT_NE(kDummyTrace, uma_proto.trace_log(0).raw_data());
 
   EXPECT_FALSE(provider.HasIndependentMetrics());
 }
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 6a11316..0a71006 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -3420,6 +3420,7 @@
 
 test("ash_pixeltests") {
   sources = [
+    "app_list/views/app_list_item_view_pixeltest.cc",
     "app_list/views/app_list_view_pixeltest.cc",
     "fullscreen_pixeltest.cc",
     "shelf/login_shelf_view_pixeltest.cc",
diff --git a/ash/app_list/model/app_list_item.h b/ash/app_list/model/app_list_item.h
index b459855..b20438d6 100644
--- a/ash/app_list/model/app_list_item.h
+++ b/ash/app_list/model/app_list_item.h
@@ -135,6 +135,7 @@
   friend class AppListBadgeController;
   friend class AppListItemList;
   friend class AppListItemListTest;
+  friend class AppListItemViewPixelTest;
   friend class AppListItemViewTest;
   friend class AppListModel;
 
diff --git a/ash/app_list/views/app_list_item_view_pixeltest.cc b/ash/app_list/views/app_list_item_view_pixeltest.cc
new file mode 100644
index 0000000..2ffb59b2
--- /dev/null
+++ b/ash/app_list/views/app_list_item_view_pixeltest.cc
@@ -0,0 +1,115 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+#include <tuple>
+
+#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/app_list/model/app_list_item.h"
+#include "ash/app_list/model/app_list_test_model.h"
+#include "ash/app_list/model/search/search_model.h"
+#include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/app_list/views/app_list_item_view.h"
+#include "ash/app_list/views/paged_apps_grid_view.h"
+#include "ash/app_list/views/scrollable_apps_grid_view.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/pixel/ash_pixel_differ.h"
+#include "ash/test/pixel/ash_pixel_test_init_params.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/strings/string_util.h"
+
+namespace ash {
+
+class AppListItemViewPixelTest : public AshTestBase,
+                                 public testing::WithParamInterface<
+                                     std::tuple</*use_tablet_mode=*/bool,
+                                                /*use_dense_ui=*/bool,
+                                                /*use_rtl=*/bool,
+                                                /*is_new_install=*/bool,
+                                                /*has_notification=*/bool>> {
+ public:
+  // AshTestBase:
+  absl::optional<pixel_test::InitParams> CreatePixelTestInitParams()
+      const override {
+    pixel_test::InitParams init_params;
+    init_params.under_rtl = use_rtl();
+    return init_params;
+  }
+
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    // As per `app_list_config_provider.cc`, dense values are used for screens
+    // with width OR height <= 675.
+    UpdateDisplay(use_dense_ui() ? "800x600" : "1200x800");
+
+    app_list_test_model_ = std::make_unique<test::AppListTestModel>();
+    search_model_ = std::make_unique<SearchModel>();
+    Shell::Get()->app_list_controller()->SetActiveModel(
+        /*profile_id=*/1, app_list_test_model_.get(), search_model_.get());
+  }
+
+  void CreateAppListItem(const std::string& name) {
+    AppListItem* item = app_list_test_model_->CreateAndAddItem(name + "_id");
+    item->SetName(name);
+    item->SetIsNewInstall(is_new_install());
+    item->UpdateNotificationBadge(has_notification());
+  }
+
+  AppListItemView* GetItemViewAt(size_t index) {
+    auto* const helper = GetAppListTestHelper();
+    if (use_tablet_mode())
+      return helper->GetRootPagedAppsGridView()->GetItemViewAt(index);
+    return helper->GetScrollableAppsGridView()->GetItemViewAt(index);
+  }
+
+  std::string GenerateScreenshotName() {
+    std::string stringified_params = base::JoinString(
+        {use_tablet_mode() ? "tablet_mode" : "clamshell_mode",
+         use_dense_ui() ? "dense_ui" : "regular_ui", use_rtl() ? "rtl" : "ltr",
+         is_new_install() ? "new_install=true" : "new_install=false",
+         has_notification() ? "has_notification=true"
+                            : "has_notification=false"},
+        "|");
+    return base::JoinString({"app_list_item_view", stringified_params, "rev_0"},
+                            ".");
+  }
+
+  bool use_tablet_mode() const { return std::get<0>(GetParam()); }
+  bool use_dense_ui() const { return std::get<1>(GetParam()); }
+  bool use_rtl() const { return std::get<2>(GetParam()); }
+  bool is_new_install() const { return std::get<3>(GetParam()); }
+  bool has_notification() const { return std::get<4>(GetParam()); }
+
+ private:
+  std::unique_ptr<test::AppListTestModel> app_list_test_model_;
+  std::unique_ptr<SearchModel> search_model_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    AppListItemViewPixelTest,
+    testing::Combine(/*use_tablet_mode=*/testing::Bool(),
+                     /*use_dense_ui=*/testing::Bool(),
+                     /*use_rtl=*/testing::Bool(),
+                     /*is_new_install=*/testing::Bool(),
+                     /*has_notification=*/testing::Bool()));
+
+TEST_P(AppListItemViewPixelTest, AppListItemView) {
+  CreateAppListItem("App");
+  CreateAppListItem("App with a loooooooong name");
+
+  if (use_tablet_mode())
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  else
+    GetAppListTestHelper()->ShowAppList();
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      GenerateScreenshotName(), GetItemViewAt(0), GetItemViewAt(1)));
+}
+
+}  // namespace ash
diff --git a/ash/app_list/views/app_list_menu_model_adapter.cc b/ash/app_list/views/app_list_menu_model_adapter.cc
index c7bccc5..f190bff4 100644
--- a/ash/app_list/views/app_list_menu_model_adapter.cc
+++ b/ash/app_list/views/app_list_menu_model_adapter.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "ash/app_list/app_list_metrics.h"
-#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/app_menu_constants.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/ash/app_list/views/app_list_menu_model_adapter.h b/ash/app_list/views/app_list_menu_model_adapter.h
index cb2d658..1180ec8 100644
--- a/ash/app_list/views/app_list_menu_model_adapter.h
+++ b/ash/app_list/views/app_list_menu_model_adapter.h
@@ -14,7 +14,6 @@
 #include "ash/ash_export.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/ui_base_types.h"
-#include "ui/views/controls/menu/menu_types.h"
 
 namespace ash {
 
diff --git a/ash/app_list/views/app_list_menu_model_adapter_unittest.cc b/ash/app_list/views/app_list_menu_model_adapter_unittest.cc
index 97fb912..335b75eb 100644
--- a/ash/app_list/views/app_list_menu_model_adapter_unittest.cc
+++ b/ash/app_list/views/app_list_menu_model_adapter_unittest.cc
@@ -4,23 +4,144 @@
 
 #include "ash/app_list/views/app_list_menu_model_adapter.h"
 
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "ash/app_list/app_list_metrics.h"
+#include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/app_menu_constants.h"
-#include "base/callback.h"
+#include "ash/test/ash_test_base.h"
+#include "base/strings/string_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/controls/menu/menu_types.h"
 
 namespace ash {
 namespace {
 
+class AppListMenuModelAdapterTest
+    : public AshTestBase,
+      public testing::WithParamInterface</*is_tablet_mode=*/bool> {
+ public:
+  std::unique_ptr<AppListMenuModelAdapter> CreateAdapter(
+      const AppLaunchedMetricParams& metric_params,
+      AppListMenuModelAdapter::AppListViewAppType type,
+      bool is_tablet_mode) const {
+    auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
+    menu_model->AddItem(LAUNCH_NEW, u"Launch app");
+    menu_model->AddItem(NOTIFICATION_CONTAINER, u"Test menu item");
+
+    return std::make_unique<AppListMenuModelAdapter>(
+        "test-app-id", std::move(menu_model), nullptr,
+        ui::MenuSourceType::MENU_SOURCE_MOUSE, metric_params, type,
+        base::OnceClosure(), is_tablet_mode);
+  }
+
+  std::string AppendClamshellOrTabletModePostfix(
+      const std::string& histogram_name) const {
+    return base::JoinString(
+        {histogram_name, is_tablet_mode() ? "TabletMode" : "ClamshellMode"},
+        ".");
+  }
+
+  bool is_tablet_mode() const { return GetParam(); }
+};
+
 // Tests that NOTIFICATION_CONTAINER is enabled. This ensures that the
 // container is able to handle gesture events.
-TEST(AppListMenuModelAdapterTest, NotificationContainerEnabled) {
-  AppListMenuModelAdapter adapter(
-      "test-app-id", std::make_unique<ui::SimpleMenuModel>(nullptr), nullptr,
-      ui::MenuSourceType::MENU_SOURCE_TYPE_LAST, AppLaunchedMetricParams(),
-      AppListMenuModelAdapter::FULLSCREEN_APP_GRID, base::OnceClosure(),
-      false /* is_tablet_mode */);
-  EXPECT_TRUE(adapter.IsCommandEnabled(NOTIFICATION_CONTAINER));
+TEST_F(AppListMenuModelAdapterTest, NotificationContainerEnabled) {
+  auto adapter =
+      CreateAdapter(AppLaunchedMetricParams(),
+                    AppListMenuModelAdapter::FULLSCREEN_APP_GRID, false);
+  EXPECT_TRUE(adapter->IsCommandEnabled(NOTIFICATION_CONTAINER));
 }
 
+TEST_P(AppListMenuModelAdapterTest, RecordsHistogramOnMenuClosed) {
+  const struct {
+    AppListMenuModelAdapter::AppListViewAppType type;
+    std::string base_histogram_name;
+    bool has_non_tablet_clamshell_histograms;
+  } test_cases[] = {
+      {AppListMenuModelAdapter::FULLSCREEN_SUGGESTED, "SuggestedAppFullscreen",
+       true},
+      {AppListMenuModelAdapter::FULLSCREEN_APP_GRID, "AppGrid", true},
+      {AppListMenuModelAdapter::PRODUCTIVITY_LAUNCHER_RECENT_APP,
+       "ProductivityLauncherRecentApp", false},
+      {AppListMenuModelAdapter::PRODUCTIVITY_LAUNCHER_APP_GRID,
+       "ProductivityLauncherAppGrid", false},
+      {AppListMenuModelAdapter::FULLSCREEN_SEARCH_RESULT, "SearchResult", true},
+  };
+
+  for (const auto& test_case : test_cases) {
+    const base::HistogramTester histogram_tester;
+
+    const auto adapter = CreateAdapter(AppLaunchedMetricParams(),
+                                       test_case.type, is_tablet_mode());
+    adapter->Run(gfx::Rect(), views::MenuAnchorPosition::kBottomCenter, 0);
+    adapter->Cancel();
+
+    const auto show_source_histogram_name = base::JoinString(
+        {"Apps", "ContextMenuShowSourceV2", test_case.base_histogram_name},
+        ".");
+    const auto user_journey_time_histogram_name = base::JoinString(
+        {"Apps", "ContextMenuUserJourneyTimeV2", test_case.base_histogram_name},
+        ".");
+
+    if (test_case.has_non_tablet_clamshell_histograms) {
+      histogram_tester.ExpectUniqueSample(
+          show_source_histogram_name, ui::MenuSourceType::MENU_SOURCE_MOUSE, 1);
+      histogram_tester.ExpectTotalCount(user_journey_time_histogram_name, 1);
+    }
+    histogram_tester.ExpectUniqueSample(
+        AppendClamshellOrTabletModePostfix(show_source_histogram_name),
+        ui::MenuSourceType::MENU_SOURCE_MOUSE, 1);
+    histogram_tester.ExpectTotalCount(
+        AppendClamshellOrTabletModePostfix(user_journey_time_histogram_name),
+        1);
+  }
+}
+
+TEST_P(AppListMenuModelAdapterTest, RecordsAppLaunched) {
+  const struct {
+    AppListLaunchedFrom launched_from;
+    AppListUserAction expected_user_action;
+  } test_cases[] = {
+      {AppListLaunchedFrom::kLaunchedFromGrid,
+       AppListUserAction::kAppLaunchFromAppsGrid},
+      {AppListLaunchedFrom::kLaunchedFromRecentApps,
+       AppListUserAction::kAppLaunchFromRecentApps},
+      {AppListLaunchedFrom::kLaunchedFromSearchBox,
+       AppListUserAction::kOpenAppSearchResult},
+  };
+
+  for (const auto& test_case : test_cases) {
+    const base::HistogramTester histogram_tester;
+
+    AppLaunchedMetricParams metric_params;
+    metric_params.launched_from = test_case.launched_from;
+    metric_params.launch_type = AppListLaunchType::kApp;
+    metric_params.is_tablet_mode = is_tablet_mode();
+    metric_params.app_list_view_state = AppListViewState::kFullscreenAllApps;
+
+    const auto adapter = CreateAdapter(
+        metric_params, AppListMenuModelAdapter::FULLSCREEN_APP_GRID,
+        is_tablet_mode());
+    adapter->Run(gfx::Rect(), views::MenuAnchorPosition::kBottomCenter, 0);
+    adapter->ExecuteCommand(LAUNCH_NEW, /*mouse_event_flags=*/0);
+
+    histogram_tester.ExpectUniqueSample("Apps.AppListAppLaunchedV2",
+                                        metric_params.launched_from, 1);
+    histogram_tester.ExpectUniqueSample(
+        AppendClamshellOrTabletModePostfix("Apps.AppList.UserAction"),
+        test_case.expected_user_action, 1);
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         AppListMenuModelAdapterTest,
+                         /*is_tablet_mode=*/testing::Bool());
+
 }  // namespace
 }  // namespace ash
diff --git a/ash/system/notification_center/notification_center_view.cc b/ash/system/notification_center/notification_center_view.cc
index 093ec13..8244c46 100644
--- a/ash/system/notification_center/notification_center_view.cc
+++ b/ash/system/notification_center/notification_center_view.cc
@@ -28,6 +28,7 @@
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/animation/linear_animation.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/views/message_view.h"
 #include "ui/views/background.h"
@@ -42,6 +43,10 @@
 
 namespace {
 
+// Inset the top and the bottom of the scroll bar so it won't be clipped by
+// rounded corners.
+constexpr auto kScrollBarInsets = gfx::Insets::TLBR(16, 0, 16, 0);
+
 constexpr base::TimeDelta kHideStackingBarAnimationDuration =
     base::Milliseconds(330);
 constexpr base::TimeDelta kCollapseAnimationDuration = base::Milliseconds(640);
@@ -88,10 +93,13 @@
           features::IsNotificationsRefreshEnabled()),
       animation_(std::make_unique<gfx::LinearAnimation>(this)),
       focus_search_(std::make_unique<views::FocusSearch>(this, false, false)) {
-  if (is_notifications_refresh_enabled_)
-    scroll_bar_ = new RoundedMessageCenterScrollBar(this);
-  else
+  if (is_notifications_refresh_enabled_) {
+    auto* scroll_bar = new RoundedMessageCenterScrollBar(this);
+    scroll_bar->SetInsets(kScrollBarInsets);
+    scroll_bar_ = scroll_bar;
+  } else {
     scroll_bar_ = new MessageCenterScrollBar(this);
+  }
 
   if (is_notifications_refresh_enabled_) {
     layout_manager_ = SetLayoutManager(std::make_unique<views::BoxLayout>(
diff --git a/base/allocator/partition_allocator/partition_alloc.gni b/base/allocator/partition_allocator/partition_alloc.gni
index 0032c9b..e0c12bba 100644
--- a/base/allocator/partition_allocator/partition_alloc.gni
+++ b/base/allocator/partition_allocator/partition_alloc.gni
@@ -108,8 +108,7 @@
   #
   # This flag is temporary, and isn't used by PA embedders, so it doesn't need
   # to go through build_overrides
-  enable_dangling_raw_ptr_perf_experiment =
-      enable_dangling_raw_ptr_checks_default && enable_backup_ref_ptr_support
+  enable_dangling_raw_ptr_perf_experiment = false
 }
 
 declare_args() {
diff --git a/base/feature_list.cc b/base/feature_list.cc
index db7fb60e..fb705f8 100644
--- a/base/feature_list.cc
+++ b/base/feature_list.cc
@@ -12,7 +12,6 @@
 #include "base/base_switches.h"
 #include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
-#include "base/debug/stack_trace.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
@@ -92,9 +91,9 @@
     DCHECK(!feature) << "Accessed feature " << feature->name
                      << " before FeatureList registration.";
     // TODO(crbug.com/1383852): When we believe that all early accesses have
-    // been fixed, add a base::debug::DumpWithoutCrashing(), to get reports from
-    // the field without making Chrome unusable. If we don't get reports, change
-    // the DCHECK above to a CHECK.
+    // been fixed, remove this base::debug::DumpWithoutCrashing() and change the
+    // above DCHECK to a CHECK.
+    base::debug::DumpWithoutCrashing();
 #endif  // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID) &&
         // !BUILDFLAG(IS_CHROMEOS)
   }
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
index a96b233..8113c0d 100644
--- a/base/trace_event/builtin_categories.h
+++ b/base/trace_event/builtin_categories.h
@@ -182,6 +182,7 @@
   X("weblayer")                                                          \
   X("WebCore")                                                           \
   X("webrtc")                                                            \
+  X("webrtc_stats")                                                      \
   X("xr")                                                                \
   X(TRACE_DISABLED_BY_DEFAULT("android_view_hierarchy"))                 \
   X(TRACE_DISABLED_BY_DEFAULT("animation-worklet"))                      \
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index bd79d9b..82b3c5dc 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -1363,7 +1363,7 @@
 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY) && !BUILDFLAG(IS_NACL)
   perfetto::TrackEvent::Flush();
 
-  if (discard_events) {
+  if (!tracing_session_ || discard_events) {
     tracing_session_.reset();
     scoped_refptr<RefCountedString> empty_result = new RefCountedString;
     cb.Run(empty_result, /*has_more_events=*/false);
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto
index 1e0a178..002d2643 100644
--- a/base/tracing/protos/chrome_track_event.proto
+++ b/base/tracing/protos/chrome_track_event.proto
@@ -34,6 +34,7 @@
     TASK_SCOPE_SCHEDULED_ACTION = 2;
     TASK_SCOPE_SCRIPT_EXECUTION = 3;
     TASK_SCOPE_POST_MESSAGE = 4;
+    TASK_SCOPE_POP_STATE = 5;
   }
   optional TaskScopeType type = 1;
   optional int64 scope_task_id = 2;
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index ba619ad7..be7de75 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -303,8 +303,15 @@
 
     # R8 OOMs with the default xmx=1G.
     cmd = build_utils.JavaCmd(options.warnings_as_errors, xmx='2G') + [
+        # Allows -whyareyounotinlining, which we don't have by default, but
+        # which is useful for one-off queries.
         '-Dcom.android.tools.r8.experimental.enablewhyareyounotinlining=1',
+        # Restricts horizontal class merging to apply only to classes that
+        # share a .java file (nested classes). https://crbug.com/1363709
         '-Dcom.android.tools.r8.enableSameFilePolicy=1',
+        # Enables API modelling for all classes that need it. Breaks reflection
+        # on SDK versions that we no longer support. http://b/259076765
+        '-Dcom.android.tools.r8.stubNonThrowableClasses=1',
     ]
     if options.dump_inputs:
       cmd += ['-Dcom.android.tools.r8.dumpinputtofile=r8inputs.zip']
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 8c89578..9acb880 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-10.20221111.0.1
+10.20221117.0.1
diff --git a/build_overrides/partition_alloc.gni b/build_overrides/partition_alloc.gni
index d80f59a..f621d80 100644
--- a/build_overrides/partition_alloc.gni
+++ b/build_overrides/partition_alloc.gni
@@ -80,4 +80,4 @@
 
 put_ref_count_in_previous_slot_default = true
 enable_backup_ref_ptr_slow_checks_default = false
-enable_dangling_raw_ptr_checks_default = true
+enable_dangling_raw_ptr_checks_default = false
diff --git a/cc/base/features.cc b/cc/base/features.cc
index eceb383..b81ea2d 100644
--- a/cc/base/features.cc
+++ b/cc/base/features.cc
@@ -78,7 +78,7 @@
 
 BASE_FEATURE(kNormalPriorityImageDecoding,
              "NormalPriorityImageDecoding",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kSkipCommitsIfNotSynchronizingCompositorState,
              "SkipCommitsIfNotSynchronizingCompositorState",
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 479d5055..61c6d719 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -1109,7 +1109,11 @@
     return TaskResult(false /* need_unref */, false /* is_at_raster_decode */,
                       image_data->decode.can_do_hardware_accelerated_decode());
   } else if (task_type == DecodeTaskType::kPartOfUploadTask &&
-             !image_data->upload.task_map.empty()) {
+             !image_data->upload.task_map.empty() &&
+             !image_data->HasUploadedData()) {
+    // If there are pending upload tasks and we haven't had data uploaded yet,
+    // another task can be created.
+
     // We had an existing upload task, ref the image and return the task.
     image_data->ValidateBudgeted();
     RefImage(draw_image, cache_key);
@@ -1131,7 +1135,11 @@
     return TaskResult(task,
                       image_data->decode.can_do_hardware_accelerated_decode());
   } else if (task_type == DecodeTaskType::kStandAloneDecodeTask &&
-             !image_data->decode.stand_alone_task_map.empty()) {
+             !image_data->decode.stand_alone_task_map.empty() &&
+             !image_data->HasUploadedData()) {
+    // If there are pending decode tasks and we haven't had decoded data yet,
+    // another task can be created.
+
     // We had an existing out of raster task, ref the image and return the task.
     image_data->ValidateBudgeted();
     RefImage(draw_image, cache_key);
@@ -1150,9 +1158,13 @@
       CHECK_EQ(task, found_task);
 #endif
     }
-    DCHECK(task);
     DCHECK(!image_data->decode.can_do_hardware_accelerated_decode());
-    return TaskResult(task, false /* can_do_hardware_accelerated_decode */);
+
+    // This will be null if the image was already decoded.
+    if (task)
+      return TaskResult(task, /*can_do_hardware_accelerated_decode=*/false);
+    return TaskResult(/*need_unref=*/true, /*is_at_raster_decode=*/false,
+                      /*can_do_hardware_accelerated_decode=*/false);
   }
 
   // Ensure that the image we're about to decode/upload will fit in memory, if
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index 537dd91..d946663 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -855,6 +855,115 @@
   }
 }
 
+// Verifies that if a client1 has uploaded the image, but haven't had its task
+// mark as completed, a client2 doesn't have a task created. Otherwise, it'll
+// crash while trying to create a decode task, which checks if the image data
+// has already been uploaded.
+TEST_P(GpuImageDecodeCacheTest, DoesNotCreateATaskForAlreadyUploadedImage) {
+  auto cache = CreateCache();
+  const uint32_t kClientId1 = cache->GenerateClientId();
+  const uint32_t kClientId2 = cache->GenerateClientId();
+
+  sk_sp<FakePaintImageGenerator> generator =
+      CreateFakePaintImageGenerator(GetNormalImageSize());
+  PaintImage image =
+      PaintImageBuilder::WithDefault()
+          .set_id(PaintImage::GetNextId())
+          .set_paint_image_generator(generator)
+          .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+          .TakePaintImage();
+
+  DrawImage draw_image =
+      CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+  EXPECT_EQ(draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+  ImageDecodeCache::TaskResult result1 = cache->GetTaskForImageAndRef(
+      kClientId1, draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(result1.need_unref);
+  EXPECT_TRUE(result1.task);
+
+  // The tasks are executed in the following order - decode1, upload1,
+  // decode2, upload2. Only the first decode/upload is executed.
+  TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+  TestTileTaskRunner::ScheduleTask(result1.task.get());
+  TestTileTaskRunner::RunTask(result1.task.get());
+
+  DrawImage another_draw_image =
+      CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+  EXPECT_EQ(another_draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+  ImageDecodeCache::TaskResult result2 = cache->GetTaskForImageAndRef(
+      kClientId2, another_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(result2.need_unref);
+  EXPECT_FALSE(result2.task);
+
+  TestTileTaskRunner::CompleteTask(result1.task.get());
+
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(another_draw_image);
+  cache->ClearCache();
+}
+
+// Almost the same as DoesNotCreateATaskForAlreadyUploadedImage, but with a
+// single client and a second request for a standalone decode task.
+TEST_P(GpuImageDecodeCacheTest, DoesNotCreateATaskForAlreadyUploadedImage2) {
+  auto cache = CreateCache();
+  const uint32_t kClientId1 = cache->GenerateClientId();
+
+  sk_sp<FakePaintImageGenerator> generator =
+      CreateFakePaintImageGenerator(GetNormalImageSize());
+  PaintImage image =
+      PaintImageBuilder::WithDefault()
+          .set_id(PaintImage::GetNextId())
+          .set_paint_image_generator(generator)
+          .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+          .TakePaintImage();
+
+  DrawImage draw_image =
+      CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+  EXPECT_EQ(draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+  // Get upload/decode task.
+  ImageDecodeCache::TaskResult result1 = cache->GetTaskForImageAndRef(
+      kClientId1, draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(result1.need_unref);
+  EXPECT_TRUE(result1.task);
+
+  // Get stand-alone decode task.
+  DrawImage another_draw_image =
+      CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+  EXPECT_EQ(another_draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+  ImageDecodeCache::TaskResult result2 =
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1,
+                                                    another_draw_image);
+  EXPECT_TRUE(result2.need_unref);
+  // It must be a valid task.
+  EXPECT_TRUE(result2.task);
+
+  // Execute decode/upload, but do not complete.
+  TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+  TestTileTaskRunner::ScheduleTask(result1.task.get());
+  TestTileTaskRunner::RunTask(result1.task.get());
+
+  DrawImage yet_another_draw_image =
+      CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+  EXPECT_EQ(yet_another_draw_image.frame_index(),
+            PaintImage::kDefaultFrameIndex);
+  // Ask for the decode standalone task again.
+  ImageDecodeCache::TaskResult result3 =
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1,
+                                                    yet_another_draw_image);
+  EXPECT_TRUE(result3.need_unref);
+  // It mustn't be created now as we already have image decoded/uploaded.
+  EXPECT_FALSE(result3.task);
+
+  // Complete and process created tasks.
+  TestTileTaskRunner::CompleteTask(result1.task.get());
+  TestTileTaskRunner::ProcessTask(result2.task.get());
+
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(another_draw_image);
+  cache->UnrefImage(yet_another_draw_image);
+  cache->ClearCache();
+}
+
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
   auto cache = CreateCache();
   const uint32_t client_id = cache->GenerateClientId();
@@ -2132,6 +2241,55 @@
   }
 }
 
+TEST_P(GpuImageDecodeCacheTest,
+       DoesNotCreateOutOfRasterDecodeTaskForNonCompletedTask) {
+  auto cache = CreateCache();
+  const uint32_t kClientId1 = cache->GenerateClientId();
+  const uint32_t kClientId2 = cache->GenerateClientId();
+
+  sk_sp<FakePaintImageGenerator> generator =
+      CreateFakePaintImageGenerator(GetNormalImageSize());
+  PaintImage image =
+      PaintImageBuilder::WithDefault()
+          .set_id(PaintImage::GetNextId())
+          .set_paint_image_generator(generator)
+          .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+          .TakePaintImage();
+
+  SkM44 matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f));
+  DrawImage draw_image =
+      CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
+                              PaintFlags::FilterQuality::kLow);
+
+  ImageDecodeCache::TaskResult result1 =
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1, draw_image);
+  EXPECT_TRUE(result1.need_unref);
+  EXPECT_TRUE(result1.task);
+  EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+
+  TestTileTaskRunner::ScheduleTask(result1.task.get());
+  TestTileTaskRunner::RunTask(result1.task.get());
+
+  DrawImage draw_image2 =
+      CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
+                              PaintFlags::FilterQuality::kLow);
+  ImageDecodeCache::TaskResult result2 =
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId2, draw_image);
+  EXPECT_TRUE(result2.need_unref);
+  EXPECT_FALSE(result2.task);
+  EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
+
+  TestTileTaskRunner::CompleteTask(result1.task.get());
+
+  // The image should remain in the cache till we unref it.
+  EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+  EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(draw_image2);
+  EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image));
+  EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image2));
+}
+
 TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
   SetCachedTexturesLimit(0);
   auto cache = CreateCache();
diff --git a/chrome/VERSION b/chrome/VERSION
index ccb49eed3..4fa8e80 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=110
 MINOR=0
-BUILD=5424
+BUILD=5425
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 09542910..259e89e 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -552,6 +552,7 @@
       "//components/content_capture/android:java",
       "//components/content_settings/android:content_settings_enums_java",
       "//components/content_settings/android:java",
+      "//components/crash/android:anr_collector_java",
       "//components/crash/android:java",
       "//components/digital_asset_links/android:java",
       "//components/digital_goods/mojom:mojom_java",
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn
index b20d6fe..422c816f 100644
--- a/chrome/android/features/keyboard_accessory/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -61,7 +61,6 @@
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java",
-    "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
index 60987a93..a51fd7b 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -411,8 +411,8 @@
     private void transitionIntoState(@KeyboardExtensionState int extensionState) {
         if (!meetsStatePreconditions(extensionState)) return;
         TraceEvent.begin("ManualFillingMediator#transitionIntoState");
+        enforceStateProperties(extensionState);
         changeBottomControlSpaceForState(extensionState);
-        enforceStateProperties(extensionState); // Triggers a relayout. Call after changing insets.
         updateKeyboard(extensionState);
         TraceEvent.end("ManualFillingMediator#transitionIntoState");
     }
@@ -559,11 +559,6 @@
         }
     }
 
-    @Override
-    public void onBarFadeInAnimationEnd() {
-        mActivity.getCurrentWebContents().scrollFocusedEditableNodeIntoView();
-    }
-
     /**
      * Opens the keyboard which implicitly dismisses the sheet. Without open sheet, this is a NoOp.
      */
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
index e70b07d..c2a57423e 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
@@ -62,12 +62,6 @@
          * Called when the sheet needs to be hidden.
          */
         void onCloseAccessorySheet();
-
-        /**
-         * Signals that the accessory bar has completed the fade-in. This may be relevant to the
-         * keyboard extensions state to adjust the scroll position.
-         */
-        void onBarFadeInAnimationEnd();
     }
 
     /**
@@ -251,7 +245,6 @@
      * while the view might still be in progress of being updated accordingly.
      * @return True if the accessory should be visible, false otherwise.
      */
-    // TODO(crbug/1385400): Hide because it's only used in tests.
     public boolean isShown() {
         return mMediator.isShown();
     }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
index 6f97991..6c08148 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.keyboard_accessory.bar_component;
 
-import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.ANIMATION_LISTENER;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING;
@@ -74,7 +73,6 @@
         mModel.set(OBFUSCATED_CHILD_AT_CALLBACK, this::onSuggestionObfuscatedAt);
         mModel.set(SHOW_KEYBOARD_CALLBACK, this::closeSheet);
         mModel.set(SHEET_OPENER_ITEM, new SheetOpenerBarItem(sheetOpenerCallbacks));
-        mModel.set(ANIMATION_LISTENER, mVisibilityDelegate::onBarFadeInAnimationEnd);
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) {
             mModel.get(BAR_ITEMS).add(mModel.get(SHEET_OPENER_ITEM));
         }
@@ -277,7 +275,7 @@
                 || propertyKey == SKIP_CLOSING_ANIMATION
                 || propertyKey == DISABLE_ANIMATIONS_FOR_TESTING
                 || propertyKey == OBFUSCATED_CHILD_AT_CALLBACK || propertyKey == SHOW_SWIPING_IPH
-                || propertyKey == HAS_SUGGESTIONS || propertyKey == ANIMATION_LISTENER) {
+                || propertyKey == HAS_SUGGESTIONS) {
             return;
         }
         assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
index 10ac0ca..36a06708 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
@@ -78,8 +78,7 @@
                     || propertyKey == KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING
                     || propertyKey == KeyboardAccessoryProperties.SHOW_SWIPING_IPH
                     || propertyKey == KeyboardAccessoryProperties.OBFUSCATED_CHILD_AT_CALLBACK
-                    || propertyKey == KeyboardAccessoryProperties.HAS_SUGGESTIONS
-                    || propertyKey == KeyboardAccessoryProperties.ANIMATION_LISTENER) {
+                    || propertyKey == KeyboardAccessoryProperties.HAS_SUGGESTIONS) {
                 return;
             }
             assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
index 164cbf6..74fceffd 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
@@ -56,15 +56,12 @@
     static final WritableBooleanPropertyKey HAS_SUGGESTIONS =
             new WritableBooleanPropertyKey("has_suggestions");
 
-    static final WritableObjectPropertyKey<KeyboardAccessoryView.AnimationListener>
-            ANIMATION_LISTENER = new WritableObjectPropertyKey<>("animation_listener");
-
     static PropertyModel.Builder defaultModelBuilder() {
         return new PropertyModel
                 .Builder(DISABLE_ANIMATIONS_FOR_TESTING, BAR_ITEMS, VISIBLE, SKIP_CLOSING_ANIMATION,
                         BOTTOM_OFFSET_PX, SHEET_OPENER_ITEM, KEYBOARD_TOGGLE_VISIBLE, SHEET_TITLE,
                         SHOW_KEYBOARD_CALLBACK, OBFUSCATED_CHILD_AT_CALLBACK, SHOW_SWIPING_IPH,
-                        HAS_SUGGESTIONS, ANIMATION_LISTENER)
+                        HAS_SUGGESTIONS)
                 .with(BAR_ITEMS, new ListModel<>())
                 .with(VISIBLE, false)
                 .with(SKIP_CLOSING_ANIMATION, false)
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
index 3e18e80..26b97a8 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
@@ -16,7 +16,6 @@
 import android.widget.LinearLayout;
 
 import androidx.annotation.CallSuper;
-import androidx.annotation.VisibleForTesting;
 import androidx.core.view.ViewCompat;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
@@ -41,16 +40,6 @@
     private boolean mShouldSkipClosingAnimation;
     private boolean mDisableAnimations;
 
-    /** Interface that allows to react to animations. */
-    interface AnimationListener {
-        /**
-         * Called if the accessory bar stopped fading in. The fade-in only happens sometimes, e.g.
-         * if the bar is already visible or animations are disabled, this signal is not issued.
-         */
-        void onFadeInEnd();
-    }
-    private AnimationListener mAnimationListener;
-
     protected static class HorizontalDividerItemDecoration extends RecyclerView.ItemDecoration {
         private final int mHorizontalMargin;
 
@@ -144,10 +133,6 @@
         mBarItemsView.setAdapter(adapter);
     }
 
-    void setAnimationListener(AnimationListener animationListener) {
-        mAnimationListener = animationListener;
-    }
-
     /** Template method. Override to be notified if the bar items change. */
     @CallSuper
     protected void onItemsChanged() {}
@@ -155,10 +140,7 @@
     private void show() {
         TraceEvent.begin("KeyboardAccessoryView#show");
         bringToFront(); // Needs to overlay every component and the bottom sheet - like a keyboard.
-        if (mRunningAnimation != null) {
-            mRunningAnimation.cancel();
-            mRunningAnimation = null;
-        }
+        if (mRunningAnimation != null) mRunningAnimation.cancel();
         if (areAnimationsDisabled()) {
             mRunningAnimation = null;
             setVisibility(View.VISIBLE);
@@ -169,20 +151,13 @@
                                     .alpha(1f)
                                     .setDuration(FADE_ANIMATION_DURATION_MS)
                                     .setInterpolator(new AccelerateInterpolator())
-                                    .withStartAction(() -> setVisibility(View.VISIBLE))
-                                    .withEndAction(() -> {
-                                        mAnimationListener.onFadeInEnd();
-                                        mRunningAnimation = null;
-                                    });
+                                    .withStartAction(() -> setVisibility(View.VISIBLE));
         announceForAccessibility(getContentDescription());
         TraceEvent.end("KeyboardAccessoryView#show");
     }
 
     private void hide() {
-        if (mRunningAnimation != null) {
-            mRunningAnimation.cancel();
-            mRunningAnimation = null;
-        }
+        if (mRunningAnimation != null) mRunningAnimation.cancel();
         if (mShouldSkipClosingAnimation || areAnimationsDisabled()) {
             mRunningAnimation = null;
             setVisibility(View.GONE);
@@ -194,10 +169,7 @@
                         .setInterpolator(new AccelerateInterpolator())
                         .setStartDelay(HIDING_ANIMATION_DELAY_MS)
                         .setDuration(FADE_ANIMATION_DURATION_MS - HIDING_ANIMATION_DELAY_MS)
-                        .withEndAction(() -> {
-                            setVisibility(View.GONE);
-                            mRunningAnimation = null;
-                        });
+                        .withEndAction(() -> setVisibility(View.GONE));
     }
 
     void setSkipClosingAnimation(boolean shouldSkipClosingAnimation) {
@@ -229,9 +201,4 @@
 
         ViewCompat.setPaddingRelative(recyclerView, pad, 0, 0, 0);
     }
-
-    @VisibleForTesting
-    boolean hasRunningAnimation() {
-        return mRunningAnimation != null;
-    }
 }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
index b233e1a..b9dedba 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.keyboard_accessory.bar_component;
 
-import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.ANIMATION_LISTENER;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING;
@@ -114,8 +113,6 @@
             if (!model.get(VISIBLE)) view.setVisible(false); // Update to cancel any animation.
         } else if (propertyKey == BOTTOM_OFFSET_PX) {
             view.setBottomOffset(model.get(BOTTOM_OFFSET_PX));
-        } else if (propertyKey == ANIMATION_LISTENER) {
-            view.setAnimationListener(model.get(ANIMATION_LISTENER));
         } else if (propertyKey == SHOW_KEYBOARD_CALLBACK || propertyKey == KEYBOARD_TOGGLE_VISIBLE
                 || propertyKey == SHEET_TITLE || propertyKey == SHEET_OPENER_ITEM
                 || propertyKey == OBFUSCATED_CHILD_AT_CALLBACK || propertyKey == SHOW_SWIPING_IPH
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java
index 9e1147a..5f3f7e7 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -8,8 +8,6 @@
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem;
-import static androidx.test.espresso.contrib.RecyclerViewActions.scrollTo;
 import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
 import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
@@ -17,12 +15,12 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertNotNull;
 
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
-import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabWithDescription;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.waitToBeHidden;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
 import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
@@ -140,11 +138,8 @@
         onView(withChild(withId(R.id.keyboard_accessory_sheet))).check(doesNotExist());
 
         // Trigger the sheet and wait for it to open and the keyboard to disappear.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        onView(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
     }
@@ -187,11 +182,8 @@
         onView(withChild(withId(R.id.keyboard_accessory_sheet))).check(doesNotExist());
 
         // Trigger the sheet and wait for it to open and the keyboard to disappear.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        onView(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet))).check((view, e) -> {
             accessorySheetView.set(view);
@@ -244,12 +236,14 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
         // Click the tab again to hide the sheet and show the keyboard.
-        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
+        onView(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardAccessoryToBeShown();
         onView(withId(R.id.keyboard_accessory)).check(matches(isDisplayed()));
         waitToBeHidden(withChild(withId(R.id.keyboard_accessory_sheet)));
@@ -268,7 +262,7 @@
         // Focus the password field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(isKeyboardAccessoryTabLayout());
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()));
 
         // Clicking a field without completion hides the accessory again.
         mHelper.clickFieldWithoutCompletion();
@@ -286,11 +280,8 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
@@ -313,11 +304,8 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
@@ -339,11 +327,8 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
     }
@@ -362,11 +347,8 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
@@ -447,11 +429,8 @@
         assertThat(mActivityTestRule.getInfoBarContainer().getVisibility(), is(not(View.VISIBLE)));
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
         assertThat(mActivityTestRule.getInfoBarContainer().getVisibility(), is(not(View.VISIBLE)));
@@ -500,11 +479,8 @@
         onView(withText(kSnackbarText)).check(matches(isCompletelyDisplayed()));
 
         // Open a keyboard accessory sheet -- this also shouldn't hide the snackbar.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
         onView(withText(kSnackbarText)).check(matches(isCompletelyDisplayed()));
 
@@ -540,11 +516,8 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
         assertThat(mActivityTestRule.getInfoBarContainer().getVisibility(), is(not(View.VISIBLE)));
 
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
index 4ea31d2d..8807c2c 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
@@ -12,12 +12,6 @@
 import static org.hamcrest.core.AllOf.allOf;
 
 import static org.chromium.autofill.mojom.FocusedFieldType.FILLABLE_NON_SEARCH_FIELD;
-import static org.chromium.base.test.util.CriteriaHelper.pollInstrumentationThread;
-import static org.chromium.base.test.util.CriteriaHelper.pollUiThread;
-import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryStartedHiding;
-import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryStartedShowing;
-import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryViewFullyHidden;
-import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryViewFullyShown;
 import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
 import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting;
 import static org.chromium.ui.test.util.ViewUtils.VIEW_GONE;
@@ -43,6 +37,7 @@
 
 import com.google.android.material.tabs.TabLayout;
 
+import org.chromium.ui.widget.ChromeImageButton;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.Matchers;
@@ -50,6 +45,7 @@
 
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.Criteria;
+import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.chrome.browser.ChromeWindow;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
@@ -73,7 +69,6 @@
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.net.test.ServerCertificate;
 import org.chromium.ui.DropdownPopupWindowInterface;
-import org.chromium.ui.widget.ChromeImageButton;
 
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
@@ -244,7 +239,7 @@
     // ---------------------------------
 
     public void waitForKeyboardToDisappear() {
-        pollUiThread(() -> {
+        CriteriaHelper.pollUiThread(() -> {
             Activity activity = mActivityTestRule.getActivity();
             return !getKeyboard().isAndroidSoftKeyboardShowing(
                     activity, activity.getCurrentFocus());
@@ -252,8 +247,15 @@
     }
 
     public void waitForKeyboardAccessoryToDisappear() {
-        pollInstrumentationThread(() -> accessoryStartedHiding(getKeyboardAccessoryBar()));
-        pollUiThread(() -> accessoryViewFullyHidden(mActivityTestRule.getActivity()));
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            KeyboardAccessoryCoordinator accessory =
+                    getManualFillingCoordinator().getMediatorForTesting().getKeyboardAccessory();
+            return accessory != null && !accessory.isShown();
+        });
+        CriteriaHelper.pollUiThread(() -> {
+            View accessory = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
+            return accessory != null && !accessory.isShown();
+        });
     }
 
     public void waitForKeyboardAccessoryToBeShown() {
@@ -261,12 +263,19 @@
     }
 
     public void waitForKeyboardAccessoryToBeShown(boolean waitForSuggestionsToLoad) {
-        pollInstrumentationThread(() -> accessoryStartedShowing(getKeyboardAccessoryBar()));
-        pollUiThread(() -> accessoryViewFullyShown(mActivityTestRule.getActivity()));
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            KeyboardAccessoryCoordinator accessory =
+                    getManualFillingCoordinator().getMediatorForTesting().getKeyboardAccessory();
+            return accessory != null && accessory.isShown();
+        });
+        CriteriaHelper.pollUiThread(() -> {
+            View accessory = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
+            return accessory != null && accessory.isShown();
+        });
         if (waitForSuggestionsToLoad) {
-            pollUiThread(() -> {
-                return getFirstAccessorySuggestion() != null;
-            }, "Waited for suggestions that never appeared.");
+            CriteriaHelper.pollUiThread(()
+                                                -> getFirstAccessorySuggestion() != null,
+                    "Waited for suggestions that never appeared.");
         }
     }
 
@@ -275,14 +284,14 @@
         final View view = webContents.getViewAndroidDelegate().getContainerView();
 
         // Wait for InputConnection to be ready and fill the filterInput. Then wait for the anchor.
-        pollUiThread(() -> {
+        CriteriaHelper.pollUiThread(() -> {
             Criteria.checkThat(
                     mInputMethodManagerWrapper.getShowSoftInputCounter(), Matchers.is(1));
         });
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             ImeAdapter.fromWebContents(webContents).setComposingTextForTest(filterInput, 4);
         });
-        pollUiThread(() -> {
+        CriteriaHelper.pollUiThread(() -> {
             Criteria.checkThat("Autofill Popup anchor view was never added.",
                     view.findViewById(R.id.dropdown_popup_window), Matchers.notNullValue());
         });
@@ -291,7 +300,7 @@
         Assert.assertTrue(anchorView.getTag() instanceof DropdownPopupWindowInterface);
         final DropdownPopupWindowInterface popup =
                 (DropdownPopupWindowInterface) anchorView.getTag();
-        pollUiThread(() -> {
+        CriteriaHelper.pollUiThread(() -> {
             Criteria.checkThat(popup.isShowing(), Matchers.is(true));
             Criteria.checkThat(popup.getListView(), Matchers.notNullValue());
             Criteria.checkThat(popup.getListView().getHeight(), Matchers.not(0));
@@ -317,10 +326,6 @@
                 .getOrCreateSheet(mWebContentsRef.get(), AccessoryTabType.CREDIT_CARDS);
     }
 
-    private KeyboardAccessoryCoordinator getKeyboardAccessoryBar() {
-        return getManualFillingCoordinator().getMediatorForTesting().getKeyboardAccessory();
-    }
-
     // ----------------------------------
     // Helpers to set up the native side.
     // ----------------------------------
@@ -439,7 +444,7 @@
         return new ViewAction() {
             @Override
             public Matcher<View> getConstraints() {
-                return allOf(isDisplayed(), isKeyboardAccessoryTabLayout());
+                return allOf(isDisplayed(), isAssignableFrom(TabLayout.class));
             }
 
             @Override
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java
deleted file mode 100644
index 6b9fac7..0000000
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.keyboard_accessory.bar_component;
-
-import android.app.Activity;
-
-import org.chromium.chrome.browser.keyboard_accessory.R;
-
-/**
- * Helpers in this class simplify interactions with the Keyboard Accessory bar component.
- */
-public class KeyboardAccessoryTestHelper {
-    /**
-     * Returns true if the accessory becomes visible. It is not guaranteed that the view reflects
-     * this state already. Use {@link #accessoryViewFullyShown(Activity)} for that.
-     *
-     * @param accessory An {@link KeyboardAccessoryCoordinator}
-     * @return True iff the component was ordered to show.
-     */
-    public static boolean accessoryStartedShowing(KeyboardAccessoryCoordinator accessory) {
-        return accessory != null && accessory.isShown();
-    }
-
-    /**
-     * Returns true if the accessory starts hiding. It is not guaranteed that the view reflects this
-     * state already. Use {@link #accessoryViewFullyHidden(Activity)} (Activity)} for that.
-     *
-     * @param accessory An {@link KeyboardAccessoryCoordinator}
-     * @return True iff the component was ordered to hide.
-     */
-    public static boolean accessoryStartedHiding(KeyboardAccessoryCoordinator accessory) {
-        return accessory != null && !accessory.isShown();
-    }
-
-    /**
-     * Helper that finds the accessory bar and checks whether it's shown. Returns false until
-     * animations have concluded.
-     *
-     * @param activity The {@link Activity} containing the accessory bar.
-     * @return True iff the bar view is visible and animations have ended.
-     */
-    public static boolean accessoryViewFullyShown(Activity activity) {
-        KeyboardAccessoryView accessory = activity.findViewById(R.id.keyboard_accessory);
-        return accessory != null && accessory.isShown() && !accessory.hasRunningAnimation();
-    }
-
-    /**
-     * Helper that finds the accessory bar and checks whether it's hidden. Returns false until
-     * animations have concluded.
-     *
-     * @param activity The {@link Activity} containing the accessory bar.
-     * @return True iff the bar view is hidden and animations have ended.
-     */
-    public static boolean accessoryViewFullyHidden(Activity activity) {
-        KeyboardAccessoryView accessory = activity.findViewById(R.id.keyboard_accessory);
-        return accessory == null || (!accessory.isShown() && !accessory.hasRunningAnimation());
-    }
-}
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
index eec8da98..ac09334 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
@@ -9,16 +9,22 @@
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem;
 import static androidx.test.espresso.contrib.RecyclerViewActions.scrollTo;
+import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
 
-import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabWithDescription;
+import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
 import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
 
+import android.widget.TextView;
+
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
@@ -130,12 +136,9 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.credit_card_accessory_sheet_toggle)));
-
+        whenDisplayed(allOf(withContentDescription(R.string.credit_card_accessory_sheet_toggle),
+                              not(isAssignableFrom(TextView.class))))
+                .perform(click());
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withId(R.id.credit_card_sheet));
         onView(withText(containsString("No saved payment methods"))).check(matches(isDisplayed()));
@@ -154,9 +157,7 @@
         // Scroll to last element and click the first icon:
         whenDisplayed(withId(R.id.bar_items_view))
                 .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.credit_card_accessory_sheet_toggle)));
+                        actionOnItem(isKeyboardAccessoryTabLayout(), selectTabAtPosition(0)));
 
         // Wait for the sheet to come up and be stable.
         whenDisplayed(withId(R.id.credit_card_sheet));
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java
index 66e2d903..4646e41f 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java
@@ -7,8 +7,6 @@
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem;
-import static androidx.test.espresso.contrib.RecyclerViewActions.scrollTo;
 import static androidx.test.espresso.matcher.ViewMatchers.isChecked;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.isNotChecked;
@@ -16,10 +14,11 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.core.AllOf.allOf;
 
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.isTransformed;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.scrollToLastElement;
-import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabWithDescription;
+import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
 import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
 
@@ -89,11 +88,8 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
 
         // Check that the provided elements are there.
         whenDisplayed(withText("mayapark@gmail.com"));
@@ -113,11 +109,8 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
 
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withId(R.id.passwords_sheet)).perform(scrollToLastElement());
@@ -134,11 +127,8 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
 
         // Click the suggestion.
         whenDisplayed(withText("ShorterPassword")).perform(click());
@@ -164,11 +154,8 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withId(R.id.passwords_sheet));
         onView(withText(containsString("No saved passwords"))).check(matches(isDisplayed()));
@@ -179,18 +166,15 @@
     @EnableFeatures({ChromeFeatureList.RECOVER_FROM_NEVER_SAVE_ANDROID,
             ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY})
     public void
-    testEnablesUndenylistingToggle() throws TimeoutException, InterruptedException {
+    testEnablesUndenylistingToggle() throws TimeoutException {
         mHelper.loadTestPage(false);
         mHelper.cacheCredentials(new String[0], new String[0], true);
 
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(withId(R.id.bar_items_view))
-                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(),
-                                selectTabWithDescription(
-                                        R.string.password_accessory_sheet_toggle)));
+        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
+                .perform(selectTabAtPosition(0));
 
         whenDisplayed(withId(R.id.option_toggle_switch)).check(matches(isNotChecked()));
         onView(withId(R.id.option_toggle_subtitle)).check(matches(withText(R.string.text_off)));
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
index 96137b6..8eb920c7 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
@@ -1116,12 +1116,6 @@
     }
 
     @Test
-    public void testScrollsPageUpAfterBarIsFullyShown() {
-        mMediator.onBarFadeInAnimationEnd();
-        verify(mLastMockWebContents).scrollFocusedEditableNodeIntoView();
-    }
-
-    @Test
     public void testShowAccessorySheetTab() {
         // Prepare a tab and register a new tab, so there is a reason to display the bar.
         addBrowserTab(mMediator, 1111, null);
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
index e6c2c8a..b87eede7 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
@@ -18,7 +18,6 @@
 
 import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.AUTOFILL_SUGGESTION;
 import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.GENERATE_PASSWORD_AUTOMATIC;
-import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.ANIMATION_LISTENER;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.HAS_SUGGESTIONS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.OBFUSCATED_CHILD_AT_CALLBACK;
@@ -586,12 +585,6 @@
         assertThat(mModel.get(HAS_SUGGESTIONS), is(false));
     }
 
-    @Test
-    public void testFowardsAnimationEventsToVisibilityDelegate() {
-        mModel.get(ANIMATION_LISTENER).onFadeInEnd();
-        verify(mMockVisibilityDelegate).onBarFadeInAnimationEnd();
-    }
-
     private int getGenerationImpressionCount() {
         return RecordHistogram.getHistogramValueCountForTesting(
                 ManualFillingMetricsRecorder.UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION,
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
index 11646a1..7a333760 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
@@ -28,11 +28,11 @@
 import com.google.android.material.appbar.AppBarLayout;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.FeatureList;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.feed.FeedStreamViewResizer;
 import org.chromium.chrome.browser.feed.FeedSurfaceCoordinator;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.ntp.IncognitoDescriptionView;
 import org.chromium.chrome.browser.ntp.search.SearchBoxCoordinator;
@@ -47,6 +47,8 @@
  */
 public class TasksView extends CoordinatorLayoutForPointer {
     private static final int OMNIBOX_BOTTOM_PADDING_DP = 4;
+    private static final MutableFlagWithSafeDefault sIncognitoRevampFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.INCOGNITO_NTP_REVAMP, false);
 
     private final Context mContext;
     private FrameLayout mCarouselTabSwitcherContainer;
@@ -224,8 +226,7 @@
 
         ViewStub incognitoDescriptionViewStub =
                 (ViewStub) findViewById(R.id.task_view_incognito_layout_stub);
-        if (FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.INCOGNITO_NTP_REVAMP)) {
+        if (sIncognitoRevampFlag.isEnabled()) {
             incognitoDescriptionViewStub.setLayoutResource(
                     R.layout.revamped_incognito_description_layout);
         } else {
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java
index 49dfeb2..14115fa4 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java
@@ -484,7 +484,6 @@
     @Test
     @MediumTest
     @Feature({"RenderTest"})
-    @DisabledTest(message = "https://crbug.com/1383178")
     public void testLongTextActionViewAndMenuItem() throws Exception {
         List<FakeTabSelectionEditorAction> actions = new ArrayList<>();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index b9a62482..1e572fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -36,7 +36,6 @@
 import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.FeatureList;
 import org.chromium.base.IntentUtils;
 import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
@@ -62,6 +61,7 @@
 import org.chromium.chrome.browser.customtabs.features.sessionrestore.SessionRestoreManagerImpl;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.metrics.PageLoadMetrics;
 import org.chromium.chrome.browser.metrics.UmaSessionStats;
@@ -183,6 +183,9 @@
     static final String GET_GREATEST_SCROLL_PERCENTAGE = "getGreatestScrollPercentage";
     @VisibleForTesting
     static final String GREATEST_SCROLL_PERCENTAGE_KEY = "greatestScrollPercentage";
+    private static final MutableFlagWithSafeDefault sRealTimeEngagementFlag =
+            new MutableFlagWithSafeDefault(
+                    ChromeFeatureList.CCT_REAL_TIME_ENGAGEMENT_SIGNALS, false);
 
     @IntDef({ParallelRequestStatus.NO_REQUEST, ParallelRequestStatus.SUCCESS,
             ParallelRequestStatus.FAILURE_NOT_INITIALIZED,
@@ -668,9 +671,7 @@
         Bundle result = null;
         switch (commandName) {
             case GET_GREATEST_SCROLL_PERCENTAGE:
-                if (!FeatureList.isInitialized()
-                        || !ChromeFeatureList.isEnabled(
-                                ChromeFeatureList.CCT_REAL_TIME_ENGAGEMENT_SIGNALS)) {
+                if (!sRealTimeEngagementFlag.isEnabled()) {
                     break;
                 }
                 Integer percentage = mGreatestScrollPercentageSupplier != null
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java
index a533132..7b41716 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.directactions;
 
-import android.content.Context;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 
@@ -12,18 +11,12 @@
 import androidx.annotation.RequiresApi;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.AppHooks;
-import org.chromium.chrome.browser.autofill_assistant.AssistantDependencyUtilsChrome;
-import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantFacade;
-import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
-import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.findinpage.FindToolbarManager;
 import org.chromium.chrome.browser.flags.ActivityType;
 import org.chromium.chrome.browser.lifecycle.DestroyObserver;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController;
 
 import java.util.Collections;
@@ -39,11 +32,6 @@
  */
 @RequiresApi(29)
 public class DirectActionInitializer implements NativeInitObserver, DestroyObserver {
-    private final Context mContext;
-    private final BottomSheetController mBottomSheetController;
-    private final BrowserControlsStateProvider mBrowserControls;
-    private final CompositorViewHolder mCompositorViewHolder;
-    private final ActivityTabProvider mActivityTabProvider;
     private final TabModelSelector mTabModelSelector;
 
     @ActivityType
@@ -59,34 +47,21 @@
     private MenuDirectActionHandler mMenuHandler;
 
     /**
-     * @param context The current context, often the activity instance.
      * @param activityType The type of the current activity
      * @param actionController Controller to use to execute menu actions
      * @param goBackAction Implementation of the "go_back" action, usually {@link
      *         android.app.Activity#onBackPressed}.
      * @param tabModelSelector The activity's {@link TabModelSelector}
      * @param findToolbarManager Manager to use for the "find_in_page" action, if it exists
-     * @param bottomSheetController Controller for the activity's bottom sheet, if it exists
-     * @param browserControls Provider of browser controls of the activity
-     * @param compositorViewHolder Compositor view holder of the activity
-     * @param activityTabProvider Activity tab provider
      */
-    public DirectActionInitializer(Context context, @ActivityType int activityType,
+    public DirectActionInitializer(@ActivityType int activityType,
             MenuOrKeyboardActionController actionController, Runnable goBackAction,
-            TabModelSelector tabModelSelector, @Nullable FindToolbarManager findToolbarManager,
-            @Nullable BottomSheetController bottomSheetController,
-            BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder,
-            ActivityTabProvider activityTabProvider) {
-        mContext = context;
+            TabModelSelector tabModelSelector, @Nullable FindToolbarManager findToolbarManager) {
         mActivityType = activityType;
         mMenuOrKeyboardActionController = actionController;
         mGoBackAction = goBackAction;
         mTabModelSelector = tabModelSelector;
         mFindToolbarManager = findToolbarManager;
-        mBottomSheetController = bottomSheetController;
-        mBrowserControls = browserControls;
-        mCompositorViewHolder = compositorViewHolder;
-        mActivityTabProvider = activityTabProvider;
 
         mDirectActionsRegistered = false;
     }
@@ -128,37 +103,21 @@
     /**
      * Registers common action that manipulate the current activity or the browser content.
      *
-     * @param context The current context, often the activity instance.
-     * @param activityType The type of the current activity
      * @param actionController Controller to use to execute menu actions
      * @param goBackAction Implementation of the "go_back" action, usually {@link
      *         android.app.Activity#onBackPressed}.
      * @param tabModelSelector The activity's {@link TabModelSelector}
      * @param findToolbarManager Manager to use for the "find_in_page" action, if it exists
-     * @param bottomSheetController Controller for the activity's bottom sheet, if it exists
-     * @param browserControls Browser controls manager of the activity
-     * @param compositorViewHolder Compositor view holder of the activity
-     * @param activityTabProvider Activity tab provider
      */
-    private void registerCommonChromeActions(Context context, @ActivityType int activityType,
-            MenuOrKeyboardActionController actionController, Runnable goBackAction,
-            TabModelSelector tabModelSelector, @Nullable FindToolbarManager findToolbarManager,
-            @Nullable BottomSheetController bottomSheetController,
-            BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder,
-            ActivityTabProvider activityTabProvider) {
+    private void registerCommonChromeActions(MenuOrKeyboardActionController actionController,
+            Runnable goBackAction, TabModelSelector tabModelSelector,
+            @Nullable FindToolbarManager findToolbarManager) {
         mCoordinator.register(new GoBackDirectActionHandler(goBackAction));
         mCoordinator.register(
                 new FindInPageDirectActionHandler(tabModelSelector, findToolbarManager));
 
         registerMenuHandlerIfNecessary(actionController, tabModelSelector)
                 .allowlistActions(R.id.forward_menu_id, R.id.reload_menu_id);
-
-        if (AssistantDependencyUtilsChrome.areDirectActionsAvailable(activityType)) {
-            DirectActionHandler handler = AutofillAssistantFacade.createDirectActionHandler(context,
-                    bottomSheetController, browserControls, compositorViewHolder,
-                    activityTabProvider);
-            if (handler != null) mCoordinator.register(handler);
-        }
     }
 
     /**
@@ -206,12 +165,8 @@
      * Registers the set of direct actions available to assist apps.
      */
     void registerDirectActions() {
-        registerCommonChromeActions(mContext, mActivityType, mMenuOrKeyboardActionController,
-                mGoBackAction, mTabModelSelector, mFindToolbarManager,
-                AssistantDependencyUtilsChrome.areDirectActionsAvailable(mActivityType)
-                        ? mBottomSheetController
-                        : null,
-                mBrowserControls, mCompositorViewHolder, mActivityTabProvider);
+        registerCommonChromeActions(mMenuOrKeyboardActionController, mGoBackAction,
+                mTabModelSelector, mFindToolbarManager);
 
         if (mActivityType == ActivityType.TABBED) {
             registerTabManipulationActions(mMenuOrKeyboardActionController, mTabModelSelector);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index d32374a..74e0f56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -95,6 +95,7 @@
 import org.chromium.components.browser_ui.share.ClipboardImageFileProvider;
 import org.chromium.components.browser_ui.share.ShareImageFileUtils;
 import org.chromium.components.content_capture.PlatformContentCaptureController;
+import org.chromium.components.crash.anr.AnrCollector;
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.components.minidump_uploader.CrashFileManager;
 import org.chromium.components.optimization_guide.proto.HintsProto;
@@ -118,6 +119,7 @@
 import org.chromium.ui.base.WindowAndroid;
 
 import java.io.File;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -185,20 +187,7 @@
         AccountManagerFacadeProvider.setInstance(
                 new AccountManagerFacadeImpl(AppHooks.get().createAccountManagerDelegate()));
 
-        // For ANR uploading - we set the version number so that when we ask Android for our ANRs,
-        // it can also give us the version it happened on. This helps in the case that before we can
-        // report the ANR, our app gets updated.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
-            ActivityManager am =
-                    (ActivityManager) ContextUtils.getApplicationContext().getSystemService(
-                            Context.ACTIVITY_SERVICE);
-            // We can only do 128 bytes in ProcessStateSummary, so only storing the most important
-            // thing that could change between the ANR happening and upload (when the rest of the
-            // metadata is gathered) - the version number. Other fields either won't change (eg.
-            // which channel) or don't matter as much (eg. what experiments are running).
-            String productVersion = VersionInfo.getProductVersion();
-            ApiHelperForR.setProcessStateSummary(am, productVersion.getBytes());
-        }
+        setProcessStateSummaryForAnrs(false);
 
         // De-jelly can also be controlled by a system property. As sandboxed processes can't
         // read this property directly, convert it to the equivalent command line flag.
@@ -278,6 +267,34 @@
         FeatureNotificationGuideService.setDelegate(new FeatureNotificationGuideDelegate());
 
         PrivacyPreferencesManagerImpl.getInstance().onNativeInitialized();
+
+        setProcessStateSummaryForAnrs(true);
+    }
+
+    /**
+     * We use the Android API to store key information which we can't afford to have wrong on our
+     * ANR reports. So, we set the version number, and the main .so file's Build ID once native has
+     * been loaded. Then, when we query Android for any ANRs that have happened, we can also pull
+     * these key fields.
+     *
+     * We are limited to 128 bytes in ProcessStateSummary, so we only store the most important
+     * things that can change between the ANR happening and an upload (when the rest of the metadata
+     * is gathered). Some fields we ignore because they won't change (eg. which channel or what the
+     * .so filename is) and some we ignore because they aren't as critical (eg. experiments). In the
+     * future, we could make this point to a file where we would write out all our crash keys, and
+     * thus get full fidelity.
+     */
+    protected void setProcessStateSummaryForAnrs(boolean includeNative) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            ActivityManager am =
+                    (ActivityManager) ContextUtils.getApplicationContext().getSystemService(
+                            Context.ACTIVITY_SERVICE);
+            String summary = VersionInfo.getProductVersion();
+            if (includeNative) {
+                summary += "," + AnrCollector.getSharedLibraryBuildId();
+            }
+            ApiHelperForR.setProcessStateSummary(am, summary.getBytes(StandardCharsets.UTF_8));
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java
index c03cb47..bd4d7f4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java
@@ -11,11 +11,11 @@
 import androidx.browser.customtabs.CustomTabsIntent;
 
 import org.chromium.base.Callback;
-import org.chromium.base.FeatureList;
 import org.chromium.base.LocaleUtils;
 import org.chromium.chrome.browser.ChromeActivitySessionTracker;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.chrome.browser.language.AppLocaleUtils;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeFactory;
 import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
@@ -49,6 +49,11 @@
 
     private static final String TAG = "CrowButton";
 
+    private static final MutableFlagWithSafeDefault sShareCrowButton =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.SHARE_CROW_BUTTON, false);
+    private static final MutableFlagWithSafeDefault sShareCrowButtonLaunchTabFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.SHARE_CROW_BUTTON_LAUNCH_TAB, false);
+
     /** Constructs a new {@link CrowButtonDelegateImpl}. */
     public CrowButtonDelegateImpl() {
         mChromeActivitySessionTracker = ChromeActivitySessionTracker.getInstance();
@@ -106,8 +111,7 @@
         String customTabUrl = getUrlForWebFlow(pageUrl, canonicalUrl, isFollowing);
 
         // Experiment flag: open in standard new tab.
-        if (FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_CROW_BUTTON_LAUNCH_TAB)) {
+        if (sShareCrowButtonLaunchTabFlag.isEnabled()) {
             // TabLaunchType.FROM_LINK will allow back to navigate back to the
             // current tab.
             LoadUrlParams loadUrlParams = new LoadUrlParams(customTabUrl);
@@ -142,8 +146,7 @@
     }
 
     public boolean isCrowEnabled() {
-        return isEnabledForLocaleAndCountry() && FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_CROW_BUTTON);
+        return isEnabledForLocaleAndCountry() && sShareCrowButton.isEnabled();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/translate/TranslateAssistContent.java b/chrome/android/java/src/org/chromium/chrome/browser/translate/TranslateAssistContent.java
index 65b7189..41096bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/translate/TranslateAssistContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/translate/TranslateAssistContent.java
@@ -12,9 +12,9 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import org.chromium.base.FeatureList;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.chrome.browser.tab.Tab;
 
 import java.lang.annotation.Retention;
@@ -30,6 +30,8 @@
     public static final String IN_LANGUAGE_KEY = "inLanguage";
     public static final String WORK_TRANSLATION_KEY = "workTranslation";
     public static final String TRANSLATION_OF_WORK_KEY = "translationOfWork";
+    private static final MutableFlagWithSafeDefault sTranslateAssistContentFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.TRANSLATE_ASSIST_CONTENT, false);
 
     /**
      * Represents the result of attempting to attach translate data to AssistContent.
@@ -79,8 +81,7 @@
      */
     public static @Nullable String getTranslateDataForTab(
             @Nullable Tab tab, boolean isInOverviewMode) {
-        if (!FeatureList.isInitialized()
-                || !ChromeFeatureList.isEnabled(ChromeFeatureList.TRANSLATE_ASSIST_CONTENT)) {
+        if (!sTranslateAssistContentFlag.isEnabled()) {
             recordTranslateAssistContentResultUMA(TranslateAssistContentResult.FEATURE_DISABLED);
             return null;
         } else if (isInOverviewMode) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
index b9f103d..6df15b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -1501,10 +1501,9 @@
     }
 
     private void initDirectActionInitializer() {
-        mDirectActionInitializer = new DirectActionInitializer(mActivity, mActivityType,
+        mDirectActionInitializer = new DirectActionInitializer(mActivityType,
                 mMenuOrKeyboardActionController, mActivity::onBackPressed,
-                mTabModelSelectorSupplier.get(), mFindToolbarManager, getBottomSheetController(),
-                mBrowserControlsManager, mCompositorViewHolderSupplier.get(), mActivityTabProvider);
+                mTabModelSelectorSupplier.get(), mFindToolbarManager);
         mActivityLifecycleDispatcher.register(mDirectActionInitializer);
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStackerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStackerUnitTest.java
index 35be8db..1ca632f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStackerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStackerUnitTest.java
@@ -18,6 +18,7 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.ui.base.LocalizationUtils;
 
@@ -79,6 +80,7 @@
     }
 
     @Test
+    @DisabledTest(message = "https://crbug.com/1385702")
     public void testComputeNewTabButtonOffset() {
         float result = mTarget.computeNewTabButtonOffset(mInput, TAB_OVERLAP, STRIP_LEFT_MARGIN,
                 STRIP_RIGHT_MARGIN, STRIP_WIDTH, BUTTON_WIDTH, TOUCH_OFFSET, CACHED_TAB_WIDTH,
@@ -87,6 +89,7 @@
     }
 
     @Test
+    @DisabledTest(message = "https://crbug.com/1385702")
     public void testComputeNewTabButtonOffset_withTabStripImprovements() {
         setTabStripImprovementFeature(true);
         float result = mTarget.computeNewTabButtonOffset(mInput, TAB_OVERLAP, STRIP_LEFT_MARGIN,
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 1816da2..ab2c080 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4166,8 +4166,6 @@
       "resource_coordinator/tab_manager.h",
       "resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc",
       "resource_coordinator/tab_manager_resource_coordinator_signal_observer.h",
-      "resource_coordinator/tab_manager_stats_collector.cc",
-      "resource_coordinator/tab_manager_stats_collector.h",
       "resource_coordinator/tab_manager_web_contents_data.cc",
       "resource_coordinator/tab_manager_web_contents_data.h",
       "resource_coordinator/tab_metrics_logger.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c6513ed..c3a23dd 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1273,69 +1273,6 @@
      kJourneysLabelsWithEntitiesNoHostnamesParams,
      std::size(kJourneysLabelsWithEntitiesNoHostnamesParams), nullptr},
 };
-const FeatureEntry::FeatureParam kJourneysShowSingleDomainClustersParams[] = {
-    {"hide_single_domain_clusters_on_prominent_ui_surfaces", "false"},
-};
-const FeatureEntry::FeatureParam kJourneysHideSingleDomainClustersParams[] = {
-    {"hide_single_domain_clusters_on_prominent_ui_surfaces", "true"},
-};
-const FeatureEntry::FeatureVariation kJourneysOnDeviceClusteringVariations[] = {
-    {"Show Single Domain Journeys", kJourneysShowSingleDomainClustersParams,
-     std::size(kJourneysShowSingleDomainClustersParams), nullptr},
-    {"Hide Single Domain Journeys", kJourneysHideSingleDomainClustersParams,
-     std::size(kJourneysHideSingleDomainClustersParams), nullptr},
-};
-const FeatureEntry::FeatureParam
-    kJourneysOnDeviceClusteringKeywordFilteringAllVariationsParams[] = {
-        {"keyword_filter_on_categories", "false"},
-        {"keyword_filter_on_noisy_visits", "false"},
-        {"keyword_filter_on_visit_hosts", "false"},
-        {"keyword_filter_on_search_terms", "true"},
-};
-const FeatureEntry::FeatureParam
-    kJourneysOnDeviceClusteringKeywordFilteringNoCategoriesParams[] = {
-        {"keyword_filter_on_categories", "false"},
-};
-const FeatureEntry::FeatureParam
-    kJourneysOnDeviceClusteringKeywordFilteringNoNoisyVisitsParams[] = {
-        {"keyword_filter_on_noisy_visits", "false"},
-};
-const FeatureEntry::FeatureParam
-    kJourneysOnDeviceClusteringKeywordFilteringNoVisitHostsParams[] = {
-        {"keyword_filter_on_visit_hosts", "false"},
-};
-const FeatureEntry::FeatureParam
-    kJourneysOnDeviceClusteringKeywordFilteringWithSearchTermsParams[] = {
-        {"keyword_filter_on_search_terms", "true"},
-};
-const FeatureEntry::FeatureVariation
-    kJourneysOnDeviceClusteringKeywordFilteringVariations[] = {
-        {"All Variations",
-         kJourneysOnDeviceClusteringKeywordFilteringAllVariationsParams,
-         std::size(
-             kJourneysOnDeviceClusteringKeywordFilteringAllVariationsParams),
-         nullptr},
-        {"No Categories",
-         kJourneysOnDeviceClusteringKeywordFilteringNoCategoriesParams,
-         std::size(
-             kJourneysOnDeviceClusteringKeywordFilteringNoCategoriesParams),
-         nullptr},
-        {"No Noisy Visits",
-         kJourneysOnDeviceClusteringKeywordFilteringNoNoisyVisitsParams,
-         std::size(
-             kJourneysOnDeviceClusteringKeywordFilteringNoNoisyVisitsParams),
-         nullptr},
-        {"No Visit Hosts",
-         kJourneysOnDeviceClusteringKeywordFilteringNoVisitHostsParams,
-         std::size(
-             kJourneysOnDeviceClusteringKeywordFilteringNoVisitHostsParams),
-         nullptr},
-        {"With Search Terms",
-         kJourneysOnDeviceClusteringKeywordFilteringWithSearchTermsParams,
-         std::size(
-             kJourneysOnDeviceClusteringKeywordFilteringWithSearchTermsParams),
-         nullptr},
-};
 const FeatureEntry::FeatureParam kJourneysVisitDedupingUseHostParams[] = {
     {"use_host_for_visit_deduping", "true"},
 };
@@ -5840,24 +5777,6 @@
          kJourneysOmniboxHistoryClusterProviderVariations,
          "JourneysOmniboxTriggering")},
 
-    {"history-journeys-on-device-clustering",
-     flag_descriptions::kJourneysOnDeviceClusteringBackendName,
-     flag_descriptions::kJourneysOnDeviceClusteringBackendDescription,
-     kOsDesktop | kOsAndroid,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         history_clusters::features::kOnDeviceClustering,
-         kJourneysOnDeviceClusteringVariations,
-         "HistoryJourneysOnDeviceClusteringBackend")},
-
-    {"history-journeys-on-device-clustering-keyword-filtering",
-     flag_descriptions::kJourneysOnDeviceClusteringKeywordFilteringName,
-     flag_descriptions::kJourneysOnDeviceClusteringKeywordFilteringDescription,
-     kOsDesktop | kOsAndroid,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         history_clusters::features::kOnDeviceClusteringKeywordFiltering,
-         kJourneysOnDeviceClusteringKeywordFilteringVariations,
-         "HistoryJourneysKeywordFiltering")},
-
     {"history-journeys-show-all-clusters",
      flag_descriptions::kJourneysShowAllClustersName,
      flag_descriptions::kJourneysShowAllClustersDescription,
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash_browsertest.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash_browsertest.cc
index fb1ef119..a5a524bc 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash_browsertest.cc
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash_browsertest.cc
@@ -20,10 +20,9 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
@@ -126,19 +125,17 @@
 
     base::RunLoop run_loop;
     auto* provider = web_app::WebAppProvider::GetForTest(browser()->profile());
-    provider->command_manager().ScheduleCommand(
-        std::make_unique<web_app::InstallFromInfoCommand>(
-            std::move(install_info), &provider->install_finalizer(),
-            /*overwrite_existing_manifest_fields=*/false,
-            webapps::WebappInstallSource::KIOSK,
-            base::BindLambdaForTesting(
-                [&app_id, &run_loop](const web_app::AppId& installed_app_id,
-                                     webapps::InstallResultCode code) {
-                  EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall,
-                            code);
-                  app_id = installed_app_id;
-                  run_loop.Quit();
-                })));
+    provider->scheduler().InstallFromInfo(
+        std::move(install_info),
+        /*overwrite_existing_manifest_fields=*/false,
+        webapps::WebappInstallSource::KIOSK,
+        base::BindLambdaForTesting(
+            [&app_id, &run_loop](const web_app::AppId& installed_app_id,
+                                 webapps::InstallResultCode code) {
+              EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, code);
+              app_id = installed_app_id;
+              run_loop.Quit();
+            }));
     run_loop.Run();
   }
 
diff --git a/chrome/browser/ash/apps/apk_web_app_installer.cc b/chrome/browser/ash/apps/apk_web_app_installer.cc
index c0ce0140..23a6f87 100644
--- a/chrome/browser/ash/apps/apk_web_app_installer.cc
+++ b/chrome/browser/ash/apps/apk_web_app_installer.cc
@@ -13,10 +13,9 @@
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ash/crosapi/web_app_service_ash.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/externally_installed_web_app_prefs.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
@@ -211,13 +210,12 @@
     // Doesn't overwrite already existing web app with manifest fields from the
     // apk.
     GURL start_url = web_app_install_info_->start_url;
-    provider->command_manager().ScheduleCommand(
-        std::make_unique<web_app::InstallFromInfoCommand>(
-            std::move(web_app_install_info_), &provider->install_finalizer(),
-            /*overwrite_existing_manifest_fields=*/false,
-            webapps::WebappInstallSource::ARC,
-            base::BindOnce(&ApkWebAppInstaller::OnWebAppCreated,
-                           base::Unretained(this), std::move(start_url))));
+    provider->scheduler().InstallFromInfo(
+        std::move(web_app_install_info_),
+        /*overwrite_existing_manifest_fields=*/false,
+        webapps::WebappInstallSource::ARC,
+        base::BindOnce(&ApkWebAppInstaller::OnWebAppCreated,
+                       base::Unretained(this), std::move(start_url)));
   }
 }
 
diff --git a/chrome/browser/ash/login/hwid_checker.cc b/chrome/browser/ash/login/hwid_checker.cc
index 70b778b..2e928c2 100644
--- a/chrome/browser/ash/login/hwid_checker.cc
+++ b/chrome/browser/ash/login/hwid_checker.cc
@@ -172,13 +172,12 @@
   if (stats->IsRunningOnVm())
     return true;
 
-  const absl::optional<base::StringPiece> hwid =
-      stats->GetMachineStatistic(chromeos::system::kHardwareClassKey);
-  if (!hwid) {
+  std::string hwid;
+  if (!stats->GetMachineStatistic(chromeos::system::kHardwareClassKey, &hwid)) {
     LOG(ERROR) << "Couldn't get machine statistic 'hardware_class'.";
     return false;
   }
-  if (!IsHWIDCorrect(std::string(hwid.value()))) {
+  if (!IsHWIDCorrect(hwid)) {
     LOG(ERROR) << "Machine has malformed HWID '" << hwid << "'. ";
     return false;
   }
diff --git a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
index 7531495..650b383 100644
--- a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
@@ -546,6 +546,10 @@
   NOTREACHED();
 }
 
+absl::optional<std::string> FakeChromeUserManager::GetOwnerEmail() {
+  return GetLocalState() ? UserManagerBase::GetOwnerEmail() : absl::nullopt;
+}
+
 void FakeChromeUserManager::UpdateUserAccountData(
     const AccountId& account_id,
     const UserAccountData& account_data) {
diff --git a/chrome/browser/ash/login/users/fake_chrome_user_manager.h b/chrome/browser/ash/login/users/fake_chrome_user_manager.h
index ffb2d9f1..974c44d 100644
--- a/chrome/browser/ash/login/users/fake_chrome_user_manager.h
+++ b/chrome/browser/ash/login/users/fake_chrome_user_manager.h
@@ -110,6 +110,7 @@
   void SaveUserDisplayEmail(const AccountId& account_id,
                             const std::string& display_email) override;
   void SaveUserType(const user_manager::User* user) override;
+  absl::optional<std::string> GetOwnerEmail() override;
   void UpdateUserAccountData(const AccountId& account_id,
                              const UserAccountData& account_data) override;
   bool IsCurrentUserOwner() const override;
diff --git a/chrome/browser/ash/login/version_info_updater.cc b/chrome/browser/ash/login/version_info_updater.cc
index 550da568..58aaeff0 100644
--- a/chrome/browser/ash/login/version_info_updater.cc
+++ b/chrome/browser/ash/login/version_info_updater.cc
@@ -161,27 +161,27 @@
   std::string device_ids_text;
 
   // Get the attested device ID and add the ZTE indication and the ID if needed.
-  const absl::optional<base::StringPiece> attested_device_id =
-      system::StatisticsProvider::GetInstance()->GetMachineStatistic(
-          chromeos::system::kAttestedDeviceIdKey);
+  std::string attested_device_id;
+  system::StatisticsProvider::GetInstance()->GetMachineStatistic(
+      chromeos::system::kAttestedDeviceIdKey, &attested_device_id);
   // Start with the ZTE indication and the attested device ID if it exists.
-  if (attested_device_id && !attested_device_id->empty()) {
+  if (!attested_device_id.empty()) {
     device_ids_text.append(kZteReady);
     // Always append the attested device ID.
     device_ids_text.append(" ");
     device_ids_text.append(kAttestedDeviceIdPrefix);
-    device_ids_text.append(std::string(attested_device_id.value()));
+    device_ids_text.append(attested_device_id);
   }
 
   // Get the serial number and add it.
-  const absl::optional<base::StringPiece> serial_number =
-      system::StatisticsProvider::GetInstance()->GetMachineID();
-  if (serial_number && !serial_number->empty()) {
+  std::string serial_number =
+      system::StatisticsProvider::GetInstance()->GetEnterpriseMachineID();
+  if (!serial_number.empty()) {
     if (!device_ids_text.empty())
       device_ids_text.append(" ");
     // Append the serial number.
     device_ids_text.append(kSerialNumberPrefix);
-    device_ids_text.append(std::string(serial_number.value()));
+    device_ids_text.append(serial_number);
   }
 
   return device_ids_text;
diff --git a/chrome/browser/ash/system/device_disabling_manager.cc b/chrome/browser/ash/system/device_disabling_manager.cc
index 5eccd0c..30fd5f13 100644
--- a/chrome/browser/ash/system/device_disabling_manager.cc
+++ b/chrome/browser/ash/system/device_disabling_manager.cc
@@ -134,8 +134,10 @@
       maybe_enrollment_domain ? *maybe_enrollment_domain : std::string();
 
   // Update the serial number.
-  serial_number_ = chromeos::system::StatisticsProvider::GetInstance()
-                       ->GetEnterpriseMachineID();
+  serial_number_ =
+      std::string(chromeos::system::StatisticsProvider::GetInstance()
+                      ->GetMachineID()
+                      .value_or(""));
 
   // Update the disabled message.
   const std::string* maybe_disabled_message =
@@ -238,8 +240,10 @@
       browser_policy_connector_->GetEnterpriseEnrollmentDomain();
 
   // Cache the device serial number.
-  serial_number_ = chromeos::system::StatisticsProvider::GetInstance()
-                       ->GetEnterpriseMachineID();
+  serial_number_ =
+      std::string(chromeos::system::StatisticsProvider::GetInstance()
+                      ->GetMachineID()
+                      .value_or(""));
 
   // If no session or login is in progress, show the device disabled screen.
   delegate_->ShowDeviceDisabledScreen();
diff --git a/chrome/browser/ash/system/input_device_settings.cc b/chrome/browser/ash/system/input_device_settings.cc
index 399d53d..09e05ca 100644
--- a/chrome/browser/ash/system/input_device_settings.cc
+++ b/chrome/browser/ash/system/input_device_settings.cc
@@ -471,13 +471,10 @@
     return true;
   }
 
-  bool keyboard_driven = false;
-  if (chromeos::system::StatisticsProvider::GetInstance()->GetMachineFlag(
-          chromeos::system::kOemKeyboardDrivenOobeKey, &keyboard_driven)) {
-    return keyboard_driven;
-  }
-
-  return false;
+  return chromeos::system::StatisticsProvider::FlagValueToBool(
+      chromeos::system::StatisticsProvider::GetInstance()->GetMachineFlag(
+          chromeos::system::kOemKeyboardDrivenOobeKey),
+      /*default_value=*/false);
 }
 
 }  // namespace system
diff --git a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/ShoppingFeatures.java b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/ShoppingFeatures.java
index 4643199..427f7b6 100644
--- a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/ShoppingFeatures.java
+++ b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/ShoppingFeatures.java
@@ -4,8 +4,8 @@
 
 package org.chromium.chrome.browser.commerce;
 
-import org.chromium.base.FeatureList;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
@@ -16,10 +16,11 @@
 
 /** Self-documenting feature class for shopping.  */
 public class ShoppingFeatures {
+    private static final MutableFlagWithSafeDefault sShoppingListFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.SHOPPING_LIST, false);
     /** Returns whether shopping is enabled. */
     public static boolean isShoppingListEnabled() {
-        return FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.SHOPPING_LIST) && isSignedIn()
+        return sShoppingListFlag.isEnabled() && isSignedIn()
                 && isAnonymizedUrlDataCollectionEnabled() && isWebAndAppActivityEnabled();
     }
 
diff --git a/chrome/browser/creator/android/BUILD.gn b/chrome/browser/creator/android/BUILD.gn
index 3c61898..965b5b33 100644
--- a/chrome/browser/creator/android/BUILD.gn
+++ b/chrome/browser/creator/android/BUILD.gn
@@ -44,6 +44,8 @@
 
 android_resources("creator_java_resources") {
   sources = [
+    "java/res/drawable/follow_add.xml",
+    "java/res/drawable/following_checkmark.xml",
     "java/res/drawable/profile_background.xml",
     "java/res/layout/creator_activity.xml",
     "java/res/layout/creator_profile.xml",
diff --git a/chrome/browser/creator/android/java/res/drawable/follow_add.xml b/chrome/browser/creator/android/java/res/drawable/follow_add.xml
new file mode 100644
index 0000000..fc479af
--- /dev/null
+++ b/chrome/browser/creator/android/java/res/drawable/follow_add.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/globalFilledButtonTextColor">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M11.25,18.75V12.75H5.25V11.25H11.25V5.25H12.75V11.25H18.75V12.75H12.75V18.75Z"/>
+</vector>
\ No newline at end of file
diff --git a/chrome/browser/creator/android/java/res/drawable/following_checkmark.xml b/chrome/browser/creator/android/java/res/drawable/following_checkmark.xml
new file mode 100644
index 0000000..77f33ef
--- /dev/null
+++ b/chrome/browser/creator/android/java/res/drawable/following_checkmark.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="@macro/default_text_color_secondary">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M9.55,17.65 L4.225,12.325 5.275,11.25 9.55,15.525 18.725,6.35 19.775,7.425Z"/>
+</vector>
diff --git a/chrome/browser/creator/android/java/res/layout/creator_profile.xml b/chrome/browser/creator/android/java/res/layout/creator_profile.xml
index bb4c63e..5696f04 100644
--- a/chrome/browser/creator/android/java/res/layout/creator_profile.xml
+++ b/chrome/browser/creator/android/java/res/layout/creator_profile.xml
@@ -27,22 +27,24 @@
         android:layout_height="wrap_content"
         android:textAppearance="@style/TextAppearance.TextSmall.Primary" />
   </LinearLayout>
-  <org.chromium.ui.widget.ButtonCompat
-      android:id="@+id/creator_follow_button"
+  <FrameLayout
       android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="16dp"
-      android:paddingHorizontal="60dp"
-      style="@style/FilledButton"
-      android:text="@string/menu_follow"
-      android:visibility="gone" />
-  <org.chromium.ui.widget.ButtonCompat
-      android:id="@+id/creator_following_button"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="16dp"
-      android:paddingHorizontal="60dp"
-      style="@style/FilledButton"
-      android:text="@string/menu_following"
-      android:visibility="gone" />
+      android:layout_height="wrap_content" >
+    <org.chromium.ui.widget.ButtonCompat
+        android:id="@+id/creator_follow_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        style="@style/CreatorFollowFilledButton"
+        android:text="@string/menu_follow"
+        android:drawableStart="@drawable/follow_add"
+        android:visibility="gone" />
+    <org.chromium.ui.widget.ButtonCompat
+        android:id="@+id/creator_following_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        style="@style/CreatorFollowReverseButton"
+        android:text="@string/menu_following"
+        android:drawableStart="@drawable/following_checkmark"
+        android:visibility="gone" />
+  </FrameLayout>
 </org.chromium.chrome.browser.creator.CreatorProfileView>
\ No newline at end of file
diff --git a/chrome/browser/creator/android/java/res/values/styles.xml b/chrome/browser/creator/android/java/res/values/styles.xml
index 54d1f3b..8287a157 100644
--- a/chrome/browser/creator/android/java/res/values/styles.xml
+++ b/chrome/browser/creator/android/java/res/values/styles.xml
@@ -9,4 +9,27 @@
     <style name="CreatorActivityNoActionBar">
         <item name="windowActionBar">false</item>
     </style>
+
+    <style name="CreatorFollowFilledButton" parent="ButtonCompatBase">
+        <item name="android:paddingStart">12dp</item>
+        <item name="android:paddingEnd">24dp</item>
+        <item name="android:drawablePadding">15dp</item>
+        <item name="android:layout_marginEnd">16dp</item>
+        <item name="android:textAppearance">@style/TextAppearance.Button.Text.Filled</item>
+        <item name="buttonTextColor">?attr/globalFilledButtonTextColor</item>
+        <item name="buttonColor">?attr/globalFilledButtonBgColor</item>
+        <item name="rippleColor">@color/filled_button_ripple_color</item>
+        <item name="buttonRaised">true</item>
+    </style>
+    <style name="CreatorFollowReverseButton" parent="ButtonCompatBase">
+        <item name="android:paddingStart">12dp</item>
+        <item name="android:paddingEnd">20dp</item>
+        <item name="android:drawablePadding">5dp</item>
+        <item name="android:layout_marginEnd">16dp</item>
+        <item name="android:textAppearance">@style/TextAppearance.Button.Text.Blue</item>
+        <item name="buttonTextColor">@macro/default_text_color_secondary</item>
+        <item name="buttonColor">@android:color/white</item>
+        <item name="rippleColor">@color/text_button_ripple_color</item>
+        <item name="buttonRaised">true</item>
+    </style>
 </resources>
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog.cc
index ed45adc..4e71533d 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog.cc
@@ -257,7 +257,7 @@
   top_level_contents_->ClearFocusedElement();
   top_level_contents_->SetIgnoreInputEvents(true);
 
-  if (ShowDialogDelay().is_zero()) {
+  if (ShowDialogDelay().is_zero() || !is_pending()) {
     ShowDialogNow();
   } else {
     content::GetUIThreadTaskRunner({})->PostDelayedTask(
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
index 2d1d4c2..564fc1b 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -32,9 +32,7 @@
 #include "chrome/browser/ui/tab_helpers.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
@@ -287,13 +285,12 @@
     auto* provider = web_app::WebAppProvider::GetForWebApps(
         Profile::FromBrowserContext(context));
 
-    provider->command_manager().ScheduleCommand(
-        std::make_unique<web_app::InstallFromInfoCommand>(
-            std::move(web_app_info), &provider->install_finalizer(),
-            /*overwrite_existing_manifest_fields=*/false,
-            webapps::WebappInstallSource::MANAGEMENT_API,
-            base::BindOnce(OnGenerateAppForLinkCompleted,
-                           base::RetainedRef(function))));
+    provider->scheduler().InstallFromInfo(
+        std::move(web_app_info),
+        /*overwrite_existing_manifest_fields=*/false,
+        webapps::WebappInstallSource::MANAGEMENT_API,
+        base::BindOnce(OnGenerateAppForLinkCompleted,
+                       base::RetainedRef(function)));
   }
 
   extensions::api::management::ExtensionInfo CreateExtensionInfoFromWebApp(
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index cc28ba2..8c27cc3 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -217,11 +217,12 @@
   DCHECK(stats);
 
   // Get the HWID.
-  std::string hwid;
-  if (!stats->GetMachineStatistic(chromeos::system::kHardwareClassKey, &hwid))
+  if (const absl::optional<base::StringPiece> hwid =
+          stats->GetMachineStatistic(chromeos::system::kHardwareClassKey)) {
+    response->emplace(kHWIDKey, std::string(hwid.value()));
+  } else {
     VLOG(1) << "Couldn't get machine statistic 'hardware_class'.";
-  else
-    response->emplace(kHWIDKey, hwid);
+  }
 
   // Get the firmware version.
   response->emplace(kChromeOsFirmwareVersion,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 5a084b1..5477247 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -813,7 +813,7 @@
   {
     "name": "canvas-oop-rasterization",
     "owners": [ "junov", "vasilyt" ],
-    "expiry_milestone": 110
+    "expiry_milestone": 120
   },
   {
     "name": "captive-portal-ui-2022",
@@ -1128,6 +1128,11 @@
     "expiry_milestone": 107
   },
   {
+    "name": "credential-provider-extension-promo",
+    "owners": [ "huitingyu", "hiramahmood", "bling-flags@google.com" ],
+    "expiry_milestone": 114
+  },
+  {
     "name": "cros-labs-float-window",
     "owners": [ "shidi", "afakhry" ],
     "expiry_milestone": 110
@@ -2243,7 +2248,12 @@
   {
     "name": "enable-expkit-calendar-text-classifier",
     "owners": [ "chrome-intelligence-core@google.com" ],
-    "expiry_milestone": 111
+    "expiry_milestone": 116
+  },
+  {
+    "name": "enable-expkit-text-classifier",
+    "owners": [ "chrome-intelligence-core@google.com" ],
+    "expiry_milestone": 116
   },
   {
     "name": "enable-external-keyboards-in-diagnostics-app",
@@ -4006,7 +4016,7 @@
   {
     "name": "history-journeys-content-clustering",
     "owners": [ "sophiechang", "chrome-journeys@google.com" ],
-    "expiry_milestone": 110
+    "expiry_milestone": 115
   },
   {
     "name": "history-journeys-images",
@@ -4029,24 +4039,14 @@
     "expiry_milestone": 115
   },
   {
-    "name": "history-journeys-on-device-clustering",
-    "owners": [ "sophiechang", "chrome-journeys@google.com", "chrome-intelligence-core@google.com" ],
-    "expiry_milestone": 110
-  },
-  {
-    "name": "history-journeys-on-device-clustering-keyword-filtering",
-    "owners": [ "sophiechang", "chrome-journeys@google.com", "chrome-intelligence-core@google.com" ],
-    "expiry_milestone": 110
-  },
-  {
     "name": "history-journeys-show-all-clusters",
     "owners": [ "sophiechang", "chrome-journeys@google.com", "chrome-intelligence-core@google.com" ],
-    "expiry_milestone": 110
+    "expiry_milestone": 115
   },
   {
     "name": "history-journeys-visit-deduping",
     "owners": [ "sophiechang", "chrome-journeys@google.com", "chrome-intelligence-core@google.com" ],
-    "expiry_milestone": 110
+    "expiry_milestone": 115
   },
   {
     "name": "hotspot",
@@ -4421,10 +4421,7 @@
   },
   {
     "name": "layout-extraction",
-    "owners": [
-      "rhalavati",
-      "//ui/accessibility/OWNERS"
-    ],
+    "owners": [ "rhalavati", "//ui/accessibility/OWNERS" ],
     "expiry_milestone": 120
   },
   {
@@ -4736,21 +4733,11 @@
     "expiry_milestone": 111
   },
   {
-    "name": "new-overflow-menu-settings-action",
-    "owners": [ "rkgibson@google.com", "bling-flags@google.com" ],
-    "expiry_milestone": 109
-  },
-  {
     "name": "new-overflow-menu-share-chrome-action",
     "owners": [ "scottyoder@google.com", "bling-flags@google.com" ],
     "expiry_milestone": 112
   },
   {
-    "name": "new-overflow-menu-simple-destination-icons",
-    "owners": [ "rkgibson@google.com", "bling-flags@google.com" ],
-    "expiry_milestone": 109
-  },
-  {
     "name": "new-shortcut-mapping",
     "owners": [ "zentaro@google.com", "jimmyxgong@google.com", "cros-peripherals@google.com"],
     "expiry_milestone": 118
@@ -5511,8 +5498,8 @@
   },
   {
     "name": "pdf-ocr",
-    "owners": [ "//ui/accessibility/OWNERS" ],
-    "expiry_milestone": 110
+    "owners": [ "rhalavati", "//ui/accessibility/OWNERS" ],
+    "expiry_milestone": 120
   },
   {
     "name": "pdf-use-skia-renderer",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index b1b1509..1403549 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1756,17 +1756,6 @@
     "Enables the History Journeys Omnibox History Cluster Provider to surface "
     "Journeys as a suggestion row instead of an action chip.";
 
-const char kJourneysOnDeviceClusteringBackendName[] =
-    "History Journeys On-Device Clustering Backend";
-const char kJourneysOnDeviceClusteringBackendDescription[] =
-    "Enables variations for the on-device clustering backend";
-
-const char kJourneysOnDeviceClusteringKeywordFilteringName[] =
-    "History Journeys On-Device Clustering Keyword Filtering";
-const char kJourneysOnDeviceClusteringKeywordFilteringDescription[] =
-    "Enables variations for the keywords output by the on-device clustering "
-    "for Journeys";
-
 const char kJourneysShowAllClustersName[] =
     "History Journeys Show All Clusters";
 const char kJourneysShowAllClustersDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 886d838f..06daf85 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -993,12 +993,6 @@
 extern const char kJourneysOmniboxHistoryClusterProviderName[];
 extern const char kJourneysOmniboxHistoryClusterProviderDescription[];
 
-extern const char kJourneysOnDeviceClusteringBackendName[];
-extern const char kJourneysOnDeviceClusteringBackendDescription[];
-
-extern const char kJourneysOnDeviceClusteringKeywordFilteringName[];
-extern const char kJourneysOnDeviceClusteringKeywordFilteringDescription[];
-
 extern const char kJourneysShowAllClustersName[];
 extern const char kJourneysShowAllClustersDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index d4ca6471..8751fa5 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -168,6 +168,7 @@
     &history_clusters::internal::kJourneys,
     &kAdaptiveButtonInTopToolbar,
     &kAdaptiveButtonInTopToolbarCustomizationV2,
+    &kAddEduAccountFromAccountSettingsForSupervisedUsers,
     &kAddToHomescreenIPH,
     &kAllowNewIncognitoTabIntents,
     &kAndroidScrollOptimizations,
@@ -460,6 +461,10 @@
              "AdaptiveButtonInTopToolbarCustomizationV2",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+BASE_FEATURE(kAddEduAccountFromAccountSettingsForSupervisedUsers,
+             "AddEduAccountFromAccountSettingsForSupervisedUsers",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kAddToHomescreenIPH,
              "AddToHomescreenIPH",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 6c71a08..0d13451 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -15,6 +15,7 @@
 // Alphabetical:
 BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbar);
 BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarCustomizationV2);
+BASE_DECLARE_FEATURE(kAddEduAccountFromAccountSettingsForSupervisedUsers);
 BASE_DECLARE_FEATURE(kAddToHomescreenIPH);
 BASE_DECLARE_FEATURE(kAllowNewIncognitoTabIntents);
 BASE_DECLARE_FEATURE(kAndroidScrollOptimizations);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 5ccf2a1a..c4c6509 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -166,6 +166,8 @@
     public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR = "AdaptiveButtonInTopToolbar";
     public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2 =
             "AdaptiveButtonInTopToolbarCustomizationV2";
+    public static final String ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS =
+            "AddEduAccountFromAccountSettingsForSupervisedUsers";
     public static final String ADD_TO_HOMESCREEN_IPH = "AddToHomescreenIPH";
     public static final String ALLOW_NEW_INCOGNITO_TAB_INTENTS = "AllowNewIncognitoTabIntents";
     public static final String ALLOW_SYNC_OFF_FOR_CHILD_ACCOUNTS = "AllowSyncOffForChildAccounts";
diff --git a/chrome/browser/lacros/standalone_browser_test_controller.cc b/chrome/browser/lacros/standalone_browser_test_controller.cc
index 7851c7f..7f391dd0 100644
--- a/chrome/browser/lacros/standalone_browser_test_controller.cc
+++ b/chrome/browser/lacros/standalone_browser_test_controller.cc
@@ -12,9 +12,8 @@
 #include "chrome/browser/extensions/extension_keeplist_chromeos.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/speech/tts_crosapi_util.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chromeos/crosapi/mojom/tts.mojom-forward.h"
@@ -118,14 +117,12 @@
   info->user_display_mode = WindowModeToUserDisplayMode(window_mode);
   Profile* profile = ProfileManager::GetPrimaryUserProfile();
   auto* provider = web_app::WebAppProvider::GetForWebApps(profile);
-  provider->command_manager().ScheduleCommand(
-      std::make_unique<web_app::InstallFromInfoCommand>(
-          std::move(info), &provider->install_finalizer(),
-          /*overwrite_existing_manifest_fields=*/false,
-          webapps::WebappInstallSource::SYNC,
-          base::BindOnce(
-              &StandaloneBrowserTestController::WebAppInstallationDone,
-              weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
+  provider->scheduler().InstallFromInfo(
+      std::move(info),
+      /*overwrite_existing_manifest_fields=*/false,
+      webapps::WebappInstallSource::SYNC,
+      base::BindOnce(&StandaloneBrowserTestController::WebAppInstallationDone,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void StandaloneBrowserTestController::LoadVpnExtension(
diff --git a/chrome/browser/lacros/web_app_provider_bridge_lacros.cc b/chrome/browser/lacros/web_app_provider_bridge_lacros.cc
index 84890a5..406e043 100644
--- a/chrome/browser/lacros/web_app_provider_bridge_lacros.cc
+++ b/chrome/browser/lacros/web_app_provider_bridge_lacros.cc
@@ -8,9 +8,8 @@
 #include "chrome/browser/apps/app_service/webapk/webapk_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_id.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
@@ -82,11 +81,10 @@
   const SkBitmap& bitmap = *arc_install_info->icon.bitmap();
   install_info->icon_bitmaps.any[bitmap.width()] = bitmap;
 
-  provider->command_manager().ScheduleCommand(
-      std::make_unique<web_app::InstallFromInfoCommand>(
-          std::move(install_info), &provider->install_finalizer(),
-          /*overwrite_existing_manifest_fields=*/false,
-          webapps::WebappInstallSource::ARC, std::move(callback)));
+  provider->scheduler().InstallFromInfo(
+      std::move(install_info),
+      /*overwrite_existing_manifest_fields=*/false,
+      webapps::WebappInstallSource::ARC, std::move(callback));
 }
 
 // static
diff --git a/chrome/browser/payments/android_payment_app_factory_browsertest.cc b/chrome/browser/payments/android_payment_app_factory_browsertest.cc
index 0e8205a..ff2d55f3 100644
--- a/chrome/browser/payments/android_payment_app_factory_browsertest.cc
+++ b/chrome/browser/payments/android_payment_app_factory_browsertest.cc
@@ -114,8 +114,8 @@
   std::string expected_response = response;
 #else
   std::string expected_response =
-      "The payment method \"https://play.google.com/billing\" is not "
-      "supported.";
+      "NotSupportedError: The payment method "
+      "\"https://play.google.com/billing\" is not supported.";
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   NavigateTo("b.com", "/payment_handler_status.html");
@@ -139,8 +139,8 @@
   std::string expected_response = response;
 #else
   std::string expected_response =
-      "The payment method \"https://play.google.com/billing\" is not "
-      "supported.";
+      "NotSupportedError: The payment method "
+      "\"https://play.google.com/billing\" is not supported.";
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   NavigateTo("b.com", "/payment_handler_status.html");
@@ -166,8 +166,8 @@
   std::string expected_response = response;
 #else
   std::string expected_response =
-      "The payment method \"https://play.google.com/billing\" is not "
-      "supported.";
+      "NotSupportedError: The payment method "
+      "\"https://play.google.com/billing\" is not supported.";
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   NavigateTo("b.com", "/payment_handler_status.html");
diff --git a/chrome/browser/payments/ignore_payment_method_browsertest.cc b/chrome/browser/payments/ignore_payment_method_browsertest.cc
index 85667e0..3bf63dd 100644
--- a/chrome/browser/payments/ignore_payment_method_browsertest.cc
+++ b/chrome/browser/payments/ignore_payment_method_browsertest.cc
@@ -73,9 +73,9 @@
 
   GetFinder()->IgnorePaymentMethodForTest(method_name_);
 
-  VerifyFunctionOutput(
-      "The payment method \"" + method_name_ + "\" is not supported.",
-      "getStatus($1)");
+  VerifyFunctionOutput("NotSupportedError: The payment method \"" +
+                           method_name_ + "\" is not supported.",
+                       "getStatus($1)");
 }
 
 IN_PROC_BROWSER_TEST_F(IgnorePaymentMethodTest,
@@ -111,9 +111,9 @@
 
   GetFinder()->IgnorePaymentMethodForTest(method_name_);
 
-  VerifyFunctionOutput(
-      "The payment method \"" + method_name_ + "\" is not supported.",
-      "getStatus($1)");
+  VerifyFunctionOutput("NotSupportedError: The payment method \"" +
+                           method_name_ + "\" is not supported.",
+                       "getStatus($1)");
 }
 
 }  // namespace
diff --git a/chrome/browser/payments/payment_handler_install_failed_browsertest.cc b/chrome/browser/payments/payment_handler_install_failed_browsertest.cc
index 482ea17d..77573f8 100644
--- a/chrome/browser/payments/payment_handler_install_failed_browsertest.cc
+++ b/chrome/browser/payments/payment_handler_install_failed_browsertest.cc
@@ -50,7 +50,7 @@
       "PaymentRequest.PaymentHandlerInstallSuccess", 0);
 
   NavigateTo("b.com", "/payment_handler_status.html");
-  EXPECT_EQ("Failed to install the payment handler.",
+  EXPECT_EQ("AbortError: Failed to install the payment handler.",
             content::EvalJs(GetActiveWebContents(),
                             content::JsReplace("getStatus($1)", method_name)));
 
diff --git a/chrome/browser/payments/payment_request_factory.cc b/chrome/browser/payments/payment_request_factory.cc
index 5d77abe..3e8be0da 100644
--- a/chrome/browser/payments/payment_request_factory.cc
+++ b/chrome/browser/payments/payment_request_factory.cc
@@ -10,9 +10,7 @@
 #include "base/no_destructor.h"
 #include "chrome/browser/payments/chrome_payment_request_delegate.h"
 #include "components/payments/content/payment_request.h"
-#include "components/payments/content/payment_request_web_contents_manager.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-shared.h"
 
@@ -54,22 +52,11 @@
                                            render_frame_host);
   }
 
-  auto* web_contents =
-      content::WebContents::FromRenderFrameHost(render_frame_host);
-  CHECK(web_contents);
-  auto* web_contents_manager =
-      PaymentRequestWebContentsManager::GetOrCreateForWebContents(
-          *web_contents);
-
-  auto delegate =
-      std::make_unique<ChromePaymentRequestDelegate>(render_frame_host);
-  auto display_manager = delegate->GetDisplayManager()->GetWeakPtr();
   // PaymentRequest is a DocumentService, whose lifetime is managed by the
   // RenderFrameHost passed in here.
-  new PaymentRequest(*render_frame_host, std::move(delegate),
-                     std::move(display_manager), std::move(receiver),
-                     web_contents_manager->transaction_mode(),
-                     /*observer_for_testing=*/nullptr);
+  auto delegate =
+      std::make_unique<ChromePaymentRequestDelegate>(render_frame_host);
+  new PaymentRequest(std::move(delegate), std::move(receiver));
 }
 
 void SetPaymentRequestFactoryForTesting(
diff --git a/chrome/browser/payments/secure_payment_confirmation_browsertest.cc b/chrome/browser/payments/secure_payment_confirmation_browsertest.cc
index 78dd504..73b19d5 100644
--- a/chrome/browser/payments/secure_payment_confirmation_browsertest.cc
+++ b/chrome/browser/payments/secure_payment_confirmation_browsertest.cc
@@ -67,13 +67,14 @@
 namespace {
 
 std::string GetIconDownloadErrorMessage() {
-  return "The payment method \"secure-payment-confirmation\" is not supported. "
+  return "NotSupportedError: The payment method "
+         "\"secure-payment-confirmation\" is not supported. "
          "The \"instrument.icon\" either could not be downloaded or decoded.";
 }
 
 std::string GetWebAuthnErrorMessage() {
-  return "The operation either timed out or was not allowed. See: "
-         "https://www.w3.org/TR/webauthn-2/"
+  return "NotAllowedError: The operation either timed out or was not allowed. "
+         "See: https://www.w3.org/TR/webauthn-2/"
          "#sctn-privacy-considerations-client.";
 }
 
@@ -282,7 +283,8 @@
 
   // EvalJs waits for JavaScript promise to resolve.
   EXPECT_EQ(
-      "The payment method \"secure-payment-confirmation\" is not supported.",
+      "NotSupportedError: The payment method \"secure-payment-confirmation\" "
+      "is not supported.",
       content::EvalJs(GetActiveWebContents(),
                       "getSecurePaymentConfirmationStatus()"));
 }
@@ -328,7 +330,8 @@
 
   // EvalJs waits for JavaScript promise to resolve.
   EXPECT_EQ(
-      "The payment method \"secure-payment-confirmation\" is not supported.",
+      "NotSupportedError: The payment method \"secure-payment-confirmation\" "
+      "is not supported.",
       content::EvalJs(GetActiveWebContents(),
                       "getSecurePaymentConfirmationStatus()"));
 }
diff --git a/chrome/browser/payments/secure_payment_confirmation_opt_out_browsertest.cc b/chrome/browser/payments/secure_payment_confirmation_opt_out_browsertest.cc
index b7d63550..271b86f 100644
--- a/chrome/browser/payments/secure_payment_confirmation_opt_out_browsertest.cc
+++ b/chrome/browser/payments/secure_payment_confirmation_opt_out_browsertest.cc
@@ -87,7 +87,7 @@
   // the PaymentRequest to be aborted.
   EXPECT_TRUE(test_controller()->ClickOptOut());
   EXPECT_EQ(
-      "User opted out of the process.",
+      "OptOutError: User opted out of the process.",
       content::EvalJs(GetActiveWebContents(), "getOutstandingStatusPromise()"));
 }
 
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 1d15732b..27da3b2 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -373,19 +373,14 @@
 
   ui::AXTreeUpdate GetAccessibilityTreeSnapshotForPdf(
       WebContents* web_contents) {
-    ui::AXTreeUpdate ax_tree = GetAccessibilityTreeSnapshot(web_contents);
+    content::FindAccessibilityNodeCriteria find_criteria;
+    find_criteria.role = ax::mojom::Role::kPdfRoot;
+    ui::AXPlatformNodeDelegate* pdf_root =
+        content::FindAccessibilityNode(web_contents, find_criteria);
+    ui::AXTreeID pdf_tree_id = pdf_root->GetTreeData().tree_id;
+    EXPECT_NE(pdf_tree_id, ui::AXTreeIDUnknown());
 
-    ui::AXTreeID child_tree_id;
-    for (const ui::AXNodeData& node : ax_tree.nodes) {
-      if (node.HasStringAttribute(ax::mojom::StringAttribute::kChildTreeId)) {
-        child_tree_id = ui::AXTreeID::FromString(
-            node.GetStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
-        break;
-      }
-    }
-
-    EXPECT_NE(child_tree_id, ui::AXTreeIDUnknown());
-    return content::GetAccessibilityTreeSnapshotFromId(child_tree_id);
+    return content::GetAccessibilityTreeSnapshotFromId(pdf_tree_id);
   }
 
   // Hooks to set up feature flags.
@@ -2192,13 +2187,14 @@
 IN_PROC_BROWSER_TEST_F(PDFExtensionTest, PdfAccessibility) {
   content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
 
-  WebContents* guest_contents = LoadPdfGetGuestContents(
+  MimeHandlerViewGuest* guest = LoadPdfGetMimeHandlerView(
       embedded_test_server()->GetURL("/pdf/test-bookmarks.pdf"));
-  ASSERT_TRUE(guest_contents);
+  ASSERT_TRUE(guest);
 
-  WaitForAccessibilityTreeToContainNodeWithName(guest_contents,
+  WaitForAccessibilityTreeToContainNodeWithName(GetActiveWebContents(),
                                                 "1 First Section\r\n");
-  ui::AXTreeUpdate ax_tree = GetAccessibilityTreeSnapshotForPdf(guest_contents);
+  ui::AXTreeUpdate ax_tree =
+      GetAccessibilityTreeSnapshotForPdf(GetActiveWebContents());
   std::string ax_tree_dump = DumpPdfAccessibilityTree(ax_tree);
 
   ASSERT_MULTILINE_STREQ(kExpectedPDFAXTree, ax_tree_dump);
diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h
index 74476288..982538f 100644
--- a/chrome/browser/printing/print_job_worker.h
+++ b/chrome/browser/printing/print_job_worker.h
@@ -160,7 +160,6 @@
   virtual void UseDefaultSettings(SettingsCallback callback);
 
   PrintingContext* printing_context() { return printing_context_.get(); }
-  PrintedDocument* document() { return document_.get(); }
   PrintJob* print_job() { return print_job_; }
   const PageNumber& page_number() { return page_number_; }
   base::SequencedTaskRunner* task_runner() { return task_runner_.get(); }
diff --git a/chrome/browser/printing/print_job_worker_oop.cc b/chrome/browser/printing/print_job_worker_oop.cc
index 9d9df36f..10feb4f5 100644
--- a/chrome/browser/printing/print_job_worker_oop.cc
+++ b/chrome/browser/printing/print_job_worker_oop.cc
@@ -83,9 +83,15 @@
     return;
   }
 
+  // Keep another reference to the document just for OOP.  This reference
+  // ensures the document object is retained even if the job cancels out and
+  // the reference to it from `PrintJobWorker` is dropped.  This guarantees
+  // that it can still be used in the various asynchronous callbacks.
+  document_oop_ = new_document;
+
   std::string device_name =
-      base::UTF16ToUTF8(document()->settings().device_name());
-  VLOG(1) << "Start printing document " << document()->cookie() << " to "
+      base::UTF16ToUTF8(document_oop_->settings().device_name());
+  VLOG(1) << "Start printing document " << document_oop_->cookie() << " to "
           << device_name;
 
   // `PrintBackendServiceManager` interactions must happen on the UI thread.
@@ -147,13 +153,13 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (result != mojom::ResultCode::kSuccess) {
     PRINTER_LOG(ERROR) << "Error initiating printing via service for document "
-                       << document()->cookie() << ": " << result;
+                       << document_oop_->cookie() << ": " << result;
     if (result != mojom::ResultCode::kAccessDenied || !TryRestartPrinting())
       NotifyFailure(result);
     return;
   }
   VLOG(1) << "Printing initiated with service for document "
-          << document()->cookie();
+          << document_oop_->cookie();
   task_runner()->PostTask(FROM_HERE,
                           base::BindOnce(&PrintJobWorker::OnNewPage,
                                          worker_weak_factory_.GetWeakPtr()));
@@ -166,21 +172,22 @@
   if (result != mojom::ResultCode::kSuccess) {
     PRINTER_LOG(ERROR)
         << "Error rendering printed page via service for document "
-        << document()->cookie() << ": " << result;
+        << document_oop_->cookie() << ": " << result;
     NotifyFailure(result);
     return;
   }
-  scoped_refptr<PrintedPage> page = document()->GetPage(page_index);
+  scoped_refptr<PrintedPage> page = document_oop_->GetPage(page_index);
   if (!page) {
     PRINTER_LOG(ERROR) << "Unable to get page " << page_index
-                       << " via service for document " << document()->cookie();
+                       << " via service for document "
+                       << document_oop_->cookie();
     task_runner()->PostTask(FROM_HERE,
                             base::BindOnce(&PrintJobWorkerOop::OnFailure,
                                            worker_weak_factory_.GetWeakPtr()));
     return;
   }
   VLOG(1) << "Rendered printed page via service for document "
-          << document()->cookie() << " page " << page_index;
+          << document_oop_->cookie() << " page " << page_index;
 
   // Signal everyone that the page is printed.
   print_job()->PostTask(
@@ -189,7 +196,7 @@
                      base::RetainedRef(page)));
 
   ++pages_printed_count_;
-  if (pages_printed_count_ == document()->page_count()) {
+  if (pages_printed_count_ == document_oop_->page_count()) {
     // The last page has printed, can proceed to document done processing.
     VLOG(1) << "All pages printed for document";
     SendDocumentDone();
@@ -202,12 +209,12 @@
   if (result != mojom::ResultCode::kSuccess) {
     PRINTER_LOG(ERROR)
         << "Error rendering printed document via service for document "
-        << document()->cookie() << ": " << result;
+        << document_oop_->cookie() << ": " << result;
     NotifyFailure(result);
     return;
   }
   VLOG(1) << "Rendered printed document via service for document "
-          << document()->cookie();
+          << document_oop_->cookie();
   SendDocumentDone();
 }
 
@@ -215,20 +222,23 @@
                                           mojom::ResultCode result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 #if BUILDFLAG(IS_WIN)
-  DCHECK_EQ(pages_printed_count_, document()->page_count());
+  DCHECK_EQ(pages_printed_count_, document_oop_->page_count());
 #endif
   if (result != mojom::ResultCode::kSuccess) {
     PRINTER_LOG(ERROR) << "Error completing printing via service for document "
-                       << document()->cookie() << ": " << result;
+                       << document_oop_->cookie() << ": " << result;
     NotifyFailure(result);
     return;
   }
   PRINTER_LOG(EVENT) << "Printing completed via service for document "
-                     << document()->cookie();
+                     << document_oop_->cookie();
   UnregisterServiceManagerClient();
   base::UmaHistogramEnumeration(kPrintOopPrintResultHistogramName,
                                 PrintOopResult::kSuccessful);
   FinishDocumentDone(job_id);
+
+  // Also done with private document reference.
+  document_oop_ = nullptr;
 }
 
 #if BUILDFLAG(IS_WIN)
@@ -237,7 +247,7 @@
   DCHECK_NE(page_number(), PageNumber::npos());
 
 #if !defined(NDEBUG)
-  DCHECK(document()->IsPageInList(*page));
+  DCHECK(document_oop_->IsPageInList(*page));
 #endif
 
   const MetafilePlayer* metafile = page->metafile();
@@ -268,7 +278,7 @@
 bool PrintJobWorkerOop::SpoolDocument() {
   DCHECK(task_runner()->RunsTasksInCurrentSequence());
 
-  const MetafilePlayer* metafile = document()->GetMetafile();
+  const MetafilePlayer* metafile = document_oop_->GetMetafile();
   DCHECK(metafile);
   base::MappedReadOnlyRegion region_mapping =
       metafile->GetDataAsSharedMemoryRegion();
@@ -500,7 +510,7 @@
   // failure.
   document_name_ = document_name;
 
-  const int32_t document_cookie = document()->cookie();
+  const int32_t document_cookie = document_oop_->cookie();
   PRINTER_LOG(DEBUG) << "Starting printing via service for to `" << device_name_
                      << "` for document " << document_cookie;
 
@@ -513,7 +523,7 @@
 
   service_mgr.StartPrinting(
       device_name_, document_cookie, document_name_, print_target_type_,
-      document()->settings(),
+      document_oop_->settings(),
       base::BindOnce(&PrintJobWorkerOop::OnDidStartPrinting,
                      ui_weak_factory_.GetWeakPtr()));
 }
@@ -527,7 +537,7 @@
 
   // Page numbers are 0-based for the printing context.
   const uint32_t page_index = page->page_number() - 1;
-  const int32_t document_cookie = document()->cookie();
+  const int32_t document_cookie = document_oop_->cookie();
   VLOG(1) << "Sending page " << page_index << " of document " << document_cookie
           << " to `" << device_name_ << "` for printing";
   PrintBackendServiceManager& service_mgr =
@@ -545,13 +555,13 @@
     base::ReadOnlySharedMemoryRegion serialized_data) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  const int32_t document_cookie = document()->cookie();
+  const int32_t document_cookie = document_oop_->cookie();
   VLOG(1) << "Sending document " << document_cookie << " to `" << device_name_
           << "` for printing";
   PrintBackendServiceManager& service_mgr =
       PrintBackendServiceManager::GetInstance();
   service_mgr.RenderPrintedDocument(
-      device_name_, document_cookie, document()->page_count(), data_type,
+      device_name_, document_cookie, document_oop_->page_count(), data_type,
       std::move(serialized_data),
       base::BindOnce(&PrintJobWorkerOop::OnDidRenderPrintedDocument,
                      ui_weak_factory_.GetWeakPtr()));
@@ -560,7 +570,7 @@
 void PrintJobWorkerOop::SendDocumentDone() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  const int32_t document_cookie = document()->cookie();
+  const int32_t document_cookie = document_oop_->cookie();
   VLOG(1) << "Sending document done for document " << document_cookie;
 
   PrintBackendServiceManager& service_mgr =
diff --git a/chrome/browser/printing/print_job_worker_oop.h b/chrome/browser/printing/print_job_worker_oop.h
index 6625bce..36d51600 100644
--- a/chrome/browser/printing/print_job_worker_oop.h
+++ b/chrome/browser/printing/print_job_worker_oop.h
@@ -129,6 +129,14 @@
   // thread.
   std::u16string document_name_;
 
+  // The printed document. Only has read-only access.  This reference separate
+  // from the one already in the base class provides a guarantee that the
+  // `PrintedDocument` will persist until OOP processing completes, even if
+  // the `PrintJob` should drop its reference as part of failure/cancel
+  // processing.  Named differently than base (even though both are private)
+  // to avoid any potential confusion between them.
+  scoped_refptr<PrintedDocument> document_oop_;
+
   // The type of target to print to.  Used only from the UI thread.
   mojom::PrintTargetType print_target_type_ =
       mojom::PrintTargetType::kDirectToDevice;
diff --git a/chrome/browser/privacy_sandbox/android/BUILD.gn b/chrome/browser/privacy_sandbox/android/BUILD.gn
index 2da63d4a..e839a01 100644
--- a/chrome/browser/privacy_sandbox/android/BUILD.gn
+++ b/chrome/browser/privacy_sandbox/android/BUILD.gn
@@ -102,6 +102,8 @@
   sources = [
     "java/res/drawable-night/privacy_sandbox_dialog_illustration.xml",
     "java/res/drawable-night/privacy_sandbox_illustration.xml",
+    "java/res/drawable/ic_checklist_24dp.xml",
+    "java/res/drawable/ic_interests_24dp.xml",
     "java/res/drawable/privacy_sandbox_dialog_illustration.xml",
     "java/res/drawable/privacy_sandbox_illustration.xml",
     "java/res/drawable/privacy_sandbox_notice_eea_illustration_v4.xml",
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/ic_checklist_24dp.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/ic_checklist_24dp.xml
new file mode 100644
index 0000000..fcdc718
--- /dev/null
+++ b/chrome/browser/privacy_sandbox/android/java/res/drawable/ic_checklist_24dp.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5.55,19 L2,15.45 3.4,14.05 5.525,16.175 9.775,11.925 11.175,13.35ZM5.55,11 L2,7.45 3.4,6.05 5.525,8.175 9.775,3.925 11.175,5.35ZM13,17V15H22V17ZM13,9V7H22V9Z" />
+</vector>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/ic_interests_24dp.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/ic_interests_24dp.xml
new file mode 100644
index 0000000..78c78cc
--- /dev/null
+++ b/chrome/browser/privacy_sandbox/android/java/res/drawable/ic_interests_24dp.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M2,11 L7,2 12,11ZM7,21Q5.35,21 4.175,19.825Q3,18.65 3,17Q3,15.325 4.175,14.162Q5.35,13 7,13Q8.65,13 9.825,14.175Q11,15.35 11,17Q11,18.65 9.825,19.825Q8.65,21 7,21ZM7,19Q7.825,19 8.412,18.413Q9,17.825 9,17Q9,16.175 8.412,15.588Q7.825,15 7,15Q6.175,15 5.588,15.588Q5,16.175 5,17Q5,17.825 5.588,18.413Q6.175,19 7,19ZM5.4,9H8.6L7,6.125ZM13,21V13H21V21ZM15,19H19V15H15ZM17,11Q15.575,9.8 14.613,8.975Q13.65,8.15 13.075,7.525Q12.5,6.9 12.25,6.35Q12,5.8 12,5.175Q12,4.05 12.788,3.275Q13.575,2.5 14.75,2.5Q15.425,2.5 16.013,2.812Q16.6,3.125 17,3.675Q17.4,3.125 17.988,2.812Q18.575,2.5 19.25,2.5Q20.425,2.5 21.212,3.275Q22,4.05 22,5.175Q22,5.8 21.75,6.35Q21.5,6.9 20.925,7.525Q20.35,8.15 19.388,8.975Q18.425,9.8 17,11ZM17,8.375Q18.8,6.875 19.4,6.25Q20,5.625 20,5.225Q20,4.9 19.812,4.7Q19.625,4.5 19.3,4.5Q19.05,4.5 18.812,4.637Q18.575,4.775 18.225,5.125L17,6.3L15.775,5.125Q15.425,4.775 15.188,4.637Q14.95,4.5 14.7,4.5Q14.375,4.5 14.188,4.7Q14,4.9 14,5.225Q14,5.625 14.6,6.25Q15.2,6.875 17,8.375ZM17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425Q17,6.425 17,6.425ZM7,7.55ZM7,17Q7,17 7,17Q7,17 7,17Q7,17 7,17Q7,17 7,17Q7,17 7,17Q7,17 7,17Q7,17 7,17Q7,17 7,17ZM17,17Z" />
+</vector>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences_v4.xml b/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences_v4.xml
index 691bafb..61bc819 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences_v4.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/xml/privacy_sandbox_preferences_v4.xml
@@ -4,5 +4,27 @@
 found in the LICENSE file.
 -->
 
-<!-- TODO(http://b/254413937): Populate page with required elements/toggles. -->
-<PreferenceScreen></PreferenceScreen>
+<!-- TODO(http://b/259525182): Implement logic for dynamic sub-labels. -->
+<!-- TODO(http://b/254414138): Add correct links to the Preference fragments. -->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+    <org.chromium.components.browser_ui.settings.ChromeBasePreference
+        android:key="topics"
+        android:title="@string/ad_privacy_page_topics_link_row_label"
+        android:summary="@string/ad_privacy_page_topics_link_row_sub_label_enabled"
+        android:icon="@drawable/ic_interests_24dp"
+        app:iconTint="@macro/default_icon_color" />
+    <org.chromium.components.browser_ui.settings.ChromeBasePreference
+        android:key="fledge"
+        android:title="@string/ad_privacy_page_fledge_link_row_label"
+        android:summary="@string/ad_privacy_page_fledge_link_row_sub_label_enabled"
+        android:icon="@drawable/ic_checklist_24dp"
+        app:iconTint="@macro/default_icon_color" />
+    <org.chromium.components.browser_ui.settings.ChromeBasePreference
+        android:key="ad_measurement"
+        android:title="@string/ad_privacy_page_ad_measurement_link_row_label"
+        android:summary="@string/ad_privacy_page_ad_measurement_link_row_sub_label_enabled"
+        android:icon="@drawable/ic_bar_chart_24dp"
+        app:iconTint="@macro/default_icon_color"
+        app:allowDividerBelow="false" />
+</PreferenceScreen>
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 8915c5c3..fcbb750 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -40,7 +40,6 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h"
-#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/browser/sessions/session_restore.h"
@@ -127,7 +126,6 @@
   session_restore_observer_ =
       std::make_unique<TabManagerSessionRestoreObserver>(this);
 
-  stats_collector_ = std::make_unique<TabManagerStatsCollector>();
   tab_load_tracker_->AddObserver(this);
 }
 
@@ -326,17 +324,6 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-void TabManager::OnActiveTabChanged(content::WebContents* old_contents,
-                                    content::WebContents* new_contents) {
-  // If |old_contents| is set, that tab has switched from being active to
-  // inactive, so record the time of that transition.
-  if (old_contents) {
-    // Only record switch-to-tab metrics when a switch happens, i.e.
-    // |old_contents| is set.
-    stats_collector_->RecordSwitchToTab(old_contents, new_contents);
-  }
-}
-
 void TabManager::OnTabStripModelChanged(
     TabStripModel* tab_strip_model,
     const TabStripModelChange& change,
@@ -345,9 +332,6 @@
     auto* replace = change.GetReplace();
     WebContentsData::CopyState(replace->old_contents, replace->new_contents);
   }
-
-  if (selection.active_tab_changed() && !tab_strip_model->empty())
-    OnActiveTabChanged(selection.old_contents, selection.new_contents);
 }
 
 void TabManager::OnStartTracking(content::WebContents* web_contents,
@@ -359,10 +343,6 @@
                                       LoadingState old_loading_state,
                                       LoadingState new_loading_state) {
   GetWebContentsData(web_contents)->SetTabLoadingState(new_loading_state);
-
-  if (new_loading_state == LoadingState::LOADED) {
-    stats_collector_->OnTabIsLoaded(web_contents);
-  }
 }
 
 void TabManager::OnStopTracking(content::WebContents* web_contents,
@@ -427,10 +407,6 @@
   TabUIHelper::FromWebContents(contents)->set_created_by_session_restore(true);
 }
 
-void TabManager::OnWebContentsDestroyed(content::WebContents* contents) {
-  stats_collector_->OnWebContentsDestroyed(contents);
-}
-
 void TabManager::OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) {
   lifecycle_units_.erase(lifecycle_unit);
 }
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 098a2063..b53d439 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -44,7 +44,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 class TabManagerDelegate;
 #endif
-class TabManagerStatsCollector;
 
 // TabManager is responsible for triggering tab lifecycle state transitions.
 //
@@ -109,10 +108,6 @@
   void AddObserver(TabLifecycleObserver* observer);
   void RemoveObserver(TabLifecycleObserver* observer);
 
-  // Notifies TabManager that one tab WebContents has been destroyed. TabManager
-  // needs to clean up data related to that tab.
-  void OnWebContentsDestroyed(content::WebContents* contents);
-
   // Return whether tabs are being loaded during session restore.
   bool IsSessionRestoreLoadingTabs() const {
     return is_session_restore_loading_tabs_;
@@ -186,10 +181,6 @@
   void UnregisterMemoryPressureListener();
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-  // Called by OnTabStripModelChanged()
-  void OnActiveTabChanged(content::WebContents* old_contents,
-                          content::WebContents* new_contents);
-
   // TabStripModelObserver:
   void OnTabStripModelChanged(
       TabStripModel* tab_strip_model,
@@ -222,8 +213,6 @@
   // Returns the number of tabs that are not pending load or discarded.
   int GetNumAliveTabs() const;
 
-  TabManagerStatsCollector* stats_collector() { return stats_collector_.get(); }
-
   // LifecycleUnitObserver:
   void OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) override;
 
@@ -250,10 +239,6 @@
   class TabManagerSessionRestoreObserver;
   std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_;
 
-  // Records UMAs for tab and system-related events and properties during
-  // session restore.
-  std::unique_ptr<TabManagerStatsCollector> stats_collector_;
-
   // A clock that advances when Chrome is in use.
   UsageClock usage_clock_;
 
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
index c1ffc512..8e6e8918 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
@@ -35,7 +35,6 @@
 #include "chrome/browser/memory/memory_kills_monitor.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
-#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/utils.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
index 0f0edcc..fc9332e 100644
--- a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
-#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/utils.h"
 #include "components/performance_manager/public/graph/graph_operations.h"
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
deleted file mode 100644
index 76b3e21..0000000
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
-
-#include <cstdint>
-#include <memory>
-#include <unordered_set>
-#include <utility>
-
-#include "base/atomic_sequence_num.h"
-#include "base/bind.h"
-#include "base/containers/contains.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/raw_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/rand_util.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom.h"
-#include "chrome/browser/resource_coordinator/tab_helper.h"
-#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
-#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h"
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
-#include "chrome/browser/resource_coordinator/time.h"
-#include "chrome/browser/sessions/session_restore.h"
-#include "content/public/browser/browser_thread.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-
-namespace resource_coordinator {
-
-namespace {
-
-using LoadingState = TabLoadTracker::LoadingState;
-
-ukm::SourceId GetUkmSourceId(content::WebContents* contents) {
-  resource_coordinator::ResourceCoordinatorTabHelper* observer =
-      resource_coordinator::ResourceCoordinatorTabHelper::FromWebContents(
-          contents);
-  if (!observer)
-    return ukm::kInvalidSourceId;
-
-  return observer->ukm_source_id();
-}
-
-}  // namespace
-
-TabManagerStatsCollector::TabManagerStatsCollector() {
-  SessionRestore::AddObserver(this);
-}
-
-TabManagerStatsCollector::~TabManagerStatsCollector() {
-  SessionRestore::RemoveObserver(this);
-}
-
-void TabManagerStatsCollector::RecordSwitchToTab(
-    content::WebContents* old_contents,
-    content::WebContents* new_contents) {
-  if (!is_session_restore_loading_tabs_) {
-    return;
-  }
-
-  auto* new_data = TabManager::WebContentsData::FromWebContents(new_contents);
-  DCHECK(new_data);
-
-  if (is_session_restore_loading_tabs_) {
-    UMA_HISTOGRAM_ENUMERATION(
-        kHistogramSessionRestoreSwitchToTab,
-        static_cast<int32_t>(new_data->tab_loading_state()),
-        static_cast<int32_t>(LoadingState::kMaxValue) + 1);
-  }
-
-  if (old_contents)
-    foreground_contents_switched_to_times_.erase(old_contents);
-  DCHECK(!base::Contains(foreground_contents_switched_to_times_, new_contents));
-  if (new_data->tab_loading_state() != LoadingState::LOADED) {
-    foreground_contents_switched_to_times_.insert(
-        std::make_pair(new_contents, NowTicks()));
-  }
-}
-
-void TabManagerStatsCollector::OnSessionRestoreStartedLoadingTabs() {
-  DCHECK(!is_session_restore_loading_tabs_);
-  UpdateSessionAndSequence();
-  is_session_restore_loading_tabs_ = true;
-}
-
-void TabManagerStatsCollector::OnSessionRestoreFinishedLoadingTabs() {
-  DCHECK(is_session_restore_loading_tabs_);
-  is_session_restore_loading_tabs_ = false;
-}
-
-void TabManagerStatsCollector::OnDidStartMainFrameNavigation(
-    content::WebContents* contents) {
-  foreground_contents_switched_to_times_.erase(contents);
-}
-
-void TabManagerStatsCollector::OnTabIsLoaded(content::WebContents* contents) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!base::Contains(foreground_contents_switched_to_times_, contents))
-    return;
-
-  base::TimeDelta switch_load_time =
-      NowTicks() - foreground_contents_switched_to_times_[contents];
-  ukm::SourceId ukm_source_id = GetUkmSourceId(contents);
-  if (is_session_restore_loading_tabs_) {
-    UMA_HISTOGRAM_MEDIUM_TIMES(kHistogramSessionRestoreTabSwitchLoadTime,
-                               switch_load_time);
-
-    if (ukm_source_id != ukm::kInvalidSourceId) {
-      ukm::builders::
-          TabManager_Experimental_SessionRestore_TabSwitchLoadStopped(
-              ukm_source_id)
-              .SetSequenceId(sequence_++)
-              .SetSessionRestoreSessionId(session_id_)
-              .SetSessionRestoreTabCount(
-                  g_browser_process->GetTabManager()->restored_tab_count())
-              .SetSystemTabCount(
-                  g_browser_process->GetTabManager()->GetTabCount())
-              .SetTabSwitchLoadTime(switch_load_time.InMilliseconds())
-              .Record(ukm::UkmRecorder::Get());
-    }
-  }
-
-  foreground_contents_switched_to_times_.erase(contents);
-}
-
-void TabManagerStatsCollector::OnWebContentsDestroyed(
-    content::WebContents* contents) {
-  foreground_contents_switched_to_times_.erase(contents);
-}
-
-void TabManagerStatsCollector::UpdateSessionAndSequence() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  ++session_id_;
-  sequence_ = 0;
-}
-
-// static
-const char TabManagerStatsCollector::kHistogramSessionRestoreSwitchToTab[] =
-    "TabManager.SessionRestore.SwitchToTab";
-
-// static
-const char
-    TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime[] =
-        "TabManager.Experimental.SessionRestore.TabSwitchLoadTime."
-        "UntilTabIsLoaded";
-
-// static
-constexpr base::TimeDelta
-    TabManagerStatsCollector::kLowFrequencySamplingInterval;
-
-}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h b/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
deleted file mode 100644
index 6be6116..0000000
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_STATS_COLLECTOR_H_
-#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_STATS_COLLECTOR_H_
-
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <unordered_map>
-
-#include "base/gtest_prod_util.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/time/time.h"
-#include "chrome/browser/resource_coordinator/decision_details.h"
-#include "chrome/browser/resource_coordinator/lifecycle_unit.h"
-#include "chrome/browser/resource_coordinator/time.h"
-#include "chrome/browser/sessions/session_restore_observer.h"
-#include "services/metrics/public/cpp/ukm_source_id.h"
-
-namespace content {
-class WebContents;
-}  // namespace content
-
-namespace resource_coordinator {
-
-// TabManagerStatsCollector records UMAs on behalf of TabManager for tab and
-// system-related events and properties during session restore.
-//
-// SessionRestore is the duration from the time when the browser starts to
-// restore tabs until the time when the browser has finished loading those tabs
-// or when the browser stops loading tabs due to memory pressure. During
-// SessionRestore, some other tabs could be open due to user action, but that
-// would not affect the session end time point. For example, a browser starts to
-// restore tab1 and tab2. Tab3 is open due to user clicking a link in tab1.
-// SessionRestore ends after tab1 and tab2 finishes loading, even if tab3 is
-// still loading.
-
-class TabManagerStatsCollector final : public SessionRestoreObserver {
- public:
-  TabManagerStatsCollector();
-  ~TabManagerStatsCollector();
-
-  // Records histograms *before* starting to urgently discard LifecycleUnits.
-  // |num_alive_tabs| is the number of tabs that are not pending load or
-  // discarded.
-  void RecordWillDiscardUrgently(int num_alive_tabs);
-
-  // Records UMA histograms for the tab state when switching to a different tab
-  // during session restore.
-  void RecordSwitchToTab(content::WebContents* old_contents,
-                         content::WebContents* new_contents);
-
-  // SessionRestoreObserver
-  void OnSessionRestoreStartedLoadingTabs() override;
-  void OnSessionRestoreFinishedLoadingTabs() override;
-
-  // Called by WebContentsData when a tab starts loading. Used to clean up
-  // |foreground_contents_switched_to_times_| if we were tracking this tab and
-  // OnDidStopLoading has not yet been called for it, which will happen if the
-  // user navigates to a new page and |contents| is resused.
-  void OnDidStartMainFrameNavigation(content::WebContents* contents);
-
-  // Called by TabManager when a tab is considered loaded. Used as the signal to
-  // record tab switch load time metrics for |contents|.
-  void OnTabIsLoaded(content::WebContents* contents);
-
-  // Called by TabManager when a WebContents is destroyed. Used to clean up
-  // |foreground_contents_switched_to_times_| if we were tracking this tab and
-  // OnDidStopLoading has not yet been called for it.
-  void OnWebContentsDestroyed(content::WebContents* contents);
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorTabSwitchTest,
-                           HistogramsSwitchToTab);
-  FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorTabSwitchTest,
-                           HistogramsTabSwitchLoadTime);
-  FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorParameterizedTest,
-                           HistogramsTabCount);
-  FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorPrerenderingTest,
-                           KeepingWebContentsMapInPrerendering);
-
-  // Update session and sequence information for UKM recording.
-  void UpdateSessionAndSequence();
-
-  static const char kHistogramSessionRestoreSwitchToTab[];
-  static const char kHistogramSessionRestoreTabSwitchLoadTime[];
-
-  // The rough sampling interval for low-frequency sampled stats. This should
-  // be O(minutes).
-  static constexpr base::TimeDelta kLowFrequencySamplingInterval =
-      base::Minutes(5);
-
-  // TabManagerStatsCollector should be used from a single sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  int session_id_ = -1;
-  int sequence_ = 0;
-
-  bool is_session_restore_loading_tabs_ = false;
-
-  // The set of foreground tabs during session restore that were switched to
-  // that have not yet finished loading, mapped to the time that they were
-  // switched to. It's possible to have multiple session restores happening
-  // simultaneously in different windows, which means there can be multiple
-  // foreground tabs that have been switched to that haven't finished loading.
-  // Because of that, we need to track each foreground tab and its corresponding
-  // switch-to time.
-  std::unordered_map<content::WebContents*, base::TimeTicks>
-      foreground_contents_switched_to_times_;
-
-  base::WeakPtrFactory<TabManagerStatsCollector> weak_factory_{this};
-};
-
-}  // namespace resource_coordinator
-
-#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_STATS_COLLECTOR_H_
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
deleted file mode 100644
index 452e8c8..0000000
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/memory/raw_ptr.h"
-#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"
-#include "base/time/time.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/resource_coordinator/tab_helper.h"
-#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/test_browser_window.h"
-#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/prerender_test_util.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;
-
-using WebContents = content::WebContents;
-
-namespace resource_coordinator {
-
-using LoadingState = TabLoadTracker::LoadingState;
-
-constexpr TabLoadTracker::LoadingState UNLOADED = LoadingState::UNLOADED;
-constexpr TabLoadTracker::LoadingState LOADING = LoadingState::LOADING;
-constexpr TabLoadTracker::LoadingState LOADED = LoadingState::LOADED;
-
-class TabManagerStatsCollectorTest : public ChromeRenderViewHostTestHarness {
- protected:
-  TabManagerStatsCollectorTest()
-      : scoped_context_(
-            std::make_unique<base::TestMockTimeTaskRunner::ScopedContext>(
-                task_runner_)),
-        scoped_set_tick_clock_for_testing_(task_runner_->GetMockTickClock()) {
-    base::CurrentThread::Get()->SetTaskRunner(task_runner_);
-
-    // Start with a non-zero time.
-    task_runner_->FastForwardBy(base::Seconds(42));
-  }
-
-  TabManagerStatsCollectorTest(const TabManagerStatsCollectorTest&) = delete;
-  TabManagerStatsCollectorTest& operator=(const TabManagerStatsCollectorTest&) =
-      delete;
-
-  ~TabManagerStatsCollectorTest() override = default;
-
-  TabManagerStatsCollector* tab_manager_stats_collector() {
-    return tab_manager()->stats_collector();
-  }
-
-  void StartSessionRestore() {
-    tab_manager()->OnSessionRestoreStartedLoadingTabs();
-    tab_manager_stats_collector()->OnSessionRestoreStartedLoadingTabs();
-  }
-
-  void FinishSessionRestore() {
-    tab_manager()->OnSessionRestoreFinishedLoadingTabs();
-    tab_manager_stats_collector()->OnSessionRestoreFinishedLoadingTabs();
-  }
-
-  TabManager::WebContentsData* GetWebContentsData(WebContents* contents) const {
-    return tab_manager()->GetWebContentsData(contents);
-  }
-
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    // Call the tab manager so that it is created right away.
-    tab_manager();
-  }
-
-  void TearDown() override {
-    task_runner_->RunUntilIdle();
-    scoped_context_.reset();
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_ =
-      base::MakeRefCounted<base::TestMockTimeTaskRunner>();
-  std::unique_ptr<base::TestMockTimeTaskRunner::ScopedContext> scoped_context_;
-  ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing_;
-  base::HistogramTester histogram_tester_;
-  ukm::TestAutoSetUkmRecorder test_ukm_recorder_;
-
- private:
-  TabManager* tab_manager() const { return g_browser_process->GetTabManager(); }
-};
-
-class TabManagerStatsCollectorTabSwitchTest
-    : public TabManagerStatsCollectorTest {
- public:
-  TabManagerStatsCollectorTabSwitchTest(
-      const TabManagerStatsCollectorTabSwitchTest&) = delete;
-  TabManagerStatsCollectorTabSwitchTest& operator=(
-      const TabManagerStatsCollectorTabSwitchTest&) = delete;
-
- protected:
-  TabManagerStatsCollectorTabSwitchTest() = default;
-  ~TabManagerStatsCollectorTabSwitchTest() override = default;
-
-  void SetForegroundTabLoadingState(LoadingState state) {
-    GetWebContentsData(foreground_tab_)->SetTabLoadingState(state);
-  }
-
-  void SetBackgroundTabLoadingState(LoadingState state) {
-    GetWebContentsData(background_tab_)->SetTabLoadingState(state);
-  }
-
-  // Creating and destroying the WebContentses need to be done in the test
-  // scope.
-  void SetForegroundAndBackgroundTabs(WebContents* foreground_tab,
-                                      WebContents* background_tab) {
-    foreground_tab_ = foreground_tab;
-    foreground_tab_->WasShown();
-    background_tab_ = background_tab;
-    background_tab_->WasHidden();
-  }
-
-  void FinishLoadingForegroundTab() {
-    SetForegroundTabLoadingState(LOADED);
-    tab_manager_stats_collector()->OnTabIsLoaded(foreground_tab_);
-  }
-
-  void FinishLoadingBackgroundTab() {
-    SetBackgroundTabLoadingState(LOADED);
-    tab_manager_stats_collector()->OnTabIsLoaded(background_tab_);
-  }
-
-  void SwitchToBackgroundTab() {
-    tab_manager_stats_collector()->RecordSwitchToTab(foreground_tab_,
-                                                     background_tab_);
-    SetForegroundAndBackgroundTabs(background_tab_, foreground_tab_);
-  }
-
- private:
-  raw_ptr<WebContents> foreground_tab_;
-  raw_ptr<WebContents> background_tab_;
-};
-
-TEST_F(TabManagerStatsCollectorTabSwitchTest, HistogramsSwitchToTab) {
-  auto* histogram_name =
-      TabManagerStatsCollector::kHistogramSessionRestoreSwitchToTab;
-
-  std::unique_ptr<WebContents> tab1(CreateTestWebContents());
-  std::unique_ptr<WebContents> tab2(CreateTestWebContents());
-  SetForegroundAndBackgroundTabs(tab1.get(), tab2.get());
-
-  StartSessionRestore();
-
-  SetBackgroundTabLoadingState(UNLOADED);
-  SetForegroundTabLoadingState(UNLOADED);
-  SwitchToBackgroundTab();
-  SwitchToBackgroundTab();
-  histogram_tester_.ExpectTotalCount(histogram_name, 2);
-  histogram_tester_.ExpectBucketCount(histogram_name, UNLOADED, 2);
-
-  SetBackgroundTabLoadingState(LOADING);
-  SetForegroundTabLoadingState(LOADING);
-  SwitchToBackgroundTab();
-  SwitchToBackgroundTab();
-  SwitchToBackgroundTab();
-  histogram_tester_.ExpectTotalCount(histogram_name, 5);
-  histogram_tester_.ExpectBucketCount(histogram_name, UNLOADED, 2);
-  histogram_tester_.ExpectBucketCount(histogram_name, LOADING, 3);
-
-  SetBackgroundTabLoadingState(LOADED);
-  SetForegroundTabLoadingState(LOADED);
-  SwitchToBackgroundTab();
-  SwitchToBackgroundTab();
-  SwitchToBackgroundTab();
-  SwitchToBackgroundTab();
-  histogram_tester_.ExpectTotalCount(histogram_name, 9);
-  histogram_tester_.ExpectBucketCount(histogram_name, UNLOADED, 2);
-  histogram_tester_.ExpectBucketCount(histogram_name, LOADING, 3);
-  histogram_tester_.ExpectBucketCount(histogram_name, LOADED, 4);
-}
-
-TEST_F(TabManagerStatsCollectorTabSwitchTest, HistogramsTabSwitchLoadTime) {
-  std::unique_ptr<WebContents> tab1(CreateTestWebContents());
-  std::unique_ptr<WebContents> tab2(CreateTestWebContents());
-  SetForegroundAndBackgroundTabs(tab1.get(), tab2.get());
-
-  StartSessionRestore();
-
-  SetBackgroundTabLoadingState(UNLOADED);
-  SetForegroundTabLoadingState(LOADED);
-  SwitchToBackgroundTab();
-  FinishLoadingForegroundTab();
-  histogram_tester_.ExpectTotalCount(
-      TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime, 1);
-
-  SetBackgroundTabLoadingState(LOADING);
-  SwitchToBackgroundTab();
-  FinishLoadingForegroundTab();
-  histogram_tester_.ExpectTotalCount(
-      TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime, 2);
-
-  // Metrics aren't recorded when the foreground tab has not finished loading
-  // and the user switches to a different tab.
-  SetBackgroundTabLoadingState(UNLOADED);
-  SetForegroundTabLoadingState(LOADED);
-  SwitchToBackgroundTab();
-  // Foreground tab is currently loading and being tracked.
-  SwitchToBackgroundTab();
-  // The previous foreground tab is no longer tracked.
-  FinishLoadingBackgroundTab();
-  SwitchToBackgroundTab();
-  histogram_tester_.ExpectTotalCount(
-      TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime, 2);
-
-  // The count shouldn't change when we're no longer in a session restore or
-  // background tab opening.
-  FinishSessionRestore();
-
-  SetBackgroundTabLoadingState(UNLOADED);
-  SetForegroundTabLoadingState(LOADED);
-  SwitchToBackgroundTab();
-  FinishLoadingForegroundTab();
-  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());
-  content::test::ScopedPrerenderWebContentsDelegate tab1_delegate(*tab1.get());
-  content::test::ScopedPrerenderWebContentsDelegate tab2_delegate(*tab2.get());
-
-  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_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 598b77c7..04a6fc13 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h"
-#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/browser/resource_coordinator/utils.h"
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 099ad94..df71dd4 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
@@ -8,7 +8,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
-#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/time.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
@@ -26,21 +25,6 @@
 
 TabManager::WebContentsData::~WebContentsData() {}
 
-void TabManager::WebContentsData::DidStartNavigation(
-    content::NavigationHandle* navigation_handle) {
-  // 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.
-  if (!navigation_handle->IsInPrimaryMainFrame() ||
-      navigation_handle->IsSameDocument()) {
-    return;
-  }
-
-  g_browser_process->GetTabManager()
-      ->stats_collector()
-      ->OnDidStartMainFrameNavigation(web_contents());
-}
-
 void TabManager::WebContentsData::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   SetIsInSessionRestore(false);
@@ -51,7 +35,6 @@
   if (g_browser_process->IsShuttingDown())
     return;
   SetIsInSessionRestore(false);
-  g_browser_process->GetTabManager()->OnWebContentsDestroyed(web_contents());
 }
 
 // static
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
index be253ff..9bde6b0 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
@@ -36,8 +36,6 @@
   ~WebContentsData() override;
 
   // WebContentsObserver implementation:
-  void DidStartNavigation(
-      content::NavigationHandle* navigation_handle) override;
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
   void WebContentsDestroyed() override;
diff --git a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.html b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.html
index 24bfedb8..7594af7b 100644
--- a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.html
+++ b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.html
@@ -60,7 +60,8 @@
             var(--oobe-modal-dialog-content-slot-padding-start, 20px);
       }
     </style>
-    <cr-dialog id="modalDialog" on-close="onClose_">
+    <cr-dialog hide-backdrop$="[[shouldHideBackdrop]]" id="modalDialog"
+        on-close="onClose_">
       <!-- Title -->
       <div id="modalDialogTitle" slot="title" hidden="[[shouldHideTitleRow]]">
         <slot name="title">
diff --git a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.js b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.js
index dbca9de..0da550a7 100644
--- a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.js
+++ b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_modal_dialog.js
@@ -38,6 +38,15 @@
       type: Boolean,
       value: false,
     },
+
+    /**
+     * True if confirmation dialog backdrop should be hidden.
+     * @type {boolean}
+     */
+    shouldHideBackdrop: {
+      type: Boolean,
+      value: false,
+    },
   },
 
   get open() {
@@ -60,5 +69,4 @@
   onClose_() {
     chrome.send('enableShelfButtons', [true]);
   },
-
 });
diff --git a/chrome/browser/resources/chromeos/login/screens/common/oobe_reset.html b/chrome/browser/resources/chromeos/login/screens/common/oobe_reset.html
index b6400ce6..3b3260c 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/oobe_reset.html
+++ b/chrome/browser/resources/chromeos/login/screens/common/oobe_reset.html
@@ -113,7 +113,8 @@
 </oobe-adaptive-dialog>
 
 <!-- Powerwash confirmation dialog (depends on powerwash mode) -->
-<oobe-modal-dialog id="confirmationDialog" on-close="onDialogClosed_">
+<oobe-modal-dialog should-hide-backdrop id="confirmationDialog"
+    on-close="onDialogClosed_">
   <div slot="title">[[confirmationDialogTitle_]]</div>
   <div slot="content">[[confirmationDialogText_]]</div>
   <div slot="buttons">
diff --git a/chrome/browser/resources/chromeos/parent_access/flows/local_web_approvals_after.html b/chrome/browser/resources/chromeos/parent_access/flows/local_web_approvals_after.html
index 04e4a30..703e1c80 100644
--- a/chrome/browser/resources/chromeos/parent_access/flows/local_web_approvals_after.html
+++ b/chrome/browser/resources/chromeos/parent_access/flows/local_web_approvals_after.html
@@ -25,11 +25,9 @@
 </style>
 
 <div class="after-screen-content">
-  <!-- TODO(b/199753545): Replace the hardcoded content when it's
-    available. -->
-  <div class="subtitle"></div>
+  <h2 class="subtitle"></h2>
   <div class="details">
-    <img class="favicon"></img>
+    <img class="favicon" alt=""></img>
     <div class="details-text"></div>
   </div>
 </div>
diff --git a/chrome/browser/resources/chromeos/parent_access/parent_access_after.html b/chrome/browser/resources/chromeos/parent_access/parent_access_after.html
index 2e6db4e..6cc3c48a 100644
--- a/chrome/browser/resources/chromeos/parent_access/parent_access_after.html
+++ b/chrome/browser/resources/chromeos/parent_access/parent_access_after.html
@@ -28,7 +28,7 @@
 
 <div id="after-screen">
   <img class="google-logo" src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90"
-    alt="Google">
+    alt="Google logo">
   </img>
   <div id="after-screen-body"></div>
   <div id="after-screen-buttons">
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc
index 39895c38..157a6ef 100644
--- a/chrome/browser/sync/test/integration/apps_helper.cc
+++ b/chrome/browser/sync/test/integration/apps_helper.cc
@@ -18,9 +18,9 @@
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_extension_helper.h"
 #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/test/web_app_test_observers.h"
 #include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_id.h"
 #include "chrome/browser/web_applications/web_app_install_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
@@ -250,19 +250,17 @@
   base::RunLoop run_loop;
   web_app::AppId app_id;
   auto* provider = web_app::WebAppProvider::GetForTest(profile);
-  provider->command_manager().ScheduleCommand(
-      std::make_unique<web_app::InstallFromInfoCommand>(
-          std::make_unique<WebAppInstallInfo>(info.Clone()),
-          &provider->install_finalizer(),
-          /*overwrite_existing_manifest_fields=*/true,
-          webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON,
-          base::BindLambdaForTesting(
-              [&run_loop, &app_id](const web_app::AppId& new_app_id,
-                                   webapps::InstallResultCode code) {
-                DCHECK_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
-                app_id = new_app_id;
-                run_loop.Quit();
-              })));
+  provider->scheduler().InstallFromInfo(
+      std::make_unique<WebAppInstallInfo>(info.Clone()),
+      /*overwrite_existing_manifest_fields=*/true,
+      webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON,
+      base::BindLambdaForTesting(
+          [&run_loop, &app_id](const web_app::AppId& new_app_id,
+                               webapps::InstallResultCode code) {
+            DCHECK_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
+            app_id = new_app_id;
+            run_loop.Quit();
+          }));
 
   run_loop.Run();
 
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc b/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
index f0e849d..8b173bc 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
 #include "chrome/browser/web_applications/os_integration/web_app_shortcut_manager.h"
 #include "chrome/browser/web_applications/test/fake_os_integration_manager.h"
@@ -25,7 +24,6 @@
 #include "chrome/browser/web_applications/test/web_app_test_utils.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_install_params.h"
@@ -139,18 +137,16 @@
     base::RunLoop run_loop;
     AppId app_id;
     auto* provider = WebAppProvider::GetForTest(profile);
-    provider->command_manager().ScheduleCommand(
-        std::make_unique<web_app::InstallFromInfoCommand>(
-            std::make_unique<WebAppInstallInfo>(info.Clone()),
-            &provider->install_finalizer(),
-            /*overwrite_existing_manifest_fields=*/true, source,
-            base::BindLambdaForTesting([&run_loop, &app_id](
-                                           const AppId& new_app_id,
-                                           webapps::InstallResultCode code) {
+    provider->scheduler().InstallFromInfo(
+        std::make_unique<WebAppInstallInfo>(info.Clone()),
+        /*overwrite_existing_manifest_fields=*/true, source,
+        base::BindLambdaForTesting(
+            [&run_loop, &app_id](const AppId& new_app_id,
+                                 webapps::InstallResultCode code) {
               DCHECK_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
               app_id = new_app_id;
               run_loop.Quit();
-            })));
+            }));
 
     run_loop.Run();
 
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml b/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml
index e3c6eb8..2c4bd68 100644
--- a/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml
+++ b/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml
@@ -8,8 +8,7 @@
              xmlns:app="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:paddingHorizontal="@dimen/ttf_for_payments_sheet_padding_horizontal">
+             android:layout_height="match_parent">
 
   <ImageView
       android:id="@+id/drag_handlebar"
@@ -39,4 +38,27 @@
       android:clipToPadding="false"
       android:divider="@null"
       tools:listitem="@layout/touch_to_fill_credit_card_sheet_item"/>
-</RelativeLayout>
+
+    <!-- Divider -->
+    <View style="@style/HorizontalDivider"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/divider_height"
+        android:layout_above="@id/scan_new_card"
+        android:layout_marginHorizontal="16dp"
+        android:layout_marginBottom="@dimen/ttf_for_payments_buttons_vertical_margin"/>
+    <TextView
+        android:id="@+id/scan_new_card"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="@dimen/ttf_for_payments_buttons_vertical_margin"
+        android:clickable="true"
+        android:drawablePadding="18dp"
+        android:focusable="true"
+        android:gravity="center_vertical|start"
+        android:paddingHorizontal="@dimen/ttf_for_payments_sheet_padding_horizontal"
+        android:textAppearance="@style/TextAppearance.TextMedium.Primary"
+        android:text="@string/autofill_scan_credit_card"
+        app:drawableStartCompat="@drawable/ic_photo_camera"
+        app:drawableTint="@color/default_icon_color_tint_list"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/res/values/dimens.xml b/chrome/browser/touch_to_fill/payments/android/internal/java/res/values/dimens.xml
index 4d991e9..f486a6a6 100644
--- a/chrome/browser/touch_to_fill/payments/android/internal/java/res/values/dimens.xml
+++ b/chrome/browser/touch_to_fill/payments/android/internal/java/res/values/dimens.xml
@@ -10,6 +10,7 @@
     <dimen name="ttf_for_payments_drag_handler_margin_top">6dp</dimen>
     <dimen name="ttf_for_payments_product_icon_height">32dp</dimen>
     <dimen name="ttf_for_payments_product_icon_margin_vertical">12dp</dimen>
+    <dimen name="ttf_for_payments_buttons_vertical_margin">18dp</dimen>
     <dimen name="touch_to_fill_payments_favicon_width">40dp</dimen>
     <dimen name="touch_to_fill_payments_favicon_height">24dp</dimen>
     <dimen name="touch_to_fill_payments_sheet_margin">24dp</dimen>
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
index 39637fa8..5c1c136 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
@@ -12,7 +12,6 @@
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
-import android.view.View.OnKeyListener;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -24,10 +23,10 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.FeatureList;
 import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.components.browser_ui.widget.text.VerticallyFixedEditText;
 
 /**
@@ -38,6 +37,8 @@
     private static final String TAG = "AutocompleteEdit";
 
     private static final boolean DEBUG = false;
+    private static final MutableFlagWithSafeDefault sSpannableInlineAutocompleteFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, true);
 
     private final AccessibilityManager mAccessibilityManager;
 
@@ -115,8 +116,7 @@
     private void ensureModel() {
         if (mModel != null) return;
 
-        if (!FeatureList.isInitialized()
-                || ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+        if (sSpannableInlineAutocompleteFlag.isEnabled()) {
             Log.w(TAG, "Using spannable model...");
             mModel = new SpannableAutocompleteEditTextModel(this);
         } else {
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
index 170d97b..6054406 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
@@ -20,7 +20,6 @@
 import org.chromium.base.ApplicationState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.CallbackController;
-import org.chromium.base.FeatureList;
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
@@ -29,6 +28,8 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
+import org.chromium.chrome.browser.flags.PostNativeFlag;
 import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.R;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
@@ -149,6 +150,21 @@
     @VisibleForTesting
     static final String EXTRA_VOICE_ENTRYPOINT = "com.android.chrome.voice.VOICE_ENTRYPOINT";
 
+    private static final MutableFlagWithSafeDefault sToolbarMicIphFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.TOOLBAR_MIC_IPH_ANDROID, false);
+    private static final MutableFlagWithSafeDefault sAssistantIntentPageUrlFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL, false);
+    private static final MutableFlagWithSafeDefault sAssistantIntentExperimentIdFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.ASSISTANT_INTENT_EXPERIMENT_ID, false);
+    private static final MutableFlagWithSafeDefault sAssistantNonPersonalizedVoiceSearchFlag =
+            new MutableFlagWithSafeDefault(
+                    ChromeFeatureList.ASSISTANT_NON_PERSONALIZED_VOICE_SEARCH, true);
+    private static final MutableFlagWithSafeDefault sAssistantIntentTranslateInfoFlag =
+            new MutableFlagWithSafeDefault(
+                    ChromeFeatureList.ASSISTANT_INTENT_TRANSLATE_INFO, false);
+    private static final PostNativeFlag sCacheVoiceSearchEnabledFlag =
+            new PostNativeFlag(ChromeFeatureList.IS_VOICE_SEARCH_ENABLED_CACHE);
+
     private static Boolean sIsRecognitionIntentPresentForTesting;
     private final Delegate mDelegate;
     private Long mQueryStartTimeMs;
@@ -477,10 +493,9 @@
             }
 
             // Log successful voice use for IPH purposes.
-            if (FeatureList.isInitialized()
-                    && ChromeFeatureList.isEnabled(ChromeFeatureList.TOOLBAR_MIC_IPH_ANDROID)
-                    && mProfileSupplier.hasValue()) {
-                // mic shouldn't be visibble
+            // Log successful voice use for IPH purposes.
+            if (sToolbarMicIphFlag.isEnabled() && mProfileSupplier.hasValue()) {
+                // mic shouldn't be visible
                 assert !mProfileSupplier.get().isOffTheRecord();
                 Tracker tracker = TrackerFactory.getTrackerForProfile(mProfileSupplier.get());
                 tracker.notifyEvent(EventConstants.SUCCESSFUL_VOICE_SEARCH);
@@ -488,8 +503,7 @@
             // Assume transcription by default when the page URL feature is disabled.
             @AssistantActionPerformed
             int actionPerformed = AssistantActionPerformed.TRANSCRIPTION;
-            if (FeatureList.isInitialized()
-                    && ChromeFeatureList.isEnabled(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL)) {
+            if (sAssistantIntentPageUrlFlag.isEnabled()) {
                 actionPerformed = getActionPerformed(data.getExtras());
             }
 
@@ -876,14 +890,11 @@
         // Allows Assistant to track intent latency.
         intent.putExtra(EXTRA_INTENT_SENT_TIMESTAMP, System.currentTimeMillis());
 
-        if (FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.ASSISTANT_INTENT_EXPERIMENT_ID)) {
+        if (sAssistantIntentExperimentIdFlag.isEnabled()) {
             attachAssistantExperimentId(intent);
         }
 
-        if (FeatureList.isInitialized()
-                && !ChromeFeatureList.isEnabled(
-                        ChromeFeatureList.ASSISTANT_NON_PERSONALIZED_VOICE_SEARCH)) {
+        if (!sAssistantNonPersonalizedVoiceSearchFlag.isEnabled()) {
             // TODO(crbug.com/1344574): This is currently still needed by AGSA.
             intent.putExtra(EXTRA_INTENT_USER_EMAIL, assistantVoiceSearchService.getUserEmail());
 
@@ -894,9 +905,8 @@
                 }
             }
 
-            if (source == VoiceInteractionSource.TOOLBAR && FeatureList.isInitialized()
-                    && ChromeFeatureList.isEnabled(
-                            ChromeFeatureList.ASSISTANT_INTENT_TRANSLATE_INFO)) {
+            if (source == VoiceInteractionSource.TOOLBAR
+                    && sAssistantIntentTranslateInfoFlag.isEnabled()) {
                 boolean attached = attachTranslateExtras(intent);
                 recordTranslateExtrasAttachResult(attached);
             }
@@ -920,8 +930,7 @@
         // less obvious that user actions in Assistant may interact with the current page. Omit the
         // page URL in those cases to signal to Assistant that page-actions (e.g. translate,
         // readout) should be disallowed.
-        return source == VoiceInteractionSource.TOOLBAR && FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL);
+        return source == VoiceInteractionSource.TOOLBAR && sAssistantIntentPageUrlFlag.isEnabled();
     }
 
     /**
@@ -1026,7 +1035,7 @@
         if (windowAndroid.getActivity().get() == null) return false;
         if (!VoiceRecognitionUtil.isVoiceSearchPermittedByPolicy(false)) return false;
 
-        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.IS_VOICE_SEARCH_ENABLED_CACHE)) {
+        if (!sCacheVoiceSearchEnabledFlag.isEnabled()) {
             return VoiceRecognitionUtil.isVoiceSearchEnabled(windowAndroid);
         }
 
@@ -1071,8 +1080,7 @@
 
         // We should only record per-action metrics when the page URL feature is enabled. When
         // disabled, only transcription should occur.
-        if (FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL)) {
+        if (sAssistantIntentPageUrlFlag.isEnabled()) {
             recordAssistantActionPerformed(source, action);
             recordPerActionVoiceSearchOpenDuration(action, elapsedTimeMs);
         }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionUtil.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionUtil.java
index 0d0f450e..4e9e74f 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionUtil.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionUtil.java
@@ -11,11 +11,11 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.FeatureList;
 import org.chromium.base.PackageManagerUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileManager;
@@ -29,6 +29,9 @@
 public class VoiceRecognitionUtil {
     private static Boolean sHasRecognitionIntentHandler;
     private static Boolean sIsVoiceSearchEnabledForTesting;
+    private static MutableFlagWithSafeDefault sVoiceSearchAudioCapturePolicyFlag =
+            new MutableFlagWithSafeDefault(
+                    ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY, false);
 
     /**
      * Returns whether voice search is enabled.
@@ -84,9 +87,7 @@
         assert LibraryLoader.getInstance().isInitialized()
             : "Premature call to check VoiceSearch eligibility may not return reliable information";
 
-        if (FeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(
-                        ChromeFeatureList.VOICE_SEARCH_AUDIO_CAPTURE_POLICY)) {
+        if (sVoiceSearchAudioCapturePolicyFlag.isEnabled()) {
             // If the PrefService isn't initialized yet we won't know here whether or not voice
             // search is allowed by policy. In that case, treat voice search as enabled but check
             // again when a Profile is set and PrefService becomes available.
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index f30896a..2acbebb 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -818,10 +818,10 @@
         Security
       </message>
       <message name="IDS_AD_PRIVACY_LINK_ROW_LABEL" translateable="false" desc="Label for the ad privacy row.">
-        Lorem ipsum
+        Donec semper
       </message>
       <message name="IDS_AD_PRIVACY_LINK_ROW_SUB_LABEL" translateable="false" desc="Sublabel for the ad privacy row.">
-        Lorem ipsum Lorem ipsum
+        Fusce purus nibh, dictum sit amet mi in, fringilla ullamcorper tortor
       </message>
       <message name="IDS_CONTEXTUAL_SEARCH_TITLE" desc="Name for the Contextual Search feature, which allows users to search for a term in a web page by tapping on it.">
         Touch to Search
@@ -1157,9 +1157,27 @@
         <ph name="BEGIN_BOLD">&lt;b&gt;</ph>Lorem ipsum:<ph name="END_BOLD">&lt;/b&gt;</ph> Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
       </message>
 
-      <!-- Privacy Sandbox v4 - Ad Privacy Page-->
-      <message name="IDS_AD_PRIVACY_PAGE_TITLE" translateable="false" desc="Title on page.">
-        Lorem Ipsum
+      <!-- Privacy Sandbox v4 - Ad Privacy Page -->
+      <message name="IDS_AD_PRIVACY_PAGE_TITLE" translateable="false" desc="Title for the Ad Privacy preferences.">
+        Donec semper
+      </message>
+      <message name="IDS_AD_PRIVACY_PAGE_TOPICS_LINK_ROW_LABEL" translateable="false" desc="Title for topics preference.">
+        Mauris interdum lectus vitae lacinia
+      </message>
+      <message name="IDS_AD_PRIVACY_PAGE_TOPICS_LINK_ROW_SUB_LABEL_ENABLED" translateable="false" desc="Description for topics preference when enabled.">
+        Enabled Nulla eros tortor, placerat blandit dictum a, interdum id metus
+      </message>
+      <message name="IDS_AD_PRIVACY_PAGE_FLEDGE_LINK_ROW_LABEL" translateable="false" desc="Title for the fledge preference when enabled.">
+        Aenean erat leo
+      </message>
+      <message name="IDS_AD_PRIVACY_PAGE_FLEDGE_LINK_ROW_SUB_LABEL_ENABLED" translateable="false" desc="Description for the fledge preference when enabled.">
+        Enabled Duis scelerisque a mi eget ultricies
+      </message>
+      <message name="IDS_AD_PRIVACY_PAGE_AD_MEASUREMENT_LINK_ROW_LABEL" translateable="false" desc="Title for the ad measurement preference.">
+        Vestibulum augue erat
+      </message>
+      <message name="IDS_AD_PRIVACY_PAGE_AD_MEASUREMENT_LINK_ROW_SUB_LABEL_ENABLED" translateable="false" desc="Description for the ad measurement preference when enabled.">
+        Enabled Vivamus id lacus et lacus porttitor vulputate. Sed semper egestas orci vel maximus.
       </message>
 
       <!-- Secure DNS Settings.  Used by //chrome/browser/privacy. -->
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarFeatures.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarFeatures.java
index 666fb807..2ef718f 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarFeatures.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarFeatures.java
@@ -6,6 +6,7 @@
 
 import org.chromium.base.FeatureList;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 
 /** Utility class for toolbar code interacting with features and params. */
 public final class ToolbarFeatures {
@@ -14,6 +15,8 @@
     // allows half of this work to still be done, allowing measurement of both halves when compared
     // to the original ablation and controls.
     private static final String ALLOW_CAPTURES = "allow_captures";
+    private static final MutableFlagWithSafeDefault sSuppressionFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.SUPPRESS_TOOLBAR_CAPTURES, false);
 
     private static Boolean sSuppressionEnabled;
 
@@ -38,21 +41,6 @@
     }
 
     public static boolean shouldSuppressCaptures() {
-        if (Boolean.TRUE.equals(sSuppressionEnabled)) return true;
-        if (Boolean.FALSE.equals(sSuppressionEnabled)) return false;
-        if (!FeatureList.isInitialized()) return false;
-        if (FeatureList.hasTestFeature(ChromeFeatureList.SUPPRESS_TOOLBAR_CAPTURES)) {
-            // Don't cache if the feature value is test-configured since it can change during the
-            // process lifetime.
-            return ChromeFeatureList.isEnabled(ChromeFeatureList.SUPPRESS_TOOLBAR_CAPTURES);
-        }
-
-        if (FeatureList.isNativeInitialized()) {
-            sSuppressionEnabled =
-                    ChromeFeatureList.isEnabled(ChromeFeatureList.SUPPRESS_TOOLBAR_CAPTURES);
-            return sSuppressionEnabled;
-        }
-
-        return false;
+        return sSuppressionFlag.isEnabled();
     }
 }
\ No newline at end of file
diff --git a/chrome/browser/ui/color/new_tab_page_color_mixer.cc b/chrome/browser/ui/color/new_tab_page_color_mixer.cc
index a0228a1..93e3e8e4 100644
--- a/chrome/browser/ui/color/new_tab_page_color_mixer.cc
+++ b/chrome/browser/ui/color/new_tab_page_color_mixer.cc
@@ -88,7 +88,7 @@
 // elements with an accent color, while, on non-white background colors we
 // compute appropriate contrasting background and foreground element colors and
 // use these to style elements.
-void AddNewTabPageComprehensiveColors(ui::ColorMixer& mixer) {
+void AddGeneratedThemeComprehensiveColors(ui::ColorMixer& mixer) {
   ui::ColorTransform element_background_color = SelectBasedOnWhiteNtpBackground(
       {kColorNewTabPageBackground},
       GetContrastingColorTransform({kColorNewTabPageBackground}));
@@ -176,23 +176,6 @@
         SelectBasedOnWhiteNtpBackground({gfx::kGoogleGrey700},
                                         primary_foreground_color);
     mixer[kColorRealboxPlaceholder] = secondary_foreground_color;
-    mixer[kColorRealboxResultsBackground] = background_color;
-    mixer[kColorRealboxResultsBackgroundHovered] = {
-        kColorOmniboxResultsBackgroundHovered};
-    mixer[kColorRealboxResultsControlBackgroundHovered] = ui::SetAlpha(
-        ui::SelectBasedOnDarkInput({kColorRealboxBackground},
-                                   gfx::kGoogleGrey200, gfx::kGoogleGrey900),
-        /* 10% opacity */ 0.1 * SK_AlphaOPAQUE);
-    mixer[kColorRealboxResultsDimSelected] = {
-        kColorOmniboxResultsBackgroundSelected};
-    mixer[kColorRealboxResultsForeground] = primary_foreground_color;
-    mixer[kColorRealboxResultsForegroundDimmed] = {
-        kColorOmniboxResultsTextDimmed};
-    mixer[kColorRealboxResultsIconSelected] = {
-        kColorOmniboxResultsIconSelected};
-    mixer[kColorRealboxResultsUrl] = {kColorOmniboxResultsUrl};
-    mixer[kColorRealboxResultsUrlSelected] = {kColorOmniboxResultsUrlSelected};
-    mixer[kColorRealboxSearchIconBackground] = secondary_foreground_color;
   }
 }
 
@@ -307,29 +290,38 @@
       ui::SetAlpha(gfx::kGoogleGrey900,
                    (dark_mode ? /* % opacity */ 0.32 : 0.28) * SK_AlphaOPAQUE);
 
-  if (base::FeatureList::IsEnabled(ntp_features::kRealboxMatchOmniboxTheme)) {
+  if (base::FeatureList::IsEnabled(ntp_features::kRealboxMatchOmniboxTheme) ||
+      base::FeatureList::IsEnabled(
+          ntp_features::kNtpComprehensiveThemeRealbox)) {
+    if (dark_mode) {
+      mixer[kColorRealboxBackground] = {kColorToolbarBackgroundSubtleEmphasis};
+      mixer[kColorRealboxBackgroundHovered] = {
+          kColorToolbarBackgroundSubtleEmphasisHovered};
+    }
+
     mixer[kColorRealboxForeground] = {ui::kColorTextfieldForeground};
     mixer[kColorRealboxPlaceholder] = {kColorOmniboxTextDimmed};
     mixer[kColorRealboxResultsBackground] = {kColorOmniboxResultsBackground};
     mixer[kColorRealboxResultsBackgroundHovered] = {
         kColorOmniboxResultsBackgroundHovered};
-    if (dark_mode) {
-      mixer[kColorRealboxResultsControlBackgroundHovered] =
-          ui::SetAlpha({gfx::kGoogleGrey200},
-                       /* 10% opacity */ 0.1 * SK_AlphaOPAQUE);
-    }
+    mixer[kColorRealboxResultsControlBackgroundHovered] = ui::SetAlpha(
+        ui::SelectBasedOnDarkInput({kColorRealboxBackground},
+                                   gfx::kGoogleGrey200, gfx::kGoogleGrey900),
+        /* 10% opacity */ 0.1 * SK_AlphaOPAQUE);
     mixer[kColorRealboxResultsDimSelected] = {
         kColorOmniboxResultsBackgroundSelected};
     mixer[kColorRealboxResultsForeground] = {ui::kColorTextfieldForeground};
     mixer[kColorRealboxResultsForegroundDimmed] = {
         kColorOmniboxResultsTextDimmed};
+    mixer[kColorRealboxResultsIcon] = {kColorOmniboxResultsIcon};
     mixer[kColorRealboxResultsIconSelected] = {
         kColorOmniboxResultsIconSelected};
-    mixer[kColorRealboxSearchIconBackground] = {kColorOmniboxResultsIcon};
-    mixer[kColorRealboxResultsIcon] = {kColorOmniboxResultsIcon};
     mixer[kColorRealboxResultsUrl] = {kColorOmniboxResultsUrl};
     mixer[kColorRealboxResultsUrlSelected] = {kColorOmniboxResultsUrlSelected};
+    mixer[kColorRealboxSearchIconBackground] = {kColorOmniboxResultsIcon};
+  }
 
+  if (base::FeatureList::IsEnabled(ntp_features::kRealboxMatchOmniboxTheme)) {
     // For details see `kRealboxMatchOmniboxThemeVariations` in
     // chrome/browser/about_flags.cc.
     switch (base::GetFieldTrialParamByFeatureAsInt(
@@ -360,14 +352,12 @@
 
   AddWebThemeNewTabPageColors(mixer, dark_mode);
 
-  // Comprehensive theming colors are currently only applied for generated
-  // themes. This ensures we do not change the 'Default color' user experience.
   using ThemeType =
       ui::ColorProviderManager::ThemeInitializerSupplier::ThemeType;
   if (base::FeatureList::IsEnabled(ntp_features::kNtpComprehensiveTheming) &&
       key.custom_theme &&
       key.custom_theme->get_theme_type() == ThemeType::kAutogenerated) {
-    AddNewTabPageComprehensiveColors(mixer);
+    AddGeneratedThemeComprehensiveColors(mixer);
   } else {
     const SkColor border_color =
         dark_mode ? gfx::kGoogleGrey700 : gfx::kGoogleGrey300;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
index dfc47b72..8f2b0cb 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/containers/fixed_flat_map.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "chrome/browser/themes/theme_properties.h"
@@ -34,10 +35,12 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "components/remote_cocoa/common/native_widget_ns_window.mojom-shared.h"
 #include "components/remote_cocoa/common/native_widget_ns_window.mojom.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/canvas.h"
+#include "ui/views/cocoa/native_widget_mac_ns_window_host.h"
 
 namespace {
 
@@ -119,8 +122,13 @@
   if (browser_view()->UsesImmersiveFullscreenMode()) {
     browser_view()->immersive_mode_controller()->SetEnabled(
         browser_view()->IsFullscreen());
+    UpdateFullscreenTopUI();
+
+    // browser_view()->Layout() is not needed since top chrome is in another
+    // widget.
     return;
   }
+
   if (browser_view()->IsFullscreen()) {
     [fullscreen_toolbar_controller_ enterFullscreenMode];
   } else {
@@ -212,12 +220,6 @@
 }
 
 void BrowserNonClientFrameViewMac::UpdateFullscreenTopUI() {
-  if (browser_view()->UsesImmersiveFullscreenMode())
-    return;
-
-  FullscreenToolbarStyle old_style =
-      [fullscreen_toolbar_controller_ toolbarStyle];
-
   // Update to the new toolbar style if needed.
   FullscreenToolbarStyle new_style;
   FullscreenController* controller =
@@ -230,11 +232,38 @@
     new_style = GetUserPreferredToolbarStyle(AlwaysShowToolbarInFullscreen());
     browser_view()->UnhideDownloadShelf();
   }
-  [fullscreen_toolbar_controller_ setToolbarStyle:new_style];
 
-  if (![fullscreen_toolbar_controller_ isInFullscreen] ||
-      old_style == new_style)
+  if (browser_view()->UsesImmersiveFullscreenMode()) {
+    remote_cocoa::mojom::NativeWidgetNSWindow* ns_window_mojo =
+        views::NativeWidgetMacNSWindowHost::GetFromNativeWindow(
+            browser_view()->GetWidget()->GetNativeWindow())
+            ->GetNSWindowMojo();
+    static constexpr auto kStyleMap =
+        base::MakeFixedFlatMap<FullscreenToolbarStyle,
+                               remote_cocoa::mojom::ToolbarVisibilityStyle>(
+            {{FullscreenToolbarStyle::TOOLBAR_PRESENT,
+              remote_cocoa::mojom::ToolbarVisibilityStyle::kAlways},
+             {FullscreenToolbarStyle::TOOLBAR_HIDDEN,
+              remote_cocoa::mojom::ToolbarVisibilityStyle::kAutohide},
+             {FullscreenToolbarStyle::TOOLBAR_NONE,
+              remote_cocoa::mojom::ToolbarVisibilityStyle::kNone}});
+    const auto* it = kStyleMap.find(new_style);
+    remote_cocoa::mojom::ToolbarVisibilityStyle mapped_style =
+        it != kStyleMap.end()
+            ? it->second
+            : remote_cocoa::mojom::ToolbarVisibilityStyle::kAutohide;
+    ns_window_mojo->UpdateToolbarVisibility(mapped_style);
+    // The layout changes further down are not needed in immersive fullscreen.
     return;
+  }
+
+  FullscreenToolbarStyle old_style =
+      [fullscreen_toolbar_controller_ toolbarStyle];
+  [fullscreen_toolbar_controller_ setToolbarStyle:new_style];
+  if (![fullscreen_toolbar_controller_ isInFullscreen] ||
+      old_style == new_style) {
+    return;
+  }
 
   // Notify browser that top ui state has been changed so that we can update
   // the bookmark bar state as well.
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm
index 891a8dd..a694cdf 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm
@@ -11,32 +11,20 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/ui/cocoa/scoped_menu_bar_lock.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
-#include "chrome/browser/ui/web_applications/app_browser_controller.h"
-#include "chrome/browser/web_applications/app_registrar_observer.h"
-#include "chrome/browser/web_applications/web_app_provider.h"
-#include "chrome/browser/web_applications/web_app_registrar.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/remote_cocoa/app_shim/bridged_content_view.h"
-#include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/cocoa/native_widget_mac_ns_window_host.h"
 #include "ui/views/focus/focus_manager.h"
-#include "ui/views/layout/layout_manager.h"
 #include "ui/views/view_observer.h"
 #include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_utils_mac.h"
 
 namespace {
 class ImmersiveModeControllerMac : public ImmersiveModeController,
                                    public views::FocusChangeListener,
                                    public views::ViewObserver,
-                                   public views::WidgetObserver,
-                                   public web_app::AppRegistrarObserver {
+                                   public views::WidgetObserver {
  public:
   class RevealedLock : public ImmersiveRevealedLock {
    public:
@@ -89,10 +77,6 @@
   // views::WidgetObserver implementation
   void OnWidgetDestroying(views::Widget* widget) override;
 
-  // web_app::AppRegistrarObserver
-  void OnAlwaysShowToolbarInFullscreenChanged(const web_app::AppId& app_id,
-                                              bool show) override;
-
  private:
   friend class RevealedLock;
 
@@ -100,9 +84,6 @@
   void LockDestroyed();
   void SetMenuRevealed(bool revealed);
 
-  // Handler of show_fullscreen_toolbar_ changes.
-  void UpdateToolbarVisibility();
-
   raw_ptr<BrowserView> browser_view_ = nullptr;  // weak
   std::unique_ptr<ImmersiveRevealedLock> focus_lock_;
   std::unique_ptr<ImmersiveRevealedLock> menu_lock_;
@@ -115,12 +96,6 @@
   base::ScopedObservation<views::Widget, views::WidgetObserver>
       overlay_widget_observation_{this};
 
-  // Used to keep track of the update of kShowFullscreenToolbar preference.
-  BooleanPrefMember show_fullscreen_toolbar_;
-  base::ScopedObservation<web_app::WebAppRegistrar,
-                          web_app::AppRegistrarObserver>
-      always_show_toolbar_in_fullscreen_observation_{this};
-
   // Used as a convenience to access
   // NativeWidgetMacNSWindowHost::GetNSWindowMojo().
   raw_ptr<remote_cocoa::mojom::NativeWidgetNSWindow> ns_window_mojo_ =
@@ -152,34 +127,6 @@
   ns_window_mojo_ = views::NativeWidgetMacNSWindowHost::GetFromNativeWindow(
                         browser_view_->GetWidget()->GetNativeWindow())
                         ->GetNSWindowMojo();
-
-  if (web_app::AppBrowserController::IsWebApp(browser_view->browser())) {
-    auto* provider =
-        web_app::WebAppProvider::GetForWebApps(browser_view->GetProfile());
-    always_show_toolbar_in_fullscreen_observation_.Observe(
-        &provider->registrar());
-  } else {
-    show_fullscreen_toolbar_.Init(
-        prefs::kShowFullscreenToolbar, browser_view->GetProfile()->GetPrefs(),
-        base::BindRepeating(
-            &ImmersiveModeControllerMac::UpdateToolbarVisibility,
-            base::Unretained(this)));
-  }
-}
-
-void ImmersiveModeControllerMac::UpdateToolbarVisibility() {
-  bool always_show_toolbar;
-  if (web_app::AppBrowserController::IsWebApp(browser_view_->browser())) {
-    web_app::AppBrowserController* controller =
-        browser_view_->browser()->app_controller();
-    always_show_toolbar = controller->AlwaysShowToolbarInFullscreen();
-  } else {
-    always_show_toolbar = *show_fullscreen_toolbar_;
-  }
-  ns_window_mojo_->UpdateToolbarVisibility(always_show_toolbar);
-
-  // TODO(bur): Re-layout so that "no show" -> "always show" will work
-  // properly.
 }
 
 void ImmersiveModeControllerMac::SetMenuRevealed(bool revealed) {
@@ -313,7 +260,6 @@
   if (!observed_view->bounds().IsEmpty()) {
     browser_view_->overlay_widget()->SetBounds(observed_view->bounds());
     ns_window_mojo_->OnTopContainerViewBoundsChanged(observed_view->bounds());
-    UpdateToolbarVisibility();
   }
 }
 
@@ -321,15 +267,6 @@
   SetEnabled(false);
 }
 
-void ImmersiveModeControllerMac::OnAlwaysShowToolbarInFullscreenChanged(
-    const web_app::AppId& app_id,
-    bool show) {
-  if (web_app::AppBrowserController::IsForWebApp(browser_view_->browser(),
-                                                 app_id)) {
-    UpdateToolbarVisibility();
-  }
-}
-
 void ImmersiveModeControllerMac::LockDestroyed() {
   revealed_lock_count_--;
   if (revealed_lock_count_ == 0)
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
index 1987a94ae..3679dcb0 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -557,10 +557,8 @@
   delegate->OverrideBrowserWindowActive(is_browser_window_active_);
   delegate_ = delegate.get();
 
-  auto display_manager = delegate->GetDisplayManager()->GetWeakPtr();
-  auto* request = new PaymentRequest(
-      *render_frame_host, std::move(delegate), std::move(display_manager),
-      std::move(receiver), SPCTransactionMode::NONE, GetWeakPtr());
+  auto* request = new PaymentRequest(std::move(delegate), std::move(receiver));
+  request->set_observer_for_test(GetWeakPtr());
   requests_.push_back(request->GetWeakPtr());
 }
 
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc
index d99cdba1..f6876648 100644
--- a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc
+++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h"
+#include <memory>
 #include <string>
 
 #include "base/metrics/user_metrics_action.h"
@@ -17,6 +18,7 @@
 #include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h"
 #include "chrome/browser/ui/views/site_data/site_data_row_view.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/browsing_data/content/browsing_data_model.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/content_settings/browser/page_specific_content_settings.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
@@ -28,20 +30,16 @@
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cookies/cookie_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/dialog_model.h"
 #include "ui/views/bubble/bubble_dialog_model_host.h"
 #include "ui/views/layout/box_layout_view.h"
 #include "ui/views/view_class_properties.h"
+#include "url/origin.h"
 
 namespace {
 
-struct PageSpecificSiteDataDialogSite {
-  url::Origin origin;
-  ContentSetting setting;
-  bool is_fully_partitioned;
-};
-
 struct PageSpecificSiteDataDialogSection {
   std::u16string title;
   std::u16string subtitle;
@@ -145,6 +143,11 @@
     blocked_cookies_tree_model_ = CreateCookiesTreeModel(
         content_settings->blocked_local_shared_objects());
 
+    allowed_browsing_data_model_ =
+        content_settings->allowed_browsing_data_model();
+    blocked_browsing_data_model_ =
+        content_settings->blocked_browsing_data_model();
+
     Profile* profile =
         Profile::FromBrowserContext(web_contents_->GetBrowserContext());
     favicon_cache_ = std::make_unique<FaviconCache>(
@@ -188,25 +191,69 @@
 
   std::vector<PageSpecificSiteDataDialogSite> GetAllSites() {
     std::map<std::string, PageSpecificSiteDataDialogSite> sites_map;
-    for (const auto& node :
+    for (const std::unique_ptr<CookieTreeNode>& node :
          allowed_cookies_tree_model_->GetRoot()->children()) {
+      std::string host_name = node->GetDetailedInfo().origin.host();
+      auto existing_site = sites_map.find(host_name);
+      if (existing_site == sites_map.end()) {
+        sites_map.emplace(
+            host_name,
+            CreateSiteFromHostNode(node.get(), /*from_allowed_tree=*/true));
+      } else {
+        // To display the result entry as fully partitioned, both entries have
+        // to be partitioned.
+        existing_site->second.is_fully_partitioned &=
+            IsCookieTreeNodeFullyPartitioned(node.get());
+      }
       sites_map.emplace(
           node->GetDetailedInfo().origin.host(),
           CreateSiteFromHostNode(node.get(), /*from_allowed_tree=*/true));
     }
-    for (const auto& node :
+    for (const BrowsingDataModel::BrowsingDataEntryView& entry :
+         *allowed_browsing_data_model_) {
+      auto existing_site = sites_map.find(*entry.primary_host);
+      if (existing_site == sites_map.end()) {
+        sites_map.emplace(
+            *entry.primary_host,
+            CreateSiteFromEntryView(entry, /*from_allowed_model=*/true));
+      } else {
+        // To display the result entry as fully partitioned, entries from both
+        // models have to be partitioned.
+        existing_site->second.is_fully_partitioned &=
+            IsBrowsingDataEntryViewFullyPartitioned(entry);
+      }
+    }
+    for (const std::unique_ptr<CookieTreeNode>& node :
          blocked_cookies_tree_model_->GetRoot()->children()) {
-      auto entry = sites_map.find(node->GetDetailedInfo().origin.host());
+      auto existing_site =
+          sites_map.find(node->GetDetailedInfo().origin.host());
       // If there are multiple entries from the same tree, ignore the entry from
       // the blocked tree. It might be caused by partitioned allowed cookies and
       // regular blocked cookies or by cookies being set after creating an
-      // exception and not reloading the page.
-      if (entry == sites_map.end()) {
+      // exception and not reloading the page. Existing site entries doesn't
+      // need to be updated as partitioned state isn't relevant for blocked
+      // entries.
+      if (existing_site == sites_map.end()) {
         sites_map.emplace(
             node->GetDetailedInfo().origin.host(),
             CreateSiteFromHostNode(node.get(), /*from_allowed_tree=*/false));
       }
     }
+    for (const BrowsingDataModel::BrowsingDataEntryView& entry :
+         *blocked_browsing_data_model_) {
+      auto existing_site = sites_map.find(*entry.primary_host);
+      if (existing_site == sites_map.end()) {
+        // If there are multiple entries from the same tree, ignore the entry
+        // from the blocked tree. It might be caused by partitioned allowed
+        // cookies and regular blocked cookies or by cookies being set after
+        // creating an exception and not reloading the page. Existing site
+        // entries doesn't need to be updated as partitioned state isn't
+        // relevant for blocked entries.
+        sites_map.emplace(
+            *entry.primary_host,
+            CreateSiteFromEntryView(entry, /*from_allowed_model=*/false));
+      }
+    }
 
     std::vector<PageSpecificSiteDataDialogSite> sites;
     for (auto site : sites_map)
@@ -288,12 +335,53 @@
   PageSpecificSiteDataDialogSite CreateSiteFromHostNode(
       CookieTreeNode* node,
       bool from_allowed_tree) {
-    GURL current_url = web_contents_->GetVisibleURL();
+    url::Origin origin = node->GetDetailedInfo().origin;
+    return CreateSite(
+        origin, from_allowed_tree,
+        from_allowed_tree && IsCookieTreeNodeFullyPartitioned(node));
+  }
 
+  PageSpecificSiteDataDialogSite CreateSiteFromEntryView(
+      const BrowsingDataModel::BrowsingDataEntryView& entry,
+      bool from_allowed_model) {
+    GURL current_url = web_contents_->GetVisibleURL();
+    // TODO(crbug.com/1271155): BDM provides host name only while
+    // CookieTreeModel provides url::Origin. This classes works with
+    // url::Origin, so here we convert host name to origin with some assumptions
+    // (which might not be true). We should either convert to work only with
+    // host names or BDM should return origins.
+    GURL site_url = net::cookie_util::CookieOriginToURL(
+        *entry.primary_host, current_url.SchemeIsCryptographic());
+    return CreateSite(url::Origin::Create(site_url), from_allowed_model,
+                      IsBrowsingDataEntryViewFullyPartitioned(entry));
+  }
+
+  bool IsBrowsingDataEntryViewFullyPartitioned(
+      const BrowsingDataModel::BrowsingDataEntryView& entry) {
+    // TODO(crbug.com/1378703): Implement showing partitioned state from
+    // BrowsingDataModel.
+    return false;
+  }
+
+  bool IsCookieTreeNodeFullyPartitioned(CookieTreeNode* node) {
+    GURL current_url = web_contents_->GetVisibleURL();
+    url::Origin origin = node->GetDetailedInfo().origin;
+    // TODO(crbug.com/1344787): Add a test to verify partitioned logic.
+    // TODO(crbug.com/1271155): Consider reporting partitioned storage access
+    // directly and remove this.
+    return GetEtldPlusOne(origin) !=
+               GetEtldPlusOne(url::Origin::Create(current_url)) &&
+           IsOnlyPartitionedStorageAccessAllowed(origin) &&
+           AreAllCookiesPartitioned(node);
+  }
+
+  PageSpecificSiteDataDialogSite CreateSite(url::Origin origin,
+                                            bool from_allowed_model,
+                                            bool is_fully_partitioned) {
     PageSpecificSiteDataDialogSite site;
-    site.origin = node->GetDetailedInfo().origin;
-    if (from_allowed_tree) {
-      // If the entry is in the allowed tree, it should have either allowed or
+    site.origin = origin;
+    if (from_allowed_model) {
+      // If the entry is in the allowed model, it should have either allowed or
       // clear-on-exit state. If the dialog is reopened after making changes but
       // before reloading the page, it will show the state of accesses on the
       // page load.
@@ -306,15 +394,8 @@
     } else {
       site.setting = CONTENT_SETTING_BLOCK;
     }
+    site.is_fully_partitioned = is_fully_partitioned;
     // TODO(crbug.com/1344787): Handle sources other than SETTING_SOURCE_USER.
-
-    // TODO(crbug.com/1344787): Add a test to verify partitioned logic.
-    site.is_fully_partitioned =
-        GetEtldPlusOne(site.origin) !=
-            GetEtldPlusOne(url::Origin::Create(current_url)) &&
-        IsOnlyPartitionedStorageAccessAllowed(site.origin) &&
-        AreAllCookiesPartitioned(node);
-
     return site;
   }
 
@@ -378,6 +459,8 @@
   // the actual content settings to determine the state.
   std::unique_ptr<CookiesTreeModel> allowed_cookies_tree_model_;
   std::unique_ptr<CookiesTreeModel> blocked_cookies_tree_model_;
+  raw_ptr<BrowsingDataModel> allowed_browsing_data_model_;
+  raw_ptr<BrowsingDataModel> blocked_browsing_data_model_;
   std::unique_ptr<FaviconCache> favicon_cache_;
   scoped_refptr<content_settings::CookieSettings> cookie_settings_;
   raw_ptr<HostContentSettingsMap> host_content_settings_map_;
@@ -451,6 +534,23 @@
 
 }  // namespace
 
+namespace test {
+
+PageSpecificSiteDataDialogTestApi::PageSpecificSiteDataDialogTestApi(
+    content::WebContents* web_contents)
+    : delegate_(std::make_unique<PageSpecificSiteDataDialogModelDelegate>(
+          web_contents)) {}
+
+PageSpecificSiteDataDialogTestApi::~PageSpecificSiteDataDialogTestApi() =
+    default;
+
+std::vector<PageSpecificSiteDataDialogSite>
+PageSpecificSiteDataDialogTestApi::GetAllSites() {
+  return delegate_->GetAllSites();
+}
+
+}  // namespace test
+
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kPageSpecificSiteDataDialogRow);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kPageSpecificSiteDataDialogFirstPartySection);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kPageSpecificSiteDataDialogThirdPartySection);
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h
index 1fe48e7a..f822af6c 100644
--- a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h
+++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_SITE_DATA_PAGE_SPECIFIC_SITE_DATA_DIALOG_H_
 #define CHROME_BROWSER_UI_VIEWS_SITE_DATA_PAGE_SPECIFIC_SITE_DATA_DIALOG_H_
 
+#include "components/content_settings/core/common/content_settings.h"
 #include "ui/base/interaction/element_identifier.h"
+#include "url/origin.h"
 
 namespace views {
 class Widget;
@@ -15,6 +17,37 @@
 class WebContents;
 }  // namespace content
 
+namespace {
+class PageSpecificSiteDataDialogModelDelegate;
+}  // namespace
+
+// |PageSpecificSiteDataDialogSite| represents a site entry in page specific
+// site data dialog. It contains information about origin, the effective content
+// setting and the partitioned state.
+struct PageSpecificSiteDataDialogSite {
+  url::Origin origin;
+  ContentSetting setting;
+  bool is_fully_partitioned;
+};
+
+namespace test {
+
+// API to expose dialog delegate for unit tests. It provides access to internal
+// methods for testing. API creates and holds a reference to a dialog delegate.
+class PageSpecificSiteDataDialogTestApi {
+ public:
+  explicit PageSpecificSiteDataDialogTestApi(
+      content::WebContents* web_contents);
+  ~PageSpecificSiteDataDialogTestApi();
+
+  std::vector<PageSpecificSiteDataDialogSite> GetAllSites();
+
+ private:
+  std::unique_ptr<PageSpecificSiteDataDialogModelDelegate> delegate_;
+};
+
+}  // namespace test
+
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kPageSpecificSiteDataDialogRow);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kPageSpecificSiteDataDialogFirstPartySection);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kPageSpecificSiteDataDialogThirdPartySection);
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_unittest.cc b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_unittest.cc
new file mode 100644
index 0000000..eb94e6c0
--- /dev/null
+++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_unittest.cc
@@ -0,0 +1,145 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h"
+
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/content_settings/page_specific_content_settings_delegate.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/content_settings/browser/page_specific_content_settings.h"
+#include "content/public/browser/cookie_access_details.h"
+
+namespace {
+
+const char kCurrentUrl[] = "https://google.com";
+const char kThirdPartyUrl[] = "https://youtube.com";
+
+}  // namespace
+
+class PageSpecificSiteDataDialogUnitTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+  PageSpecificSiteDataDialogUnitTest() = default;
+
+  PageSpecificSiteDataDialogUnitTest(
+      const PageSpecificSiteDataDialogUnitTest&) = delete;
+  PageSpecificSiteDataDialogUnitTest& operator=(
+      const PageSpecificSiteDataDialogUnitTest&) = delete;
+
+  ~PageSpecificSiteDataDialogUnitTest() override = default;
+
+  content_settings::PageSpecificContentSettings* GetContentSettings() {
+    return content_settings::PageSpecificContentSettings::GetForFrame(
+        main_rfh());
+  }
+
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    NavigateAndCommit(GURL(kCurrentUrl));
+    content_settings::PageSpecificContentSettings::CreateForWebContents(
+        web_contents(),
+        std::make_unique<chrome::PageSpecificContentSettingsDelegate>(
+            web_contents()));
+  }
+};
+
+TEST_F(PageSpecificSiteDataDialogUnitTest, CookieAccessed) {
+  // Verify that site data access through CookiesTreeModel is correctly
+  // displayed in the dialog.
+  auto* content_settings = GetContentSettings();
+
+  std::unique_ptr<net::CanonicalCookie> first_party_cookie(
+      net::CanonicalCookie::Create(GURL(kCurrentUrl), "A=B", base::Time::Now(),
+                                   absl::nullopt /* server_time */,
+                                   absl::nullopt /* cookie_partition_key */));
+  std::unique_ptr<net::CanonicalCookie> third_party_cookie(
+      net::CanonicalCookie::Create(GURL(kThirdPartyUrl), "C=D",
+                                   base::Time::Now(),
+                                   absl::nullopt /* server_time */,
+                                   absl::nullopt /* cookie_partition_key */));
+  ASSERT_TRUE(first_party_cookie);
+  ASSERT_TRUE(third_party_cookie);
+  content_settings->OnCookiesAccessed(
+      {content::CookieAccessDetails::Type::kRead,
+       GURL(kCurrentUrl),
+       GURL(kCurrentUrl),
+       {*first_party_cookie},
+       false});
+  content_settings->OnCookiesAccessed(
+      {content::CookieAccessDetails::Type::kRead,
+       GURL(kThirdPartyUrl),
+       /*firstparty*/ GURL(kCurrentUrl),
+       {*third_party_cookie},
+       false});
+
+  auto delegate =
+      std::make_unique<test::PageSpecificSiteDataDialogTestApi>(web_contents());
+  auto sites = delegate->GetAllSites();
+  ASSERT_EQ(sites.size(), 2u);
+
+  auto first_site = sites[0];
+  EXPECT_EQ(first_site.origin.host(), GURL(kCurrentUrl).host());
+  EXPECT_EQ(first_site.setting, CONTENT_SETTING_ALLOW);
+  EXPECT_EQ(first_site.is_fully_partitioned, false);
+
+  auto second_site = sites[1];
+  EXPECT_EQ(second_site.origin.host(), GURL(kThirdPartyUrl).host());
+  EXPECT_EQ(second_site.setting, CONTENT_SETTING_ALLOW);
+  EXPECT_EQ(second_site.is_fully_partitioned, false);
+}
+
+TEST_F(PageSpecificSiteDataDialogUnitTest, TrustTokenAccessed) {
+  // Verify that site data access through BrowsingDataModel is correctly
+  // displayed in the dialog.]
+  auto* content_settings = GetContentSettings();
+
+  content_settings->OnTrustTokenAccessed(
+      url::Origin::Create(GURL(kThirdPartyUrl)),
+      /*blocked=*/false);
+
+  auto delegate =
+      std::make_unique<test::PageSpecificSiteDataDialogTestApi>(web_contents());
+  auto sites = delegate->GetAllSites();
+  ASSERT_EQ(sites.size(), 1u);
+  auto first_site = sites[0];
+  EXPECT_EQ(first_site.origin.host(), GURL(kThirdPartyUrl).host());
+  EXPECT_EQ(first_site.setting, CONTENT_SETTING_ALLOW);
+  EXPECT_EQ(first_site.is_fully_partitioned, false);
+}
+
+TEST_F(PageSpecificSiteDataDialogUnitTest, MixedModelAccess) {
+  // Verify that site data access through CookiesTreeModel and BrowsingDataModel
+  // is correctly displayed in the dialog.
+  auto* content_settings = GetContentSettings();
+
+  std::unique_ptr<net::CanonicalCookie> third_party_cookie(
+      net::CanonicalCookie::Create(GURL(kThirdPartyUrl), "C=D",
+                                   base::Time::Now(),
+                                   absl::nullopt /* server_time */,
+                                   absl::nullopt /* cookie_partition_key */));
+  ASSERT_TRUE(third_party_cookie);
+  content_settings->OnCookiesAccessed(
+      {content::CookieAccessDetails::Type::kRead,
+       GURL(kThirdPartyUrl),
+       /*firstparty*/ GURL(kCurrentUrl),
+       {*third_party_cookie},
+       false});
+  content_settings->OnTrustTokenAccessed(
+      url::Origin::Create(GURL(kThirdPartyUrl)),
+      /*blocked=*/false);
+
+  auto delegate =
+      std::make_unique<test::PageSpecificSiteDataDialogTestApi>(web_contents());
+  auto sites = delegate->GetAllSites();
+  // kThirdPartyUrl has accessed two types of site data and it's being reported
+  // through two models: CookieTreeModel and BrowsingDataModel. It should be
+  // combined into single entry in the site data dialog.
+  ASSERT_EQ(sites.size(), 1u);
+
+  auto first_site = sites[0];
+  EXPECT_EQ(first_site.origin.host(), GURL(kThirdPartyUrl).host());
+  EXPECT_EQ(first_site.setting, CONTENT_SETTING_ALLOW);
+  EXPECT_EQ(first_site.is_fully_partitioned, false);
+}
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 57a5651..d720c9c 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -53,14 +53,11 @@
 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/extension_status_utils.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
-#include "chrome/browser/web_applications/web_app_icon_manager.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_install_manager.h"
@@ -1308,12 +1305,11 @@
   install_params.add_to_quick_launch_bar = false;
   install_params.add_to_applications_menu = true;
 
-  web_app_provider_->command_manager().ScheduleCommand(
-      std::make_unique<web_app::InstallFromInfoCommand>(
-          std::move(web_app), &web_app_provider_->install_finalizer(),
-          /*overwrite_existing_manifest_fields=*/false,
-          webapps::WebappInstallSource::SYNC,
-          std::move(install_complete_callback), install_params));
+  web_app_provider_->scheduler().InstallFromInfoWithParams(
+      std::move(web_app),
+      /*overwrite_existing_manifest_fields=*/false,
+      webapps::WebappInstallSource::SYNC, std::move(install_complete_callback),
+      install_params);
 }
 
 void AppLauncherHandler::OnExtensionPreferenceChanged() {
diff --git a/chrome/browser/web_applications/commands/install_from_info_command.cc b/chrome/browser/web_applications/commands/install_from_info_command.cc
index cfbb5a1..bf374fb 100644
--- a/chrome/browser/web_applications/commands/install_from_info_command.cc
+++ b/chrome/browser/web_applications/commands/install_from_info_command.cc
@@ -24,7 +24,6 @@
 
 InstallFromInfoCommand::InstallFromInfoCommand(
     std::unique_ptr<WebAppInstallInfo> install_info,
-    WebAppInstallFinalizer* install_finalizer,
     bool overwrite_existing_manifest_fields,
     webapps::WebappInstallSource install_surface,
     OnceInstallCallback install_callback)
@@ -35,14 +34,12 @@
       app_id_(
           GenerateAppId(install_info->manifest_id, install_info->start_url)),
       install_info_(std::move(install_info)),
-      install_finalizer_(install_finalizer),
       overwrite_existing_manifest_fields_(overwrite_existing_manifest_fields),
       install_surface_(install_surface),
       install_callback_(std::move(install_callback)) {}
 
 InstallFromInfoCommand::InstallFromInfoCommand(
     std::unique_ptr<WebAppInstallInfo> install_info,
-    WebAppInstallFinalizer* install_finalizer,
     bool overwrite_existing_manifest_fields,
     webapps::WebappInstallSource install_surface,
     OnceInstallCallback install_callback,
@@ -54,7 +51,6 @@
       app_id_(
           GenerateAppId(install_info->manifest_id, install_info->start_url)),
       install_info_(std::move(install_info)),
-      install_finalizer_(install_finalizer),
       overwrite_existing_manifest_fields_(overwrite_existing_manifest_fields),
       install_surface_(install_surface),
       install_callback_(std::move(install_callback)),
@@ -72,7 +68,9 @@
   return *lock_description_;
 }
 
-void InstallFromInfoCommand::Start() {
+void InstallFromInfoCommand::StartWithLock(std::unique_ptr<AppLock> lock) {
+  lock_ = std::move(lock);
+
   PopulateProductIcons(install_info_.get(),
                        /*icons_map=*/nullptr);
   // No IconsMap to populate shortcut item icons from.
@@ -97,7 +95,7 @@
     options.bypass_os_hooks = true;
   }
 
-  install_finalizer_->FinalizeInstall(
+  lock_->install_finalizer().FinalizeInstall(
       *install_info_, options,
       base::BindOnce(&InstallFromInfoCommand::OnInstallCompleted,
                      weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/web_applications/commands/install_from_info_command.h b/chrome/browser/web_applications/commands/install_from_info_command.h
index 6ff94e4..1f66d29 100644
--- a/chrome/browser/web_applications/commands/install_from_info_command.h
+++ b/chrome/browser/web_applications/commands/install_from_info_command.h
@@ -20,9 +20,9 @@
 
 namespace web_app {
 
+class AppLock;
 class AppLockDescription;
 class LockDescription;
-class WebAppInstallFinalizer;
 
 // Starts a web app installation process using prefilled
 // |install_info| which holds all the data needed for installation.
@@ -37,16 +37,14 @@
 // then the existing web app manifest fields will be overwritten.
 // If `install_info` contains data freshly fetched from the web app's
 // site then `overwrite_existing_manifest_fields` should be true.
-class InstallFromInfoCommand : public WebAppCommand {
+class InstallFromInfoCommand : public WebAppCommandTemplate<AppLock> {
  public:
   InstallFromInfoCommand(std::unique_ptr<WebAppInstallInfo> install_info,
-                         WebAppInstallFinalizer* install_finalizer,
                          bool overwrite_existing_manifest_fields,
                          webapps::WebappInstallSource install_surface,
                          OnceInstallCallback install_callback);
 
   InstallFromInfoCommand(std::unique_ptr<WebAppInstallInfo> install_info,
-                         WebAppInstallFinalizer* install_finalizer,
                          bool overwrite_existing_manifest_fields,
                          webapps::WebappInstallSource install_surface,
                          OnceInstallCallback install_callback,
@@ -56,7 +54,7 @@
 
   LockDescription& lock_description() const override;
 
-  void Start() override;
+  void StartWithLock(std::unique_ptr<AppLock> lock) override;
   void OnSyncSourceRemoved() override;
   void OnShutdown() override;
 
@@ -70,9 +68,10 @@
                           OsHooksErrors os_hooks_errors);
 
   std::unique_ptr<AppLockDescription> lock_description_;
+  std::unique_ptr<AppLock> lock_;
+
   AppId app_id_;
   std::unique_ptr<WebAppInstallInfo> install_info_;
-  raw_ptr<WebAppInstallFinalizer> install_finalizer_;
   bool overwrite_existing_manifest_fields_;
   webapps::WebappInstallSource install_surface_;
   OnceInstallCallback install_callback_;
diff --git a/chrome/browser/web_applications/commands/install_from_info_command_browsertest.cc b/chrome/browser/web_applications/commands/install_from_info_command_browsertest.cc
index 0fcae44..288b4451 100644
--- a/chrome/browser/web_applications/commands/install_from_info_command_browsertest.cc
+++ b/chrome/browser/web_applications/commands/install_from_info_command_browsertest.cc
@@ -13,12 +13,11 @@
 #include "chrome/browser/web_applications/test/fake_os_integration_manager.h"
 #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_icon_manager.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
-#include "chrome/browser/web_applications/web_app_utils.h"
 #include "components/webapps/browser/install_result_code.h"
 #include "content/public/test/browser_test.h"
 #include "install_from_info_command.h"
@@ -68,16 +67,15 @@
 
   base::RunLoop loop;
   AppId result_app_id;
-  provider().command_manager().ScheduleCommand(
-      std::make_unique<InstallFromInfoCommand>(
-          std::move(info), &provider().install_finalizer(),
-          /*overwrite_existing_manifest_fields=*/false, install_source,
-          base::BindLambdaForTesting(
-              [&](const AppId& app_id, webapps::InstallResultCode code) {
-                EXPECT_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
-                result_app_id = app_id;
-                loop.Quit();
-              })));
+  provider().scheduler().InstallFromInfo(
+      std::move(info),
+      /*overwrite_existing_manifest_fields=*/false, install_source,
+      base::BindLambdaForTesting(
+          [&](const AppId& app_id, webapps::InstallResultCode code) {
+            EXPECT_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
+            result_app_id = app_id;
+            loop.Quit();
+          }));
   loop.Run();
 
   EXPECT_TRUE(provider().registrar().IsActivelyInstalled(result_app_id));
@@ -109,18 +107,17 @@
   install_params.add_to_desktop = true;
 
   base::RunLoop loop;
-  provider().command_manager().ScheduleCommand(
-      std::make_unique<InstallFromInfoCommand>(
-          std::move(info), &provider().install_finalizer(),
-          /*overwrite_existing_manifest_fields=*/false,
-          webapps::WebappInstallSource::MENU_BROWSER_TAB,
-          base::BindLambdaForTesting(
-              [&](const AppId& app_id, webapps::InstallResultCode code) {
-                EXPECT_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
-                EXPECT_TRUE(provider().registrar().IsActivelyInstalled(app_id));
-                loop.Quit();
-              }),
-          install_params));
+  provider().scheduler().InstallFromInfoWithParams(
+      std::move(info),
+      /*overwrite_existing_manifest_fields=*/false,
+      webapps::WebappInstallSource::MENU_BROWSER_TAB,
+      base::BindLambdaForTesting(
+          [&](const AppId& app_id, webapps::InstallResultCode code) {
+            EXPECT_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
+            EXPECT_TRUE(provider().registrar().IsActivelyInstalled(app_id));
+            loop.Quit();
+          }),
+      install_params);
   loop.Run();
   EXPECT_EQ(provider()
                 .os_integration_manager()
diff --git a/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc b/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc
index 6a8ee1d..3d30d20 100644
--- a/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc
@@ -34,7 +34,7 @@
 #include "chrome/browser/web_applications/test/web_app_test_utils.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_data_retriever.h"
 #include "chrome/browser/web_applications/web_app_id.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
@@ -303,7 +303,7 @@
     auto* provider = FakeWebAppProvider::Get(profile());
     provider->SetDefaultFakeSubsystems();
     registrar_ = &provider->GetRegistrarMutable();
-    command_manager_ = &provider->GetCommandManager();
+    command_scheduler_ = &provider->scheduler();
     ui_manager_ = static_cast<FakeWebAppUiManager*>(&provider->GetUiManager());
 
     auto install_finalizer =
@@ -329,7 +329,7 @@
   TestExternallyManagedAppInstallFinalizer* finalizer() {
     return install_finalizer_;
   }
-  WebAppCommandManager* command_manager() { return command_manager_; }
+  WebAppCommandScheduler* command_scheduler() { return command_scheduler_; }
 
   FakeDataRetriever* data_retriever() { return data_retriever_; }
 
@@ -367,7 +367,7 @@
 
     auto task = std::make_unique<ExternallyManagedAppInstallTask>(
         profile(), url_loader_.get(), registrar_, ui_manager_,
-        install_finalizer_, command_manager_, std::move(options));
+        install_finalizer_, command_scheduler_, std::move(options));
     task->SetDataRetrieverFactoryForTesting(
         GetFactoryForRetriever(std::move(data_retriever)));
     return task;
@@ -375,7 +375,7 @@
 
  private:
   std::unique_ptr<TestWebAppUrlLoader> url_loader_;
-  raw_ptr<WebAppCommandManager> command_manager_ = nullptr;
+  raw_ptr<WebAppCommandScheduler> command_scheduler_ = nullptr;
   raw_ptr<WebAppRegistrar> registrar_ = nullptr;
   raw_ptr<FakeDataRetriever> data_retriever_ = nullptr;
   raw_ptr<TestExternallyManagedAppInstallFinalizer> install_finalizer_ =
@@ -874,7 +874,7 @@
         ExternalInstallSource::kInternalDefault);
     ExternallyManagedAppInstallTask install_task(
         profile(), &url_loader(), registrar(), ui_manager(), finalizer(),
-        command_manager(), install_options);
+        command_scheduler(), install_options);
     url_loader().SetPrepareForLoadResultLoaded();
     url_loader().SetNextLoadUrlResult(GURL(), result_pair.loader_result);
 
@@ -896,7 +896,7 @@
       ExternalInstallSource::kInternalDefault);
   ExternallyManagedAppInstallTask install_task(
       profile(), &url_loader(), registrar(), ui_manager(), finalizer(),
-      command_manager(), install_options);
+      command_scheduler(), install_options);
   url_loader().SetPrepareForLoadResultLoaded();
   url_loader().SetNextLoadUrlResult(
       GURL(), WebAppUrlLoader::Result::kFailedWebContentsDestroyed);
@@ -924,7 +924,7 @@
 
   ExternallyManagedAppInstallTask task(profile(), /*url_loader=*/nullptr,
                                        registrar(), ui_manager(), finalizer(),
-                                       command_manager(), std::move(options));
+                                       command_scheduler(), std::move(options));
 
   finalizer()->SetNextFinalizeInstallResult(
       kWebAppUrl, webapps::InstallResultCode::kSuccessNewInstall);
@@ -971,7 +971,7 @@
 
   ExternallyManagedAppInstallTask task(profile(), /*url_loader=*/nullptr,
                                        registrar(), ui_manager(), finalizer(),
-                                       command_manager(), std::move(options));
+                                       command_scheduler(), std::move(options));
 
   finalizer()->SetNextFinalizeInstallResult(
       kWebAppUrl, webapps::InstallResultCode::kWriteDataFailed);
diff --git a/chrome/browser/web_applications/externally_managed_app_install_task.cc b/chrome/browser/web_applications/externally_managed_app_install_task.cc
index bb07e913..85cd331 100644
--- a/chrome/browser/web_applications/externally_managed_app_install_task.cc
+++ b/chrome/browser/web_applications/externally_managed_app_install_task.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_data_retriever.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
@@ -53,13 +53,13 @@
     WebAppRegistrar* registrar,
     WebAppUiManager* ui_manager,
     WebAppInstallFinalizer* install_finalizer,
-    WebAppCommandManager* command_manager,
+    WebAppCommandScheduler* command_scheduler,
     ExternalInstallOptions install_options)
     : profile_(profile),
       url_loader_(url_loader),
       registrar_(registrar),
       install_finalizer_(install_finalizer),
-      command_manager_(command_manager),
+      command_scheduler_(command_scheduler),
       ui_manager_(ui_manager),
       externally_installed_app_prefs_(profile_->GetPrefs()),
       install_options_(std::move(install_options)) {}
@@ -177,14 +177,14 @@
     web_app_info->additional_search_terms.push_back(std::move(search_term));
   }
   web_app_info->install_url = install_params.install_url;
-  command_manager_->ScheduleCommand(std::make_unique<InstallFromInfoCommand>(
-      std::move(web_app_info), install_finalizer_,
+  command_scheduler_->InstallFromInfoWithParams(
+      std::move(web_app_info),
       /*overwrite_existing_manifest_fields=*/install_params.force_reinstall,
       internal_install_source,
       base::BindOnce(&ExternallyManagedAppInstallTask::OnWebAppInstalled,
                      weak_ptr_factory_.GetWeakPtr(), /* is_placeholder=*/false,
                      /*offline_install=*/true, std::move(result_callback)),
-      install_params));
+      install_params);
 }
 
 void ExternallyManagedAppInstallTask::UninstallPlaceholderApp(
@@ -235,14 +235,13 @@
         []() { return std::make_unique<WebAppDataRetriever>(); });
   }
 
-  command_manager_->ScheduleCommand(
-      std::make_unique<ExternallyManagedInstallCommand>(
-          install_options_,
-          base::BindOnce(&ExternallyManagedAppInstallTask::OnWebAppInstalled,
-                         weak_ptr_factory_.GetWeakPtr(),
-                         /*is_placeholder=*/false,
-                         /*offline_install=*/false, std::move(result_callback)),
-          web_contents->GetWeakPtr(), data_retriever_factory_.Run()));
+  command_scheduler_->InstallExternallyManagedApp(
+      install_options_,
+      base::BindOnce(&ExternallyManagedAppInstallTask::OnWebAppInstalled,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     /*is_placeholder=*/false,
+                     /*offline_install=*/false, std::move(result_callback)),
+      web_contents->GetWeakPtr(), data_retriever_factory_.Run());
 }
 
 void ExternallyManagedAppInstallTask::InstallPlaceholder(
diff --git a/chrome/browser/web_applications/externally_managed_app_install_task.h b/chrome/browser/web_applications/externally_managed_app_install_task.h
index 20f4d4d..346d74c 100644
--- a/chrome/browser/web_applications/externally_managed_app_install_task.h
+++ b/chrome/browser/web_applications/externally_managed_app_install_task.h
@@ -35,7 +35,7 @@
 
 class WebAppUrlLoader;
 class WebAppInstallFinalizer;
-class WebAppCommandManager;
+class WebAppCommandScheduler;
 class WebAppUiManager;
 class WebAppDataRetriever;
 
@@ -55,7 +55,7 @@
       WebAppRegistrar* registrar,
       WebAppUiManager* ui_manager,
       WebAppInstallFinalizer* install_finalizer,
-      WebAppCommandManager* command_manager,
+      WebAppCommandScheduler* command_scheduler,
       ExternalInstallOptions install_options);
 
   ExternallyManagedAppInstallTask(const ExternallyManagedAppInstallTask&) =
@@ -139,7 +139,7 @@
   const raw_ptr<WebAppUrlLoader, DanglingUntriaged> url_loader_;
   const raw_ptr<WebAppRegistrar> registrar_;
   const raw_ptr<WebAppInstallFinalizer> install_finalizer_;
-  const raw_ptr<WebAppCommandManager> command_manager_;
+  const raw_ptr<WebAppCommandScheduler> command_scheduler_;
   const raw_ptr<WebAppUiManager> ui_manager_;
 
   ExternallyInstalledWebAppPrefs externally_installed_app_prefs_;
diff --git a/chrome/browser/web_applications/externally_managed_app_manager.cc b/chrome/browser/web_applications/externally_managed_app_manager.cc
index ee64b2b9..85a9c1c9 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager.cc
+++ b/chrome/browser/web_applications/externally_managed_app_manager.cc
@@ -75,12 +75,12 @@
     WebAppRegistrar* registrar,
     WebAppUiManager* ui_manager,
     WebAppInstallFinalizer* finalizer,
-    WebAppCommandManager* command_manager,
+    WebAppCommandScheduler* command_scheduler,
     WebAppSyncBridge* sync_bridge) {
   registrar_ = registrar;
   ui_manager_ = ui_manager;
   finalizer_ = finalizer;
-  command_manager_ = command_manager;
+  command_scheduler_ = command_scheduler;
   sync_bridge_ = sync_bridge;
 }
 
diff --git a/chrome/browser/web_applications/externally_managed_app_manager.h b/chrome/browser/web_applications/externally_managed_app_manager.h
index 7df3952..1b7eb9d0 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager.h
+++ b/chrome/browser/web_applications/externally_managed_app_manager.h
@@ -26,7 +26,7 @@
 
 class WebAppRegistrar;
 class WebAppInstallFinalizer;
-class WebAppCommandManager;
+class WebAppCommandScheduler;
 class WebAppUiManager;
 class WebAppSyncBridge;
 
@@ -92,7 +92,7 @@
   void SetSubsystems(WebAppRegistrar* registrar,
                      WebAppUiManager* ui_manager,
                      WebAppInstallFinalizer* finalizer,
-                     WebAppCommandManager* command_manager,
+                     WebAppCommandScheduler* command_scheduler,
                      WebAppSyncBridge* sync_bridge);
 
   // Queues an installation operation with the highest priority. Essentially
@@ -162,7 +162,7 @@
   WebAppRegistrar* registrar() { return registrar_; }
   WebAppUiManager* ui_manager() { return ui_manager_; }
   WebAppInstallFinalizer* finalizer() { return finalizer_; }
-  WebAppCommandManager* command_manager() { return command_manager_; }
+  WebAppCommandScheduler* command_scheduler() { return command_scheduler_; }
   WebAppSyncBridge* sync_bridge() { return sync_bridge_; }
 
   virtual void OnRegistrationFinished(const GURL& launch_url,
@@ -202,7 +202,8 @@
   raw_ptr<WebAppRegistrar> registrar_ = nullptr;
   raw_ptr<WebAppUiManager, DanglingUntriaged> ui_manager_ = nullptr;
   raw_ptr<WebAppInstallFinalizer> finalizer_ = nullptr;
-  raw_ptr<WebAppCommandManager, DanglingUntriaged> command_manager_ = nullptr;
+  raw_ptr<WebAppCommandScheduler, DanglingUntriaged> command_scheduler_ =
+      nullptr;
   raw_ptr<WebAppSyncBridge> sync_bridge_ = nullptr;
 
   base::flat_map<ExternalInstallSource, SynchronizeRequest>
diff --git a/chrome/browser/web_applications/externally_managed_app_manager_impl.cc b/chrome/browser/web_applications/externally_managed_app_manager_impl.cc
index 747ad8b..a0670f4 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager_impl.cc
+++ b/chrome/browser/web_applications/externally_managed_app_manager_impl.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/externally_managed_app_registration_task.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
 #include "chrome/browser/web_applications/web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
@@ -124,7 +124,7 @@
     ExternalInstallOptions install_options) {
   return std::make_unique<ExternallyManagedAppInstallTask>(
       profile_, url_loader_.get(), registrar(), ui_manager(), finalizer(),
-      command_manager(), std::move(install_options));
+      command_scheduler(), std::move(install_options));
 }
 
 std::unique_ptr<ExternallyManagedAppRegistrationTaskBase>
diff --git a/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc b/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc
index d5ecce3..737c683 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc
+++ b/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc
@@ -33,7 +33,7 @@
 #include "chrome/browser/web_applications/test/web_app_test_utils.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
@@ -284,7 +284,7 @@
               externally_managed_app_manager_impl->registrar(),
               externally_managed_app_manager_impl->ui_manager(),
               externally_managed_app_manager_impl->finalizer(),
-              externally_managed_app_manager_impl->command_manager(),
+              externally_managed_app_manager_impl->command_scheduler(),
               std::move(install_options)),
           externally_managed_app_manager_impl_(
               externally_managed_app_manager_impl),
@@ -448,7 +448,7 @@
   }
 
   void TearDown() override {
-    command_manager().Shutdown();
+    command_scheduler().Shutdown();
     WebAppTest::TearDown();
   }
 
@@ -578,9 +578,7 @@
 
   FakeInstallFinalizer& install_finalizer() { return *install_finalizer_; }
 
-  WebAppCommandManager& command_manager() {
-    return provider().command_manager();
-  }
+  WebAppCommandScheduler& command_scheduler() { return provider().scheduler(); }
 
  private:
   raw_ptr<FakeWebAppProvider> provider_;
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc b/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc
index 4b3ef8d1..68afd03 100644
--- a/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc
+++ b/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc
@@ -10,13 +10,12 @@
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/externally_installed_web_app_prefs.h"
 #include "chrome/browser/web_applications/policy/web_app_policy_constants.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/test/web_app_test_observers.h"
 #include "chrome/browser/web_applications/test/web_app_test_utils.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_id.h"
@@ -227,11 +226,10 @@
                                install_info.get());
 
   auto* provider = WebAppProvider::GetForTest(profile());
-  provider->command_manager().ScheduleCommand(
-      std::make_unique<InstallFromInfoCommand>(
-          std::move(install_info), &provider->install_finalizer(),
-          /*overwrite_existing_manifest_fields=*/true,
-          webapps::WebappInstallSource::EXTERNAL_POLICY, base::DoNothing()));
+  provider->scheduler().InstallFromInfo(
+      std::move(install_info),
+      /*overwrite_existing_manifest_fields=*/true,
+      webapps::WebappInstallSource::EXTERNAL_POLICY, base::DoNothing());
 
   externally_installed_app_prefs().Insert(
       GURL(kInstallUrl), GenerateAppId(absl::nullopt, GURL(kStartUrl)),
diff --git a/chrome/browser/web_applications/test/web_app_install_test_utils.cc b/chrome/browser/web_applications/test/web_app_install_test_utils.cc
index 66ef599..7335be2 100644
--- a/chrome/browser/web_applications/test/web_app_install_test_utils.cc
+++ b/chrome/browser/web_applications/test/web_app_install_test_utils.cc
@@ -9,10 +9,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "build/build_config.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/test/fake_web_app_provider.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
@@ -85,16 +84,15 @@
   // In unit tests, we do not have Browser or WebContents instances. Hence we
   // use `InstallFromInfoCommand` instead of `FetchManifestAndInstallCommand` or
   // `WebAppInstallCommand` to install the web app.
-  provider->command_manager().ScheduleCommand(
-      std::make_unique<InstallFromInfoCommand>(
-          std::move(web_app_info), &provider->install_finalizer(),
-          overwrite_existing_manifest_fields, install_source,
-          base::BindLambdaForTesting([&](const AppId& installed_app_id,
-                                         webapps::InstallResultCode code) {
+  provider->scheduler().InstallFromInfo(
+      std::move(web_app_info), overwrite_existing_manifest_fields,
+      install_source,
+      base::BindLambdaForTesting(
+          [&](const AppId& installed_app_id, webapps::InstallResultCode code) {
             EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, code);
             app_id = installed_app_id;
             run_loop.Quit();
-          })));
+          }));
 
   run_loop.Run();
   // Allow updates to be published to App Service listeners.
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.cc b/chrome/browser/web_applications/web_app_command_scheduler.cc
index 337e9ef..012e705 100644
--- a/chrome/browser/web_applications/web_app_command_scheduler.cc
+++ b/chrome/browser/web_applications/web_app_command_scheduler.cc
@@ -7,8 +7,10 @@
 #include "base/functional/bind.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/commands/callback_command.h"
+#include "chrome/browser/web_applications/commands/externally_managed_install_command.h"
 #include "chrome/browser/web_applications/commands/fetch_installability_for_chrome_management.h"
 #include "chrome/browser/web_applications/commands/fetch_manifest_and_install_command.h"
+#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/commands/manifest_update_data_fetch_command.h"
 #include "chrome/browser/web_applications/commands/manifest_update_finalize_command.h"
 #include "chrome/browser/web_applications/commands/run_on_os_login_command.h"
@@ -79,6 +81,79 @@
           std::make_unique<WebAppDataRetriever>()));
 }
 
+void WebAppCommandScheduler::InstallFromInfo(
+    std::unique_ptr<WebAppInstallInfo> install_info,
+    bool overwrite_existing_manifest_fields,
+    webapps::WebappInstallSource install_surface,
+    OnceInstallCallback install_callback) {
+  if (is_in_shutdown_)
+    return;
+
+  if (!provider_->is_registry_ready()) {
+    provider_->on_registry_ready().Post(
+        FROM_HERE,
+        base::BindOnce(&WebAppCommandScheduler::InstallFromInfo,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(install_info),
+                       overwrite_existing_manifest_fields,
+                       std::move(install_surface),
+                       std::move(install_callback)));
+    return;
+  }
+  provider_->command_manager().ScheduleCommand(
+      std::make_unique<InstallFromInfoCommand>(
+          std::move(install_info), overwrite_existing_manifest_fields,
+          std::move(install_surface), std::move(install_callback)));
+}
+
+void WebAppCommandScheduler::InstallFromInfoWithParams(
+    std::unique_ptr<WebAppInstallInfo> install_info,
+    bool overwrite_existing_manifest_fields,
+    webapps::WebappInstallSource install_surface,
+    OnceInstallCallback install_callback,
+    const WebAppInstallParams& install_params) {
+  if (is_in_shutdown_)
+    return;
+
+  if (!provider_->is_registry_ready()) {
+    provider_->on_registry_ready().Post(
+        FROM_HERE,
+        base::BindOnce(&WebAppCommandScheduler::InstallFromInfoWithParams,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(install_info),
+                       overwrite_existing_manifest_fields,
+                       std::move(install_surface), std::move(install_callback),
+                       install_params));
+    return;
+  }
+  provider_->command_manager().ScheduleCommand(
+      std::make_unique<InstallFromInfoCommand>(
+          std::move(install_info), overwrite_existing_manifest_fields,
+          std::move(install_surface), std::move(install_callback),
+          install_params));
+}
+
+void WebAppCommandScheduler::InstallExternallyManagedApp(
+    const ExternalInstallOptions& external_install_options,
+    OnceInstallCallback callback,
+    base::WeakPtr<content::WebContents> contents,
+    std::unique_ptr<WebAppDataRetriever> data_retriever) {
+  if (is_in_shutdown_)
+    return;
+
+  if (!provider_->is_registry_ready()) {
+    provider_->on_registry_ready().Post(
+        FROM_HERE,
+        base::BindOnce(&WebAppCommandScheduler::InstallExternallyManagedApp,
+                       weak_ptr_factory_.GetWeakPtr(), external_install_options,
+                       std::move(callback), contents,
+                       std::move(data_retriever)));
+    return;
+  }
+  provider_->command_manager().ScheduleCommand(
+      std::make_unique<ExternallyManagedInstallCommand>(
+          external_install_options, std::move(callback), contents,
+          std::move(data_retriever)));
+}
+
 void WebAppCommandScheduler::PersistFileHandlersUserChoice(
     const AppId& app_id,
     bool allowed,
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.h b/chrome/browser/web_applications/web_app_command_scheduler.h
index 66f9689..0a790944 100644
--- a/chrome/browser/web_applications/web_app_command_scheduler.h
+++ b/chrome/browser/web_applications/web_app_command_scheduler.h
@@ -12,12 +12,15 @@
 #include "chrome/browser/web_applications/commands/install_isolated_web_app_command.h"
 #include "chrome/browser/web_applications/commands/manifest_update_data_fetch_command.h"
 #include "chrome/browser/web_applications/commands/manifest_update_finalize_command.h"
+#include "chrome/browser/web_applications/external_install_options.h"
 #include "chrome/browser/web_applications/web_app_install_params.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
 
 class GURL;
 class Profile;
 
+struct WebAppInstallInfo;
+
 namespace content {
 class WebContents;
 }  // namespace content
@@ -25,6 +28,7 @@
 namespace web_app {
 
 class IsolatedWebAppUrlInfo;
+class WebAppDataRetriever;
 class WebAppProvider;
 struct IsolationData;
 
@@ -60,6 +64,27 @@
                                OnceInstallCallback callback,
                                bool use_fallback);
 
+  // Install with provided `WebAppInstallInfo` instead of fetching data from
+  // manifest.
+  void InstallFromInfo(std::unique_ptr<WebAppInstallInfo> install_info,
+                       bool overwrite_existing_manifest_fields,
+                       webapps::WebappInstallSource install_surface,
+                       OnceInstallCallback install_callback);
+
+  void InstallFromInfoWithParams(
+      std::unique_ptr<WebAppInstallInfo> install_info,
+      bool overwrite_existing_manifest_fields,
+      webapps::WebappInstallSource install_surface,
+      OnceInstallCallback install_callback,
+      const WebAppInstallParams& install_params);
+
+  // Install web apps managed by `ExternallyInstalledAppsManager`.
+  void InstallExternallyManagedApp(
+      const ExternalInstallOptions& external_install_options,
+      OnceInstallCallback callback,
+      base::WeakPtr<content::WebContents> contents,
+      std::unique_ptr<WebAppDataRetriever> data_retriever);
+
   void PersistFileHandlersUserChoice(const AppId& app_id,
                                      bool allowed,
                                      base::OnceClosure callback);
diff --git a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
index 8f5da08..c118a61 100644
--- a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
@@ -13,10 +13,9 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/web_applications/web_app_browser_controller.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
-#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_icon_generator.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_install_utils.h"
@@ -90,18 +89,17 @@
     base::RunLoop run_loop;
 
     auto* provider = WebAppProvider::GetForTest(browser()->profile());
-    provider->command_manager().ScheduleCommand(
-        std::make_unique<InstallFromInfoCommand>(
-            std::move(install_info), &provider->install_finalizer(),
-            /*overwrite_existing_manifest_fields=*/false,
-            webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON,
-            base::BindLambdaForTesting([&app_id, &run_loop](
-                                           const AppId& installed_app_id,
-                                           webapps::InstallResultCode code) {
+    provider->scheduler().InstallFromInfo(
+        std::move(install_info),
+        /*overwrite_existing_manifest_fields=*/false,
+        webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON,
+        base::BindLambdaForTesting(
+            [&app_id, &run_loop](const AppId& installed_app_id,
+                                 webapps::InstallResultCode code) {
               EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, code);
               app_id = installed_app_id;
               run_loop.Quit();
-            })));
+            }));
 
     run_loop.Run();
   }
diff --git a/chrome/browser/web_applications/web_app_install_manager_unittest.cc b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
index 4644b00..386e1ce3 100644
--- a/chrome/browser/web_applications/web_app_install_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
@@ -20,7 +20,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/traits_bag.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/commands/web_app_command.h"
 #include "chrome/browser/web_applications/commands/web_app_uninstall_command.h"
 #include "chrome/browser/web_applications/test/fake_data_retriever.h"
@@ -37,6 +36,7 @@
 #include "chrome/browser/web_applications/user_uninstalled_preinstalled_web_app_prefs.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_data_retriever.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_icon_generator.h"
@@ -188,15 +188,15 @@
       webapps::WebappInstallSource install_source) {
     InstallResult result;
     base::RunLoop run_loop;
-    command_manager().ScheduleCommand(std::make_unique<InstallFromInfoCommand>(
-        std::move(install_info), &finalizer(),
-        overwrite_existing_manifest_fields, install_source,
+    provider().scheduler().InstallFromInfo(
+        std::move(install_info), overwrite_existing_manifest_fields,
+        install_source,
         base::BindLambdaForTesting([&](const AppId& installed_app_id,
                                        webapps::InstallResultCode code) {
           result.app_id = installed_app_id;
           result.code = code;
           run_loop.Quit();
-        })));
+        }));
 
     run_loop.Run();
     return result;
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 888685e..a4c967d 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -321,7 +321,7 @@
       command_scheduler_.get());
   externally_managed_app_manager_->SetSubsystems(
       registrar_.get(), ui_manager_.get(), install_finalizer_.get(),
-      command_manager_.get(), sync_bridge_.get());
+      command_scheduler_.get(), sync_bridge_.get());
   preinstalled_web_app_manager_->SetSubsystems(
       registrar_.get(), ui_manager_.get(),
       externally_managed_app_manager_.get());
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 890e302..9077140d 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1668664741-b8160182596fd53398d6aec23a6ad9e1b33f6565.profdata
+chrome-mac-arm-main-1668686205-641aaf02f1e4b397854cff3b7172b4f527f10d49.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 9092f79..77faceb8 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1668675513-1137b50debfe2732fa5feb7b90eb659f8003b970.profdata
+chrome-win64-main-1668686205-267f0d844bd5ca130f55ff4225213ff7a6ad0450.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 5a86bc5..37d7fb6 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6761,7 +6761,6 @@
       "../browser/resource_coordinator/tab_activity_watcher_unittest.cc",
       "../browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc",
       "../browser/resource_coordinator/tab_lifecycle_unit_unittest.cc",
-      "../browser/resource_coordinator/tab_manager_stats_collector_unittest.cc",
       "../browser/resource_coordinator/tab_manager_unittest.cc",
       "../browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc",
       "../browser/resource_coordinator/tab_memory_metrics_reporter_unittest.cc",
@@ -8911,6 +8910,7 @@
       "../browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc",
       "../browser/ui/views/side_panel/side_panel_coordinator_unittest.cc",
       "../browser/ui/views/side_panel/user_note/user_note_ui_coordinator_unittest.cc",
+      "../browser/ui/views/site_data/page_specific_site_data_dialog_unittest.cc",
       "../browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views_unittest.cc",
       "../browser/ui/views/tabs/color_picker_view_unittest.cc",
       "../browser/ui/views/tabs/compound_tab_container_unittest.cc",
diff --git a/chrome/test/data/webui/new_tab_page/modules/recipes/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/recipes/module_test.ts
index 028de542..1b204a9b 100644
--- a/chrome/test/data/webui/new_tab_page/modules/recipes/module_test.ts
+++ b/chrome/test/data/webui/new_tab_page/modules/recipes/module_test.ts
@@ -212,7 +212,10 @@
     const restoreCallback = dismissEvent.detail.restoreCallback;
 
     // Assert.
-    assertEquals('Recipe ideas hidden', toastMessage);
+    const moduleHeaderTitle =
+        moduleElement.shadowRoot!.querySelector(
+                                     'ntp-module-header')!.textContent!.trim();
+    assertEquals(moduleHeaderTitle + ' hidden', toastMessage);
     assertEquals('Hello world', await handler.whenCalled('dismissTask'));
 
     // Act.
diff --git a/chrome/test/payments/payment_request_test_controller_desktop.cc b/chrome/test/payments/payment_request_test_controller_desktop.cc
index 382c222e..d91e7782 100644
--- a/chrome/test/payments/payment_request_test_controller_desktop.cc
+++ b/chrome/test/payments/payment_request_test_controller_desktop.cc
@@ -215,12 +215,6 @@
          content::RenderFrameHost* render_frame_host) {
         DCHECK(render_frame_host);
         DCHECK(render_frame_host->IsActive());
-        auto* web_contents =
-            content::WebContents::FromRenderFrameHost(render_frame_host);
-        DCHECK(web_contents);
-        auto* manager =
-            PaymentRequestWebContentsManager::GetOrCreateForWebContents(
-                *web_contents);
 
         auto delegate = std::make_unique<TestChromePaymentRequestDelegate>(
             render_frame_host);
@@ -239,12 +233,12 @@
               ->SetAppForTesting(twa_package_name, twa_payment_app_method_name,
                                  twa_payment_app_response);
         }
-        auto display_manager = delegate->GetDisplayManager()->GetWeakPtr();
+
         // PaymentRequest is a DocumentService, whose lifetime is managed by the
-        // RenderFrameHost passed in here.
-        new PaymentRequest(*render_frame_host, std::move(delegate),
-                           std::move(display_manager), std::move(receiver),
-                           manager->transaction_mode(), observer_for_test);
+        // RenderFrameHost passed into the delegate.
+        auto* request =
+            new PaymentRequest(std::move(delegate), std::move(receiver));
+        request->set_observer_for_test(observer_for_test);
       },
       observer_converter_->GetWeakPtr(), is_off_the_record_, valid_ssl_,
       prefs_.get(), twa_package_name_, has_authenticator_,
diff --git a/chrome/updater/app/server/win/service_main.cc b/chrome/updater/app/server/win/service_main.cc
index 931bfb2..765e42e 100644
--- a/chrome/updater/app/server/win/service_main.cc
+++ b/chrome/updater/app/server/win/service_main.cc
@@ -209,10 +209,30 @@
   sd.SetOwner(Sids::Admins());
   sd.SetGroup(Sids::Admins());
 
+  // These are the flags being set:
+  // EOAC_DYNAMIC_CLOAKING: DCOM uses the thread token (if present) when
+  //   determining the client's identity. Useful when impersonating another
+  //   user.
+  // EOAC_SECURE_REFS: Authenticates distributed reference count calls to
+  //   prevent malicious users from releasing objects that are still being used.
+  // EOAC_DISABLE_AAA: Causes any activation where a server process would be
+  //   launched under the caller's identity (activate-as-activator) to fail with
+  //   E_ACCESSDENIED.
+  // EOAC_NO_CUSTOM_MARSHAL: reduces the chances of executing arbitrary DLLs
+  //   because it allows the marshaling of only CLSIDs that are implemented in
+  //   Ole32.dll, ComAdmin.dll, ComSvcs.dll, or Es.dll, or that implement the
+  //   CATID_MARSHALER category ID.
+  // RPC_C_AUTHN_LEVEL_PKT_PRIVACY: prevents replay attacks, verifies that none
+  //   of the data transferred between the client and server has been modified,
+  //   ensures that the data transferred can only be seen unencrypted by the
+  //   client and the server.
   return ::CoInitializeSecurity(
       const_cast<SECURITY_DESCRIPTOR*>(sd.GetPSECURITY_DESCRIPTOR()), -1,
       nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY,
-      nullptr, EOAC_DYNAMIC_CLOAKING | EOAC_NO_CUSTOM_MARSHAL, nullptr);
+      nullptr,
+      EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_SECURE_REFS |
+          EOAC_NO_CUSTOM_MARSHAL,
+      nullptr);
 }
 
 }  // namespace updater
diff --git a/chrome/updater/util/win_util.cc b/chrome/updater/util/win_util.cc
index 13bbfbe3..6f6d50d 100644
--- a/chrome/updater/util/win_util.cc
+++ b/chrome/updater/util/win_util.cc
@@ -202,94 +202,6 @@
   return (error_code != NO_ERROR) ? HRESULT_FROM_WIN32(error_code) : E_FAIL;
 }
 
-// This sets up COM security to allow NetworkService, LocalService, and System
-// to call back into the process. It is largely inspired by
-// http://msdn.microsoft.com/en-us/library/windows/desktop/aa378987.aspx
-// static
-bool InitializeCOMSecurity() {
-  // Create the security descriptor explicitly as follows because
-  // CoInitializeSecurity() will not accept the relative security descriptors
-  // returned by ConvertStringSecurityDescriptorToSecurityDescriptor().
-  const size_t kSidCount = 5;
-  uint64_t* sids[kSidCount][(SECURITY_MAX_SID_SIZE + sizeof(uint64_t) - 1) /
-                            sizeof(uint64_t)] = {
-      {}, {}, {}, {}, {},
-  };
-
-  // These are ordered by most interesting ones to try first.
-  WELL_KNOWN_SID_TYPE sid_types[kSidCount] = {
-      WinBuiltinAdministratorsSid,  // administrator group security identifier
-      WinLocalServiceSid,           // local service security identifier
-      WinNetworkServiceSid,         // network service security identifier
-      WinSelfSid,                   // personal account security identifier
-      WinLocalSystemSid,            // local system security identifier
-  };
-
-  // This creates a security descriptor that is equivalent to the following
-  // security descriptor definition language (SDDL) string:
-  //   O:BAG:BAD:(A;;0x1;;;LS)(A;;0x1;;;NS)(A;;0x1;;;PS)
-  //   (A;;0x1;;;SY)(A;;0x1;;;BA)
-
-  // Initialize the security descriptor.
-  SECURITY_DESCRIPTOR security_desc = {};
-  if (!::InitializeSecurityDescriptor(&security_desc,
-                                      SECURITY_DESCRIPTOR_REVISION))
-    return false;
-
-  DCHECK_EQ(kSidCount, std::size(sids));
-  DCHECK_EQ(kSidCount, std::size(sid_types));
-  for (size_t i = 0; i < kSidCount; ++i) {
-    DWORD sid_bytes = sizeof(sids[i]);
-    if (!::CreateWellKnownSid(sid_types[i], nullptr, sids[i], &sid_bytes))
-      return false;
-  }
-
-  // Setup the access control entries (ACE) for COM. You may need to modify
-  // the access permissions for your application. COM_RIGHTS_EXECUTE and
-  // COM_RIGHTS_EXECUTE_LOCAL are the minimum access rights required.
-  EXPLICIT_ACCESS explicit_access[kSidCount] = {};
-  DCHECK_EQ(kSidCount, std::size(sids));
-  DCHECK_EQ(kSidCount, std::size(explicit_access));
-  for (size_t i = 0; i < kSidCount; ++i) {
-    explicit_access[i].grfAccessPermissions =
-        COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL;
-    explicit_access[i].grfAccessMode = SET_ACCESS;
-    explicit_access[i].grfInheritance = NO_INHERITANCE;
-    explicit_access[i].Trustee.pMultipleTrustee = nullptr;
-    explicit_access[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
-    explicit_access[i].Trustee.TrusteeForm = TRUSTEE_IS_SID;
-    explicit_access[i].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
-    explicit_access[i].Trustee.ptstrName = reinterpret_cast<LPTSTR>(sids[i]);
-  }
-
-  // Create an access control list (ACL) using this ACE list, if this succeeds
-  // make sure to ::LocalFree(acl).
-  ACL* acl = nullptr;
-  DWORD acl_result = ::SetEntriesInAcl(std::size(explicit_access),
-                                       explicit_access, nullptr, &acl);
-  if (acl_result != ERROR_SUCCESS || acl == nullptr)
-    return false;
-
-  HRESULT hr = E_FAIL;
-
-  // Set the security descriptor owner and group to Administrators and set the
-  // discretionary access control list (DACL) to the ACL.
-  if (::SetSecurityDescriptorOwner(&security_desc, sids[0], FALSE) &&
-      ::SetSecurityDescriptorGroup(&security_desc, sids[0], FALSE) &&
-      ::SetSecurityDescriptorDacl(&security_desc, TRUE, acl, FALSE)) {
-    // Initialize COM. You may need to modify the parameters of
-    // CoInitializeSecurity() for your application. Note that an
-    // explicit security descriptor is being passed down.
-    hr = ::CoInitializeSecurity(
-        &security_desc, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
-        RPC_C_IMP_LEVEL_IDENTIFY, nullptr,
-        EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL, nullptr);
-  }
-
-  ::LocalFree(acl);
-  return SUCCEEDED(hr);
-}
-
 HMODULE GetModuleHandleFromAddress(void* address) {
   MEMORY_BASIC_INFORMATION mbi = {0};
   size_t result = ::VirtualQuery(address, &mbi, sizeof(mbi));
diff --git a/chrome/updater/util/win_util.h b/chrome/updater/util/win_util.h
index 4b0c08c5..d763cff 100644
--- a/chrome/updater/util/win_util.h
+++ b/chrome/updater/util/win_util.h
@@ -102,8 +102,6 @@
 // Returns true if every running processes are stopped.
 bool WaitForProcessesStopped(const wchar_t* executable);
 
-bool InitializeCOMSecurity();
-
 // Gets the handle to the module containing the given executing address.
 HMODULE GetModuleHandleFromAddress(void* address);
 
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn
index 741cbc1..a9bc66a 100644
--- a/chromecast/app/BUILD.gn
+++ b/chromecast/app/BUILD.gn
@@ -65,8 +65,6 @@
     sources += [
       "android/cast_crash_reporter_client_android.cc",
       "android/cast_crash_reporter_client_android.h",
-      "android/crash_handler.cc",
-      "android/crash_handler.h",
     ]
     deps += [
       "//chromecast/base:android_create_sys_info",
@@ -76,6 +74,35 @@
   }
 }
 
+cast_source_set("crash_uploader") {
+  sources = [ "cast_crash_uploader.h" ]
+  public_deps = [ "//components/prefs:prefs" ]
+  if (is_android) {
+    sources += [
+      "android/cast_crash_uploader_android.cc",
+      "android/cast_crash_uploader_android.h",
+    ]
+
+    deps = [
+      ":cast_crash_client",
+      "//base",
+      "//chromecast/base",
+      "//chromecast/base:android_create_sys_info",
+      "//chromecast/base:cast_version",
+      "//chromecast/browser:jni_headers",
+      "//components/crash/core/app",
+      "//components/crash/core/common:crash_key",
+      "//components/minidump_uploader",
+      "//content/public/common",
+    ]
+  } else {
+    sources += [
+      "cast_crash_uploader_default.cc",
+      "cast_crash_uploader_default.h",
+    ]
+  }
+}
+
 cast_source_set("test_support") {
   testonly = true
   sources = [ "cast_test_launcher.cc" ]
diff --git a/chromecast/app/DEPS b/chromecast/app/DEPS
index b2871c3b..8439cfd 100644
--- a/chromecast/app/DEPS
+++ b/chromecast/app/DEPS
@@ -6,6 +6,7 @@
   "+chromecast/renderer",
   "+chromecast/utility",
   "+components/crash",
+  "+components/prefs",
   "+content/public/app",
   "+content/public/browser",
   "+content/public/common",
diff --git a/chromecast/app/android/DEPS b/chromecast/app/android/DEPS
index cf43394..88922ef 100644
--- a/chromecast/app/android/DEPS
+++ b/chromecast/app/android/DEPS
@@ -2,4 +2,5 @@
   "+chromecast/android",
   "+chromecast/browser/android",
   "+jni",
+  "+components/prefs",
 ]
diff --git a/chromecast/app/android/cast_crash_uploader_android.cc b/chromecast/app/android/cast_crash_uploader_android.cc
new file mode 100644
index 0000000..b8f46c0f
--- /dev/null
+++ b/chromecast/app/android/cast_crash_uploader_android.cc
@@ -0,0 +1,125 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/app/android/cast_crash_uploader_android.h"
+
+#include <jni.h>
+#include <stdlib.h>
+#include <memory>
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "chromecast/app/android/cast_crash_reporter_client_android.h"
+#include "chromecast/base/cast_paths.h"
+#include "chromecast/base/pref_names.h"
+#include "chromecast/browser/jni_headers/CastCrashHandler_jni.h"
+#include "components/crash/core/app/crash_reporter_client.h"
+#include "components/crash/core/app/crashpad.h"
+#include "components/crash/core/common/crash_key.h"
+#include "content/public/common/content_switches.h"
+
+namespace chromecast {
+// static
+std::unique_ptr<CastCrashUploader> CastCrashUploader::Create(
+    PrefService* pref_service) {
+  const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
+  std::string process_type =
+      command_line->GetSwitchValueASCII(switches::kProcessType);
+
+  base::FilePath log_file;
+  base::PathService::Get(FILE_CAST_ANDROID_LOG, &log_file);
+
+  return std::make_unique<CastCrashUploaderAndroid>(
+      std::move(process_type), std::move(log_file), pref_service);
+}
+
+CastCrashUploaderAndroid::CastCrashUploaderAndroid(
+    const std::string process_type,
+    const base::FilePath log_file_path,
+    PrefService* pref_service)
+    : log_file_path_(log_file_path),
+      pref_service_(pref_service),
+      process_type_(process_type),
+      crash_reporter_client_(new CastCrashReporterClientAndroid(process_type)),
+      weak_factory_(this) {
+  crash_reporter::SetCrashReporterClient(crash_reporter_client_.get());
+  crash_reporter::InitializeCrashpad(process_type_.empty(), process_type_);
+  crash_reporter::InitializeCrashKeys();
+  crash_reporter_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+  StartPeriodicCrashReportUpload();
+}
+
+CastCrashUploaderAndroid::~CastCrashUploaderAndroid() = default;
+
+void CastCrashUploaderAndroid::UploadDumps(
+    const std::string& uuid,
+    const std::string& application_feedback,
+    const bool can_send_usage_stats) {
+  base::FilePath crash_dump_path;
+  if (!crash_reporter_client_->GetCrashDumpLocation(&crash_dump_path)) {
+    LOG(ERROR) << "Could not get crash dump location.";
+    return;
+  }
+  base::FilePath crash_reports_path;
+  if (!crash_reporter_client_->GetCrashReportsLocation(process_type_,
+                                                       &crash_reports_path)) {
+    LOG(ERROR) << "Could not get crash report location.";
+    return;
+  }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jstring> crash_dump_path_java =
+      base::android::ConvertUTF8ToJavaString(env, crash_dump_path.value());
+  base::android::ScopedJavaLocalRef<jstring> reports_path_java =
+      base::android::ConvertUTF8ToJavaString(env, crash_reports_path.value());
+  base::android::ScopedJavaLocalRef<jstring> uuid_java =
+      base::android::ConvertUTF8ToJavaString(env, uuid);
+  base::android::ScopedJavaLocalRef<jstring> application_feedback_java =
+      base::android::ConvertUTF8ToJavaString(env, application_feedback);
+  // TODO(servolk): Remove the UploadToStaging param and clean up Java code, if
+  // dev crash uploading to prod server works fine (b/113130776)
+
+  if (can_send_usage_stats) {
+    Java_CastCrashHandler_uploadOnce(env, crash_dump_path_java,
+                                     reports_path_java, uuid_java,
+                                     application_feedback_java,
+                                     /* uploadCrashToStaging = */ false);
+  } else {
+    Java_CastCrashHandler_removeCrashDumps(env, crash_dump_path_java,
+                                           reports_path_java, uuid_java,
+                                           application_feedback_java,
+                                           /* uploadCrashToStaging = */ false);
+  }
+}
+
+void CastCrashUploaderAndroid::StartPeriodicCrashReportUpload() {
+  OnStartPeriodicCrashReportUpload();
+  crash_reporter_timer_ = std::make_unique<base::RepeatingTimer>();
+  crash_reporter_timer_->Start(
+      FROM_HERE, base::TimeDelta::FromMinutes(20), this,
+      &CastCrashUploaderAndroid::OnStartPeriodicCrashReportUpload);
+}
+
+void CastCrashUploaderAndroid::OnStartPeriodicCrashReportUpload() {
+  crash_reporter_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&CastCrashUploaderAndroid::UploadCrashReport,
+                                weak_factory_.GetWeakPtr(),
+                                pref_service_->GetBoolean(prefs::kOptInStats)));
+}
+
+void CastCrashUploaderAndroid::UploadCrashReport(bool opt_in_stats) {
+  DCHECK(crash_reporter_runner_->RunsTasksInCurrentSequence());
+  CastCrashUploaderAndroid::UploadDumps("", "", opt_in_stats);
+}
+}  // namespace chromecast
diff --git a/chromecast/app/android/cast_crash_uploader_android.h b/chromecast/app/android/cast_crash_uploader_android.h
new file mode 100644
index 0000000..cfe49db
--- /dev/null
+++ b/chromecast/app/android/cast_crash_uploader_android.h
@@ -0,0 +1,55 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_APP_ANDROID_CAST_CRASH_UPLOADER_ANDROID_H_
+#define CHROMECAST_APP_ANDROID_CAST_CRASH_UPLOADER_ANDROID_H_
+
+#include <jni.h>
+
+#include <memory>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "chromecast/app/cast_crash_uploader.h"
+#include "components/prefs/pref_service.h"
+
+namespace chromecast {
+class CastCrashReporterClientAndroid;
+
+class CastCrashUploaderAndroid : public CastCrashUploader {
+ public:
+  void UploadDumps(const std::string& uuid,
+                   const std::string& application_feedback,
+                   const bool can_send_usage_stats) override;
+
+  CastCrashUploaderAndroid(const std::string process_type,
+                           const base::FilePath log_file_path,
+                           PrefService* pref_service);
+  ~CastCrashUploaderAndroid() override;
+
+ private:
+  void StartPeriodicCrashReportUpload();
+  void OnStartPeriodicCrashReportUpload();
+  void UploadCrashReport(bool opt_in_stats);
+
+  // Path to the current process's log file.
+  base::FilePath log_file_path_;
+
+  PrefService* pref_service_;
+
+  std::string process_type_;
+  scoped_refptr<base::SequencedTaskRunner> crash_reporter_runner_;
+  std::unique_ptr<base::RepeatingTimer> crash_reporter_timer_;
+
+  std::unique_ptr<CastCrashReporterClientAndroid> crash_reporter_client_;
+  base::WeakPtrFactory<CastCrashUploaderAndroid> weak_factory_;
+  DISALLOW_COPY_AND_ASSIGN(CastCrashUploaderAndroid);
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_APP_ANDROID_CAST_CRASH_UPLOADER_ANDROID_H_
diff --git a/chromecast/app/android/crash_handler.cc b/chromecast/app/android/crash_handler.cc
deleted file mode 100644
index cfe273d..0000000
--- a/chromecast/app/android/crash_handler.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/app/android/crash_handler.h"
-
-#include <jni.h>
-#include <stdlib.h>
-#include <string>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "chromecast/app/android/cast_crash_reporter_client_android.h"
-#include "chromecast/base/version.h"
-#include "chromecast/browser/jni_headers/CastCrashHandler_jni.h"
-#include "components/crash/core/app/crash_reporter_client.h"
-#include "components/crash/core/app/crashpad.h"
-#include "content/public/common/content_switches.h"
-
-namespace {
-
-chromecast::CrashHandler* g_crash_handler = NULL;
-
-}  // namespace
-
-namespace chromecast {
-
-// static
-void CrashHandler::Initialize(const std::string& process_type,
-                              const base::FilePath& log_file_path) {
-  DCHECK(!g_crash_handler);
-  g_crash_handler = new CrashHandler(process_type, log_file_path);
-  g_crash_handler->Initialize();
-}
-
-// static
-bool CrashHandler::GetCrashDumpLocation(base::FilePath* crash_dir) {
-  DCHECK(g_crash_handler);
-  return g_crash_handler->crash_reporter_client_->GetCrashDumpLocation(
-      crash_dir);
-}
-
-// static
-bool CrashHandler::GetCrashReportsLocation(base::FilePath* reports_dir) {
-  DCHECK(g_crash_handler);
-  return g_crash_handler->crash_reporter_client_->GetCrashReportsLocation(
-      g_crash_handler->process_type_, reports_dir);
-}
-
-CrashHandler::CrashHandler(const std::string& process_type,
-                           const base::FilePath& log_file_path)
-    : log_file_path_(log_file_path),
-      process_type_(process_type),
-      crash_reporter_client_(new CastCrashReporterClientAndroid(process_type)) {
-  if (!crash_reporter_client_->GetCrashDumpLocation(&crash_dump_path_)) {
-    LOG(ERROR) << "Could not get crash dump location";
-  }
-  SetCrashReporterClient(crash_reporter_client_.get());
-}
-
-CrashHandler::~CrashHandler() {
-  DCHECK(g_crash_handler);
-  g_crash_handler = NULL;
-}
-
-void CrashHandler::Initialize() {
-  crash_reporter::InitializeCrashpad(process_type_.empty(), process_type_);
-}
-
-// static
-void CrashHandler::UploadDumps(const base::FilePath& crash_dump_path,
-                               const base::FilePath& reports_path,
-                               const std::string& uuid,
-                               const std::string& application_feedback,
-                               const bool can_send_usage_stats) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  base::android::ScopedJavaLocalRef<jstring> crash_dump_path_java =
-      base::android::ConvertUTF8ToJavaString(env, crash_dump_path.value());
-  base::android::ScopedJavaLocalRef<jstring> reports_path_java =
-      base::android::ConvertUTF8ToJavaString(env, reports_path.value());
-  base::android::ScopedJavaLocalRef<jstring> uuid_java =
-      base::android::ConvertUTF8ToJavaString(env, uuid);
-  base::android::ScopedJavaLocalRef<jstring> application_feedback_java =
-      base::android::ConvertUTF8ToJavaString(env, application_feedback);
-  // TODO(servolk): Remove the UploadToStaging param and clean up Java code, if
-  // dev crash uploading to prod server works fine (b/113130776)
-
-  if (can_send_usage_stats) {
-    Java_CastCrashHandler_uploadOnce(env, crash_dump_path_java,
-                                     reports_path_java, uuid_java,
-                                     application_feedback_java,
-                                     /* UploadToStaging = */ false);
-  } else {
-    Java_CastCrashHandler_removeCrashDumps(env, crash_dump_path_java,
-                                           reports_path_java, uuid_java,
-                                           application_feedback_java,
-                                           /* UploadToStaging = */ false);
-  }
-}
-
-}  // namespace chromecast
diff --git a/chromecast/app/android/crash_handler.h b/chromecast/app/android/crash_handler.h
deleted file mode 100644
index b866d47..0000000
--- a/chromecast/app/android/crash_handler.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMECAST_APP_ANDROID_CRASH_HANDLER_H_
-#define CHROMECAST_APP_ANDROID_CRASH_HANDLER_H_
-
-#include <jni.h>
-
-#include <memory>
-#include <string>
-
-#include "base/files/file_path.h"
-
-namespace chromecast {
-class CastCrashReporterClientAndroid;
-
-class CrashHandler {
- public:
-  CrashHandler(const CrashHandler&) = delete;
-  CrashHandler& operator=(const CrashHandler&) = delete;
-
-  // Initializes the crash handler for attempting to upload crash dumps with
-  // the current process's log file.
-  // Must not be called more than once.
-  static void Initialize(const std::string& process_type,
-                         const base::FilePath& log_file_path);
-
-  // Returns the directory location to use for a crashpad::CrashReportDatabase
-  // of raw minidump files. Prior to upload, these files are re-written as MIME
-  // multipart messages allowing upload metadata and attachments to be included
-  // as parts of the message.
-  static bool GetCrashDumpLocation(base::FilePath* crash_dir);
-
-  // Returns the directory of crash reports re-written as MIME messages.
-  static bool GetCrashReportsLocation(base::FilePath* reports_dir);
-
-  static void UploadDumps(const base::FilePath& crash_dump_path,
-                          const base::FilePath& reports_path,
-                          const std::string& uuid,
-                          const std::string& application_feedback,
-                          const bool can_send_usage_stats);
-
- private:
-  CrashHandler(const std::string& process_type,
-               const base::FilePath& log_file_path);
-  ~CrashHandler();
-
-  void Initialize();
-
-  // Path to the current process's log file.
-  base::FilePath log_file_path_;
-
-  // Location to which crash dumps should be written.
-  base::FilePath crash_dump_path_;
-
-  std::string process_type_;
-
-  std::unique_ptr<CastCrashReporterClientAndroid> crash_reporter_client_;
-};
-
-}  // namespace chromecast
-
-#endif  // CHROMECAST_APP_ANDROID_CRASH_HANDLER_H_
diff --git a/chromecast/app/cast_crash_uploader.h b/chromecast/app/cast_crash_uploader.h
new file mode 100644
index 0000000..e9196085
--- /dev/null
+++ b/chromecast/app/cast_crash_uploader.h
@@ -0,0 +1,24 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_APP_CAST_CRASH_UPLOADER_H_
+#define CHROMECAST_APP_CAST_CRASH_UPLOADER_H_
+
+#include <memory>
+
+#include "components/prefs/pref_service.h"
+
+namespace chromecast {
+class CastCrashUploader {
+ public:
+  static std::unique_ptr<CastCrashUploader> Create(PrefService*);
+  virtual ~CastCrashUploader() = default;
+
+  virtual void UploadDumps(const std::string& uuid,
+                           const std::string& application_feedback,
+                           const bool can_send_usage_stats) = 0;
+};
+}  // namespace chromecast
+
+#endif  // CHROMECAST_APP_CAST_CRASH_UPLOADER_H_
diff --git a/chromecast/app/cast_crash_uploader_default.cc b/chromecast/app/cast_crash_uploader_default.cc
new file mode 100644
index 0000000..0778961
--- /dev/null
+++ b/chromecast/app/cast_crash_uploader_default.cc
@@ -0,0 +1,22 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/app/cast_crash_uploader_default.h"
+#include <memory>
+
+namespace chromecast {
+
+// static
+std::unique_ptr<CastCrashUploader> CastCrashUploader::Create(
+    PrefService* pref_service) {
+  return std::make_unique<CastCrashUploaderDefault>();
+}
+void CastCrashUploaderDefault::UploadDumps(
+    const std::string& uuid,
+    const std::string& application_feedback,
+    const bool can_send_usage_stats) {
+  NOTREACHED() << "TODO(b/258269114): Move non-android implementations of "
+                  "crash reporting here.";
+}
+}  // namespace chromecast
diff --git a/chromecast/app/cast_crash_uploader_default.h b/chromecast/app/cast_crash_uploader_default.h
new file mode 100644
index 0000000..19e2df22
--- /dev/null
+++ b/chromecast/app/cast_crash_uploader_default.h
@@ -0,0 +1,21 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_APP_CAST_CRASH_UPLOADER_DEFAULT_H_
+#define CHROMECAST_APP_CAST_CRASH_UPLOADER_DEFAULT_H_
+
+#include "chromecast/app/cast_crash_uploader.h"
+#include "components/prefs/pref_service.h"
+
+namespace chromecast {
+class CastCrashUploaderDefault : public CastCrashUploader {
+ public:
+  static CastCrashUploader* Create(PrefService*);
+  void UploadDumps(const std::string& uuid,
+                   const std::string& application_feedback,
+                   const bool can_send_usage_stats) override;
+};
+}  // namespace chromecast
+
+#endif  // CHROMECAST_APP_CAST_CRASH_UPLOADER_DEFAULT_H_
diff --git a/chromecast/app/cast_main_delegate.cc b/chromecast/app/cast_main_delegate.cc
index 1eb5c729..cdec40b1 100644
--- a/chromecast/app/cast_main_delegate.cc
+++ b/chromecast/app/cast_main_delegate.cc
@@ -43,7 +43,6 @@
 #if BUILDFLAG(IS_ANDROID)
 #include "base/android/apk_assets.h"
 #include "chromecast/app/android/cast_crash_reporter_client_android.h"
-#include "chromecast/app/android/crash_handler.h"
 #include "ui/base/resource/resource_bundle_android.h"
 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 #include "chromecast/app/linux/cast_crash_reporter_client.h"
@@ -178,23 +177,18 @@
   std::string process_type =
       command_line->GetSwitchValueASCII(switches::kProcessType);
 
-  bool enable_crash_reporter = !command_line->HasSwitch(
-      switches::kDisableCrashReporter);
+  bool enable_crash_reporter =
+      !command_line->HasSwitch(switches::kDisableCrashReporter);
   if (enable_crash_reporter) {
     // TODO(crbug.com/1226159): Complete crash reporting integration on Fuchsia.
-#if BUILDFLAG(IS_ANDROID)
-    base::FilePath log_file;
-    base::PathService::Get(FILE_CAST_ANDROID_LOG, &log_file);
-    chromecast::CrashHandler::Initialize(process_type, log_file);
-#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     crash_reporter::SetCrashReporterClient(GetCastCrashReporter());
 
     if (process_type != switches::kZygoteProcess) {
       CastCrashReporterClient::InitCrashReporter(process_type);
     }
-#endif  // BUILDFLAG(IS_ANDROID)
-
     crash_reporter::InitializeCrashKeys();
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   }
 
   InitializeResourceBundle();
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index 40b0660..ef9f139 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -98,8 +98,6 @@
 #endif
 
 #if BUILDFLAG(IS_ANDROID)
-#include "chromecast/app/android/crash_handler.h"
-#include "chromecast/base/pref_names.h"
 #include "components/crash/content/browser/child_exit_observer_android.h"
 #include "components/crash/content/browser/child_process_crash_observer_android.h"
 #include "net/android/network_change_notifier_factory_android.h"
@@ -566,13 +564,6 @@
   cast_content_browser_client_->SetPersistentCookieAccessSettings(
       cast_browser_process_->pref_service());
 
-#if BUILDFLAG(IS_ANDROID)
-  crash_reporter_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
-       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-  StartPeriodicCrashReportUpload();
-#endif  // BUILDFLAG(IS_ANDROID)
-
   cast_browser_process_->SetBrowserContext(
       std::make_unique<CastBrowserContext>());
 
@@ -690,36 +681,6 @@
   return content::RESULT_CODE_NORMAL_EXIT;
 }
 
-#if BUILDFLAG(IS_ANDROID)
-void CastBrowserMainParts::StartPeriodicCrashReportUpload() {
-  OnStartPeriodicCrashReportUpload();
-  crash_reporter_timer_.reset(new base::RepeatingTimer());
-  crash_reporter_timer_->Start(
-      FROM_HERE, base::Minutes(20), this,
-      &CastBrowserMainParts::OnStartPeriodicCrashReportUpload);
-}
-
-void CastBrowserMainParts::OnStartPeriodicCrashReportUpload() {
-  crash_reporter_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CastBrowserMainParts::UploadCrashReport,
-                     weak_factory_.GetWeakPtr(),
-                     cast_browser_process_->pref_service()->GetBoolean(
-                         prefs::kOptInStats)));
-}
-
-void CastBrowserMainParts::UploadCrashReport(bool opt_in_stats) {
-  DCHECK(crash_reporter_runner_->RunsTasksInCurrentSequence());
-  base::FilePath crash_dir;
-  if (!CrashHandler::GetCrashDumpLocation(&crash_dir))
-    return;
-  base::FilePath reports_dir;
-  if (!CrashHandler::GetCrashReportsLocation(&reports_dir))
-    return;
-  CrashHandler::UploadDumps(crash_dir, reports_dir, "", "", opt_in_stats);
-}
-#endif  // BUILDFLAG(IS_ANDROID)
-
 void CastBrowserMainParts::WillRunMainMessageLoop(
     std::unique_ptr<base::RunLoop>& run_loop) {
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chromecast/browser/cast_browser_main_parts.h b/chromecast/browser/cast_browser_main_parts.h
index c9754cc..5685282c 100644
--- a/chromecast/browser/cast_browser_main_parts.h
+++ b/chromecast/browser/cast_browser_main_parts.h
@@ -141,11 +141,6 @@
   std::unique_ptr<DisplaySettingsManager> display_settings_manager_;
 
 #if BUILDFLAG(IS_ANDROID)
-  void StartPeriodicCrashReportUpload();
-  void OnStartPeriodicCrashReportUpload();
-  void UploadCrashReport(bool opt_in_stats);
-  scoped_refptr<base::SequencedTaskRunner> crash_reporter_runner_;
-  std::unique_ptr<base::RepeatingTimer> crash_reporter_timer_;
   std::unique_ptr<crash_reporter::ChildExitObserver> child_exit_observer_;
 #endif
 
diff --git a/components/attribution_reporting/bounded_list.h b/components/attribution_reporting/bounded_list.h
index ff7de36..e41e5da 100644
--- a/components/attribution_reporting/bounded_list.h
+++ b/components/attribution_reporting/bounded_list.h
@@ -29,16 +29,24 @@
   }
 
   template <typename Error, typename F>
-  static base::expected<BoundedList, Error> Build(base::Value::List& list,
+  static base::expected<BoundedList, Error> Build(base::Value* input_value,
+                                                  Error wrong_type,
                                                   Error out_of_bounds,
                                                   F&& build_element) {
-    if (list.size() > kMaxSize)
+    if (!input_value)
+      return BoundedList();
+
+    base::Value::List* list = input_value->GetIfList();
+    if (!list)
+      return base::unexpected(wrong_type);
+
+    if (list->size() > kMaxSize)
       return base::unexpected(out_of_bounds);
 
     std::vector<T> vec;
-    vec.reserve(list.size());
+    vec.reserve(list->size());
 
-    for (auto& value : list) {
+    for (auto& value : *list) {
       base::expected<T, Error> element = base::invoke(build_element, value);
       if (!element.has_value())
         return base::unexpected(element.error());
diff --git a/components/attribution_reporting/trigger_registration.cc b/components/attribution_reporting/trigger_registration.cc
index 7395a96..82e684392 100644
--- a/components/attribution_reporting/trigger_registration.cc
+++ b/components/attribution_reporting/trigger_registration.cc
@@ -22,38 +22,6 @@
 
 using ::attribution_reporting::mojom::TriggerRegistrationError;
 
-base::expected<EventTriggerDataList, TriggerRegistrationError>
-ParseEventTriggerDataList(base::Value* value) {
-  if (!value)
-    return EventTriggerDataList();
-
-  base::Value::List* list = value->GetIfList();
-  if (!list) {
-    return base::unexpected(
-        TriggerRegistrationError::kEventTriggerDataListWrongType);
-  }
-
-  return EventTriggerDataList::Build(
-      *list, TriggerRegistrationError::kEventTriggerDataListTooLong,
-      &EventTriggerData::FromJSON);
-}
-
-base::expected<AggregatableTriggerDataList, TriggerRegistrationError>
-ParseAggregatableTriggerDataList(base::Value* value) {
-  if (!value)
-    return AggregatableTriggerDataList();
-
-  base::Value::List* list = value->GetIfList();
-  if (!list) {
-    return base::unexpected(
-        TriggerRegistrationError::kAggregatableTriggerDataListWrongType);
-  }
-
-  return AggregatableTriggerDataList::Build(
-      *list, TriggerRegistrationError::kAggregatableTriggerDataListTooLong,
-      &AggregatableTriggerData::FromJSON);
-}
-
 }  // namespace
 
 // static
@@ -68,13 +36,19 @@
   if (!not_filters.has_value())
     return base::unexpected(not_filters.error());
 
-  auto event_triggers =
-      ParseEventTriggerDataList(registration.Find("event_trigger_data"));
+  auto event_triggers = EventTriggerDataList::Build(
+      registration.Find("event_trigger_data"),
+      TriggerRegistrationError::kEventTriggerDataListWrongType,
+      TriggerRegistrationError::kEventTriggerDataListTooLong,
+      &EventTriggerData::FromJSON);
   if (!event_triggers.has_value())
     return base::unexpected(event_triggers.error());
 
-  auto aggregatable_trigger_data = ParseAggregatableTriggerDataList(
-      registration.Find("aggregatable_trigger_data"));
+  auto aggregatable_trigger_data = AggregatableTriggerDataList::Build(
+      registration.Find("aggregatable_trigger_data"),
+      TriggerRegistrationError::kAggregatableTriggerDataListWrongType,
+      TriggerRegistrationError::kAggregatableTriggerDataListTooLong,
+      &AggregatableTriggerData::FromJSON);
   if (!aggregatable_trigger_data.has_value())
     return base::unexpected(aggregatable_trigger_data.error());
 
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd
index a513a166..3eb2a0c 100644
--- a/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -941,43 +941,43 @@
       </message>
 
       <!-- Page Zoom -->
-      <message name="IDS_PAGE_ZOOM_TITLE" desc="Title of the preference that allows the user to update the accessibility page zoom feature that applies to the web contents." translateable="false">
+      <message name="IDS_PAGE_ZOOM_TITLE" desc="Title of the preference that allows the user to update the accessibility page zoom feature that applies to the web contents.">
         Zoom
       </message>
-      <message name="IDS_PAGE_ZOOM_LABEL" desc="Accessibility label for control to allow user to change page zoom" translateable="false">
+      <message name="IDS_PAGE_ZOOM_LABEL" desc="Accessibility label for control to allow user to change page zoom">
         Page zoom
       </message>
-      <message name="IDS_PAGE_ZOOM_LEVEL_LABEL" desc="Accessibility label for indicator of current page zoom level set by the user" translateable="false">
+      <message name="IDS_PAGE_ZOOM_LEVEL_LABEL" desc="Accessibility label for indicator of current page zoom level set by the user">
         Current zoom is <ph name="ZOOM_LEVEL">%1$d<ex>100</ex></ph> %%
       </message>
-      <message name="IDS_PAGE_ZOOM_SUMMARY" desc="Summary of the preference that allows the user to update the accessibility page zoom feature that applies to the web contents." translateable="false">
+      <message name="IDS_PAGE_ZOOM_SUMMARY" desc="Summary of the preference that allows the user to update the accessibility page zoom feature that applies to the web contents.">
         Make the default text and images on sites smaller or larger
       </message>
-      <message name="IDS_PAGE_ZOOM_DECREASE_ZOOM_BUTTON_TEXT" desc="Accessibility label for button to allow user to decrease page zoom" translateable="false">
+      <message name="IDS_PAGE_ZOOM_DECREASE_ZOOM_BUTTON_TEXT" desc="Accessibility label for button to allow user to decrease page zoom">
         Decrease zoom
       </message>
-      <message name="IDS_PAGE_ZOOM_INCREASE_ZOOM_BUTTON_TEXT" desc="Accessibility label for button to allow user to increase page zoom" translateable="false">
+      <message name="IDS_PAGE_ZOOM_INCREASE_ZOOM_BUTTON_TEXT" desc="Accessibility label for button to allow user to increase page zoom">
         Increase zoom
       </message>
-      <message name="IDS_PAGE_ZOOM_LEVEL" desc="Text description of the current page zoom level set by the user" translateable="false">
+      <message name="IDS_PAGE_ZOOM_LEVEL" desc="Text description of the current page zoom level set by the user">
         <ph name="ZOOM_LEVEL">%1$d<ex>100</ex></ph> %%
       </message>
-      <message name="IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_TITLE" desc="Title of the preference that allows the user to always show the menu item for zoom" translateable="false">
+      <message name="IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_TITLE" desc="Title of the preference that allows the user to always show the menu item for zoom">
         Show zoom
       </message>
-      <message name="IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_SUMMARY" desc="Summary of the preference that allows the user to always show the menu item for zoom." translateable="false">
+      <message name="IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_SUMMARY" desc="Summary of the preference that allows the user to always show the menu item for zoom.">
         Zoom in or out on a page from the main menu
       </message>
-      <message name="IDS_PAGE_ZOOM_PREVIEW_TITLE" desc="Label of the section of sample text shown to the user to preview zoom level." translateable="false">
+      <message name="IDS_PAGE_ZOOM_PREVIEW_TITLE" desc="Label of the section of sample text shown to the user to preview zoom level.">
         Preview
       </message>
-      <message name="IDS_PAGE_ZOOM_PREVIEW_TEXT_TITLE" desc="Sample text displayed to user in settings to see/test a desired zoom level." translateable="false">
+      <message name="IDS_PAGE_ZOOM_PREVIEW_TEXT_TITLE" desc="Sample text displayed to user in settings to see/test a desired zoom level.">
         The Wonderful Wizard of Oz
       </message>
-      <message name="IDS_PAGE_ZOOM_PREVIEW_TEXT_SUMMARY" desc="Sample text displayed to user in settings to see/test a desired zoom level." translateable="false">
+      <message name="IDS_PAGE_ZOOM_PREVIEW_TEXT_SUMMARY" desc="Sample text displayed to user in settings to see/test a desired zoom level.">
         Chapter 11: The Wonderful Emerald City of Oz
       </message>
-      <message name="IDS_PAGE_ZOOM_PREVIEW_TEXT_ITEM" desc="Sample text displayed to user in settings to see/test a desired zoom level." translateable="false">
+      <message name="IDS_PAGE_ZOOM_PREVIEW_TEXT_ITEM" desc="Sample text displayed to user in settings to see/test a desired zoom level.">
         Even with eyes protected by the green spectacles Dorothy and her friends were at first dazzled by the
       </message>
 
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_SUMMARY.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_SUMMARY.png.sha1
new file mode 100644
index 0000000..8e09563
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_SUMMARY.png.sha1
@@ -0,0 +1 @@
+35567ca38fcc25c9b5d8555eb7ffbacdeef459be
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_TITLE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_TITLE.png.sha1
new file mode 100644
index 0000000..aa271ce
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_ALWAYS_SHOW_PREFERENCE_TITLE.png.sha1
@@ -0,0 +1 @@
+e804030fe0acd36452306df88389f61390b5cceb
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_DECREASE_ZOOM_BUTTON_TEXT.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_DECREASE_ZOOM_BUTTON_TEXT.png.sha1
new file mode 100644
index 0000000..2a721fb
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_DECREASE_ZOOM_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@
+3c6880b6fe24af33978ae70b966c99800d4e634b
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_INCREASE_ZOOM_BUTTON_TEXT.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_INCREASE_ZOOM_BUTTON_TEXT.png.sha1
new file mode 100644
index 0000000..2a721fb
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_INCREASE_ZOOM_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@
+3c6880b6fe24af33978ae70b966c99800d4e634b
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LABEL.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LABEL.png.sha1
new file mode 100644
index 0000000..2a721fb
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LABEL.png.sha1
@@ -0,0 +1 @@
+3c6880b6fe24af33978ae70b966c99800d4e634b
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LEVEL.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LEVEL.png.sha1
new file mode 100644
index 0000000..2a721fb
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LEVEL.png.sha1
@@ -0,0 +1 @@
+3c6880b6fe24af33978ae70b966c99800d4e634b
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LEVEL_LABEL.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LEVEL_LABEL.png.sha1
new file mode 100644
index 0000000..2a721fb
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_LEVEL_LABEL.png.sha1
@@ -0,0 +1 @@
+3c6880b6fe24af33978ae70b966c99800d4e634b
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_ITEM.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_ITEM.png.sha1
new file mode 100644
index 0000000..5f61a7dd
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_ITEM.png.sha1
@@ -0,0 +1 @@
+41988862f19deed76d02229918ca555ce7f49995
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_SUMMARY.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_SUMMARY.png.sha1
new file mode 100644
index 0000000..5f61a7dd
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_SUMMARY.png.sha1
@@ -0,0 +1 @@
+41988862f19deed76d02229918ca555ce7f49995
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_TITLE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_TITLE.png.sha1
new file mode 100644
index 0000000..5f61a7dd
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TEXT_TITLE.png.sha1
@@ -0,0 +1 @@
+41988862f19deed76d02229918ca555ce7f49995
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TITLE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TITLE.png.sha1
new file mode 100644
index 0000000..4fc14303
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_PREVIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+f64d2b60758373d25a04d4575c14391e07e2cfff
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_SUMMARY.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_SUMMARY.png.sha1
new file mode 100644
index 0000000..1dce946d
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_SUMMARY.png.sha1
@@ -0,0 +1 @@
+b9ba4e164c73712289760a5e9a5d23c3138320fb
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_TITLE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_TITLE.png.sha1
new file mode 100644
index 0000000..409e203
--- /dev/null
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_ZOOM_TITLE.png.sha1
@@ -0,0 +1 @@
+2109e8c7337a48f04d9e8edd9d07be646da1677c
\ No newline at end of file
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index f3668e5..51f490d 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "15.1",
-  "log_list_timestamp": "2022-11-16T12:54:50Z",
+  "version": "15.2",
+  "log_list_timestamp": "2022-11-17T12:56:41Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/content_settings/browser/page_specific_content_settings.cc b/components/content_settings/browser/page_specific_content_settings.cc
index 506fb1a4..483ffe2 100644
--- a/components/content_settings/browser/page_specific_content_settings.cc
+++ b/components/content_settings/browser/page_specific_content_settings.cc
@@ -415,6 +415,10 @@
                                     /*ignore_empty_localstorage=*/false,
                                     delegate_->GetAdditionalFileSystemTypes(),
                                     delegate_->GetIsDeletionDisabledCallback()),
+      allowed_browsing_data_model_(
+          BrowsingDataModel::BuildEmpty(GetWebContents()->GetBrowserContext())),
+      blocked_browsing_data_model_(
+          BrowsingDataModel::BuildEmpty(GetWebContents()->GetBrowserContext())),
       microphone_camera_state_(MICROPHONE_CAMERA_NOT_ACCESSED) {
   observation_.Observe(map_.get());
   if (page.GetMainDocument().GetLifecycleState() ==
@@ -825,6 +829,27 @@
                     blocked_by_policy, topic);
 }
 
+void PageSpecificContentSettings::OnTrustTokenAccessed(
+    const url::Origin api_origin,
+    bool blocked) {
+  // TODO(crbug.com/1378703): Call this method.
+  // The size isn't relevant here and won't be displayed in the UI.
+  const int kTrustTokenSize = 0;
+  auto& model =
+      blocked ? blocked_browsing_data_model_ : allowed_browsing_data_model_;
+  model->AddBrowsingData(api_origin,
+                         BrowsingDataModel::StorageType::kTrustTokens,
+                         kTrustTokenSize);
+  if (blocked) {
+    OnContentBlocked(ContentSettingsType::COOKIES);
+  } else {
+    OnContentAllowed(ContentSettingsType::COOKIES);
+  }
+  MaybeUpdateParent(&PageSpecificContentSettings::OnTrustTokenAccessed,
+                    api_origin, blocked);
+  MaybeNotifySiteDataObservers();
+}
+
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
 void PageSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet(
     const GURL& requesting_origin,
diff --git a/components/content_settings/browser/page_specific_content_settings.h b/components/content_settings/browser/page_specific_content_settings.h
index c0f52e7..d9570e9 100644
--- a/components/content_settings/browser/page_specific_content_settings.h
+++ b/components/content_settings/browser/page_specific_content_settings.h
@@ -19,6 +19,7 @@
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "components/browsing_data/content/browsing_data_model.h"
 #include "components/browsing_data/content/cookie_helper.h"
 #include "components/browsing_data/content/local_shared_objects_container.h"
 #include "components/content_settings/common/content_settings_manager.mojom.h"
@@ -322,6 +323,14 @@
     return blocked_local_shared_objects_;
   }
 
+  BrowsingDataModel* allowed_browsing_data_model() const {
+    return allowed_browsing_data_model_.get();
+  }
+
+  BrowsingDataModel* blocked_browsing_data_model() const {
+    return blocked_browsing_data_model_.get();
+  }
+
   void OnContentBlocked(ContentSettingsType type);
   void OnContentAllowed(ContentSettingsType type);
 
@@ -342,6 +351,7 @@
   void OnTopicAccessed(const url::Origin api_origin,
                        bool blocked_by_policy,
                        privacy_sandbox::CanonicalTopic topic);
+  void OnTrustTokenAccessed(const url::Origin api_origin, bool blocked);
 
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
   void OnProtectedMediaIdentifierPermissionSet(const GURL& requesting_frame,
@@ -479,6 +489,9 @@
   browsing_data::LocalSharedObjectsContainer allowed_local_shared_objects_;
   browsing_data::LocalSharedObjectsContainer blocked_local_shared_objects_;
 
+  std::unique_ptr<BrowsingDataModel> allowed_browsing_data_model_;
+  std::unique_ptr<BrowsingDataModel> blocked_browsing_data_model_;
+
   // The origin of the media stream request. Note that we only support handling
   // settings for one request per tab. The latest request's origin will be
   // stored here. http://crbug.com/259794
diff --git a/components/crash/android/BUILD.gn b/components/crash/android/BUILD.gn
index 795c9bf..3c1d1ed 100644
--- a/components/crash/android/BUILD.gn
+++ b/components/crash/android/BUILD.gn
@@ -63,12 +63,14 @@
 
 source_set("crash_android") {
   sources = [
+    "anr_build_id_provider.cc",
     "crash_keys_android.cc",
     "crash_keys_android.h",
     "pure_java_exception_handler.cc",
     "pure_java_exception_handler.h",
   ]
   deps = [
+    ":anr_collector_jni_headers",
     ":jni_headers",
     "//base",
     "//components/crash/core/common:crash_key",
@@ -124,12 +126,21 @@
   sources = [ "anr_data.proto" ]
 }
 
+_anr_collector_jni_sources =
+    [ "java/src/org/chromium/components/crash/anr/AnrCollector.java" ]
+
+generate_jni("anr_collector_jni_headers") {
+  sources = _anr_collector_jni_sources
+}
 android_library("anr_collector_java") {
   deps = [
     ":anr_data_proto_java",
     "//base:base_java",
+    "//base:jni_java",
+    "//build/android:build_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
   ]
+  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
   srcjar_deps = [ ":anr_skipped_reason_enum" ]
-  sources = [ "java/src/org/chromium/components/crash/anr/AnrCollector.java" ]
+  sources = _anr_collector_jni_sources
 }
diff --git a/components/crash/android/anr_build_id_provider.cc b/components/crash/android/anr_build_id_provider.cc
new file mode 100644
index 0000000..6937966
--- /dev/null
+++ b/components/crash/android/anr_build_id_provider.cc
@@ -0,0 +1,19 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/debug/elf_reader.h"
+#include "components/crash/android/anr_collector_jni_headers/AnrCollector_jni.h"
+
+extern char __executable_start;
+
+base::android::ScopedJavaLocalRef<jstring>
+JNI_AnrCollector_GetSharedLibraryBuildId(JNIEnv* env) {
+  base::debug::ElfBuildIdBuffer build_id;
+  base::debug::ReadElfBuildId(&__executable_start, false, build_id);
+  return base::android::ConvertUTF8ToJavaString(env, std::string(build_id));
+}
diff --git a/components/crash/android/java/src/org/chromium/components/crash/anr/AnrCollector.java b/components/crash/android/java/src/org/chromium/components/crash/anr/AnrCollector.java
index 15f02ba..05c6b75 100644
--- a/components/crash/android/java/src/org/chromium/components/crash/anr/AnrCollector.java
+++ b/components/crash/android/java/src/org/chromium/components/crash/anr/AnrCollector.java
@@ -16,6 +16,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.components.crash.anr.AnrDataOuterClass.AnrData;
 
@@ -25,6 +26,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -47,16 +49,20 @@
     private static final String ANR_UPLOAD_UMA = "Crashpad.AnrUpload.Skipped";
 
     /**
-     * Grabs ANR reports from Android and writes them as serialized protos.
+     * Grabs ANR reports from Android and writes them as 3-tuples as 3 entries in a string list.
      * This writes to disk synchronously, so should be called on a background thread.
      */
-    public static List<Pair<File, String>> collectAndWriteAnrs(File outDir) {
+    public static List<String> collectAndWriteAnrs(File outDir) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
             return Collections.emptyList();
         }
         return writeAnrs(collectAnrs(), outDir);
     }
 
+    public static String getSharedLibraryBuildId() {
+        return AnrCollectorJni.get().getSharedLibraryBuildId();
+    }
+
     @VisibleForTesting
     static AnrData parseAnrFromReport(BufferedReader reader) throws IOException {
         // For each thread, the header line always looks the same - example:
@@ -113,8 +119,8 @@
             return null;
         }
 
-        byte[] versionBytes = reason.getProcessStateSummary();
-        if (versionBytes == null || versionBytes.length == 0) {
+        byte[] processStateSummaryBytes = reason.getProcessStateSummary();
+        if (processStateSummaryBytes == null || processStateSummaryBytes.length == 0) {
             // We have gotten an ANR without an attached process state summary and thus
             // can't be be confident which version this ANR happened on. This would
             // happen if we ANRed before Chrome had set the process state summary.
@@ -122,8 +128,8 @@
                     ANR_UPLOAD_UMA, AnrSkippedReason.MISSING_VERSION, AnrSkippedReason.MAX_VALUE);
             return null;
         }
-        String version = new String(versionBytes);
-        return new Pair<>(anr, version);
+        String processStateSummary = new String(processStateSummaryBytes, StandardCharsets.UTF_8);
+        return new Pair<>(anr, processStateSummary);
     }
 
     private static List<Pair<AnrData, String>> collectAnrs() {
@@ -157,29 +163,50 @@
         return anrs;
     }
 
-    private static List<Pair<File, String>> writeAnrs(
-            List<Pair<AnrData, String>> anrs, File outDir) {
-        List<Pair<File, String>> anrFiles = new ArrayList<>();
+    private static List<String> writeAnrs(List<Pair<AnrData, String>> anrs, File outDir) {
+        List<String> anrFiles = new ArrayList<>();
         for (Pair<AnrData, String> pair : anrs) {
             AnrData anr = pair.first;
-            String version = pair.second;
-            try {
-                // Writing with .tmp suffix to enable cleanup later - CrashFileManager looks for
-                // files with a .tmp suffix and deletes them as soon as it no longer needs them.
-                File anrFile = File.createTempFile("anr_data_proto", ".tmp", outDir);
-                try (FileOutputStream out = new FileOutputStream(anrFile)) {
-                    anr.writeTo(out);
-                }
-                anrFiles.add(new Pair<>(anrFile, version));
-            } catch (IOException e) {
-                Log.e(TAG, "Couldn't write ANR proto", e);
-                RecordHistogram.recordEnumeratedHistogram(ANR_UPLOAD_UMA,
-                        AnrSkippedReason.FILESYSTEM_WRITE_FAILURE, AnrSkippedReason.MAX_VALUE);
+            String[] splitStateSummary = pair.second.split(",");
+            String version = splitStateSummary[0];
+            // There will always be a version number, but there's a chance that there won't be a
+            // buildId.
+            String buildId = "";
+            if (splitStateSummary.length > 1) {
+                buildId = splitStateSummary[1];
+            }
+            String anrFileName = writeAnr(anr, outDir);
+            if (anrFileName != null) {
+                anrFiles.add(anrFileName);
+                anrFiles.add(version);
+                anrFiles.add(buildId);
             }
         }
         return anrFiles;
     }
 
+    private static String writeAnr(AnrData data, File outDir) {
+        try {
+            // Writing with .tmp suffix to enable cleanup later - CrashFileManager looks for
+            // files with a .tmp suffix and deletes them as soon as it no longer needs them.
+            File anrFile = File.createTempFile("anr_data_proto", ".tmp", outDir);
+            try (FileOutputStream out = new FileOutputStream(anrFile)) {
+                data.writeTo(out);
+            }
+            return anrFile.getAbsolutePath();
+        } catch (IOException e) {
+            Log.e(TAG, "Couldn't write ANR proto", e);
+            RecordHistogram.recordEnumeratedHistogram(ANR_UPLOAD_UMA,
+                    AnrSkippedReason.FILESYSTEM_WRITE_FAILURE, AnrSkippedReason.MAX_VALUE);
+            return null;
+        }
+    }
+
     // Pure static class.
     private AnrCollector() {}
+
+    @NativeMethods
+    interface Natives {
+        String getSharedLibraryBuildId();
+    }
 }
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 060a10f..34e5610 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -188,6 +188,7 @@
     "//ui/base/cursor/mojom:cursor_type",
     "//ui/base/dragdrop/mojom:mojom_shared",
     "//ui/base/wayland:color_manager_util",
+    "//ui/base/wayland:wayland_display_util",
     "//ui/base/wayland:wayland_server_input_types",
     "//ui/display/manager",
     "//ui/events:dom_keycode_converter",
diff --git a/components/exo/wayland/zaura_shell.cc b/components/exo/wayland/zaura_shell.cc
index c35bd0c..7cb6eaf 100644
--- a/components/exo/wayland/zaura_shell.cc
+++ b/components/exo/wayland/zaura_shell.cc
@@ -46,6 +46,7 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window_occlusion_tracker.h"
+#include "ui/base/wayland/wayland_display_util.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/display_observer.h"
 #include "ui/display/manager/display_manager.h"
@@ -883,9 +884,8 @@
 
   if (wl_resource_get_version(resource_) >=
       ZAURA_OUTPUT_DISPLAY_ID_SINCE_VERSION) {
-    uint32_t display_id_hi = static_cast<uint32_t>(display.id() >> 32);
-    uint32_t display_id_lo = static_cast<uint32_t>(display.id());
-    zaura_output_send_display_id(resource_, display_id_hi, display_id_lo);
+    auto display_id = ui::wayland::ToWaylandDisplayIdPair(display.id());
+    zaura_output_send_display_id(resource_, display_id.high, display_id.low);
   }
 
   if (wl_resource_get_version(resource_) >= ZAURA_OUTPUT_SCALE_SINCE_VERSION) {
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index 74b6a7a9..05bf088 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -358,6 +358,7 @@
   public_deps = [ ":metrics" ]
   deps = [
     "//base",
+    "//build/config/chromebox_for_meetings:buildflags",
     "//ui/base",
     "//ui/display",
     "//ui/gfx",
diff --git a/components/metrics/ui/form_factor_metrics_provider.cc b/components/metrics/ui/form_factor_metrics_provider.cc
index 2086265..4d1d5e8 100644
--- a/components/metrics/ui/form_factor_metrics_provider.cc
+++ b/components/metrics/ui/form_factor_metrics_provider.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "components/metrics/ui/form_factor_metrics_provider.h"
+#include "build/config/chromebox_for_meetings/buildflags.h"  // PLATFORM_CFM
 
 #include "build/build_config.h"
 #include "ui/base/device_form_factor.h"
@@ -27,6 +28,9 @@
     return SystemProfileProto::Hardware::FORM_FACTOR_TV;
 #endif  // BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(PLATFORM_CFM)
+  return SystemProfileProto::Hardware::FORM_FACTOR_MEET_DEVICE;
+#else
   switch (ui::GetDeviceFormFactor()) {
     case ui::DEVICE_FORM_FACTOR_DESKTOP:
       return SystemProfileProto::Hardware::FORM_FACTOR_DESKTOP;
@@ -37,6 +41,7 @@
     default:
       return SystemProfileProto::Hardware::FORM_FACTOR_UNKNOWN;
   }
+#endif  // BUILDFLAG(PLATFORM_CFM)
 }
 
 }  // namespace metrics
diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
index 204ebe7..382ca08d 100644
--- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
+++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
@@ -4,8 +4,6 @@
 
 package org.chromium.components.minidump_uploader;
 
-import android.util.Pair;
-
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
@@ -370,9 +368,12 @@
             File anrDir = new File(getCrashDirectory(), ANR_DIR);
             anrDir.mkdir();
 
-            List<Pair<File, String>> anrFiles = AnrCollector.collectAndWriteAnrs(anrDir);
+            List<String> anrs = AnrCollector.collectAndWriteAnrs(anrDir);
+            if (anrs.isEmpty()) {
+                return;
+            }
             File crashDir = getCrashDirectory();
-            CrashReportMimeWriter.rewriteAnrsAsMIMEs(anrFiles, crashDir);
+            CrashReportMimeWriter.rewriteAnrsAsMIMEs(anrs, crashDir);
         }
     }
 
diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashReportMimeWriter.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashReportMimeWriter.java
index 407769f..59a2f0b 100644
--- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashReportMimeWriter.java
+++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashReportMimeWriter.java
@@ -4,8 +4,6 @@
 
 package org.chromium.components.minidump_uploader;
 
-import android.util.Pair;
-
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 
@@ -42,15 +40,9 @@
      * @param anrFiles Pairs of serialized ANR proto file names and the versions they happened on.
      * @param destDir The directory in which to write the MIME files.
      */
-    public static void rewriteAnrsAsMIMEs(List<Pair<File, String>> anrFiles, File destDir) {
-        String[] anrFileNames = new String[anrFiles.size()];
-        String[] versionNumbers = new String[anrFiles.size()];
-        for (int i = 0; i < anrFiles.size(); i++) {
-            anrFileNames[i] = anrFiles.get(i).first.getAbsolutePath();
-            versionNumbers[i] = anrFiles.get(i).second;
-        }
+    public static void rewriteAnrsAsMIMEs(List<String> anrs, File destDir) {
         CrashReportMimeWriterJni.get().rewriteAnrsAsMIMEs(
-                anrFileNames, versionNumbers, destDir.getAbsolutePath());
+                anrs.toArray(new String[0]), destDir.getAbsolutePath());
     }
 
     /*
@@ -93,6 +85,6 @@
     interface Natives {
         void rewriteMinidumpsAsMIMEs(String srcDir, String destDir);
         String[] rewriteMinidumpsAsMIMEsAndGetCrashKeys(String srcDir, String destDir);
-        void rewriteAnrsAsMIMEs(String[] anrFiles, String[] versionNumbers, String destDir);
+        void rewriteAnrsAsMIMEs(String[] anrs, String destDir);
     }
 }
diff --git a/components/minidump_uploader/rewrite_minidumps_as_mimes.cc b/components/minidump_uploader/rewrite_minidumps_as_mimes.cc
index 1650b4b..d749d12 100644
--- a/components/minidump_uploader/rewrite_minidumps_as_mimes.cc
+++ b/components/minidump_uploader/rewrite_minidumps_as_mimes.cc
@@ -223,6 +223,7 @@
 static void WriteAnrAsMime(crashpad::FileReader* anr_reader,
                            crashpad::FileWriter* writer,
                            const std::string& version_number,
+                           const std::string& build_id,
                            const std::string& anr_file_name) {
   static constexpr char kAnrKey[] = "anr_data";
 
@@ -232,6 +233,9 @@
   std::string channel =
       version_info::GetChannelString(version_info::android::GetChannel());
   builder.SetFormData("channel", channel);
+  if (!build_id.empty()) {
+    builder.SetFormData("elf_build_id", build_id);
+  }
 
   // We can't use crashpad::AnnotationList::Get() as it contains a number of
   // fields which change on each Chrome restart.
@@ -267,25 +271,23 @@
 
 static void JNI_CrashReportMimeWriter_RewriteAnrsAsMIMEs(
     JNIEnv* env,
-    const base::android::JavaParamRef<jobjectArray>& j_anr_files,
-    const base::android::JavaParamRef<jobjectArray>& j_version_numbers,
+    const base::android::JavaParamRef<jobjectArray>& j_anrs,
     const base::android::JavaParamRef<jstring>& j_dest_dir) {
-  std::vector<std::string> anr_files;
-  AppendJavaStringArrayToStringVector(env, j_anr_files, &anr_files);
-  std::vector<std::string> version_numbers;
-  AppendJavaStringArrayToStringVector(env, j_version_numbers, &version_numbers);
-  // We are assuming a 1:1 mapping between an ANR and its version number.
-  DCHECK_EQ(anr_files.size(), version_numbers.size());
+  std::vector<std::string> anr_strings;
+  base::android::AppendJavaStringArrayToStringVector(env, j_anrs, &anr_strings);
   std::string dest_dir;
   base::android::ConvertJavaStringToUTF8(env, j_dest_dir, &dest_dir);
 
-  for (size_t i = 0; i < anr_files.size(); ++i) {
+  for (size_t i = 0; i < anr_strings.size(); i += 3) {
+    std::string anr_proto_file_path = anr_strings.at(i);
+    std::string chrome_version = anr_strings.at(i + 1);
+    std::string build_id = anr_strings.at(i + 2);
     crashpad::FileWriter writer;
     crashpad::FileReader reader;
     crashpad::UUID uuid;
     uuid.InitializeWithNew();
     std::string anr_file_name = uuid.ToString() + "_ANR.dmp";
-    if (!reader.Open(base::FilePath(anr_files[i]))) {
+    if (!reader.Open(base::FilePath(anr_proto_file_path))) {
       reportAnrUploadFailure(AnrSkippedReason::kFilesystemReadFailure);
       continue;
     }
@@ -296,7 +298,7 @@
       continue;
     }
 
-    WriteAnrAsMime(&reader, &writer, version_numbers[i], anr_file_name);
+    WriteAnrAsMime(&reader, &writer, chrome_version, build_id, anr_file_name);
   }
 }
 
diff --git a/components/password_manager/core/browser/export/password_csv_writer.cc b/components/password_manager/core/browser/export/password_csv_writer.cc
index ec9cab9..043368b 100644
--- a/components/password_manager/core/browser/export/password_csv_writer.cc
+++ b/components/password_manager/core/browser/export/password_csv_writer.cc
@@ -31,7 +31,8 @@
   header[2] = kUsernameColumnName;
   header[3] = kPasswordColumnName;
   if (base::FeatureList::IsEnabled(syncer::kPasswordNotesWithBackup)) {
-    header.push_back(kNoteColumnName);
+    header.resize(5);
+    header[4] = kNoteColumnName;
   }
 
   std::vector<std::map<std::string, std::string>> records;
@@ -48,13 +49,13 @@
 std::map<std::string, std::string> PasswordCSVWriter::PasswordFormToRecord(
     const CredentialUIEntry& credential) {
   std::map<std::string, std::string> record;
+  record[kTitleColumnName] = GetShownOrigin(credential);
   record[kUrlColumnName] = credential.GetURL().spec();
   record[kUsernameColumnName] = base::UTF16ToUTF8(credential.username);
   record[kPasswordColumnName] = base::UTF16ToUTF8(credential.password);
   if (base::FeatureList::IsEnabled(syncer::kPasswordNotesWithBackup)) {
     record[kNoteColumnName] = base::UTF16ToUTF8(credential.note.value);
   }
-  record[kTitleColumnName] = GetShownOrigin(credential);
   return record;
 }
 
diff --git a/components/password_manager/core/browser/export/password_csv_writer_unittest.cc b/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
index 23ba45c..f27085d 100644
--- a/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
+++ b/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
@@ -73,7 +73,8 @@
     EXPECT_THAT(pwds, ElementsAre(FormHasOriginUsernamePassword(
                           "http://example.com/", "Someone", "Secret")));
 
-    // TODO: remove this when CSVPasswordSequence will support notes.
+    // TODO(crbug.com/1383938): remove this when CSVPasswordSequence will
+    // support notes.
     std::string expected =
         is_notes_enabled
             ? "name,url,username,password,note" + kLineEnding +
diff --git a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
index 60b0e9b..292b6b4 100644
--- a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
@@ -268,10 +268,6 @@
 }
 
 TEST_F(LeakDetectionDelegateTest, StartCheckWithEnhancedProtection) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      /* enabled_features */ {safe_browsing::kEnhancedProtection},
-      /* disabled_features */ {});
   SetSBState(safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION);
   SetLeakDetectionEnabled(false);
   const PasswordForm form = CreateTestForm();
diff --git a/components/password_manager/core/browser/store_metrics_reporter.cc b/components/password_manager/core/browser/store_metrics_reporter.cc
index 8d8cee5..3e5a030 100644
--- a/components/password_manager/core/browser/store_metrics_reporter.cc
+++ b/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -329,7 +329,7 @@
     BulkCheckDone bulk_check_done,
     const std::vector<std::unique_ptr<PasswordForm>>& forms) {
   int count_leaked = base::ranges::count_if(forms, [](const auto& form) {
-    return !form->password_issues.contains(InsecureType::kLeaked);
+    return form->password_issues.contains(InsecureType::kLeaked);
   });
   base::UmaHistogramCounts100(
       base::StrCat({kPasswordManager, ".CompromisedCredentials3.CountLeaked"}),
@@ -342,7 +342,7 @@
   }
 
   int count_phished = base::ranges::count_if(forms, [](const auto& form) {
-    return !form->password_issues.contains(InsecureType::kPhished);
+    return form->password_issues.contains(InsecureType::kPhished);
   });
   base::UmaHistogramCounts100(
       base::StrCat({kPasswordManager, ".CompromisedCredentials3.CountPhished"}),
diff --git a/components/password_manager/core/browser/store_metrics_reporter_unittest.cc b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
index 32699f0..ed0cf68a 100644
--- a/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
+++ b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
@@ -1109,5 +1109,48 @@
   RunUntilIdle();
 }
 
+TEST_F(StoreMetricsReporterTest, ReportPasswordInsecureCredentialMetrics) {
+  auto profile_store =
+      base::MakeRefCounted<TestPasswordStore>(IsAccountStore(false));
+  profile_store->Init(&prefs_, /*affiliated_match_helper=*/nullptr);
+
+  const std::string kRealm1 = "https://example.com";
+
+  PasswordForm secure_password = CreateForm(kRealm1, "user", "pass");
+  profile_store->AddLogin(secure_password);
+
+  PasswordForm leaked_password = CreateForm(kRealm1, "user2", "pass");
+  leaked_password.password_issues.insert(
+      {InsecureType::kLeaked, InsecurityMetadata()});
+  profile_store->AddLogin(leaked_password);
+
+  PasswordForm phished_and_leaked_password =
+      CreateForm(kRealm1, "user3", "pass");
+  phished_and_leaked_password.password_issues.insert(
+      {InsecureType::kLeaked, InsecurityMetadata()});
+  phished_and_leaked_password.password_issues.insert(
+      {InsecureType::kPhished, InsecurityMetadata()});
+  profile_store->AddLogin(phished_and_leaked_password);
+
+  base::HistogramTester histogram_tester;
+  StoreMetricsReporter reporter(profile_store.get(), /*account_store=*/nullptr,
+                                sync_service(), identity_manager(), &prefs_,
+                                /*password_reuse_manager=*/nullptr,
+                                /*is_under_advanced_protection=*/false,
+                                /*done_callback*/ base::DoNothing());
+
+  RunUntilIdle();
+
+  histogram_tester.ExpectUniqueSample(
+      "PasswordManager.CompromisedCredentials3.CountPhished", 1, 1);
+  histogram_tester.ExpectUniqueSample(
+      "PasswordManager.CompromisedCredentials3.CountLeaked", 2, 1);
+
+  profile_store->ShutdownOnUIThread();
+  // Make sure the PasswordStore destruction parts on the background sequence
+  // finish, otherwise we get memory leak reports.
+  RunUntilIdle();
+}
+
 }  // namespace
 }  // namespace password_manager
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index 05ab578..ba4c542 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -18,6 +18,7 @@
 #include "components/payments/content/payment_app.h"
 #include "components/payments/content/payment_details_converter.h"
 #include "components/payments/content/payment_request_converter.h"
+#include "components/payments/content/payment_request_web_contents_manager.h"
 #include "components/payments/content/secure_payment_confirmation_no_creds.h"
 #include "components/payments/core/can_make_payment_query.h"
 #include "components/payments/core/error_message_util.h"
@@ -67,28 +68,27 @@
 }  // namespace
 
 PaymentRequest::PaymentRequest(
-    content::RenderFrameHost& render_frame_host,
     std::unique_ptr<ContentPaymentRequestDelegate> delegate,
-    base::WeakPtr<PaymentRequestDisplayManager> display_manager,
-    mojo::PendingReceiver<mojom::PaymentRequest> receiver,
-    SPCTransactionMode spc_transaction_mode,
-    base::WeakPtr<ObserverForTest> observer_for_testing)
-    : DocumentService(render_frame_host, std::move(receiver)),
-      WebContentsObserver(
-          content::WebContents::FromRenderFrameHost(&render_frame_host)),
+    mojo::PendingReceiver<mojom::PaymentRequest> receiver)
+    : DocumentService(*delegate->GetRenderFrameHost(), std::move(receiver)),
+      WebContentsObserver(content::WebContents::FromRenderFrameHost(
+          delegate->GetRenderFrameHost())),
       log_(web_contents()),
       delegate_(std::move(delegate)),
-      display_manager_(display_manager),
+      display_manager_(delegate_->GetDisplayManager()->GetWeakPtr()),
       display_handle_(nullptr),
       top_level_origin_(url_formatter::FormatUrlForSecurityDisplay(
           web_contents()->GetLastCommittedURL())),
       frame_origin_(url_formatter::FormatUrlForSecurityDisplay(
-          render_frame_host.GetLastCommittedURL())),
-      frame_security_origin_(render_frame_host.GetLastCommittedOrigin()),
-      spc_transaction_mode_(spc_transaction_mode),
-      observer_for_testing_(observer_for_testing),
+          delegate_->GetRenderFrameHost()->GetLastCommittedURL())),
+      frame_security_origin_(
+          delegate_->GetRenderFrameHost()->GetLastCommittedOrigin()),
+      spc_transaction_mode_(
+          PaymentRequestWebContentsManager::GetOrCreateForWebContents(
+              *web_contents())
+              ->transaction_mode()),
       journey_logger_(delegate_->IsOffTheRecord(),
-                      render_frame_host.GetPageUkmSourceId()) {
+                      delegate_->GetRenderFrameHost()->GetPageUkmSourceId()) {
   payment_handler_host_ = std::make_unique<PaymentHandlerHost>(
       web_contents(), weak_ptr_factory_.GetWeakPtr());
 }
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index a05a465c..83ddbe77 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -79,12 +79,8 @@
     virtual ~ObserverForTest() {}
   };
 
-  PaymentRequest(content::RenderFrameHost& render_frame_host,
-                 std::unique_ptr<ContentPaymentRequestDelegate> delegate,
-                 base::WeakPtr<PaymentRequestDisplayManager> display_manager,
-                 mojo::PendingReceiver<mojom::PaymentRequest> receiver,
-                 SPCTransactionMode spc_transaction_mode,
-                 base::WeakPtr<ObserverForTest> observer_for_testing);
+  PaymentRequest(std::unique_ptr<ContentPaymentRequestDelegate> delegate,
+                 mojo::PendingReceiver<mojom::PaymentRequest> receiver);
 
   PaymentRequest(const PaymentRequest&) = delete;
   PaymentRequest& operator=(const PaymentRequest&) = delete;
@@ -162,6 +158,10 @@
 
   base::WeakPtr<PaymentRequest> GetWeakPtr();
 
+  void set_observer_for_test(base::WeakPtr<ObserverForTest> observer_for_test) {
+    observer_for_testing_ = observer_for_test;
+  }
+
  private:
   // CSPChecker.
   void AllowConnectToSource(
diff --git a/components/payments/content/payment_request_web_contents_manager_unittest.cc b/components/payments/content/payment_request_web_contents_manager_unittest.cc
index 75f5c4e..8fc3074 100644
--- a/components/payments/content/payment_request_web_contents_manager_unittest.cc
+++ b/components/payments/content/payment_request_web_contents_manager_unittest.cc
@@ -26,21 +26,21 @@
   content::WebContents* web_contents() { return web_contents_; }
 
   PaymentRequest* CreateAndReturnPaymentRequest(SPCTransactionMode mode) {
+    manager_->SetSPCTransactionMode(mode);
+
     std::unique_ptr<TestContentPaymentRequestDelegate> delegate =
         std::make_unique<TestContentPaymentRequestDelegate>(
             /*task_executor=*/nullptr, &test_personal_data_manager_);
-    auto display_manager = delegate->GetDisplayManager()->GetWeakPtr();
+    delegate->set_frame_routing_id(
+        web_contents()->GetPrimaryMainFrame()->GetGlobalId());
 
     mojo::PendingRemote<payments::mojom::PaymentRequest> remote;
     mojo::PendingReceiver<payments::mojom::PaymentRequest> receiver =
         remote.InitWithNewPipeAndPassReceiver();
 
     // PaymentRequest is a DocumentService, whose lifetime is managed by the
-    // RenderFrameHost passed in here.
-    return new PaymentRequest(*web_contents()->GetPrimaryMainFrame(),
-                              std::move(delegate), std::move(display_manager),
-                              std::move(receiver), mode,
-                              /*observer_for_testing=*/nullptr);
+    // RenderFrameHost passed into the delegate.
+    return new PaymentRequest(std::move(delegate), std::move(receiver));
   }
 
   // The PaymentRequestWebContentsManager under test.
diff --git a/components/payments/content/test_content_payment_request_delegate.cc b/components/payments/content/test_content_payment_request_delegate.cc
index df24ce8..007ff36 100644
--- a/components/payments/content/test_content_payment_request_delegate.cc
+++ b/components/payments/content/test_content_payment_request_delegate.cc
@@ -8,6 +8,7 @@
 
 #include "components/payments/content/payment_manifest_web_data_service.h"
 #include "components/payments/core/error_strings.h"
+#include "content/public/browser/render_frame_host.h"
 
 namespace payments {
 
@@ -21,7 +22,7 @@
 
 content::RenderFrameHost*
 TestContentPaymentRequestDelegate::GetRenderFrameHost() const {
-  return nullptr;
+  return content::RenderFrameHost::FromID(frame_routing_id_);
 }
 
 std::unique_ptr<webauthn::InternalAuthenticator>
diff --git a/components/payments/content/test_content_payment_request_delegate.h b/components/payments/content/test_content_payment_request_delegate.h
index f3c7a0f..5077d9b 100644
--- a/components/payments/content/test_content_payment_request_delegate.h
+++ b/components/payments/content/test_content_payment_request_delegate.h
@@ -10,6 +10,7 @@
 #include "components/payments/content/content_payment_request_delegate.h"
 #include "components/payments/content/payment_request_display_manager.h"
 #include "components/payments/core/test_payment_request_delegate.h"
+#include "content/public/browser/global_routing_id.h"
 
 namespace autofill {
 class PersonalDataManager;
@@ -78,9 +79,15 @@
       base::OnceClosure response_callback,
       base::OnceClosure opt_out_callback) override;
 
+  // Must be called if GetRenderFrameHost() needs to return non-null.
+  void set_frame_routing_id(content::GlobalRenderFrameHostId frame_routing_id) {
+    frame_routing_id_ = frame_routing_id;
+  }
+
  private:
   TestPaymentRequestDelegate core_delegate_;
   PaymentRequestDisplayManager payment_request_display_manager_;
+  content::GlobalRenderFrameHostId frame_routing_id_;
 };
 
 }  // namespace payments
diff --git a/components/remote_cocoa/app_shim/immersive_mode_controller.h b/components/remote_cocoa/app_shim/immersive_mode_controller.h
index 496ce8de..d2dc1a2 100644
--- a/components/remote_cocoa/app_shim/immersive_mode_controller.h
+++ b/components/remote_cocoa/app_shim/immersive_mode_controller.h
@@ -11,6 +11,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/mac/scoped_nsobject.h"
 #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
+#include "components/remote_cocoa/common/native_widget_ns_window.mojom-shared.h"
 
 @class ClearTitlebarViewController;
 @class ImmersiveModeMapper;
@@ -37,7 +38,7 @@
 
   void Enable();
   void OnTopViewBoundsChanged(const gfx::Rect& bounds);
-  void UpdateToolbarVisibility(bool always_show);
+  void UpdateToolbarVisibility(mojom::ToolbarVisibilityStyle style);
 
   // Reveal top chrome leaving it visible until all outstanding calls to
   // RevealLock() are balanced with RevealUnlock().
@@ -67,7 +68,8 @@
       immersive_mode_window_observer_;
 
   int revealed_lock_count_ = 0;
-  bool always_show_toolbar_ = false;
+  mojom::ToolbarVisibilityStyle last_used_style_ =
+      mojom::ToolbarVisibilityStyle::kAutohide;
 
   base::WeakPtrFactory<ImmersiveModeController> weak_ptr_factory_;
 };
diff --git a/components/remote_cocoa/app_shim/immersive_mode_controller.mm b/components/remote_cocoa/app_shim/immersive_mode_controller.mm
index bf9b9ed..5b69d4b 100644
--- a/components/remote_cocoa/app_shim/immersive_mode_controller.mm
+++ b/components/remote_cocoa/app_shim/immersive_mode_controller.mm
@@ -356,30 +356,37 @@
   size.height = frame.size.height;
   [overlay_view setFrameSize:size];
   PropagateFrameSizeToViewsSubviews(overlay_view);
+  UpdateToolbarVisibility(last_used_style_);
 }
 
-void ImmersiveModeController::UpdateToolbarVisibility(bool always_show) {
-  // Remember the last used always_show for internal use of
-  // UpdateToolbarVisibility.
-  always_show_toolbar_ = always_show;
+void ImmersiveModeController::UpdateToolbarVisibility(
+    mojom::ToolbarVisibilityStyle style) {
+  // Remember the last used style for internal use of UpdateToolbarVisibility.
+  last_used_style_ = style;
 
   // Only make changes if there are no outstanding reveal locks.
   if (revealed_lock_count_ > 0) {
     return;
   }
+  switch (style) {
+    case mojom::ToolbarVisibilityStyle::kAlways:
+      immersive_mode_titlebar_view_controller_.get().fullScreenMinHeight =
+          immersive_mode_titlebar_view_controller_.get().view.frame.size.height;
+      browser_widget_.styleMask &= ~NSWindowStyleMaskFullSizeContentView;
 
-  if (always_show) {
-    immersive_mode_titlebar_view_controller_.get().fullScreenMinHeight =
-        immersive_mode_titlebar_view_controller_.get().view.frame.size.height;
-    browser_widget_.styleMask &= ~NSWindowStyleMaskFullSizeContentView;
-
-    // Toggling the controller will allow the content view to resize below Top
-    // Chrome.
-    immersive_mode_titlebar_view_controller_.get().hidden = YES;
-    immersive_mode_titlebar_view_controller_.get().hidden = NO;
-  } else {
-    immersive_mode_titlebar_view_controller_.get().fullScreenMinHeight = 0;
-    browser_widget_.styleMask |= NSWindowStyleMaskFullSizeContentView;
+      // Toggling the controller will allow the content view to resize below Top
+      // Chrome.
+      immersive_mode_titlebar_view_controller_.get().hidden = YES;
+      immersive_mode_titlebar_view_controller_.get().hidden = NO;
+      break;
+    case mojom::ToolbarVisibilityStyle::kAutohide:
+      immersive_mode_titlebar_view_controller_.get().hidden = NO;
+      immersive_mode_titlebar_view_controller_.get().fullScreenMinHeight = 0;
+      browser_widget_.styleMask |= NSWindowStyleMaskFullSizeContentView;
+      break;
+    case mojom::ToolbarVisibilityStyle::kNone:
+      immersive_mode_titlebar_view_controller_.get().hidden = YES;
+      break;
   }
 
   // Unpin the titlebar.
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
index e2f00d7..156d06e 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
@@ -19,6 +19,7 @@
 #include "components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h"
 #include "components/remote_cocoa/app_shim/ns_view_ids.h"
 #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
+#include "components/remote_cocoa/common/native_widget_ns_window.mojom-shared.h"
 #include "components/remote_cocoa/common/native_widget_ns_window.mojom.h"
 #include "components/remote_cocoa/common/text_input_host.mojom.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
@@ -288,7 +289,8 @@
       uint64_t fullscreen_overlay_widget_id,
       EnableImmersiveFullscreenCallback callback) override;
   void DisableImmersiveFullscreen() override;
-  void UpdateToolbarVisibility(bool always_show) override;
+  void UpdateToolbarVisibility(
+      remote_cocoa::mojom::ToolbarVisibilityStyle style) override;
   void OnTopContainerViewBoundsChanged(const gfx::Rect& bounds) override;
   void SetCanGoBack(bool can_go_back) override;
   void SetCanGoForward(bool can_go_back) override;
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
index 1b91b71..70bc4eb 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -923,9 +923,10 @@
   immersive_mode_controller_.reset();
 }
 
-void NativeWidgetNSWindowBridge::UpdateToolbarVisibility(bool always_show) {
+void NativeWidgetNSWindowBridge::UpdateToolbarVisibility(
+    remote_cocoa::mojom::ToolbarVisibilityStyle style) {
   if (immersive_mode_controller_) {
-    immersive_mode_controller_->UpdateToolbarVisibility(always_show);
+    immersive_mode_controller_->UpdateToolbarVisibility(style);
   }
 }
 
diff --git a/components/remote_cocoa/common/native_widget_ns_window.mojom b/components/remote_cocoa/common/native_widget_ns_window.mojom
index 5229d8a..ebd822e 100644
--- a/components/remote_cocoa/common/native_widget_ns_window.mojom
+++ b/components/remote_cocoa/common/native_widget_ns_window.mojom
@@ -91,6 +91,19 @@
   kWebAppFrameToolbar,
 };
 
+// The visibility style of the toolbar in immersive fullscreen.
+enum ToolbarVisibilityStyle {
+  // No toolbar. Used for content fullscreen.
+  kNone,
+
+  // The toolbar is always shown.
+  kAlways,
+
+  // The toolbar will autohide. It can be revealed by placing the mouse at the
+  // top of the screen.
+  kAutohide,
+};
+
 // The interface through which a NativeWidgetMac may interact with an NSWindow
 // (possibly in a process separate from the browser process).
 interface NativeWidgetNSWindow {
@@ -273,8 +286,9 @@
 
   // Update the visibility of the toolbar (top chrome) while in immersive
   // fullscreen. Typically this is used in response to the
-  // View -> "Always Show Toolbar in Full Screen" menu changing.
-  UpdateToolbarVisibility(bool always_show);
+  // View -> "Always Show Toolbar in Full Screen" menu changing or content
+  // going fullscreen.
+  UpdateToolbarVisibility(ToolbarVisibilityStyle style);
 
   // Also used during immersive fullscreen. Update the bounds of the AppKit
   // NSWindow hosting top chrome.
diff --git a/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc b/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc
index 19b1c6a07..0b1f074 100644
--- a/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc
+++ b/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc
@@ -88,24 +88,18 @@
 
 TEST_F(RealTimePolicyEngineTest,
        TestCanPerformFullURLLookup_EnhancedProtection) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   pref_service_.SetBoolean(prefs::kSafeBrowsingEnhanced, true);
   ASSERT_TRUE(CanPerformFullURLLookup(/* is_off_the_record */ false));
 }
 
 TEST_F(RealTimePolicyEngineTest,
        TestCanPerformFullURLLookup_DisabledEnhancedProtection) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(kEnhancedProtection);
-  pref_service_.SetBoolean(prefs::kSafeBrowsingEnhanced, true);
+  pref_service_.SetBoolean(prefs::kSafeBrowsingEnhanced, false);
   ASSERT_FALSE(CanPerformFullURLLookup(/* is_off_the_record */ false));
 }
 
 TEST_F(RealTimePolicyEngineTest,
        TestCanPerformFullURLLookup_RTLookupForEpEnabled_WithTokenDisabled) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   pref_service_.SetBoolean(prefs::kSafeBrowsingEnhanced, true);
   EXPECT_TRUE(CanPerformFullURLLookup(/* is_off_the_record */ false));
   EXPECT_TRUE(CanPerformFullURLLookupWithToken(
@@ -140,8 +134,6 @@
 TEST_F(
     RealTimePolicyEngineTest,
     TestCanPerformFullURLLookupWithToken_ClientControlledWithEnhancedProtection) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   // Enhanced protection is disabled: token fetches should be disallowed whether
   // or not they are configured in the client.
   EXPECT_FALSE(CanPerformFullURLLookupWithToken(
diff --git a/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc b/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
index 8b45b853..af104e6 100644
--- a/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
+++ b/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
@@ -1021,8 +1021,6 @@
 TEST_F(RealTimeUrlLookupServiceTest,
        TestReferrerChain_NotSanitizedIfSubresourceAllowed) {
   EnableMbb();
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   // Subresource is allowed when enhanced protection is enabled.
   SetSafeBrowsingState(&test_pref_service_,
                        SafeBrowsingState::ENHANCED_PROTECTION);
diff --git a/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc b/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc
index 22425ea..d115494 100644
--- a/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc
+++ b/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc
@@ -199,8 +199,6 @@
 
 TEST_F(SafeBrowsingMetricsCollectorTest,
        AddSafeBrowsingEventToPref_OldestTsRemoved) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
   metrics_collector_->AddSafeBrowsingEventToPref(
       EventType::DATABASE_INTERSTITIAL_BYPASS);
@@ -230,8 +228,6 @@
 
 TEST_F(SafeBrowsingMetricsCollectorTest,
        AddSafeBrowsingEventToPref_SafeBrowsingManaged) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
   metrics_collector_->AddSafeBrowsingEventToPref(
       EventType::DATABASE_INTERSTITIAL_BYPASS);
@@ -253,8 +249,6 @@
 TEST_F(SafeBrowsingMetricsCollectorTest,
        LogEnhancedProtectionDisabledMetrics_GetLastBypassEventType) {
   base::HistogramTester histograms;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
 
   FastForwardAndAddEvent(base::Hours(1),
@@ -338,8 +332,6 @@
 TEST_F(SafeBrowsingMetricsCollectorTest,
        LogEnhancedProtectionDisabledMetrics_GetLastSecuritySensitiveEventType) {
   base::HistogramTester histograms;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
 
   FastForwardAndAddEvent(
@@ -570,8 +562,6 @@
 TEST_F(SafeBrowsingMetricsCollectorTest,
        LogEnhancedProtectionDisabledMetrics_NotLoggedIfHitQuotaLimit) {
   base::HistogramTester histograms;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
 
   FastForwardAndAddEvent(base::Hours(1),
@@ -625,8 +615,6 @@
 TEST_F(SafeBrowsingMetricsCollectorTest, LogDailyEventMetrics_LoggedDaily) {
   base::HistogramTester histograms;
   SetSafeBrowsingMetricsLastLogTime(base::Time::Now());
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
   metrics_collector_->StartLogging();
   FastForwardAndAddEvent(base::Hours(1),
@@ -713,8 +701,6 @@
        LogDailyEventMetrics_DoesNotCountOldEvent) {
   base::HistogramTester histograms;
   SetSafeBrowsingMetricsLastLogTime(base::Time::Now());
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
   metrics_collector_->StartLogging();
   FastForwardAndAddEvent(base::Hours(1),
@@ -757,8 +743,6 @@
        LogDailyEventMetrics_SwitchBetweenDifferentUserState) {
   base::HistogramTester histograms;
   SetSafeBrowsingMetricsLastLogTime(base::Time::Now());
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
   metrics_collector_->StartLogging();
   FastForwardAndAddEvent(base::Hours(1),
@@ -813,8 +797,6 @@
 }
 
 TEST_F(SafeBrowsingMetricsCollectorTest, GetUserState) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kEnhancedProtection);
   SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
   EXPECT_EQ(UserState::kEnhancedProtection, metrics_collector_->GetUserState());
 
diff --git a/components/safe_browsing/core/browser/user_population_unittest.cc b/components/safe_browsing/core/browser/user_population_unittest.cc
index 297e62b..1abb2b4e 100644
--- a/components/safe_browsing/core/browser/user_population_unittest.cc
+++ b/components/safe_browsing/core/browser/user_population_unittest.cc
@@ -35,10 +35,6 @@
 TEST(GetUserPopulationTest, PopulatesPopulation) {
   base::test::TaskEnvironment task_environment;
   auto pref_service = CreatePrefService();
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      /* enabled_features */ {safe_browsing::kEnhancedProtection},
-      /* disabled_features */ {});
 
   SetSafeBrowsingState(pref_service.get(),
                        SafeBrowsingState::STANDARD_PROTECTION);
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc b/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc
index 73a9bc8..fe3da0d 100644
--- a/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc
+++ b/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc
@@ -105,16 +105,8 @@
   EXPECT_FALSE(IsEnhancedProtectionEnabled(prefs_));
 
   SetEnhancedProtectionPrefForTests(&prefs_, true);
+  EXPECT_TRUE(IsEnhancedProtectionEnabled(prefs_));
   {
-    base::test::ScopedFeatureList scoped_feature_list;
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitAndEnableFeature(kEnhancedProtection);
-    EXPECT_TRUE(IsEnhancedProtectionEnabled(prefs_));
-  }
-  {
-    base::test::ScopedFeatureList scoped_feature_list;
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitAndDisableFeature(kEnhancedProtection);
     prefs_.SetBoolean(prefs::kSafeBrowsingEnabled, false);
     EXPECT_FALSE(IsEnhancedProtectionEnabled(prefs_));
   }
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index 4488026..30abb2c 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -199,10 +199,9 @@
       return "search/touch/";
     case ui::DEVICE_FORM_FACTOR_TABLET:
       return "search/pad/";
-    default:
-      NOTREACHED();
-      return std::string();
   }
+  NOTREACHED();
+  return std::string();
 }
 
 }  // namespace
diff --git a/components/sync_sessions/synced_session_tracker.cc b/components/sync_sessions/synced_session_tracker.cc
index 300fa5b4..fbfc729 100644
--- a/components/sync_sessions/synced_session_tracker.cc
+++ b/components/sync_sessions/synced_session_tracker.cc
@@ -263,25 +263,19 @@
   return &GetTrackedSession(session_tag)->synced_session;
 }
 
-bool SyncedSessionTracker::DeleteForeignSession(
+void SyncedSessionTracker::DeleteForeignSession(
     const std::string& session_tag) {
   DCHECK_NE(local_session_tag_, session_tag);
 
   auto iter = session_map_.find(session_tag);
   if (iter == session_map_.end()) {
-    return false;
+    return;
   }
 
-  // An implicitly created session that has children tabs but no header node
-  // will have never had the device_type changed from unset.
-  const bool header_existed =
-      iter->second.synced_session.device_type != sync_pb::SyncEnums::TYPE_UNSET;
   // SyncedSession's destructor will trigger deletion of windows which will in
   // turn trigger the deletion of tabs. This doesn't affect the convenience
   // maps.
   session_map_.erase(iter);
-
-  return header_existed;
 }
 
 void SyncedSessionTracker::ResetSessionTracking(
diff --git a/components/sync_sessions/synced_session_tracker.h b/components/sync_sessions/synced_session_tracker.h
index 3c193484..860f4e2 100644
--- a/components/sync_sessions/synced_session_tracker.h
+++ b/components/sync_sessions/synced_session_tracker.h
@@ -163,8 +163,7 @@
   void DeleteForeignTab(const std::string& session_tag, int tab_node_id);
 
   // Deletes the session associated with |session_tag| if it exists.
-  // Returns true if the session existed and was deleted, false otherwise.
-  bool DeleteForeignSession(const std::string& session_tag);
+  void DeleteForeignSession(const std::string& session_tag);
 
   // **** Methods specific to the local session. ****
 
diff --git a/components/sync_sessions/synced_session_tracker_unittest.cc b/components/sync_sessions/synced_session_tracker_unittest.cc
index 225e149..76a0ad823 100644
--- a/components/sync_sessions/synced_session_tracker_unittest.cc
+++ b/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -302,7 +302,7 @@
   tabs2.push_back(tracker_.GetTab(kTag2, kTab1));
   ASSERT_EQ(1U, tracker_.num_synced_tabs(kTag2));
   ASSERT_EQ(2U, tracker_.num_synced_sessions());
-  ASSERT_FALSE(tracker_.DeleteForeignSession(kTag3));
+  tracker_.DeleteForeignSession(kTag3);
 
   SyncedSession* session = tracker_.GetSession(kTag);
   ASSERT_EQ(2U, tracker_.num_synced_sessions());
@@ -317,7 +317,7 @@
   ASSERT_TRUE(session3);
   ASSERT_NE(session, session2);
   ASSERT_NE(session2, session3);
-  ASSERT_TRUE(tracker_.DeleteForeignSession(kTag3));
+  tracker_.DeleteForeignSession(kTag3);
   ASSERT_EQ(2U, tracker_.num_synced_sessions());
 
   tracker_.PutWindowInSession(kTag, kWindow1);     // Create a window.
@@ -388,10 +388,10 @@
   tracker_.PutWindowInSession(kTag3, kWindow2);
   tracker_.PutTabInWindow(kTag3, kWindow2, kTab2);
   EXPECT_THAT(tracker_.LookupTabNodeIds(kTag3), IsEmpty());
-  EXPECT_FALSE(tracker_.DeleteForeignSession(kTag3));
+  tracker_.DeleteForeignSession(kTag3);
   EXPECT_THAT(tracker_.LookupTabNodeIds(kTag3), IsEmpty());
 
-  EXPECT_FALSE(tracker_.DeleteForeignSession(kTag));
+  tracker_.DeleteForeignSession(kTag);
   EXPECT_THAT(tracker_.LookupTabNodeIds(kTag), IsEmpty());
   EXPECT_THAT(tracker_.LookupTabNodeIds(kTag2), ElementsAre(21, 22));
 
@@ -399,7 +399,7 @@
   tracker_.OnTabNodeSeen(kTag2, 23, kTab7);
   EXPECT_THAT(tracker_.LookupTabNodeIds(kTag2), ElementsAre(21, 22, 23));
 
-  EXPECT_FALSE(tracker_.DeleteForeignSession(kTag2));
+  tracker_.DeleteForeignSession(kTag2);
   EXPECT_THAT(tracker_.LookupTabNodeIds(kTag2), IsEmpty());
 }
 
diff --git a/components/test/data/payments/payment_handler_status.js b/components/test/data/payments/payment_handler_status.js
index 9dd5560..da601934 100644
--- a/components/test/data/payments/payment_handler_status.js
+++ b/components/test/data/payments/payment_handler_status.js
@@ -63,7 +63,7 @@
     }
     return response.details.status;
   } catch (e) {
-    return e.message;
+    return e.toString();
   }
 }
 
@@ -88,7 +88,7 @@
     }
     return response.details.status;
   } catch (e) {
-    return e.message;
+    return e.toString();
   }
 }
 
@@ -111,6 +111,6 @@
     }
     return response.details.status;
   } catch (e) {
-    return e.message;
+    return e.toString();
   }
 }
diff --git a/components/tracing/common/background_tracing_metrics_provider.cc b/components/tracing/common/background_tracing_metrics_provider.cc
index a74b33c..d4483137 100644
--- a/components/tracing/common/background_tracing_metrics_provider.cc
+++ b/components/tracing/common/background_tracing_metrics_provider.cc
@@ -39,11 +39,6 @@
     return;
   }
 
-  base::UmaHistogramCounts100000("Tracing.Background.UploadingTraceSizeInKB",
-                                 serialized_trace.size() / 1024);
-  metrics::TraceLog* log = uma_proto->add_trace_log();
-  log->set_raw_data(std::move(serialized_trace));
-
   auto* system_profile = uma_proto->mutable_system_profile();
 
   for (auto& provider : system_profile_providers_) {
@@ -51,12 +46,28 @@
         base::TimeTicks::Now(), system_profile);
   }
 
-  ProvideEmbedderMetrics(uma_proto, snapshot_manager);
-  std::move(done_callback).Run(true);
+  metrics::TraceLog* log = uma_proto->add_trace_log();
+  ProvideEmbedderMetrics(*uma_proto, std::move(serialized_trace), *log,
+                         snapshot_manager, std::move(done_callback));
 }
 
 void BackgroundTracingMetricsProvider::ProvideEmbedderMetrics(
-    metrics::ChromeUserMetricsExtension* uma_proto,
-    base::HistogramSnapshotManager* snapshot_manager) {}
+    metrics::ChromeUserMetricsExtension& uma_proto,
+    std::string&& serialized_trace,
+    metrics::TraceLog& log,
+    base::HistogramSnapshotManager* snapshot_manager,
+    base::OnceCallback<void(bool)> done_callback) {
+  SetTrace(log, std::move(serialized_trace));
+  std::move(done_callback).Run(true);
+}
+
+void BackgroundTracingMetricsProvider::SetTrace(
+    metrics::TraceLog& log,
+    std::string&& serialized_trace) {
+  base::UmaHistogramCounts100000("Tracing.Background.UploadingTraceSizeInKB",
+                                 serialized_trace.size() / 1024);
+
+  log.set_raw_data(std::move(serialized_trace));
+}
 
 }  // namespace tracing
diff --git a/components/tracing/common/background_tracing_metrics_provider.h b/components/tracing/common/background_tracing_metrics_provider.h
index 7b89cb59..29ac36e5 100644
--- a/components/tracing/common/background_tracing_metrics_provider.h
+++ b/components/tracing/common/background_tracing_metrics_provider.h
@@ -9,6 +9,7 @@
 
 #include "components/metrics/metrics_provider.h"
 #include "components/tracing/tracing_export.h"
+#include "third_party/metrics_proto/trace_log.pb.h"
 
 namespace tracing {
 
@@ -39,10 +40,17 @@
 
  protected:
   // Embedders can override this to do any additional processing of the log
-  // before it is sent.
+  // before it is sent. This includes processing of the trace itself (e.g.
+  // compression).
   virtual void ProvideEmbedderMetrics(
-      metrics::ChromeUserMetricsExtension* uma_proto,
-      base::HistogramSnapshotManager* snapshot_manager);
+      metrics::ChromeUserMetricsExtension& uma_proto,
+      std::string&& serialized_trace,
+      metrics::TraceLog& log,
+      base::HistogramSnapshotManager* snapshot_manager,
+      base::OnceCallback<void(bool)> done_callback);
+
+  // Writes |serialized_trace| into |logs|'s |raw_data| field.
+  void SetTrace(metrics::TraceLog& log, std::string&& serialized_trace);
 
   std::vector<std::unique_ptr<metrics::MetricsProvider>>
       system_profile_providers_;
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm
index c0be953..f06cc18 100644
--- a/components/translate/ios/browser/ios_translate_driver.mm
+++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -319,6 +319,7 @@
                         pending_page_seq_no_, source_language,
                         translation_time);
   pending_page_seq_no_ = -1;
+  timeout_timer_.Stop();
 }
 
 void IOSTranslateDriver::StopObservingWebState() {
diff --git a/content/BUILD.gn b/content/BUILD.gn
index 30c96d5..618cb81 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -121,7 +121,6 @@
     "//content/browser/aggregation_service:mojo_bindings_webui_js",
     "//content/browser/attribution_reporting:internals_mojo_bindings_webui_js",
     "//content/browser/attribution_reporting:mojo_bindings_webui_js",
-    "//content/browser/preloading/prerender:mojo_bindings_webui_js",
     "//content/browser/resources/aggregation_service:build_ts",
     "//content/browser/resources/attribution_reporting:build_ts",
     "//content/browser/resources/gpu:html_wrapper_files",
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d519feb5..096f8de 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -136,7 +136,6 @@
     "//content/browser/indexed_db:mojo_bindings",
     "//content/browser/notifications:notification_proto",
     "//content/browser/payments:payment_app_proto",
-    "//content/browser/preloading/prerender:mojo_bindings",
     "//content/browser/private_aggregation/proto:private_aggregation_budgets_proto",
     "//content/browser/process_internals:mojo_bindings",
     "//content/browser/resources:resources",
@@ -1473,10 +1472,6 @@
     "preloading/prerender/prerender_host.h",
     "preloading/prerender/prerender_host_registry.cc",
     "preloading/prerender/prerender_host_registry.h",
-    "preloading/prerender/prerender_internals_handler_impl.cc",
-    "preloading/prerender/prerender_internals_handler_impl.h",
-    "preloading/prerender/prerender_internals_ui.cc",
-    "preloading/prerender/prerender_internals_ui.h",
     "preloading/prerender/prerender_metrics.cc",
     "preloading/prerender/prerender_metrics.h",
     "preloading/prerender/prerender_navigation_throttle.cc",
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 2928d958..f9c1ed1 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -740,10 +740,6 @@
   return CreateTextPositionAt(offset)->AsDomSelectionPosition();
 }
 
-const std::string& BrowserAccessibility::GetName() const {
-  return node()->GetNameUTF8();
-}
-
 std::u16string BrowserAccessibility::GetNameAsString16() const {
   return node()->GetNameUTF16();
 }
@@ -860,14 +856,6 @@
   return true;
 }
 
-bool BrowserAccessibility::IsReadOnlySupported() const {
-  return node()->IsReadOnlySupported();
-}
-
-bool BrowserAccessibility::IsReadOnlyOrDisabled() const {
-  return node()->IsReadOnlyOrDisabled();
-}
-
 bool BrowserAccessibility::HasVisibleCaretOrSelection() const {
   // The caret should be visible if Caret Browsing is enabled.
   //
@@ -966,6 +954,11 @@
   return result;
 }
 
+void BrowserAccessibility::EnableGlobalAccessibilityModeOnApiUsage() const {
+  content::BrowserAccessibilityStateImpl::GetInstance()
+      ->OnAccessibilityApiUsage();
+}
+
 const std::vector<gfx::NativeViewAccessible>
 BrowserAccessibility::GetUIADirectChildrenInRange(
     ui::AXPlatformNodeDelegate* start,
@@ -976,10 +969,6 @@
   return {};
 }
 
-std::string BrowserAccessibility::GetLanguage() const {
-  return node()->GetLanguage();
-}
-
 gfx::NativeViewAccessible BrowserAccessibility::GetNativeViewAccessible() {
   // TODO(703369) On Windows, where we have started to migrate to an
   // AXPlatformNode implementation, the BrowserAccessibilityWin subclass has
@@ -998,202 +987,6 @@
   return node()->data();
 }
 
-const ui::AXTreeData& BrowserAccessibility::GetTreeData() const {
-  return manager()->GetTreeData();
-}
-
-ax::mojom::Role BrowserAccessibility::GetRole() const {
-  // Getting the role is generally the result of an accessibility API call, so
-  // we should reset the auto-disable accessibility code.
-  content::BrowserAccessibilityStateImpl::GetInstance()
-      ->OnAccessibilityApiUsage();
-
-  // TODO(accessibility): Why is role checked after this object has been
-  // destructed causing a dangling pointer bug?
-  return node() ? node()->GetRole() : ax::mojom::Role::kUnknown;
-}
-
-bool BrowserAccessibility::HasBoolAttribute(
-    ax::mojom::BoolAttribute attribute) const {
-  return node()->HasBoolAttribute(attribute);
-}
-
-bool BrowserAccessibility::GetBoolAttribute(
-    ax::mojom::BoolAttribute attribute) const {
-  return node()->GetBoolAttribute(attribute);
-}
-
-bool BrowserAccessibility::GetBoolAttribute(ax::mojom::BoolAttribute attribute,
-                                            bool* value) const {
-  return node()->GetBoolAttribute(attribute, value);
-}
-
-bool BrowserAccessibility::HasFloatAttribute(
-    ax::mojom::FloatAttribute attribute) const {
-  return node()->HasFloatAttribute(attribute);
-}
-
-float BrowserAccessibility::GetFloatAttribute(
-    ax::mojom::FloatAttribute attribute) const {
-  return node()->GetFloatAttribute(attribute);
-}
-
-bool BrowserAccessibility::GetFloatAttribute(
-    ax::mojom::FloatAttribute attribute,
-    float* value) const {
-  return node()->GetFloatAttribute(attribute, value);
-}
-
-const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
-BrowserAccessibility::GetIntAttributes() const {
-  return node()->GetIntAttributes();
-}
-
-bool BrowserAccessibility::HasIntAttribute(
-    ax::mojom::IntAttribute attribute) const {
-  return node()->HasIntAttribute(attribute);
-}
-
-int BrowserAccessibility::GetIntAttribute(
-    ax::mojom::IntAttribute attribute) const {
-  return node()->GetIntAttribute(attribute);
-}
-
-bool BrowserAccessibility::GetIntAttribute(ax::mojom::IntAttribute attribute,
-                                           int* value) const {
-  return node()->GetIntAttribute(attribute, value);
-}
-
-const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
-BrowserAccessibility::GetStringAttributes() const {
-  return node()->GetStringAttributes();
-}
-
-bool BrowserAccessibility::HasStringAttribute(
-    ax::mojom::StringAttribute attribute) const {
-  return node()->HasStringAttribute(attribute);
-}
-
-const std::string& BrowserAccessibility::GetStringAttribute(
-    ax::mojom::StringAttribute attribute) const {
-  return node()->GetStringAttribute(attribute);
-}
-
-bool BrowserAccessibility::GetStringAttribute(
-    ax::mojom::StringAttribute attribute,
-    std::string* value) const {
-  return node()->GetStringAttribute(attribute, value);
-}
-
-std::u16string BrowserAccessibility::GetString16Attribute(
-    ax::mojom::StringAttribute attribute) const {
-  return node()->GetString16Attribute(attribute);
-}
-
-bool BrowserAccessibility::GetString16Attribute(
-    ax::mojom::StringAttribute attribute,
-    std::u16string* value) const {
-  return node()->GetString16Attribute(attribute, value);
-}
-
-const std::string& BrowserAccessibility::GetInheritedStringAttribute(
-    ax::mojom::StringAttribute attribute) const {
-  return node()->GetInheritedStringAttribute(attribute);
-}
-
-std::u16string BrowserAccessibility::GetInheritedString16Attribute(
-    ax::mojom::StringAttribute attribute) const {
-  return node()->GetInheritedString16Attribute(attribute);
-}
-
-const std::vector<std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
-BrowserAccessibility::GetIntListAttributes() const {
-  return node()->GetIntListAttributes();
-}
-
-bool BrowserAccessibility::HasIntListAttribute(
-    ax::mojom::IntListAttribute attribute) const {
-  return node()->HasIntListAttribute(attribute);
-}
-
-const std::vector<int32_t>& BrowserAccessibility::GetIntListAttribute(
-    ax::mojom::IntListAttribute attribute) const {
-  return node()->GetIntListAttribute(attribute);
-}
-
-bool BrowserAccessibility::GetIntListAttribute(
-    ax::mojom::IntListAttribute attribute,
-    std::vector<int32_t>* value) const {
-  return node()->GetIntListAttribute(attribute, value);
-}
-
-bool BrowserAccessibility::HasStringListAttribute(
-    ax::mojom::StringListAttribute attribute) const {
-  return node()->HasStringListAttribute(attribute);
-}
-
-const std::vector<std::string>& BrowserAccessibility::GetStringListAttribute(
-    ax::mojom::StringListAttribute attribute) const {
-  return node()->GetStringListAttribute(attribute);
-}
-
-bool BrowserAccessibility::GetStringListAttribute(
-    ax::mojom::StringListAttribute attribute,
-    std::vector<std::string>* value) const {
-  return node()->GetStringListAttribute(attribute, value);
-}
-
-bool BrowserAccessibility::HasHtmlAttribute(const char* attribute) const {
-  return node()->HasHtmlAttribute(attribute);
-}
-
-const BrowserAccessibility::HtmlAttributes&
-BrowserAccessibility::GetHtmlAttributes() const {
-  return node()->GetHtmlAttributes();
-}
-
-bool BrowserAccessibility::GetHtmlAttribute(const char* attribute,
-                                            std::string* value) const {
-  return node()->GetHtmlAttribute(attribute, value);
-}
-
-bool BrowserAccessibility::GetHtmlAttribute(const char* attribute,
-                                            std::u16string* value) const {
-  return node()->GetHtmlAttribute(attribute, value);
-}
-
-ui::AXTextAttributes BrowserAccessibility::GetTextAttributes() const {
-  return node()->GetTextAttributes();
-}
-
-bool BrowserAccessibility::HasState(ax::mojom::State state) const {
-  return node()->HasState(state);
-}
-
-ax::mojom::State BrowserAccessibility::GetState() const {
-  return node()->GetState();
-}
-
-bool BrowserAccessibility::HasAction(ax::mojom::Action action) const {
-  return node()->HasAction(action);
-}
-
-bool BrowserAccessibility::HasTextStyle(ax::mojom::TextStyle text_style) const {
-  return node()->HasTextStyle(text_style);
-}
-
-ax::mojom::NameFrom BrowserAccessibility::GetNameFrom() const {
-  return node()->GetNameFrom();
-}
-
-ax::mojom::DescriptionFrom BrowserAccessibility::GetDescriptionFrom() const {
-  return GetData().GetDescriptionFrom();
-}
-
-const ui::AXSelection BrowserAccessibility::GetUnignoredSelection() const {
-  return node()->GetUnignoredSelection();
-}
-
 BrowserAccessibility::AXPosition BrowserAccessibility::CreateTextPositionAt(
     int offset,
     ax::mojom::TextAffinity affinity) const {
@@ -1300,10 +1093,6 @@
   return manager()->GetFocus() == this;
 }
 
-bool BrowserAccessibility::IsInvisibleOrIgnored() const {
-  return node()->IsInvisibleOrIgnored();
-}
-
 bool BrowserAccessibility::IsToplevelBrowserWindow() {
   return false;
 }
@@ -1483,18 +1272,6 @@
   return root_delegate->AccessibilityGetAcceleratedWidget();
 }
 
-bool BrowserAccessibility::IsTable() const {
-  return node()->IsTable();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableRowCount() const {
-  return node()->GetTableRowCount();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableColCount() const {
-  return node()->GetTableColCount();
-}
-
 absl::optional<int> BrowserAccessibility::GetTableAriaColCount() const {
   return node()->GetTableAriaColCount();
 }
@@ -1503,33 +1280,6 @@
   return node()->GetTableAriaRowCount();
 }
 
-absl::optional<int> BrowserAccessibility::GetTableCellCount() const {
-  return node()->GetTableCellCount();
-}
-
-absl::optional<bool> BrowserAccessibility::GetTableHasColumnOrRowHeaderNode()
-    const {
-  return node()->GetTableHasColumnOrRowHeaderNode();
-}
-
-std::vector<ui::AXNodeID> BrowserAccessibility::GetColHeaderNodeIds() const {
-  return node()->GetTableColHeaderNodeIds();
-}
-
-std::vector<ui::AXNodeID> BrowserAccessibility::GetColHeaderNodeIds(
-    int col_index) const {
-  return node()->GetTableColHeaderNodeIds(col_index);
-}
-
-std::vector<ui::AXNodeID> BrowserAccessibility::GetRowHeaderNodeIds() const {
-  return node()->GetTableCellRowHeaderNodeIds();
-}
-
-std::vector<ui::AXNodeID> BrowserAccessibility::GetRowHeaderNodeIds(
-    int row_index) const {
-  return node()->GetTableRowHeaderNodeIds(row_index);
-}
-
 ui::AXPlatformNode* BrowserAccessibility::GetTableCaption() const {
   ui::AXNode* caption = node()->GetTableCaption();
   if (caption) {
@@ -1539,66 +1289,6 @@
   return nullptr;
 }
 
-bool BrowserAccessibility::IsTableRow() const {
-  return node()->IsTableRow();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableRowRowIndex() const {
-  return node()->GetTableRowRowIndex();
-}
-
-bool BrowserAccessibility::IsTableCellOrHeader() const {
-  return node()->IsTableCellOrHeader();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableCellColIndex() const {
-  return node()->GetTableCellColIndex();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableCellRowIndex() const {
-  return node()->GetTableCellRowIndex();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableCellColSpan() const {
-  return node()->GetTableCellColSpan();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableCellRowSpan() const {
-  return node()->GetTableCellRowSpan();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableCellAriaColIndex() const {
-  return node()->GetTableCellAriaColIndex();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableCellAriaRowIndex() const {
-  return node()->GetTableCellAriaRowIndex();
-}
-
-absl::optional<int32_t> BrowserAccessibility::GetCellId(int row_index,
-                                                        int col_index) const {
-  ui::AXNode* cell = node()->GetTableCellFromCoords(row_index, col_index);
-  if (!cell)
-    return absl::nullopt;
-  return cell->id();
-}
-
-absl::optional<int> BrowserAccessibility::GetTableCellIndex() const {
-  return node()->GetTableCellIndex();
-}
-
-absl::optional<int32_t> BrowserAccessibility::CellIndexToId(
-    int cell_index) const {
-  ui::AXNode* cell = node()->GetTableCellFromIndex(cell_index);
-  if (!cell)
-    return absl::nullopt;
-  return cell->id();
-}
-
-bool BrowserAccessibility::IsCellOrHeaderOfAriaGrid() const {
-  return node()->IsCellOrHeaderOfAriaGrid();
-}
-
 bool BrowserAccessibility::AccessibilityPerformAction(
     const ui::AXActionData& data) {
   // TODO(crbug.com/1049261): Move the ability to perform actions to
@@ -2224,14 +1914,6 @@
   return accessibility_state->disable_hot_tracking_for_testing();
 }
 
-bool BrowserAccessibility::IsOrderedSetItem() const {
-  return node()->IsOrderedSetItem();
-}
-
-bool BrowserAccessibility::IsOrderedSet() const {
-  return node()->IsOrderedSet();
-}
-
 absl::optional<int> BrowserAccessibility::GetPosInSet() const {
   // TODO(nektar): Make `AXNode::GetPosInSet()` const and remove const_cast.
   return const_cast<ui::AXNode*>(node())->GetPosInSet();
@@ -2242,14 +1924,6 @@
   return const_cast<ui::AXNode*>(node())->GetSetSize();
 }
 
-SkColor BrowserAccessibility::GetColor() const {
-  return node()->ComputeColor();
-}
-
-SkColor BrowserAccessibility::GetBackgroundColor() const {
-  return node()->ComputeBackgroundColor();
-}
-
 bool BrowserAccessibility::IsInListMarker() const {
   return node()->IsInListMarker();
 }
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index e2fee78..0789b7a 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -377,67 +377,6 @@
   // `AXPlatformNodeDelegate` implementation.
   std::u16string GetAuthorUniqueId() const override;
   const ui::AXNodeData& GetData() const override;
-  const ui::AXTreeData& GetTreeData() const override;
-  ax::mojom::Role GetRole() const override;
-  bool HasBoolAttribute(ax::mojom::BoolAttribute attribute) const override;
-  bool GetBoolAttribute(ax::mojom::BoolAttribute attribute) const override;
-  bool GetBoolAttribute(ax::mojom::BoolAttribute attribute,
-                        bool* value) const override;
-  bool HasFloatAttribute(ax::mojom::FloatAttribute attribute) const override;
-  float GetFloatAttribute(ax::mojom::FloatAttribute attribute) const override;
-  bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
-                         float* value) const override;
-  const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
-  GetIntAttributes() const override;
-  bool HasIntAttribute(ax::mojom::IntAttribute attribute) const override;
-  int GetIntAttribute(ax::mojom::IntAttribute attribute) const override;
-  bool GetIntAttribute(ax::mojom::IntAttribute attribute,
-                       int* value) const override;
-  const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
-  GetStringAttributes() const override;
-  bool HasStringAttribute(ax::mojom::StringAttribute attribute) const override;
-  const std::string& GetStringAttribute(
-      ax::mojom::StringAttribute attribute) const override;
-  bool GetStringAttribute(ax::mojom::StringAttribute attribute,
-                          std::string* value) const override;
-  std::u16string GetString16Attribute(
-      ax::mojom::StringAttribute attribute) const override;
-  bool GetString16Attribute(ax::mojom::StringAttribute attribute,
-                            std::u16string* value) const override;
-  const std::string& GetInheritedStringAttribute(
-      ax::mojom::StringAttribute attribute) const override;
-  std::u16string GetInheritedString16Attribute(
-      ax::mojom::StringAttribute attribute) const override;
-  const std::vector<
-      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
-  GetIntListAttributes() const override;
-  bool HasIntListAttribute(
-      ax::mojom::IntListAttribute attribute) const override;
-  const std::vector<int32_t>& GetIntListAttribute(
-      ax::mojom::IntListAttribute attribute) const override;
-  bool GetIntListAttribute(ax::mojom::IntListAttribute attribute,
-                           std::vector<int32_t>* value) const override;
-  bool HasStringListAttribute(
-      ax::mojom::StringListAttribute attribute) const override;
-  const std::vector<std::string>& GetStringListAttribute(
-      ax::mojom::StringListAttribute attribute) const override;
-  bool GetStringListAttribute(ax::mojom::StringListAttribute attribute,
-                              std::vector<std::string>* value) const override;
-  typedef base::StringPairs HtmlAttributes;
-  bool HasHtmlAttribute(const char* attribute) const override;
-  const HtmlAttributes& GetHtmlAttributes() const override;
-  bool GetHtmlAttribute(const char* attribute,
-                        std::string* value) const override;
-  bool GetHtmlAttribute(const char* attribute,
-                        std::u16string* value) const override;
-  ui::AXTextAttributes GetTextAttributes() const override;
-  bool HasState(ax::mojom::State state) const override;
-  ax::mojom::State GetState() const override;
-  bool HasAction(ax::mojom::Action action) const override;
-  bool HasTextStyle(ax::mojom::TextStyle text_style) const override;
-  ax::mojom::NameFrom GetNameFrom() const override;
-  ax::mojom::DescriptionFrom GetDescriptionFrom() const override;
-  const ui::AXSelection GetUnignoredSelection() const override;
   AXPosition CreatePositionAt(
       int offset,
       ax::mojom::TextAffinity affinity =
@@ -462,7 +401,6 @@
   bool IsLeaf() const override;
   bool IsFocused() const override;
   bool IsIgnored() const override;
-  bool IsInvisibleOrIgnored() const override;
   bool IsToplevelBrowserWindow() override;
   gfx::NativeViewAccessible GetLowestPlatformAncestor() const override;
   gfx::NativeViewAccessible GetTextFieldAncestor() const override;
@@ -472,7 +410,6 @@
   std::unique_ptr<ChildIterator> ChildrenBegin() override;
   std::unique_ptr<ChildIterator> ChildrenEnd() override;
 
-  const std::string& GetName() const override;
   const std::string& GetDescription() const override;
   std::u16string GetHypertext() const override;
   const std::map<int, int>& GetHypertextOffsetToHyperlinkChildIndex()
@@ -509,37 +446,10 @@
       ui::AXPlatformNodeDelegate* start,
       ui::AXPlatformNodeDelegate* end) override;
 
-  std::string GetLanguage() const override;
-
-  bool IsTable() const override;
-  absl::optional<int> GetTableColCount() const override;
-  absl::optional<int> GetTableRowCount() const override;
   absl::optional<int> GetTableAriaColCount() const override;
   absl::optional<int> GetTableAriaRowCount() const override;
-  absl::optional<int> GetTableCellCount() const override;
-  absl::optional<bool> GetTableHasColumnOrRowHeaderNode() const override;
-  std::vector<ui::AXNodeID> GetColHeaderNodeIds() const override;
-  std::vector<ui::AXNodeID> GetColHeaderNodeIds(int col_index) const override;
-  std::vector<ui::AXNodeID> GetRowHeaderNodeIds() const override;
-  std::vector<ui::AXNodeID> GetRowHeaderNodeIds(int row_index) const override;
   ui::AXPlatformNode* GetTableCaption() const override;
 
-  bool IsTableRow() const override;
-  absl::optional<int> GetTableRowRowIndex() const override;
-
-  bool IsTableCellOrHeader() const override;
-  absl::optional<int> GetTableCellIndex() const override;
-  absl::optional<int> GetTableCellColIndex() const override;
-  absl::optional<int> GetTableCellRowIndex() const override;
-  absl::optional<int> GetTableCellColSpan() const override;
-  absl::optional<int> GetTableCellRowSpan() const override;
-  absl::optional<int> GetTableCellAriaColIndex() const override;
-  absl::optional<int> GetTableCellAriaRowIndex() const override;
-  absl::optional<int32_t> GetCellId(int row_index,
-                                    int col_index) const override;
-  absl::optional<int32_t> CellIndexToId(int cell_index) const override;
-  bool IsCellOrHeaderOfAriaGrid() const override;
-
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
   std::u16string GetLocalizedStringForImageAnnotationStatus(
       ax::mojom::ImageAnnotationStatus status) const override;
@@ -555,8 +465,6 @@
   bool IsMinimized() const override;
   bool IsText() const override;
   bool IsWebContent() const override;
-  bool IsReadOnlySupported() const override;
-  bool IsReadOnlyOrDisabled() const override;
   bool HasVisibleCaretOrSelection() const override;
   ui::AXPlatformNode* GetTargetNodeForRelation(
       ax::mojom::IntAttribute attr) override;
@@ -566,12 +474,8 @@
       ax::mojom::IntAttribute attr) override;
   std::set<ui::AXPlatformNode*> GetReverseRelations(
       ax::mojom::IntListAttribute attr) override;
-  bool IsOrderedSetItem() const override;
-  bool IsOrderedSet() const override;
   absl::optional<int> GetPosInSet() const override;
   absl::optional<int> GetSetSize() const override;
-  SkColor GetColor() const override;
-  SkColor GetBackgroundColor() const override;
 
   // Returns true if this node is a list marker or if it's a descendant
   // of a list marker node. Returns false otherwise.
@@ -611,6 +515,8 @@
 
   std::string SubtreeToStringHelper(size_t level) override;
 
+  void EnableGlobalAccessibilityModeOnApiUsage() const override;
+
   // The UIA tree formatter needs access to GetUniqueId() to identify the
   // starting point for tree dumps.
   friend class AccessibilityTreeFormatterUia;
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 9c7eb729..0ecaeb1 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -2232,8 +2232,9 @@
   RunHtmlTest(FILE_PATH_LITERAL("in-page-links.html"));
 }
 
+// TODO(crbug.com/1367886): This test is flaky.
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTestWithIgnoredNodes,
-                       InertAttribute) {
+                       DISABLED_InertAttribute) {
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kEnableBlinkFeatures, "InertAttribute");
   RunHtmlTest(FILE_PATH_LITERAL("inert-attribute.html"));
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index d0e12fa..1122c02c 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -42,8 +42,6 @@
 #include "content/browser/network/reporting_service_proxy.h"
 #include "content/browser/picture_in_picture/picture_in_picture_service_impl.h"
 #include "content/browser/preloading/anchor_element_interaction_host_impl.h"
-#include "content/browser/preloading/prerender/prerender_internals.mojom.h"
-#include "content/browser/preloading/prerender/prerender_internals_ui.h"
 #include "content/browser/preloading/speculation_rules/speculation_host_impl.h"
 #include "content/browser/process_internals/process_internals.mojom.h"
 #include "content/browser/process_internals/process_internals_ui.h"
@@ -1060,8 +1058,6 @@
                                          AttributionInternalsUI>(map);
   RegisterWebUIControllerInterfaceBinder<storage::mojom::IdbInternalsHandler,
                                          IndexedDBInternalsUI>(map);
-  RegisterWebUIControllerInterfaceBinder<mojom::PrerenderInternalsHandler,
-                                         PrerenderInternalsUI>(map);
   RegisterWebUIControllerInterfaceBinder<::mojom::ProcessInternalsHandler,
                                          ProcessInternalsUI>(map);
   RegisterWebUIControllerInterfaceBinder<storage::mojom::QuotaInternalsHandler,
diff --git a/content/browser/interest_group/interest_group_k_anonymity_manager_unittest.cc b/content/browser/interest_group/interest_group_k_anonymity_manager_unittest.cc
index c187eaeb..4a27a2f 100644
--- a/content/browser/interest_group/interest_group_k_anonymity_manager_unittest.cc
+++ b/content/browser/interest_group/interest_group_k_anonymity_manager_unittest.cc
@@ -179,7 +179,7 @@
   std::string group_update_url = kUpdateURL;
 
   auto manager = CreateManager();
-  EXPECT_FALSE(getLastReported(manager.get(), group_name_url));
+  EXPECT_EQ(base::Time::Min(), getLastReported(manager.get(), group_name_url));
   EXPECT_FALSE(getGroup(manager.get(), owner, name));
   base::Time before_join = base::Time::Now();
 
@@ -229,7 +229,7 @@
 
   auto manager = CreateManager();
   EXPECT_FALSE(getGroup(manager.get(), owner, name));
-  EXPECT_FALSE(getLastReported(manager.get(), kAdURL));
+  EXPECT_EQ(base::Time::Min(), getLastReported(manager.get(), kAdURL));
 
   manager->JoinInterestGroup(MakeInterestGroup(owner, "foo"), top_frame);
   // The group *must* exist when JoinInterestGroup returns.
diff --git a/content/browser/interest_group/interest_group_storage.cc b/content/browser/interest_group/interest_group_storage.cc
index 20ee26c..6606a00 100644
--- a/content/browser/interest_group/interest_group_storage.cc
+++ b/content/browser/interest_group/interest_group_storage.cc
@@ -200,6 +200,7 @@
     list.Append(s);
   return Serialize(list);
 }
+
 absl::optional<std::vector<std::string>> DeserializeStringVector(
     const std::string& serialized_vector) {
   std::unique_ptr<base::Value> list = DeserializeValue(serialized_vector);
@@ -211,6 +212,11 @@
   return result;
 }
 
+StorageInterestGroup::KAnonymityData DefaultKAnonymityData(
+    const std::string& key) {
+  return {key, /*is_k_anonymous=*/false, /*last_updated=*/base::Time::Min()};
+}
+
 // Merges new `priority_signals_overrides` received from an update with an
 // existing set of overrides store with an interest group. Populates `overrides`
 // if it was previously null.
@@ -641,16 +647,10 @@
   return true;
 }
 
-bool DoCreateOrMarkKAnonReferenced(sql::Database& db,
-                                   const std::string key,
-                                   const base::Time& now) {
+bool MaybeCreateKAnonEntry(sql::Database& db,
+                           const std::string& key,
+                           const base::Time& now) {
   base::Time distant_past = base::Time::Min();
-  base::Time cutoff = now - InterestGroupStorage::kHistoryLength;
-
-  // This flow basically emulates SQLite's UPSERT feature which is disabled in
-  // Chrome. Although there are two statements executed, we don't need to
-  // enclose them in a transaction since only one will actually modify the
-  // database.
 
   // clang-format off
   sql::Statement maybe_insert_kanon(
@@ -663,7 +663,6 @@
               "last_reported_to_anon_server_time) "
             "VALUES(?,?,0,?,?)"
       ));
-
   // clang-format on
   if (!maybe_insert_kanon.is_valid())
     return false;
@@ -674,92 +673,7 @@
   maybe_insert_kanon.BindTime(2, distant_past);
   maybe_insert_kanon.BindTime(3, distant_past);
 
-  if (!maybe_insert_kanon.Run())
-    return false;
-
-  // If the insert changed the database return early.
-  if (db.GetLastChangeCount() > 0)
-    return true;
-
-  // Update last referenced time, clearing previous k-anon data if their values
-  // have expired.
-  // clang-format off
-  sql::Statement update_kanon(
-      db.GetCachedStatement(SQL_FROM_HERE,
-          "UPDATE k_anon "
-          "SET last_referenced_time=?1,"
-              "is_k_anon=IIF(last_referenced_time>?2,is_k_anon,0),"
-              "last_k_anon_updated_time="
-                "IIF(last_referenced_time>?2,last_k_anon_updated_time,?3),"
-              "last_reported_to_anon_server_time=IIF(last_referenced_time>?2,"
-                "last_reported_to_anon_server_time,?3) "
-          "WHERE key=?4"));
-  // clang-format on
-  if (!update_kanon.is_valid())
-    return false;
-
-  update_kanon.Reset(true);
-  update_kanon.BindTime(0, now);
-  update_kanon.BindTime(1, cutoff);
-  update_kanon.BindTime(2, distant_past);
-  update_kanon.BindString(3, key);
-
-  return update_kanon.Run();
-}
-
-bool DoCreateOrMarkInterestGroupNameReferenced(sql::Database& db,
-                                               url::Origin owner,
-                                               const std::string& name,
-                                               const base::Time& now) {
-  return DoCreateOrMarkKAnonReferenced(db, KAnonKeyFor(owner, name), now);
-}
-
-bool DoCreateOrMarkInterestGroupUpdateURLReferenced(
-    sql::Database& db,
-    const GURL& daily_update_url,
-    const base::Time& now) {
-  return DoCreateOrMarkKAnonReferenced(db, daily_update_url.spec(), now);
-}
-
-bool DoCreateOrMarkAdReferenced(sql::Database& db,
-                                const blink::InterestGroup::Ad& ad,
-                                const base::Time& now) {
-  return DoCreateOrMarkKAnonReferenced(db, ad.render_url.spec(), now);
-}
-
-// Takes a blink::InterestGroup, or InterestGroupUpdate.
-bool DoCreateOrMarkInterestGroupAndAdsReferenced(
-    sql::Database& db,
-    const blink::InterestGroup& data,
-    const base::Time& now) {
-  if (data.ads) {
-    // Mark these ads as being 'in use'.
-    for (const blink::InterestGroup::Ad& ad : data.ads.value()) {
-      if (!DoCreateOrMarkAdReferenced(db, ad, now))
-        return false;
-    }
-  }
-
-  if (data.ad_components) {
-    // Mark these ads as being 'in use'.
-    for (const blink::InterestGroup::Ad& ad : data.ad_components.value()) {
-      if (!DoCreateOrMarkAdReferenced(db, ad, now))
-        return false;
-    }
-  }
-
-  if (!DoCreateOrMarkInterestGroupNameReferenced(db, data.owner, data.name,
-                                                 now)) {
-    return false;
-  }
-
-  if (data.daily_update_url) {
-    if (!DoCreateOrMarkInterestGroupUpdateURLReferenced(
-            db, data.daily_update_url.value(), now)) {
-      return false;
-    }
-  }
-  return true;
+  return maybe_insert_kanon.Run();
 }
 
 bool RemoveJoinHistory(sql::Database& db,
@@ -1076,9 +990,6 @@
   if (!DoRecordInterestGroupJoin(db, data.owner, data.name, last_updated))
     return false;
 
-  if (!DoCreateOrMarkInterestGroupAndAdsReferenced(db, data, last_updated))
-    return false;
-
   return transaction.Commit();
 }
 
@@ -1200,10 +1111,6 @@
   if (!DoStoreInterestGroupUpdate(db, stored_group, now))
     return false;
 
-  // Updates do not change the expiration time so we do not need to refresh the
-  // referenced field for fields that didn't change.
-  if (!DoCreateOrMarkInterestGroupAndAdsReferenced(db, stored_group, now))
-    return false;
   return transaction.Commit();
 }
 
@@ -1318,12 +1225,22 @@
 }
 
 bool DoUpdateKAnonymity(sql::Database& db,
-                        const StorageInterestGroup::KAnonymityData& data) {
+                        const StorageInterestGroup::KAnonymityData& data,
+                        base::Time now) {
+  sql::Transaction transaction(&db);
+  if (!transaction.Begin())
+    return false;
+
+  if (!MaybeCreateKAnonEntry(db, data.key, now))
+    return false;
+
   // clang-format off
   sql::Statement update(
       db.GetCachedStatement(SQL_FROM_HERE,
       "UPDATE k_anon "
-      "SET is_k_anon=?, last_k_anon_updated_time=? "
+      "SET is_k_anon=?,"
+          "last_k_anon_updated_time=?,"
+          "last_referenced_time=? "
       "WHERE key=?"));
   // clang-format on
   if (!update.is_valid())
@@ -1332,12 +1249,17 @@
   update.Reset(true);
   update.BindInt(0, data.is_k_anonymous);
   update.BindTime(1, data.last_updated);
-  update.BindString(2, data.key);
-  return update.Run();
+  update.BindTime(2, now);
+  update.BindString(3, data.key);
+  if (!update.Run())
+    return false;
+  return transaction.Commit();
 }
 
 absl::optional<base::Time> DoGetLastKAnonymityReported(sql::Database& db,
                                                        const std::string& key) {
+  const base::Time distant_past = base::Time::Min();
+
   sql::Statement get_reported(db.GetCachedStatement(
       SQL_FROM_HERE,
       "SELECT last_reported_to_anon_server_time FROM k_anon WHERE key=?"));
@@ -1349,7 +1271,7 @@
   get_reported.Reset(true);
   get_reported.BindString(0, key);
   if (!get_reported.Step()) {
-    return absl::nullopt;
+    return distant_past;
   }
   if (!get_reported.Succeeded())
     return absl::nullopt;
@@ -1359,9 +1281,21 @@
 void DoUpdateLastKAnonymityReported(sql::Database& db,
                                     const std::string& key,
                                     base::Time now) {
+  sql::Transaction transaction(&db);
+  if (!transaction.Begin())
+    return;
+
+  if (!MaybeCreateKAnonEntry(db, key, now))
+    return;
+
+  // clang-format off
   sql::Statement set_reported(db.GetCachedStatement(
       SQL_FROM_HERE,
-      "UPDATE k_anon SET last_reported_to_anon_server_time=? WHERE key=?"));
+      "UPDATE k_anon "
+      "SET last_reported_to_anon_server_time=?,"
+          "last_referenced_time=? "
+      "WHERE key=?"));
+  // clang-format on
   if (!set_reported.is_valid()) {
     DLOG(ERROR)
         << "DoUpdateLastKAnonymityReported SQL statement did not compile: "
@@ -1370,10 +1304,12 @@
   }
   set_reported.Reset(true);
   set_reported.BindTime(0, now);
-  set_reported.BindString(1, key);
+  set_reported.BindTime(1, now);
+  set_reported.BindString(2, key);
   if (!set_reported.Run()) {
     return;
   }
+  transaction.Commit();
 }
 
 absl::optional<std::vector<url::Origin>> DoGetAllInterestGroupOwners(
@@ -1448,7 +1384,9 @@
   interest_group_kanon.BindString(0, key);
 
   if (!interest_group_kanon.Step()) {
-    return false;
+    // Not in the table, so return the defaults.
+    output = DefaultKAnonymityData(key);
+    return true;
   }
 
   output = {key, /*is_k_anonymous=*/interest_group_kanon.ColumnInt(0) > 0,
@@ -1624,8 +1562,7 @@
       if (!DoGetURLKAnonymity(db, ad.render_url, ad_kanon)) {
         return absl::nullopt;
       }
-      if (!ad_kanon)
-        continue;
+      DCHECK(ad_kanon);
       db_interest_group.ads_kanon.push_back(std::move(ad_kanon).value());
     }
   }
@@ -1635,8 +1572,7 @@
       if (!DoGetURLKAnonymity(db, ad.render_url, ad_kanon)) {
         return absl::nullopt;
       }
-      if (!ad_kanon)
-        continue;
+      DCHECK(ad_kanon);
       db_interest_group.ads_kanon.push_back(std::move(ad_kanon).value());
     }
   }
@@ -2258,7 +2194,7 @@
   if (!EnsureDBInitialized())
     return;
 
-  if (!DoUpdateKAnonymity(*db_, data)) {
+  if (!DoUpdateKAnonymity(*db_, data, base::Time::Now())) {
     DLOG(ERROR) << "Could not update k-anonymity: " << db_->GetErrorMessage();
   }
 }
diff --git a/content/browser/interest_group/interest_group_storage_unittest.cc b/content/browser/interest_group/interest_group_storage_unittest.cc
index ea56710e..247b33c 100644
--- a/content/browser/interest_group/interest_group_storage_unittest.cc
+++ b/content/browser/interest_group/interest_group_storage_unittest.cc
@@ -723,6 +723,10 @@
   groups = storage->GetInterestGroupsForOwner(test_origin);
   ASSERT_EQ(0u, groups.size());
 
+  // Allow enough idle time to trigger maintenance.
+  task_environment().FastForwardBy(InterestGroupStorage::kIdlePeriod +
+                                   base::Seconds(1));
+
   // Join again and expect the default kanon values.
   g.expiry = base::Time::Now() + base::Days(1);
   storage->JoinInterestGroup(g, GURL("https://owner.example.com/join3"));
@@ -858,6 +862,7 @@
                              joining_originA.GetURL());
   storage->JoinInterestGroup(NewInterestGroup(owner_originB, "exampleB"),
                              joining_originB.GetURL());
+  storage->UpdateLastKAnonymityReported(KAnonKeyFor(owner_originA, "example"));
 
   std::vector<url::Origin> origins = storage->GetAllInterestGroupOwners();
   EXPECT_THAT(origins, UnorderedElementsAre(owner_originA, owner_originB,
@@ -896,13 +901,13 @@
   EXPECT_EQ(0u, origins.size());
 
   // DeleteInterestGroupData shouldn't have deleted kanon data.
-  EXPECT_TRUE(storage->GetLastKAnonymityReported(
-      KAnonKeyFor(owner_originA, "example")));
+  EXPECT_NE(base::Time::Min(), storage->GetLastKAnonymityReported(
+                                   KAnonKeyFor(owner_originA, "example")));
 
   storage->DeleteAllInterestGroupData();
   // DeleteAllInterestGroupData should have deleted *everything*.
-  EXPECT_FALSE(storage->GetLastKAnonymityReported(
-      KAnonKeyFor(owner_originA, "example")));
+  EXPECT_EQ(base::Time::Min(), storage->GetLastKAnonymityReported(
+                                   KAnonKeyFor(owner_originA, "example")));
 }
 
 // Maintenance should prune the number of interest groups and interest group
@@ -1614,7 +1619,7 @@
 
   absl::optional<base::Time> last_report =
       storage->GetLastKAnonymityReported(ad1_url.spec());
-  EXPECT_FALSE(last_report);  // Not in the database.
+  EXPECT_EQ(base::Time::Min(), last_report);  // Not in the database.
 
   storage->JoinInterestGroup(g, GURL("https://owner.example.com/join"));
 
@@ -1763,4 +1768,45 @@
       storage_interest_groups[0].interest_group.priority_signals_overrides);
 }
 
+TEST_F(InterestGroupStorageTest, OnlyDeletesExpiredKAnon) {
+  url::Origin test_origin =
+      url::Origin::Create(GURL("https://owner.example.com"));
+  GURL ad1_url = GURL("https://owner.example.com/ad1");
+  GURL ad2_url = GURL("https://owner.example.com/ad2");
+
+  InterestGroup g = NewInterestGroup(test_origin, "name");
+  g.ads.emplace();
+  g.ads->push_back(blink::InterestGroup::Ad(ad1_url, "metadata1"));
+  g.ads->push_back(blink::InterestGroup::Ad(ad2_url, "metadata2"));
+  std::unique_ptr<InterestGroupStorage> storage = CreateStorage();
+
+  storage->JoinInterestGroup(g, GURL("https://owner.example.com/join"));
+
+  std::vector<StorageInterestGroup> groups =
+      storage->GetInterestGroupsForOwner(test_origin);
+
+  storage->UpdateLastKAnonymityReported(ad1_url.spec());
+  storage->UpdateLastKAnonymityReported(ad2_url.spec());
+
+  EXPECT_NE(base::Time::Min(),
+            storage->GetLastKAnonymityReported(ad1_url.spec()));
+  EXPECT_NE(base::Time::Min(),
+            storage->GetLastKAnonymityReported(ad2_url.spec()));
+
+  task_environment().FastForwardBy(base::Days(1));
+
+  // fast-forward 30 days.
+  for (int i = 0; i < InterestGroupStorage::kHistoryLength / base::Days(1);
+       i++) {
+    storage->JoinInterestGroup(g, GURL("https://owner.example.com/join"));
+    storage->UpdateLastKAnonymityReported(ad1_url.spec());
+    task_environment().FastForwardBy(base::Days(1));
+  }
+
+  EXPECT_NE(base::Time::Min(),
+            storage->GetLastKAnonymityReported(ad1_url.spec()));
+  EXPECT_EQ(base::Time::Min(),
+            storage->GetLastKAnonymityReported(ad2_url.spec()));
+}
+
 }  // namespace content
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index ab12b21..8ef6fa51 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -330,16 +330,6 @@
   }
   DCHECK(frame);
 
-  base::TimeDelta capture_time(base::Milliseconds(frame->capture_time_ms()));
-
-  // The two UMA_ blocks must be put in its own scope since it creates a static
-  // variable which expected constant histogram name.
-  if (capturer_type_ == DesktopMediaID::TYPE_SCREEN) {
-    UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time);
-  } else {
-    UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time);
-  }
-
   // If the frame size has changed, drop the output frame (if any), and
   // determine the new output size.
   if (!previous_frame_size_.equals(frame->size())) {
diff --git a/content/browser/media/capture/desktop_capture_device_uma_types.cc b/content/browser/media/capture/desktop_capture_device_uma_types.cc
index 9d8a463..f3cf867 100644
--- a/content/browser/media/capture/desktop_capture_device_uma_types.cc
+++ b/content/browser/media/capture/desktop_capture_device_uma_types.cc
@@ -8,9 +8,6 @@
 
 namespace content {
 
-const char kUmaScreenCaptureTime[] = "WebRTC.ScreenCaptureTime";
-const char kUmaWindowCaptureTime[] = "WebRTC.WindowCaptureTime";
-
 void IncrementDesktopCaptureCounter(DesktopCaptureCounters counter) {
   UMA_HISTOGRAM_ENUMERATION("WebRTC.DesktopCaptureCounters",
                             counter,
diff --git a/content/browser/media/capture/desktop_capture_device_uma_types.h b/content/browser/media/capture/desktop_capture_device_uma_types.h
index fdd7a29..c4d3343 100644
--- a/content/browser/media/capture/desktop_capture_device_uma_types.h
+++ b/content/browser/media/capture/desktop_capture_device_uma_types.h
@@ -32,9 +32,6 @@
   DESKTOP_CAPTURE_COUNTER_BOUNDARY
 };
 
-extern const char kUmaScreenCaptureTime[];
-extern const char kUmaWindowCaptureTime[];
-
 void IncrementDesktopCaptureCounter(DesktopCaptureCounters counter);
 
 }  // namespace content
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 2b4d560..4ea64cd 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -148,7 +148,10 @@
  public:
   using RenderFrameHostImpl::RenderFrameHostImpl;
 
-  void GoToEntryAtOffset(int32_t offset, bool has_user_gesture) override {
+  void GoToEntryAtOffset(int32_t offset,
+                         bool has_user_gesture,
+                         absl::optional<blink::scheduler::TaskAttributionId>
+                             soft_navigation_heuristic_task_id) override {
     if (quit_handler_)
       std::move(quit_handler_).Run();
   }
diff --git a/content/browser/preloading/prerender/BUILD.gn b/content/browser/preloading/prerender/BUILD.gn
deleted file mode 100644
index 7e64be6..0000000
--- a/content/browser/preloading/prerender/BUILD.gn
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojo_bindings") {
-  sources = [ "prerender_internals.mojom" ]
-
-  deps = [ "//url/mojom:url_mojom_gurl" ]
-  webui_module_path = "/"
-}
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h
index 9f103cd..ae783e4 100644
--- a/content/browser/preloading/prerender/prerender_host.h
+++ b/content/browser/preloading/prerender/prerender_host.h
@@ -227,7 +227,6 @@
   absl::optional<url::Origin> initiator_origin() const {
     return attributes_.initiator_origin;
   }
-  const GURL& initiator_url() const { return attributes_.initiator_url; }
 
   const GURL& prerendering_url() const { return attributes_.prerendering_url; }
 
diff --git a/content/browser/preloading/prerender/prerender_host_registry.cc b/content/browser/preloading/prerender/prerender_host_registry.cc
index 82191622..5d294a2c 100644
--- a/content/browser/preloading/prerender/prerender_host_registry.cc
+++ b/content/browser/preloading/prerender/prerender_host_registry.cc
@@ -578,16 +578,6 @@
   return weak_factory_.GetWeakPtr();
 }
 
-void PrerenderHostRegistry::ForEachPrerenderHost(
-    base::RepeatingCallback<void(PrerenderHost&)> callback) {
-  for (auto& iter : prerender_host_by_frame_tree_node_id_) {
-    callback.Run(*iter.second);
-  }
-
-  if (reserved_prerender_host_)
-    callback.Run(*reserved_prerender_host_);
-}
-
 void PrerenderHostRegistry::DidFinishNavigation(
     NavigationHandle* navigation_handle) {
   auto* navigation_request = NavigationRequest::From(navigation_handle);
diff --git a/content/browser/preloading/prerender/prerender_host_registry.h b/content/browser/preloading/prerender/prerender_host_registry.h
index 9a17476..30ed59c 100644
--- a/content/browser/preloading/prerender/prerender_host_registry.h
+++ b/content/browser/preloading/prerender/prerender_host_registry.h
@@ -171,11 +171,6 @@
 
   base::WeakPtr<PrerenderHostRegistry> GetWeakPtr();
 
-  // Applies the callback function to all prerender hosts owned by
-  // this registry.
-  void ForEachPrerenderHost(
-      base::RepeatingCallback<void(PrerenderHost&)> callback);
-
   // Only used for tests.
   base::OneShotTimer* GetTimerForTesting() { return &timeout_timer_; }
   void SetTaskRunnerForTesting(
diff --git a/content/browser/preloading/prerender/prerender_internals.mojom b/content/browser/preloading/prerender/prerender_internals.mojom
deleted file mode 100644
index 8cb78d77..0000000
--- a/content/browser/preloading/prerender/prerender_internals.mojom
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module content.mojom;
-
-import "url/mojom/url.mojom";
-
-// Contains prerendered page info. Created per prerendered page.
-struct PrerenderedPageInfo {
-  // The URL of the prerendered page.
-  url.mojom.Url url;
-
-  // The URL of the page that started prerendering.
-  url.mojom.Url trigger_page_url;
-
-  // The final status of prerendering.
-  // This is a stringified representation of PrerenderFinalStatus.
-  string final_status;
-};
-
-// Created per WebContents.
-struct PrerenderInfo {
-  array<PrerenderedPageInfo> prerendered_page_infos;
-};
-
-// Interface for retrieving information about prerendering. Lives in the browser
-// process and used to implement an internal page about prerendering.
-interface PrerenderInternalsHandler {
-  // Gets information about prerendered pages per WebContents.
-  GetPrerenderInfo() => (array<PrerenderInfo> infos);
-};
diff --git a/content/browser/preloading/prerender/prerender_internals_handler_impl.cc b/content/browser/preloading/prerender/prerender_internals_handler_impl.cc
deleted file mode 100644
index fd87c87..0000000
--- a/content/browser/preloading/prerender/prerender_internals_handler_impl.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/preloading/prerender/prerender_internals_handler_impl.h"
-#include "content/browser/preloading/prerender/prerender_final_status.h"
-#include "content/browser/preloading/prerender/prerender_host_registry.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-
-namespace content {
-
-namespace {
-
-const char* FinalStatusToString(PrerenderFinalStatus final_status) {
-  switch (final_status) {
-    case PrerenderFinalStatus::kActivated:
-      return "Activated";
-    case PrerenderFinalStatus::kDestroyed:
-      return "Destroyed";
-    case PrerenderFinalStatus::kLowEndDevice:
-      return "LowEndDevice";
-    case PrerenderFinalStatus::kInvalidSchemeRedirect:
-      return "InvalidSchemeRedirect";
-    case PrerenderFinalStatus::kInvalidSchemeNavigation:
-      return "InvalidSchemeNavigation";
-    case PrerenderFinalStatus::kInProgressNavigation:
-      return "InProgressNavigation";
-    case PrerenderFinalStatus::kNavigationRequestBlockedByCsp:
-      return "NavigationRequestBlockedByCsp";
-    case PrerenderFinalStatus::kMainFrameNavigation:
-      return "MainFrameNavigation";
-    case PrerenderFinalStatus::kMojoBinderPolicy:
-      return "MojoBinderPolicy";
-    case PrerenderFinalStatus::kRendererProcessCrashed:
-      return "RendererProcessCrashed";
-    case PrerenderFinalStatus::kRendererProcessKilled:
-      return "RendererProcessKilled";
-    case PrerenderFinalStatus::kDownload:
-      return "Download";
-    case PrerenderFinalStatus::kTriggerDestroyed:
-      return "TriggerDestroyed";
-    case PrerenderFinalStatus::kNavigationNotCommitted:
-      return "NavigationNotCommitted";
-    case PrerenderFinalStatus::kNavigationBadHttpStatus:
-      return "NavigationBadHttpStatus";
-    case PrerenderFinalStatus::kClientCertRequested:
-      return "ClientCertRequested";
-    case PrerenderFinalStatus::kNavigationRequestNetworkError:
-      return "NavigationRequestNetworkError";
-    case PrerenderFinalStatus::kMaxNumOfRunningPrerendersExceeded:
-      return "MaxNumOfRunningPrerendersExceeded";
-    case PrerenderFinalStatus::kCancelAllHostsForTesting:
-      return "CancelAllHostsForTesting";
-    case PrerenderFinalStatus::kDidFailLoad:
-      return "DidFailLoad";
-    case PrerenderFinalStatus::kStop:
-      return "Stop";
-    case PrerenderFinalStatus::kSslCertificateError:
-      return "SslCertificateError";
-    case PrerenderFinalStatus::kLoginAuthRequested:
-      return "LoginAuthRequested";
-    case PrerenderFinalStatus::kUaChangeRequiresReload:
-      return "UaChangeRequiresReload";
-    case PrerenderFinalStatus::kBlockedByClient:
-      return "BlockedByClient";
-    case PrerenderFinalStatus::kAudioOutputDeviceRequested:
-      return "AudioOutputDeviceRequested";
-    case PrerenderFinalStatus::kMixedContent:
-      return "MixedContent";
-    case PrerenderFinalStatus::kTriggerBackgrounded:
-      return "TriggerBackgrounded";
-    case PrerenderFinalStatus::kEmbedderTriggeredAndCrossOriginRedirected:
-      return "EmbedderTriggeredAndCrossOriginRedirected";
-    case PrerenderFinalStatus::kMemoryLimitExceeded:
-      return "MemoryLimitExceeded";
-    case PrerenderFinalStatus::kFailToGetMemoryUsage:
-      return "FailToGetMemoryUsage";
-    case PrerenderFinalStatus::kDataSaverEnabled:
-      return "DataSaverEnabled";
-    case PrerenderFinalStatus::kHasEffectiveUrl:
-      return "HasEffectiveUrl";
-    case PrerenderFinalStatus::kActivatedBeforeStarted:
-      return "ActivatedBeforeStarted";
-    case PrerenderFinalStatus::kInactivePageRestriction:
-      return "InactivePageRestriction";
-    case PrerenderFinalStatus::kStartFailed:
-      return "StartFailed";
-    case PrerenderFinalStatus::kTimeoutBackgrounded:
-      return "TimeoutBackgrounded";
-    case PrerenderFinalStatus::kCrossSiteRedirect:
-      return "CrossSiteRedirect";
-    case PrerenderFinalStatus::kCrossSiteNavigation:
-      return "CrossSiteNavigation";
-    case PrerenderFinalStatus::kSameSiteCrossOriginRedirect:
-      return "SameSiteCrossOriginRedirect";
-    case PrerenderFinalStatus::kSameSiteCrossOriginNavigation:
-      return "SameSiteCrossOriginNavigation";
-    case PrerenderFinalStatus::kSameSiteCrossOriginRedirectNotOptIn:
-      return "SameSiteCrossOriginRedirectNotOptIn";
-    case PrerenderFinalStatus::kSameSiteCrossOriginNavigationNotOptIn:
-      return "SameSiteCrossOriginNavigationNotOptIn";
-    case PrerenderFinalStatus::kActivationNavigationParameterMismatch:
-      return "ActivationNavigationParameterMismatch";
-  }
-  NOTREACHED();
-  return "";
-}
-
-const char* GetFinalStatus(PrerenderHost& host) {
-  absl::optional<PrerenderFinalStatus> final_status = host.final_status();
-  if (final_status) {
-    return FinalStatusToString(final_status.value());
-  } else {
-    return "FinalStatus is not set";
-  }
-}
-
-}  // namespace
-
-PrerenderInternalsHandlerImpl::PrerenderInternalsHandlerImpl(
-    mojo::PendingReceiver<mojom::PrerenderInternalsHandler> receiver)
-    : receiver_(this, std::move(receiver)) {}
-
-PrerenderInternalsHandlerImpl::~PrerenderInternalsHandlerImpl() = default;
-
-void PrerenderInternalsHandlerImpl::GetPrerenderInfo(
-    GetPrerenderInfoCallback callback) {
-  if (!blink::features::IsPrerender2Enabled()) {
-    std::move(callback).Run(std::vector<mojom::PrerenderInfoPtr>());
-    return;
-  }
-
-  std::vector<mojom::PrerenderInfoPtr> infos;
-  std::vector<WebContentsImpl*> all_contents =
-      WebContentsImpl::GetAllWebContents();
-
-  for (WebContentsImpl* web_contents : all_contents) {
-    mojom::PrerenderInfoPtr info = mojom::PrerenderInfo::New();
-
-    PrerenderHostRegistry* prerender_host_registry =
-        web_contents->GetPrerenderHostRegistry();
-
-    prerender_host_registry->ForEachPrerenderHost(base::BindRepeating(
-        [](mojom::PrerenderInfo* info, PrerenderHost& host) {
-          mojom::PrerenderedPageInfoPtr prerendered_page_info =
-              mojom::PrerenderedPageInfo::New();
-          RenderFrameHostImpl* render_frame_host =
-              host.GetPrerenderedMainFrameHost();
-          prerendered_page_info->url = render_frame_host->GetLastCommittedURL();
-          prerendered_page_info->trigger_page_url = host.initiator_url();
-          prerendered_page_info->final_status = GetFinalStatus(host);
-
-          info->prerendered_page_infos.push_back(
-              std::move(prerendered_page_info));
-        },
-        info.get()));
-
-    if (info->prerendered_page_infos.empty()) {
-      continue;
-    }
-
-    infos.push_back(std::move(info));
-  }
-
-  std::move(callback).Run(std::move(infos));
-}
-
-}  // namespace content
diff --git a/content/browser/preloading/prerender/prerender_internals_handler_impl.h b/content/browser/preloading/prerender/prerender_internals_handler_impl.h
deleted file mode 100644
index 4111b0a..0000000
--- a/content/browser/preloading/prerender/prerender_internals_handler_impl.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_PRELOADING_PRERENDER_PRERENDER_INTERNALS_HANDLER_IMPL_H_
-#define CONTENT_BROWSER_PRELOADING_PRERENDER_PRERENDER_INTERNALS_HANDLER_IMPL_H_
-
-#include "content/browser/preloading/prerender/prerender_internals.mojom.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace content {
-
-class PrerenderInternalsHandlerImpl : public mojom::PrerenderInternalsHandler {
- public:
-  explicit PrerenderInternalsHandlerImpl(
-      mojo::PendingReceiver<mojom::PrerenderInternalsHandler> receiver);
-  ~PrerenderInternalsHandlerImpl() override;
-
-  void GetPrerenderInfo(GetPrerenderInfoCallback callback) override;
-
- private:
-  mojo::Receiver<mojom::PrerenderInternalsHandler> receiver_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_PRELOADING_PRERENDER_PRERENDER_INTERNALS_HANDLER_IMPL_H_
diff --git a/content/browser/preloading/prerender/prerender_internals_ui.cc b/content/browser/preloading/prerender/prerender_internals_ui.cc
deleted file mode 100644
index e7f6ed3..0000000
--- a/content/browser/preloading/prerender/prerender_internals_ui.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/preloading/prerender/prerender_internals_ui.h"
-
-#include "content/browser/preloading/prerender/prerender_internals.mojom.h"
-#include "content/browser/preloading/prerender/prerender_internals_handler_impl.h"
-#include "content/grit/dev_ui_content_resources.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "content/public/common/url_constants.h"
-
-namespace content {
-
-PrerenderInternalsUI::PrerenderInternalsUI(WebUI* web_ui)
-    : WebUIController(web_ui) {
-  // Set up the chrome://prerender-internals source.
-  WebUIDataSource* source = WebUIDataSource::CreateAndAdd(
-      web_ui->GetWebContents()->GetBrowserContext(),
-      kChromeUIPrerenderInternalsHost);
-
-  // Add required resources.
-  source->AddResourcePath("prerender_internals.js", IDR_PRERENDER_INTERNALS_JS);
-  source->AddResourcePath("prerender_internals.mojom-webui.js",
-                          IDR_PRERENDER_INTERNALS_MOJO_JS);
-  source->SetDefaultResource(IDR_PRERENDER_INTERNALS_HTML);
-}
-
-WEB_UI_CONTROLLER_TYPE_IMPL(PrerenderInternalsUI)
-
-PrerenderInternalsUI::~PrerenderInternalsUI() = default;
-
-void PrerenderInternalsUI::WebUIRenderFrameCreated(RenderFrameHost* rfh) {
-  rfh->EnableMojoJsBindings(nullptr);
-}
-
-void PrerenderInternalsUI::BindInterface(
-    mojo::PendingReceiver<mojom::PrerenderInternalsHandler> receiver) {
-  ui_handler_ =
-      std::make_unique<PrerenderInternalsHandlerImpl>(std::move(receiver));
-}
-
-}  // namespace content
diff --git a/content/browser/preloading/prerender/prerender_internals_ui.h b/content/browser/preloading/prerender/prerender_internals_ui.h
deleted file mode 100644
index a44e53a9..0000000
--- a/content/browser/preloading/prerender/prerender_internals_ui.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_PRELOADING_PRERENDER_PRERENDER_INTERNALS_UI_H_
-#define CONTENT_BROWSER_PRELOADING_PRERENDER_PRERENDER_INTERNALS_UI_H_
-
-#include "content/browser/preloading/prerender/prerender_internals.mojom-forward.h"
-#include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/webui_config.h"
-#include "content/public/common/url_constants.h"
-
-namespace content {
-
-class PrerenderInternalsUI;
-
-class PrerenderInternalsUIConfig
-    : public DefaultWebUIConfig<PrerenderInternalsUI> {
- public:
-  PrerenderInternalsUIConfig()
-      : DefaultWebUIConfig(kChromeUIScheme, kChromeUIPrerenderInternalsHost) {}
-};
-
-// The WebUI for chrome://prerender-internals.
-class PrerenderInternalsUI : public WebUIController {
- public:
-  explicit PrerenderInternalsUI(WebUI* web_ui);
-  PrerenderInternalsUI(const PrerenderInternalsUI&) = delete;
-  PrerenderInternalsUI& operator=(const PrerenderInternalsUI&) = delete;
-  ~PrerenderInternalsUI() override;
-
-  void WebUIRenderFrameCreated(RenderFrameHost* render_frame_host) override;
-
-  void BindInterface(
-      mojo::PendingReceiver<mojom::PrerenderInternalsHandler> receiver);
-
- private:
-  std::unique_ptr<mojom::PrerenderInternalsHandler> ui_handler_;
-
-  WEB_UI_CONTROLLER_TYPE_DECL();
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_PRELOADING_PRERENDER_PRERENDER_INTERNALS_UI_H_
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index f0f23c6..e80a94e13 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -884,8 +884,11 @@
 
   // location.reload() goes through BeginNavigation, so all reloads triggered
   // via this codepath are browser initiated.
-  NavigateToExistingPendingEntry(reload_type, nullptr /* initiator_frame */,
-                                 nullptr /* navigation_api_key */);
+  NavigateToExistingPendingEntry(
+      reload_type,
+      /*initiator_rfh=*/nullptr,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt,
+      /*navigation_api_key=*/nullptr);
 }
 
 void NavigationControllerImpl::CancelPendingReload() {
@@ -1111,13 +1114,16 @@
 }
 
 void NavigationControllerImpl::GoToIndex(int index) {
-  GoToIndex(index, nullptr /* initiator_frame */,
-            nullptr /* navigation_api_key */);
+  GoToIndex(index, /*initiator_rfh=*/nullptr,
+            /*soft_navigation_heuristics_task_id=*/absl::nullopt,
+            /*navigation_api_key=*/nullptr);
 }
 
 void NavigationControllerImpl::GoToIndex(
     int index,
     RenderFrameHostImpl* initiator_rfh,
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id,
     const std::string* navigation_api_key) {
   SCOPED_CRASH_KEY_NUMBER("nav_reentrancy_caller1", "GoToIndex_index", index);
   TRACE_EVENT0("browser,navigation,benchmark",
@@ -1147,6 +1153,7 @@
   pending_entry_->SetTransitionType(ui::PageTransitionFromInt(
       pending_entry_->GetTransitionType() | ui::PAGE_TRANSITION_FORWARD_BACK));
   NavigateToExistingPendingEntry(ReloadType::NONE, initiator_rfh,
+                                 soft_navigation_heuristics_task_id,
                                  navigation_api_key);
 }
 
@@ -1160,13 +1167,16 @@
 
 void NavigationControllerImpl::GoToOffsetFromRenderer(
     int offset,
-    RenderFrameHostImpl* initiator_rfh) {
+    RenderFrameHostImpl* initiator_rfh,
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   // Note: This is actually reached in unit tests.
   if (!CanGoToOffset(offset))
     return;
 
   GoToIndex(GetIndexForOffset(offset), initiator_rfh,
-            nullptr /* navigation_api_key */);
+            soft_navigation_heuristics_task_id,
+            /*navigation_api_key=*/nullptr);
 }
 
 #if BUILDFLAG(IS_ANDROID)
@@ -3042,6 +3052,8 @@
 void NavigationControllerImpl::NavigateToExistingPendingEntry(
     ReloadType reload_type,
     RenderFrameHostImpl* initiator_rfh,
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id,
     const std::string* navigation_api_key) {
   TRACE_EVENT0("navigation",
                "NavigationControllerImpl::NavigateToExistingPendingEntry");
@@ -3059,6 +3071,11 @@
   FrameTreeNode* root = frame_tree_->root();
   int nav_entry_id = pending_entry_->GetUniqueID();
   bool is_browser_initiated = !initiator_rfh;
+  // Only pass down the soft_navigation_heuristics_task_id when the initiator is
+  // the same as the top level frame being navigated.
+  if (root->current_frame_host() != initiator_rfh) {
+    soft_navigation_heuristics_task_id = absl::nullopt;
+  }
 
   // If we were navigating to a slow-to-commit page, and the user performs
   // a session history navigation to the last committed page, RenderViewHost
@@ -3080,7 +3097,8 @@
   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);
+                       soft_navigation_heuristics_task_id, &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
@@ -3379,6 +3397,8 @@
     FrameTreeNode* frame,
     ReloadType reload_type,
     bool is_browser_initiated,
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id,
     std::vector<std::unique_ptr<NavigationRequest>>* same_document_loads,
     std::vector<std::unique_ptr<NavigationRequest>>* different_document_loads) {
   DCHECK(pending_entry_);
@@ -3390,9 +3410,9 @@
     std::unique_ptr<NavigationRequest> navigation_request =
         CreateNavigationRequestFromEntry(
             frame, pending_entry_, new_item, reload_type,
-            true /* is_same_document_history_load */,
-            false /* is_history_navigation_in_new_child */,
-            is_browser_initiated);
+            /*is_same_document_history_load=*/true,
+            /*is_history_navigation_in_new_child_frame=*/false,
+            is_browser_initiated, soft_navigation_heuristics_task_id);
     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.
@@ -3417,8 +3437,12 @@
     return;
   }
 
+  // Do not pass down the soft_navigation_heuristics_task_id to child frames, as
+  // we currently only support soft navigation heuristics for the top level
+  // frame.
   for (size_t i = 0; i < frame->child_count(); i++) {
     FindFramesToNavigate(frame->child_at(i), reload_type, is_browser_initiated,
+                         /*soft_navigation_heuristics_task_id=*/absl::nullopt,
                          same_document_loads, different_document_loads);
   }
 }
@@ -3843,44 +3867,46 @@
           common_params->url, common_params->method,
           params.can_load_local_resources,
           frame_entry->page_state().ToEncodedData(), entry->GetUniqueID(),
-          entry->GetSubframeUniqueNames(node), true /* intended_as_new_entry */,
-          -1 /* pending_history_list_offset */,
+          entry->GetSubframeUniqueNames(node),
+          /*intended_as_new_entry=*/true,
+          /*pending_history_list_offset=*/-1,
           params.should_clear_history_list ? -1 : GetLastCommittedEntryIndex(),
           params.should_clear_history_list ? 0 : GetEntryCount(),
-          false /* was_discarded */, is_view_source_mode,
+          /*was_discarded=*/false, is_view_source_mode,
           params.should_clear_history_list,
           blink::mojom::NavigationTiming::New(),
           blink::mojom::WasActivatedOption::kUnknown,
-          base::UnguessableToken::Create() /* navigation_token */,
+          /*navigation_token=*/base::UnguessableToken::Create(),
           std::vector<blink::mojom::PrefetchedSignedExchangeInfoPtr>(),
 #if BUILDFLAG(IS_ANDROID)
-          std::string(), /* data_url_as_string */
+          /*data_url_as_string=*/std::string(),
 #endif
-          !params.is_renderer_initiated, /* is_browser_initiated */
-          GURL() /* web_bundle_physical_url */,
-          GURL() /* base_url_override_for_web_bundle */,
-          ukm::kInvalidSourceId /* document_ukm_source_id */,
+          /*is_browser_initiated=*/!params.is_renderer_initiated,
+          /*web_bundle_physical_url=*/GURL(),
+          /*base_url_override_for_web_bundle=*/GURL(),
+          /*document_ukm_source_id=*/ukm::kInvalidSourceId,
           node->pending_frame_policy(),
-          std::vector<std::string>() /* force_enabled_origin_trials */,
-          false /* origin_agent_cluster */,
-          true /* origin_agent_cluster_left_as_default */,
-          std::vector<
-              network::mojom::WebClientHintsType>() /* enabled_client_hints */,
-          false /* is_cross_browsing_instance */, nullptr /* old_page_info */,
-          -1 /* http_response_code */,
+          /*force_enabled_origin_trials=*/std::vector<std::string>(),
+          /*origin_agent_cluster=*/false,
+          /*origin_agent_cluster_left_as_default=*/true,
+          /*enabled_client_hints=*/
+          std::vector<network::mojom::WebClientHintsType>(),
+          /*is_cross_browsing_instance=*/false, /*old_page_info=*/nullptr,
+          /*http_response_code=*/-1,
           blink::mojom::NavigationApiHistoryEntryArrays::New(),
-          std::vector<GURL>() /* early_hints_preloaded_resources */,
-          absl::nullopt /* ad_auction_components */,
+          /*early_hints_preloaded_resources=*/std::vector<GURL>(),
+          /*ad_auction_components=*/absl::nullopt,
           /*fenced_frame_reporting_metadata=*/nullptr,
           // This timestamp will be populated when the commit IPC is sent.
-          base::TimeTicks() /* commit_sent */, std::string() /* srcdoc_value */,
-          GURL() /* fallback_srcdoc_baseurl_value */,
-          false /* should_load_data_url */,
+          /*commit_sent=*/base::TimeTicks(), /*srcdoc_value=*/std::string(),
+          /*fallback_srcdoc_baseurl_value=*/GURL(),
+          /*should_load_data_url=*/false,
           /*ancestor_or_self_has_cspee=*/node->AncestorOrSelfHasCSPEE(),
-          std::string() /* reduced_accept_language */,
+          /*reduced_accept_language=*/std::string(),
           /*navigation_delivery_type=*/
           network::mojom::NavigationDeliveryType::kDefault,
-          /*view_transition_state=*/absl::nullopt);
+          /*view_transition_state=*/absl::nullopt,
+          /*soft_navigation_heuristics_task_id=*/absl::nullopt);
 #if BUILDFLAG(IS_ANDROID)
   if (ValidateDataURLAsString(params.data_url_as_string)) {
     commit_params->data_url_as_string = params.data_url_as_string->data();
@@ -3919,7 +3945,9 @@
     ReloadType reload_type,
     bool is_same_document_history_load,
     bool is_history_navigation_in_new_child_frame,
-    bool is_browser_initiated) {
+    bool is_browser_initiated,
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   DCHECK(frame_entry);
   GURL dest_url = frame_entry->url();
   // We should never navigate to an existing initial NavigationEntry that is the
@@ -4012,7 +4040,8 @@
           GetPendingEntryIndex() == -1 /* intended_as_new_entry */,
           GetIndexOfEntry(entry), GetLastCommittedEntryIndex(), GetEntryCount(),
           frame_tree_node->pending_frame_policy(),
-          frame_tree_node->AncestorOrSelfHasCSPEE());
+          frame_tree_node->AncestorOrSelfHasCSPEE(),
+          soft_navigation_heuristics_task_id);
   commit_params->post_content_type = post_content_type;
 
   if (common_params->url.IsAboutSrcdoc()) {
@@ -4075,17 +4104,21 @@
   // Explicitly use NavigateToPendingEntry so that the renderer uses the
   // cached state.
   if (pending_entry_) {
-    NavigateToExistingPendingEntry(ReloadType::NONE,
-                                   nullptr /* initiator_frame */,
-                                   nullptr /* navigation_api_key */);
+    NavigateToExistingPendingEntry(
+        ReloadType::NONE,
+        /*initiator_rfh=*/nullptr,
+        /*soft_navigation_heuristics_task_id=*/absl::nullopt,
+        /*navigation_api_key=*/nullptr);
   } else if (last_committed_entry_index_ != -1 &&
              !GetLastCommittedEntry()
                   ->IsInitialEntryNotForSynchronousAboutBlank()) {
     pending_entry_ = entries_[last_committed_entry_index_].get();
     pending_entry_index_ = last_committed_entry_index_;
-    NavigateToExistingPendingEntry(ReloadType::NONE,
-                                   nullptr /* initiator_frame */,
-                                   nullptr /* navigation_api_key */);
+    NavigateToExistingPendingEntry(
+        ReloadType::NONE,
+        /*initiator_rfh=*/nullptr,
+        /*soft_navigation_heuristics_task_id=*/absl::nullopt,
+        /*navigation_api_key=*/nullptr);
   } else {
     // We should never navigate to an existing initial NavigationEntry that is
     // the initial NavigationEntry for the initial empty document that hasn't
@@ -4606,6 +4639,9 @@
   if (!current_entry)
     return;
 
+  // TODO(https://crbug.com/1383704): Make sure that the right task ID is passed
+  // when `navigation.traverseTo()` is called.
+
   // We want to find the nearest matching entry that is contiguously
   // same-instance and same-origin. Check back first, then forward.
   // TODO(japhet): Link spec here once it exists.
@@ -4615,7 +4651,8 @@
     if (result == HistoryNavigationAction::kStopLooking)
       break;
     if (result != HistoryNavigationAction::kKeepLooking) {
-      GoToIndex(i, initiator_rfh, &key);
+      GoToIndex(i, initiator_rfh,
+                /*soft_navigation_heuristics_task_id=*/absl::nullopt, &key);
       return;
     }
   }
@@ -4625,7 +4662,8 @@
     if (result == HistoryNavigationAction::kStopLooking)
       break;
     if (result != HistoryNavigationAction::kKeepLooking) {
-      GoToIndex(i, initiator_rfh, &key);
+      GoToIndex(i, initiator_rfh,
+                /*soft_navigation_heuristics_task_id=*/absl::nullopt, &key);
       return;
     }
   }
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index 54321f8..b825b00 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -32,6 +32,7 @@
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "services/network/public/mojom/source_location.mojom-forward.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/scheduler/task_attribution_id.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/mojom/navigation/navigation_api_history_entry_arrays.mojom-forward.h"
 #include "third_party/blink/public/mojom/navigation/navigation_params.mojom-forward.h"
@@ -181,7 +182,13 @@
   // Navigates to the specified offset from the "current entry" and marks the
   // navigations as initiated by the renderer.
   // |initiator_rfh| is the frame that requested the navigation.
-  void GoToOffsetFromRenderer(int offset, RenderFrameHostImpl* initiator_rfh);
+  // |soft_navigation_heuristic_task_id| is the task in the renderer that
+  // initiated this call (if any).
+  void GoToOffsetFromRenderer(
+      int offset,
+      RenderFrameHostImpl* initiator_rfh,
+      absl::optional<blink::scheduler::TaskAttributionId>
+          soft_navigation_heuristic_task_id);
 
 #if BUILDFLAG(IS_ANDROID)
   // The difference between (Can)GoToOffsetWithSkipping and
@@ -542,11 +549,15 @@
 
   // Navigates in session history to the given index.
   // |initiator_rfh| is nullptr for browser-initiated navigations.
+  // |soft_navigation_heuristic_task_id|: The task in the renderer that
+  // initiated this call (if any).
   // If this navigation originated from the navigation API, |navigation_api_key|
   // will be set and indicate the navigation api key that |initiator_rfh|
   // asked to be navigated to.
   void GoToIndex(int index,
                  RenderFrameHostImpl* initiator_rfh,
+                 absl::optional<blink::scheduler::TaskAttributionId>
+                     soft_navigation_heuristics_task_id,
                  const std::string* navigation_api_key);
 
   // Starts a navigation to an already existing pending NavigationEntry.
@@ -554,9 +565,14 @@
   // If this navigation originated from the navigation API, |navigation_api_key|
   // will be set and indicate the navigation api key that |initiator_rfh|
   // asked to be navigated to.
-  void NavigateToExistingPendingEntry(ReloadType reload_type,
-                                      RenderFrameHostImpl* initiator_rfh,
-                                      const std::string* navigation_api_key);
+  // |soft_navigation_heuristic_task_id|: The task in the renderer that
+  // initiated this call (if any).
+  void NavigateToExistingPendingEntry(
+      ReloadType reload_type,
+      RenderFrameHostImpl* initiator_rfh,
+      absl::optional<blink::scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id,
+      const std::string* navigation_api_key);
 
   // Helper function used by FindFramesToNavigate to determine the appropriate
   // action to take for a particular frame while navigating to
@@ -569,10 +585,14 @@
   // to |pending_entry_|, starting at |frame| and exploring its children.
   // |same_document_loads| and |different_document_loads| will be filled with
   // the NavigationRequests needed to navigate to |pending_entry_|.
+  // |soft_navigation_heuristic_task_id|: The task in the renderer that
+  // initiated this call (if any).
   void FindFramesToNavigate(
       FrameTreeNode* frame,
       ReloadType reload_type,
       bool is_browser_initiated,
+      absl::optional<blink::scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id,
       std::vector<std::unique_ptr<NavigationRequest>>* same_document_loads,
       std::vector<std::unique_ptr<NavigationRequest>>*
           different_document_loads);
@@ -623,6 +643,8 @@
   // Creates and returns a NavigationRequest for a navigation to |entry|. Will
   // return nullptr if the parameters are invalid and the navigation cannot
   // start.
+  // |soft_navigation_heuristic_task_id|: The task in the renderer that
+  // initiated this call (if any).
   // TODO(clamy): Ensure this is only called for navigations to existing
   // NavigationEntries.
   std::unique_ptr<NavigationRequest> CreateNavigationRequestFromEntry(
@@ -632,7 +654,9 @@
       ReloadType reload_type,
       bool is_same_document_history_load,
       bool is_history_navigation_in_new_child_frame,
-      bool is_browser_initiated);
+      bool is_browser_initiated,
+      absl::optional<blink::scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id = absl::nullopt);
 
   // 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_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index a1d625b98..b61f9fe1 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -3718,7 +3718,7 @@
   process()->sink().ClearMessages();
 
   // Simulate the page calling history.back(). It should create a pending entry.
-  main_test_rfh()->GoToEntryAtOffset(-1, false);
+  main_test_rfh()->GoToEntryAtOffset(-1, false, absl::nullopt);
   EXPECT_EQ(0, controller.GetPendingEntryIndex());
 
   // Also make sure we told the page to navigate.
@@ -3728,7 +3728,7 @@
   process()->sink().ClearMessages();
 
   // Now test history.forward()
-  main_test_rfh()->GoToEntryAtOffset(2, false);
+  main_test_rfh()->GoToEntryAtOffset(2, false, absl::nullopt);
   EXPECT_EQ(2, controller.GetPendingEntryIndex());
 
   nav_url = GetLastNavigationURL();
@@ -3739,7 +3739,8 @@
   controller.DiscardNonCommittedEntries();
 
   // Make sure an extravagant history.go() doesn't break.
-  main_test_rfh()->GoToEntryAtOffset(120, false);  // Out of bounds.
+  main_test_rfh()->GoToEntryAtOffset(120, false,
+                                     absl::nullopt);  // Out of bounds.
   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   // TODO(https://crbug.com/1232883): Figure out why HasNavigationRequest() is
   // true when back/forward cache is enabled.
diff --git a/content/browser/renderer_host/navigation_entry_impl.cc b/content/browser/renderer_host/navigation_entry_impl.cc
index b4a28ed..52bcc44 100644
--- a/content/browser/renderer_host/navigation_entry_impl.cc
+++ b/content/browser/renderer_host/navigation_entry_impl.cc
@@ -857,7 +857,9 @@
     int current_history_list_offset,
     int current_history_list_length,
     const blink::FramePolicy& frame_policy,
-    bool ancestor_or_self_has_cspee) {
+    bool ancestor_or_self_has_cspee,
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   // Set the redirect chain to the navigation's redirects, unless returning to a
   // completed navigation (whose previous redirects don't apply).
   // Note that this is actually does not work as intended right now because
@@ -924,7 +926,8 @@
           std::string() /* reduced_accept_language */,
           /*navigation_delivery_type=*/
           network::mojom::NavigationDeliveryType::kDefault,
-          /*view_transition_state=*/absl::nullopt);
+          /*view_transition_state=*/absl::nullopt,
+          soft_navigation_heuristics_task_id);
 #if BUILDFLAG(IS_ANDROID)
   // `data_url_as_string` is saved in NavigationEntry but should only be used by
   // main frames, because loadData* navigations can only happen on the main
diff --git a/content/browser/renderer_host/navigation_entry_impl.h b/content/browser/renderer_host/navigation_entry_impl.h
index 929c26c..775ff57 100644
--- a/content/browser/renderer_host/navigation_entry_impl.h
+++ b/content/browser/renderer_host/navigation_entry_impl.h
@@ -35,6 +35,9 @@
 
 namespace blink {
 struct FramePolicy;
+namespace scheduler {
+class TaskAttributionId;
+}  // namespace scheduler
 }  // namespace blink
 
 namespace content {
@@ -218,7 +221,9 @@
       int current_offset_to_send,
       int current_length_to_send,
       const blink::FramePolicy& frame_policy,
-      bool ancestor_or_self_has_cspee);
+      bool ancestor_or_self_has_cspee,
+      absl::optional<blink::scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id);
 
   // Once a navigation entry is committed, we should no longer track several
   // pieces of non-persisted state, as documented on the members below.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 8d58dc1..60177b7 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1255,18 +1255,20 @@
           /*old_page_info=*/nullptr, /*http_response_code=*/-1,
           blink::mojom::NavigationApiHistoryEntryArrays::New(),
           /*early_hints_preloaded_resources=*/
-          std::vector<GURL>(), absl::nullopt /* ad_auction_components */,
+          std::vector<GURL>(),
+          /*ad_auction_components=*/absl::nullopt,
           /*fenced_frame_reporting_metadata=*/nullptr,
           // This timestamp will be populated when the commit IPC is sent.
-          base::TimeTicks() /* commit_sent */, std::string() /* srcdoc_value */,
-          GURL() /* fallback_srcdoc_baseurl */,
-          false /* should_load_data_url */,
+          /*commit_sent=*/base::TimeTicks(), /*srcdoc_value=*/std::string(),
+          /*fallback_srcdoc_baseurl=*/GURL(),
+          /*should_load_data_url=*/false,
           /*ancestor_or_self_has_cspee=*/
           frame_tree_node->AncestorOrSelfHasCSPEE(),
-          std::string() /* reduced_accept_language */,
+          /*reduced_accept_language=*/std::string(),
           /*navigation_delivery_type=*/
           network::mojom::NavigationDeliveryType::kDefault,
-          /*view_transition_state=*/absl::nullopt);
+          /*view_transition_state=*/absl::nullopt,
+          /*soft_navigation_heuristic_task_id=*/absl::nullopt);
 
   // CreateRendererInitiated() should only be triggered when the navigation is
   // initiated by a frame in the same process.
@@ -1356,50 +1358,58 @@
           // The correct storage key is computed right after creating the
           // NavigationRequest below.
           blink::StorageKey(), is_overriding_user_agent, redirects,
+          /*redirect_response=*/
           std::vector<network::mojom::URLResponseHeadPtr>(),
-          std::vector<net::RedirectInfo>(),
-          std::string() /* redirect_response */, original_url,
-          method /* original_method */, false /* can_load_local_resources */,
-          std::string(), 0 /* nav_entry_id*/,
-          base::flat_map<std::string, bool>() /* subframe_unique_names */,
-          false /* intended_as_new_entry */,
-          -1 /* pending_history_list_offset */,
-          -1 /* current_history_list_offset */,
-          -1 /* current_history_list_length */, false /* was_discard */,
-          false /* is_view_source */, false /* should_clear_history_list */,
-          blink::mojom::NavigationTiming::New(),
+          /*redirect_infos=*/std::vector<net::RedirectInfo>(),
+          /*post_content_type=*/std::string(), original_url,
+          /*original_method=*/method,
+          /*can_load_local_resources=*/false,
+          /*page_state=*/std::string(),
+          /*nav_entry_id=*/0,
+          /*subframe_unique_names=*/base::flat_map<std::string, bool>(),
+          /*intended_as_new_entry=*/false,
+          /*pending_history_list_offset=*/-1,
+          /*current_history_list_offset=*/-1,
+          /*current_history_list_length=*/-1,
+          /*was_discarded=*/false,
+          /*is_view_source=*/false,
+          /*should_clear_history_list=*/false,
+          /*navigation_timing=*/blink::mojom::NavigationTiming::New(),
           blink::mojom::WasActivatedOption::kUnknown,
-          base::UnguessableToken::Create() /* navigation_token */,
+          /*navigation_token=*/base::UnguessableToken::Create(),
+          /*prefetched_signed_exchanges=*/
           std::vector<blink::mojom::PrefetchedSignedExchangeInfoPtr>(),
 #if BUILDFLAG(IS_ANDROID)
-          std::string() /* data_url_as_string */,
+          /*data_url_as_string=*/std::string(),
 #endif
-          false /* is_browser_initiated */,
-          GURL() /* web_bundle_physical_url */,
-          GURL() /* base_url_override_for_web_bundle */,
-          ukm::kInvalidSourceId /* document_ukm_source_id */,
+          /*is_browser_initiated=*/false,
+          /*web_bundle_physical_url=*/GURL(),
+          /*base_url_override_for_web_bundle=*/GURL(),
+          /*document_ukm_source_id=*/ukm::kInvalidSourceId,
           frame_tree_node->pending_frame_policy(),
-          std::vector<std::string>() /* force_enabled_origin_trials */,
-          false /* origin_agent_cluster */,
-          true /* origin_agent_cluster_left_as_default */,
-          std::vector<
-              network::mojom::WebClientHintsType>() /* enabled_client_hints */,
-          false /* is_cross_browsing_instance */, nullptr /* old_page_info */,
-          http_response_code,
+          /*force_enabled_origin_trials=*/std::vector<std::string>(),
+          /*origin_agent_cluster=*/false,
+          /*origin_agent_cluster_left_as_default=*/true,
+          /*enabled_client_hints=*/
+          std::vector<network::mojom::WebClientHintsType>(),
+          /*is_cross_browsing_instance=*/false,
+          /*old_page_info=*/nullptr, http_response_code,
           blink::mojom::NavigationApiHistoryEntryArrays::New(),
-          std::vector<GURL>() /* early_hints_preloaded_resources */,
-          absl::nullopt /* ad_auction_components */,
+          /*early_hints_preloaded_resources=*/
+          std::vector<GURL>(),
+          /*ad_auction_components=*/absl::nullopt,
           /*fenced_frame_reporting_metadata=*/nullptr,
           // This timestamp will be populated when the commit IPC is sent.
-          base::TimeTicks() /* commit_sent */, std::string() /* srcdoc_value */,
-          GURL() /* fallback_srcdoc_baseurl_value */,
-          false /* should_load_data_url */,
+          /*commit_sent=*/base::TimeTicks(), /*srcdoc_value=*/std::string(),
+          /*fallback_srcdoc_baseurl=*/GURL(),
+          /*should_load_data_url=*/false,
           /*ancestor_or_self_has_cspee=*/
           frame_tree_node->AncestorOrSelfHasCSPEE(),
-          std::string() /* reduced_accept_language */,
+          /*reduced_accept_language=*/std::string(),
           /*navigation_delivery_type=*/
           network::mojom::NavigationDeliveryType::kDefault,
-          /*view_transition_state=*/absl::nullopt);
+          /*view_transition_state=*/absl::nullopt,
+          /*soft_navigation_heuristic_task_id=*/absl::nullopt);
   blink::mojom::BeginNavigationParamsPtr begin_params =
       blink::mojom::BeginNavigationParams::New();
   std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
@@ -2609,6 +2619,7 @@
   navigation_handle_timing_ = NavigationHandleTiming();
 
   policy_container_builder_->ResetForCrossDocumentRestart();
+  commit_params_->soft_navigation_heuristic_task_id = absl::nullopt;
 }
 
 void NavigationRequest::ResetStateForSiteInstanceChange() {
@@ -4964,6 +4975,11 @@
   // A navigation request should only commit once the response has been
   // processed.
   DCHECK_GE(state_, WILL_PROCESS_RESPONSE);
+  // In NavigationControllerImpl::NavigateToExistingPendingEntry we're verifying
+  // that the task ID is only passed along if the initiator RFH is the same as
+  // the navigated RFH.
+  DCHECK((IsSameDocument() && IsInOutermostMainFrame()) ||
+         !commit_params_->soft_navigation_heuristic_task_id);
 
   if (!CoopCoepSanityCheck())
     return;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index d0f6d48..9d0f0a67 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6133,8 +6133,11 @@
     proxy->GetAssociatedRemoteFrame()->DispatchLoadEventForFrameOwner();
 }
 
-void RenderFrameHostImpl::GoToEntryAtOffset(int32_t offset,
-                                            bool has_user_gesture) {
+void RenderFrameHostImpl::GoToEntryAtOffset(
+    int32_t offset,
+    bool has_user_gesture,
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristic_task_id) {
   OPTIONAL_TRACE_EVENT2("content", "RenderFrameHostImpl::GoToEntryAtOffset",
                         "render_frame_host", this, "offset", offset);
 
@@ -6151,7 +6154,8 @@
 
   // All frames are allowed to navigate the global history.
   if (delegate_->IsAllowedToGoToEntryAtOffset(offset)) {
-    frame_tree_->controller().GoToOffsetFromRenderer(offset, this);
+    frame_tree_->controller().GoToOffsetFromRenderer(
+        offset, this, soft_navigation_heuristic_task_id);
   }
 }
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 7208de9..b867d260 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2191,7 +2191,10 @@
   void DidChangeLoadProgress(double load_progress) override;
   void DidFinishLoad(const GURL& validated_url) override;
   void DispatchLoad() override;
-  void GoToEntryAtOffset(int32_t offset, bool has_user_gesture) override;
+  void GoToEntryAtOffset(int32_t offset,
+                         bool has_user_gesture,
+                         absl::optional<blink::scheduler::TaskAttributionId>
+                             soft_navigation_heuristic_task_id) override;
   void NavigateToNavigationApiKey(const std::string& key,
                                   bool has_user_gesture) override;
   void UpdateTitle(const absl::optional<::std::u16string>& title,
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 1c380f1..afb45e5d 100644
--- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -423,7 +423,8 @@
             controller.GetIndexOfEntry(entry),
             controller.GetLastCommittedEntryIndex(), controller.GetEntryCount(),
             frame_tree_node->current_replication_state().frame_policy,
-            frame_tree_node->AncestorOrSelfHasCSPEE());
+            frame_tree_node->AncestorOrSelfHasCSPEE(),
+            /*soft_navigation_heuristics_task_id=*/absl::nullopt);
     commit_params->post_content_type = post_content_type;
 
     std::unique_ptr<NavigationRequest> navigation_request =
@@ -3169,7 +3170,8 @@
           controller().GetLastCommittedEntryIndex(),
           controller().GetEntryCount(),
           frame_tree_node->current_replication_state().frame_policy,
-          frame_tree_node->AncestorOrSelfHasCSPEE());
+          frame_tree_node->AncestorOrSelfHasCSPEE(),
+          /*soft_navigation_heuristics_task_id=*/absl::nullopt);
 
   std::unique_ptr<NavigationRequest> navigation_request =
       NavigationRequest::CreateBrowserInitiated(
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 16968fd3..ee95253 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -113,7 +113,7 @@
 static const char kAsyncReadBackString[] = "Compositing.CopyFromSurfaceTime";
 static const base::TimeDelta kClickCountInterval = base::Seconds(0.5);
 static const float kClickCountRadiusSquaredDIP = 25;
-static const base::TimeDelta kRotationTimeout = base::Milliseconds(100);
+static const base::TimeDelta kThrottleTimeout = base::Milliseconds(200);
 
 std::unique_ptr<ui::TouchSelectionController> CreateSelectionController(
     ui::TouchSelectionControllerClient* client,
@@ -281,6 +281,14 @@
   BeginScreenStateChange();
   pending_screen_state_.is_fullscreen = true;
   HandleScreenStateChanges(cc::DeadlinePolicy::UseDefaultDeadline());
+
+  if (throttle_timeout_.IsRunning())
+    throttle_timeout_.Stop();
+  throttle_timeout_.Start(
+      FROM_HERE, kThrottleTimeout,
+      base::BindOnce(
+          &RenderWidgetHostViewAndroid::ScreenStateChangeHandler::Unthrottle,
+          base::Unretained(this)));
 }
 
 void RenderWidgetHostViewAndroid::ScreenStateChangeHandler::
@@ -339,6 +347,26 @@
   HandleScreenStateChanges(cc::DeadlinePolicy::UseDefaultDeadline());
 }
 
+void RenderWidgetHostViewAndroid::ScreenStateChangeHandler::WasEvicted() {
+  if (!IsFullscreenSurfaceSyncSupported())
+    return;
+  // Reset the world upon eviction. We will re-esatblish the world when we next
+  // become visible and begin embedding content again. This should not call
+  // HandleScreenStateChanges, as we explicitly to not want to do any syncing
+  // when we are evicted.
+  BeginScreenStateChange();
+}
+
+void RenderWidgetHostViewAndroid::ScreenStateChangeHandler::
+    WasShownAfterEviction() {
+  if (!IsFullscreenSurfaceSyncSupported())
+    return;
+  // The screen state can change while we were evicted. Reset the world for
+  // future changes.
+  BeginScreenStateChange();
+  HandleScreenStateChanges(cc::DeadlinePolicy::UseDefaultDeadline());
+}
+
 void RenderWidgetHostViewAndroid::ScreenStateChangeHandler::
     BeginScreenStateChange() {
   current_screen_state_.visible_viewport_size = rwhva_->view_.GetSize();
@@ -502,6 +530,13 @@
     rwhva_->BeginRotationBatching();
     return true;
   } else if (end_rotation) {
+    // The rotation timeout is intended to catch edge-cases where Android::View
+    // code does not give us some aspects of re-layouts. However on slower
+    // devices the timeout may fire before the final signals arrive. In these
+    // cases call BeginRotationBatching to properly enqueue the rotation, before
+    // immediately embedding the new content.
+    if (!rwhva_->in_rotation_)
+      rwhva_->BeginRotationBatching();
     rwhva_->EndRotationAndSyncIfNecessary();
   } else if (sync_needed) {
     rwhva_->SynchronizeVisualProperties(deadline_policy, absl::nullopt);
@@ -532,6 +567,11 @@
   return true;
 }
 
+void RenderWidgetHostViewAndroid::ScreenStateChangeHandler::Unthrottle() {
+  pending_screen_state_.any_non_rotation_size_changed = true;
+  HandleScreenStateChanges(cc::DeadlinePolicy::UseDefaultDeadline());
+}
+
 RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
     RenderWidgetHostImpl* widget_host,
     gfx::NativeView parent_native_view)
@@ -1614,7 +1654,7 @@
 
 void RenderWidgetHostViewAndroid::ClearFallbackSurfaceForCommitPending() {
   delegated_frame_host_->ClearFallbackSurfaceForCommitPending();
-  local_surface_id_allocator_.Invalidate();
+  EvictInternal();
 }
 
 void RenderWidgetHostViewAndroid::ResetFallbackToFirstNavigationSurface() {
@@ -2842,7 +2882,7 @@
     // Navigating while hidden should not allocate a new LocalSurfaceID. Once
     // sizes are ready, or we begin to Show, we can then allocate the new
     // LocalSurfaceId.
-    local_surface_id_allocator_.Invalidate();
+    EvictInternal();
     navigation_while_hidden_ = true;
   } else {
     // TODO(jonross): This was a legacy optimization to not perform too many
@@ -2976,9 +3016,11 @@
   if (overscroll_controller_)
     overscroll_controller_->Enable();
 
+  bool was_evicted = false;
   if ((delegated_frame_host_ &&
        delegated_frame_host_->IsPrimarySurfaceEvicted()) ||
       !local_surface_id_allocator_.HasValidLocalSurfaceId()) {
+    was_evicted = true;
     ui::WindowAndroidCompositor* compositor =
         view_.GetWindowAndroid() ? view_.GetWindowAndroid()->GetCompositor()
                                  : nullptr;
@@ -3050,6 +3092,14 @@
     rotation_metrics_.begin()->first = base::TimeTicks::Now();
     BeginRotationEmbed();
   }
+
+  // TODO(crbug.com/1385146): Ideally we would do no synchronizing at all when
+  // hidden. We should just amass all the new blink::VisualProperties and send
+  // them once when becoming visible. However the refactor would be difficult
+  // right now. We will revisit this once we are satisfied with the rollout of
+  // content::kSurfaceSyncFullscreenKillswitch.
+  if (was_evicted)
+    screen_state_change_handler_.WasShownAfterEviction();
 }
 
 void RenderWidgetHostViewAndroid::RequestPresentationTimeFromHostOrDelegate(
@@ -3164,7 +3214,7 @@
         cc::DeadlinePolicy::UseExistingDeadline(),
         local_surface_id_allocator_.GetCurrentLocalSurfaceId());
   } else {
-    local_surface_id_allocator_.Invalidate();
+    EvictInternal();
   }
 }
 
@@ -3208,7 +3258,7 @@
   if (rotation_timeout_.IsRunning())
     rotation_timeout_.Stop();
   rotation_timeout_.Start(
-      FROM_HERE, kRotationTimeout,
+      FROM_HERE, kThrottleTimeout,
       base::BindOnce(
           &RenderWidgetHostViewAndroid::EndRotationAndSyncIfNecessary,
           base::Unretained(this)));
@@ -3260,4 +3310,9 @@
   BeginRotationEmbed();
 }
 
+void RenderWidgetHostViewAndroid::EvictInternal() {
+  screen_state_change_handler_.WasEvicted();
+  local_surface_id_allocator_.Invalidate();
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index b6346c00..d021a91 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -446,6 +446,8 @@
     void LockOrientation(device::mojom::ScreenOrientationLockType orientation);
     void UnlockOrientation();
     void SetHasPersistentVideo(bool has_persistent_video);
+    void WasEvicted();
+    void WasShownAfterEviction();
 
    private:
     // Sets the `current_screen_state_` to be the current values. Clears
@@ -456,13 +458,17 @@
     // fullscreen, and Picture-in-Picture mode.
     bool HandleScreenStateChanges(const cc::DeadlinePolicy& deadline_policy);
 
+    // Clears flags used to throttle SurfaceSync.
+    void Unthrottle();
+
     // The ScreenState of the current world, the pending visual properties, or
     // the properties from before we entered Picture-in-Picture mode.
     ScreenState current_screen_state_;
     ScreenState pending_screen_state_;
     ScreenState pre_picture_in_picture_;
 
-   private:
+    base::OneShotTimer throttle_timeout_;
+
     RenderWidgetHostViewAndroid* rwhva_;
   };
 
@@ -540,6 +546,7 @@
   void EndRotationBatching();
   void BeginRotationEmbed();
   void EndRotationAndSyncIfNecessary();
+  void EvictInternal();
 
   bool is_showing_;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
index 1f522a3a..4386123 100644
--- a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
@@ -912,6 +912,29 @@
   GetLocalSurfaceIdAndConfirmNewerThan(hidden_local_surface_id);
 }
 
+// Tests that when we are evicted while waiting for fullscreen transition, that
+// we stop throttling, and can successfully re-embed later.
+TEST_F(RenderWidgetHostViewAndroidRotationTest, FullscreenEviction) {
+  RenderWidgetHostViewAndroid* rwhva = render_widget_host_view_android();
+  auto local_surface_id = rwhva->GetLocalSurfaceId();
+  EnterFullscreenMode();
+  EXPECT_FALSE(rwhva->CanSynchronizeVisualProperties());
+
+  // When we are evicted while hidden, the viz::LocalSurfaceId should be
+  // invalidated, and we should no longer throttle syncrhonizing.
+  rwhva->Hide();
+  rwhva->WasEvicted();
+  auto evicted_local_surface_id = rwhva->GetLocalSurfaceId();
+  EXPECT_FALSE(evicted_local_surface_id.is_valid());
+  EXPECT_TRUE(rwhva->CanSynchronizeVisualProperties());
+
+  // This shouldn't crash
+  rwhva->ShowWithVisibility(blink::mojom::PageVisibilityState::kVisible);
+  // We should also have a new viz::LocalSurfaceId to become embedded again.
+  EXPECT_TRUE(rwhva->CanSynchronizeVisualProperties());
+  GetLocalSurfaceIdAndConfirmNewerThan(local_surface_id);
+}
+
 // Tests rotation and fullscreen cases that are supported by both the visual
 // properties analysis, and the fullscreen killswitch legacy path.
 //
diff --git a/content/browser/resources/prerender/DIR_METADATA b/content/browser/resources/prerender/DIR_METADATA
deleted file mode 100644
index 9ec2740c..0000000
--- a/content/browser/resources/prerender/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-mixins: "//content/browser/preloading/prerender/COMMON_METADATA"
-
diff --git a/content/browser/resources/prerender/OWNERS b/content/browser/resources/prerender/OWNERS
deleted file mode 100644
index 03a1d5b..0000000
--- a/content/browser/resources/prerender/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://content/browser/preloading/prerender/OWNERS
diff --git a/content/browser/resources/prerender/prerender_internals.html b/content/browser/resources/prerender/prerender_internals.html
deleted file mode 100644
index a9261ccd..0000000
--- a/content/browser/resources/prerender/prerender_internals.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <meta charset="utf-8">
-  <script type='module' src='prerender_internals.js'></script>
-  <title>Prerender Internals</title>
-</head>
-<body>
-  <h1>Prerender Internals</h1>
-  <div id="prerender-info-name">
-    <div>triggerPageUrl</div>
-    <div>url</div>
-    <div>finalStatus</div>
-  </div>
-  <ul id="prerender-info"></ul>
-</body>
-</html>
diff --git a/content/browser/resources/prerender/prerender_internals.js b/content/browser/resources/prerender/prerender_internals.js
deleted file mode 100644
index c553999..0000000
--- a/content/browser/resources/prerender/prerender_internals.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {$} from 'chrome://resources/js/util.js';
-import {PrerenderInternalsHandler} from './prerender_internals.mojom-webui.js';
-
-let pageHandler;
-
-function addDivElement(li, text) {
-  const div = document.createElement('div');
-  div.appendChild(document.createTextNode(text));
-  li.appendChild(div);
-}
-
-document.addEventListener('DOMContentLoaded', _ => {
-  pageHandler = PrerenderInternalsHandler.getRemote();
-
-  pageHandler.getPrerenderInfo().then((response) => {
-    for (const info of response.infos) {
-      const li = document.createElement('li');
-      for (const pageInfo of info.prerenderedPageInfos) {
-        addDivElement(li, pageInfo.triggerPageUrl.url);
-        addDivElement(li, pageInfo.url.url);
-        addDivElement(li, pageInfo.finalStatus);
-      }
-      $('prerender-info').appendChild(li);
-    }
-  });
-});
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index b13b67fc..5db406b 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -265,9 +265,13 @@
     group.owner = origin;
     group.name = "Name";
     group.expiry = base::Time::Now() + base::Days(30);
-    static_cast<InterestGroupManagerImpl*>(
-        storage_partition_->GetInterestGroupManager())
-        ->JoinInterestGroup(group, origin.GetURL());
+    InterestGroupManagerImpl* interest_group_manager =
+        static_cast<InterestGroupManagerImpl*>(
+            storage_partition_->GetInterestGroupManager());
+    interest_group_manager->JoinInterestGroup(group, origin.GetURL());
+    // Update the K-anonymity so that we can tell when it gets removed.
+    interest_group_manager->UpdateLastKAnonymityReported(
+        KAnonKeyFor(origin, "Name"));
   }
 
  private:
@@ -278,7 +282,8 @@
 
   void GetLastKAnonymityReportedCallback(
       absl::optional<base::Time> last_reported) {
-    contains_kanon_ = last_reported.has_value();
+    contains_kanon_ =
+        last_reported.has_value() && last_reported.value() > base::Time::Min();
     await_completion_.Notify();
   }
 
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index 86f2e64..b143387 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -306,20 +306,17 @@
   return FormatUrlForDisplay(origin.GetURL());
 }
 
-bool ShouldFailIfNotSignedInWithIdp(
+bool ShouldFailBecauseNotSignedInWithIdp(
     const GURL& idp_url,
     FederatedIdentitySharingPermissionContextDelegate*
         sharing_permission_delegate) {
-  if (!IsFedCmIdpSigninStatusEnabled())
+  if (GetFedCmIdpSigninStatusMode() == FedCmIdpSigninStatusMode::DISABLED)
     return false;
 
   const url::Origin idp_origin = url::Origin::Create(idp_url);
   const absl::optional<bool> idp_signin_status =
       sharing_permission_delegate->GetIdpSigninStatus(idp_origin);
-  if (!idp_signin_status.value_or(true))
-    return true;
-
-  return false;
+  return !idp_signin_status.value_or(true);
 }
 
 FederatedAuthRequestWebContentsData* GetWebContentsData(
@@ -526,8 +523,13 @@
 
       // TODO(crbug.com/1382545): Handle ShouldFailIfNotSignedInWithIdp in the
       // multi IDP use case.
-      if (ShouldFailIfNotSignedInWithIdp(idp_ptr->config_url,
-                                         sharing_permission_delegate_)) {
+      IdentityProviderInfo& idp_info = idp_info_[idp_ptr->config_url];
+      idp_info.has_failing_idp_signin_status =
+          ShouldFailBecauseNotSignedInWithIdp(idp_ptr->config_url,
+                                              sharing_permission_delegate_);
+
+      if (idp_info.has_failing_idp_signin_status &&
+          GetFedCmIdpSigninStatusMode() == FedCmIdpSigninStatusMode::ENABLED) {
         CompleteRequestWithError(FederatedAuthRequestResult::kError,
                                  TokenStatus::kNotSignedInWithIdp,
                                  /*should_delay_callback=*/true);
@@ -830,8 +832,11 @@
 
   // Make sure that we don't fetch accounts if the IDP sign-in bit is reset to
   // false during the API call. e.g. by the login/logout HEADER.
-  if (ShouldFailIfNotSignedInWithIdp(idp_info.provider.config_url,
-                                     sharing_permission_delegate_)) {
+  idp_info_[idp_info.provider.config_url].has_failing_idp_signin_status =
+      ShouldFailBecauseNotSignedInWithIdp(idp_info.provider.config_url,
+                                          sharing_permission_delegate_);
+  if (idp_info.has_failing_idp_signin_status &&
+      GetFedCmIdpSigninStatusMode() == FedCmIdpSigninStatusMode::ENABLED) {
     CompleteRequestWithError(FederatedAuthRequestResult::kError,
                              TokenStatus::kNotSignedInWithIdp,
                              /*should_delay_callback=*/true);
@@ -926,7 +931,7 @@
     const url::Origin& idp_origin,
     blink::mojom::FederatedAuthRequestResult result,
     absl::optional<TokenStatus> token_status) {
-  if (!IsFedCmIdpSigninStatusEnabled()) {
+  if (GetFedCmIdpSigninStatusMode() == FedCmIdpSigninStatusMode::DISABLED) {
     CompleteRequestWithError(result, token_status,
                              /*should_delay_callback=*/true);
     return;
@@ -934,15 +939,17 @@
 
   const absl::optional<bool> idp_signin_status =
       sharing_permission_delegate_->GetIdpSigninStatus(idp_origin);
+
   // Ensures that we only fetch accounts unconditionally once.
-  if (!idp_signin_status.has_value()) {
-    sharing_permission_delegate_->SetIdpSigninStatus(idp_origin, false);
+  sharing_permission_delegate_->SetIdpSigninStatus(idp_origin, false);
+
+  if (!idp_signin_status.has_value() ||
+      GetFedCmIdpSigninStatusMode() == FedCmIdpSigninStatusMode::METRICS_ONLY) {
     CompleteRequestWithError(result, token_status,
                              /*should_delay_callback=*/true);
     return;
   }
 
-  sharing_permission_delegate_->SetIdpSigninStatus(idp_origin, false);
   // TODO(crbug.com/1357790): we should figure out how to handle multiple IDP
   // w.r.t. showing a static failure UI. e.g. one IDP is always successful and
   // one always returns 404.
@@ -966,11 +973,13 @@
     IdpNetworkRequestManager::AccountList accounts) {
   url::Origin idp_origin = url::Origin::Create(idp_info.provider.config_url);
 
-  // Record metrics on effect of IDP sign-in status API.
-  const absl::optional<bool> idp_signin_status =
-      sharing_permission_delegate_->GetIdpSigninStatus(idp_origin);
-  fedcm_metrics_->RecordIdpSigninMatchStatus(idp_signin_status,
-                                             status.parse_status);
+  if (GetFedCmIdpSigninStatusMode() != FedCmIdpSigninStatusMode::DISABLED) {
+    // Record metrics on effect of IDP sign-in status API.
+    const absl::optional<bool> idp_signin_status =
+        sharing_permission_delegate_->GetIdpSigninStatus(idp_origin);
+    fedcm_metrics_->RecordIdpSigninMatchStatus(idp_signin_status,
+                                               status.parse_status);
+  }
 
   constexpr char kAccountsUrl[] = "accounts endpoint";
   switch (status.parse_status) {
@@ -1001,7 +1010,12 @@
     case IdpNetworkRequestManager::ParseStatus::kSuccess: {
       ComputeLoginStateAndReorderAccounts(idp_info.provider, accounts);
 
-      sharing_permission_delegate_->SetIdpSigninStatus(idp_origin, true);
+      if (!idp_info.has_failing_idp_signin_status) {
+        // This scenario occurs in FedCmIdpSigninStatusMode::METRICS_ONLY mode.
+        // Don't set the IDP sign-in status because we would not get here in
+        // FedCmIdpSigninStatusMode::ENABLED mode.
+        sharing_permission_delegate_->SetIdpSigninStatus(idp_origin, true);
+      }
 
       bool need_client_metadata = false;
       for (const IdentityRequestAccount& account : accounts) {
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h
index 090043fe..b7f5f00 100644
--- a/content/browser/webid/federated_auth_request_impl.h
+++ b/content/browser/webid/federated_auth_request_impl.h
@@ -94,6 +94,7 @@
 
     blink::mojom::IdentityProvider provider;
     Endpoints endpoints;
+    bool has_failing_idp_signin_status{false};
     bool manifest_list_checked{false};
     absl::optional<IdentityProviderMetadata> metadata;
   };
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc
index 32c0366..7bfd577 100644
--- a/content/browser/webid/federated_auth_request_impl_unittest.cc
+++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -2398,6 +2398,72 @@
   RunAuthTest(kDefaultRequestParameters, expectations, configuration);
 }
 
+// Test that when IdpSigninStatus API is in the metrics-only mode, that an IDP
+// signed-out status stays signed-out regardless of what is returned by the
+// accounts endpoint.
+TEST_F(FederatedAuthRequestImplTest, IdpSigninStatusMetricsModeStaysSignedout) {
+  base::test::ScopedFeatureList list;
+  list.InitAndEnableFeatureWithParameters(
+      features::kFedCm,
+      {{features::kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName,
+        "true"}});
+
+  EXPECT_CALL(*mock_sharing_permission_delegate_, GetIdpSigninStatus(_))
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(*mock_sharing_permission_delegate_, SetIdpSigninStatus(_, _))
+      .Times(0);
+
+  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
+              kConfigurationValid);
+}
+
+// Test that when IdpSigninStatus API does not have any state for an IDP, that
+// the state transitions to sign-in if the accounts endpoint returns a
+// non-empty list of accounts.
+TEST_F(
+    FederatedAuthRequestImplTest,
+    IdpSigninStatusMetricsModeUndefinedTransitionsToSignedinWhenHaveAccounts) {
+  base::test::ScopedFeatureList list;
+  list.InitAndEnableFeatureWithParameters(
+      features::kFedCm,
+      {{features::kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName,
+        "true"}});
+
+  EXPECT_CALL(*mock_sharing_permission_delegate_, GetIdpSigninStatus(_))
+      .WillRepeatedly(Return(absl::nullopt));
+  EXPECT_CALL(*mock_sharing_permission_delegate_,
+              SetIdpSigninStatus(OriginFromString(kProviderUrlFull), true));
+
+  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
+              kConfigurationValid);
+}
+
+// Test that when IdpSigninStatus API is in metrics-only mode, that IDP sign-in
+// status transitions to signed-out if the accounts endpoint returns no
+// information.
+TEST_F(FederatedAuthRequestImplTest,
+       IdpSigninStatusMetricsModeTransitionsToSignedoutWhenNoAccounts) {
+  base::test::ScopedFeatureList list;
+  list.InitAndEnableFeatureWithParameters(
+      features::kFedCm,
+      {{features::kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName,
+        "true"}});
+
+  EXPECT_CALL(*mock_sharing_permission_delegate_, GetIdpSigninStatus(_))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(*mock_sharing_permission_delegate_,
+              SetIdpSigninStatus(OriginFromString(kProviderUrlFull), false));
+
+  MockConfiguration configuration = kConfigurationValid;
+  configuration.idp_info[kProviderUrlFull].accounts_response.parse_status =
+      ParseStatus::kInvalidResponseError;
+  RequestExpectations expectations = {
+      RequestTokenStatus::kError, absl::nullopt, absl::nullopt,
+      FetchedEndpoint::ACCOUNTS | FetchedEndpoint::MANIFEST |
+          FetchedEndpoint::MANIFEST_LIST};
+  RunAuthTest(kDefaultRequestParameters, expectations, configuration);
+}
+
 // Tests that multiple IDPs provided results in an error if the
 // `kFedCmMultipleIdentityProviders` flag is disabled.
 TEST_F(FederatedAuthRequestImplTest, MultiIdpError) {
diff --git a/content/browser/webid/flags.cc b/content/browser/webid/flags.cc
index 0864fe54..019db2f 100644
--- a/content/browser/webid/flags.cc
+++ b/content/browser/webid/flags.cc
@@ -26,10 +26,19 @@
       features::kFedCmMultipleIdentityProviders);
 }
 
-bool IsFedCmIdpSigninStatusEnabled() {
-  return GetFieldTrialParamByFeatureAsBool(
-      features::kFedCm, features::kFedCmIdpSigninStatusFieldTrialParamName,
-      false);
+FedCmIdpSigninStatusMode GetFedCmIdpSigninStatusMode() {
+  if (GetFieldTrialParamByFeatureAsBool(
+          features::kFedCm, features::kFedCmIdpSigninStatusFieldTrialParamName,
+          false)) {
+    return FedCmIdpSigninStatusMode::ENABLED;
+  }
+  if (GetFieldTrialParamByFeatureAsBool(
+          features::kFedCm,
+          features::kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName,
+          true)) {
+    return FedCmIdpSigninStatusMode::METRICS_ONLY;
+  }
+  return FedCmIdpSigninStatusMode::DISABLED;
 }
 
 bool IsFedCmMetricsEndpointEnabled() {
diff --git a/content/browser/webid/flags.h b/content/browser/webid/flags.h
index d2a99a0..0698bda 100644
--- a/content/browser/webid/flags.h
+++ b/content/browser/webid/flags.h
@@ -9,6 +9,9 @@
 
 namespace content {
 
+// IDP IdpSigninStatus API modes.
+enum class FedCmIdpSigninStatusMode { DISABLED, METRICS_ONLY, ENABLED };
+
 // Whether FedCM auto sign-in is enabled.
 bool IsFedCmAutoSigninEnabled();
 
@@ -18,8 +21,8 @@
 // Whether multiple identity providers are enabled.
 bool IsFedCmMultipleIdentityProvidersEnabled();
 
-// Whether IdpSigninStatus is enabled.
-bool IsFedCmIdpSigninStatusEnabled();
+// Returns the IdpSigninStatus API mode.
+FedCmIdpSigninStatusMode GetFedCmIdpSigninStatusMode();
 
 // Whether metrics endpoint is enabled.
 bool IsFedCmMetricsEndpointEnabled();
diff --git a/content/browser/webui/content_web_ui_configs.cc b/content/browser/webui/content_web_ui_configs.cc
index 93097699..f152faf 100644
--- a/content/browser/webui/content_web_ui_configs.cc
+++ b/content/browser/webui/content_web_ui_configs.cc
@@ -13,7 +13,6 @@
 #include "content/browser/media/media_internals_ui.h"
 #include "content/browser/metrics/histograms_internals_ui.h"
 #include "content/browser/network/network_errors_listing_ui.h"
-#include "content/browser/preloading/prerender/prerender_internals_ui.h"
 #include "content/browser/process_internals/process_internals_ui.h"
 #include "content/browser/quota/quota_internals_ui.h"
 #include "content/browser/service_worker/service_worker_internals_ui.h"
@@ -36,7 +35,6 @@
   map.AddWebUIConfig(std::make_unique<MediaInternalsUIConfig>());
   map.AddWebUIConfig(std::make_unique<HistogramsInternalsUIConfig>());
   map.AddWebUIConfig(std::make_unique<NetworkErrorsListingUIConfig>());
-  map.AddWebUIConfig(std::make_unique<PrerenderInternalsUIConfig>());
   map.AddWebUIConfig(std::make_unique<ProcessInternalsUIConfig>());
   map.AddWebUIConfig(std::make_unique<QuotaInternalsUIConfig>());
   map.AddWebUIConfig(std::make_unique<ServiceWorkerInternalsUIConfig>());
diff --git a/content/common/webid/identity_url_loader_throttle.cc b/content/common/webid/identity_url_loader_throttle.cc
index 5db57faa..552663ea 100644
--- a/content/common/webid/identity_url_loader_throttle.cc
+++ b/content/common/webid/identity_url_loader_throttle.cc
@@ -28,10 +28,14 @@
 static constexpr char kIdpHeaderValueSignin[] = "action=signin";
 static constexpr char kIdpHeaderValueSignout[] = "action=signout";
 
-bool IsFedCmIdpSigninStatusEnabled() {
+bool IsFedCmIdpSigninStatusThrottleEnabled() {
   return GetFieldTrialParamByFeatureAsBool(
-      features::kFedCm, features::kFedCmIdpSigninStatusFieldTrialParamName,
-      false);
+             features::kFedCm,
+             features::kFedCmIdpSigninStatusFieldTrialParamName, false) ||
+         GetFieldTrialParamByFeatureAsBool(
+             features::kFedCm,
+             features::kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName,
+             true);
 }
 
 }  // namespace
@@ -40,7 +44,7 @@
 
 std::unique_ptr<blink::URLLoaderThrottle> MaybeCreateIdentityUrlLoaderThrottle(
     SetIdpStatusCallback cb) {
-  if (!IsFedCmIdpSigninStatusEnabled())
+  if (!IsFedCmIdpSigninStatusThrottleEnabled())
     return nullptr;
   return std::make_unique<IdentityUrlLoaderThrottle>(std::move(cb));
 }
diff --git a/content/common/webid/identity_url_loader_throttle_unittest.cc b/content/common/webid/identity_url_loader_throttle_unittest.cc
index aca3adee..91aa830 100644
--- a/content/common/webid/identity_url_loader_throttle_unittest.cc
+++ b/content/common/webid/identity_url_loader_throttle_unittest.cc
@@ -33,7 +33,6 @@
     cb_signin_status_ = status;
   }
 
-  base::test::ScopedFeatureList scoped_feature_list_;
   base::HistogramTester histogram_tester_;
   int cb_num_calls_ = 0;
   url::Origin cb_origin_;
@@ -45,7 +44,13 @@
       public testing::WithParamInterface<
           std::tuple<IdpSigninStatus, bool, bool>> {};
 
-TEST_F(IdentityUrlLoaderThrottleTest, OffByDefault) {
+TEST_F(IdentityUrlLoaderThrottleTest, DisabledByKillSwitch) {
+  base::test::ScopedFeatureList list;
+  list.InitAndEnableFeatureWithParameters(
+      features::kFedCm,
+      {{features::kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName,
+        "false"}});
+
   std::unique_ptr<blink::URLLoaderThrottle> throttle =
       MaybeCreateIdentityUrlLoaderThrottle(CreateCallback());
   EXPECT_EQ(nullptr, throttle);
@@ -56,10 +61,6 @@
   bool has_user_gesture = std::get<1>(GetParam());
   bool is_google_header = std::get<2>(GetParam());
 
-  scoped_feature_list_.InitAndEnableFeatureWithParameters(
-      features::kFedCm,
-      {{features::kFedCmIdpSigninStatusFieldTrialParamName, "true"}});
-
   std::unique_ptr<blink::URLLoaderThrottle> throttle =
       MaybeCreateIdentityUrlLoaderThrottle(CreateCallback());
   ASSERT_NE(nullptr, throttle);
@@ -113,10 +114,6 @@
                      testing::Values(false, true)));
 
 TEST_F(IdentityUrlLoaderThrottleTest, NoRelevantHeader) {
-  scoped_feature_list_.InitAndEnableFeatureWithParameters(
-      features::kFedCm,
-      {{features::kFedCmIdpSigninStatusFieldTrialParamName, "true"}});
-
   std::unique_ptr<blink::URLLoaderThrottle> throttle =
       MaybeCreateIdentityUrlLoaderThrottle(CreateCallback());
   ASSERT_NE(nullptr, throttle);
diff --git a/content/dev_ui_content_resources.grd b/content/dev_ui_content_resources.grd
index 061d3ec..59fed7d 100644
--- a/content/dev_ui_content_resources.grd
+++ b/content/dev_ui_content_resources.grd
@@ -43,9 +43,6 @@
       <include name="IDR_NETWORK_ERROR_LISTING_HTML" file="browser/resources/net/network_errors_listing.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_NETWORK_ERROR_LISTING_JS" file="browser/resources/net/network_errors_listing.js" type="BINDATA" />
       <include name="IDR_NETWORK_ERROR_LISTING_CSS" file="browser/resources/net/network_errors_listing.css" type="BINDATA" />
-      <include name="IDR_PRERENDER_INTERNALS_HTML" file="browser/resources/prerender/prerender_internals.html" type="BINDATA" />
-      <include name="IDR_PRERENDER_INTERNALS_MOJO_JS" file="${root_gen_dir}/mojom-webui/content/browser/preloading/prerender/prerender_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_PRERENDER_INTERNALS_JS" file="browser/resources/prerender/prerender_internals.js" type="BINDATA" />
       <include name="IDR_PROCESS_INTERNALS_HTML" file="browser/resources/process/process_internals.html" type="BINDATA" />
       <include name="IDR_PROCESS_INTERNALS_MOJO_JS" file="${root_gen_dir}/content/browser/resources/process/tsc/process_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_PROCESS_INTERNALS_CSS" file="browser/resources/process/process_internals.css" type="BINDATA" />
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index acf7d14..ce5a163 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -386,6 +386,14 @@
 // used in FedCM API.
 const char kFedCmIdpSigninStatusFieldTrialParamName[] = "IdpSigninStatus";
 
+// Alternative to `kFedCmIdpSigninStatusFieldTrialParamName` which runs
+// IdpSigninStatus API in a metrics-only mode. This field trial is default-on
+// and is intended as a kill switch.
+// `kFedCmIdpSigninStatusFieldTrialParamName` takes precedence over
+// `kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName`.
+const char kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName[] =
+    "IdpSigninStatusMetricsOnly";
+
 // Enables usage of First Party Sets to determine cookie availability.
 BASE_FEATURE(kFirstPartySets,
              "FirstPartySets",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index f74b9b7..aa3ce940 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -80,6 +80,8 @@
 CONTENT_EXPORT extern const char kFedCmIdpSignoutFieldTrialParamName[];
 CONTENT_EXPORT extern const char kFedCmIframeSupportFieldTrialParamName[];
 CONTENT_EXPORT extern const char kFedCmIdpSigninStatusFieldTrialParamName[];
+CONTENT_EXPORT extern const char
+    kFedCmIdpSigninStatusMetricsOnlyFieldTrialParamName[];
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmMetricsEndpoint);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmMultipleIdentityProviders);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFirstPartySets);
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc
index b856cfc..cf074a4 100644
--- a/content/public/common/url_constants.cc
+++ b/content/public/common/url_constants.cc
@@ -36,7 +36,6 @@
 const char kChromeUIMemoryExhaustHost[] = "memory-exhaust";
 const char kChromeUINetworkErrorHost[] = "network-error";
 const char kChromeUINetworkErrorsListingHost[] = "network-errors";
-const char kChromeUIPrerenderInternalsHost[] = "prerender-internals";
 const char kChromeUIPrivateAggregationInternalsHost[] =
     "private-aggregation-internals";
 const char kChromeUIProcessInternalsHost[] = "process-internals";
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h
index 9dd3437..73e4b9b 100644
--- a/content/public/common/url_constants.h
+++ b/content/public/common/url_constants.h
@@ -46,7 +46,6 @@
 CONTENT_EXPORT extern const char kChromeUIMemoryExhaustHost[];
 CONTENT_EXPORT extern const char kChromeUINetworkErrorHost[];
 CONTENT_EXPORT extern const char kChromeUINetworkErrorsListingHost[];
-CONTENT_EXPORT extern const char kChromeUIPrerenderInternalsHost[];
 CONTENT_EXPORT extern const char kChromeUIPrivateAggregationInternalsHost[];
 CONTENT_EXPORT extern const char kChromeUIProcessInternalsHost[];
 CONTENT_EXPORT extern const char kChromeUIQuotaInternalsHost[];
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 4204722d..36bfded 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3095,6 +3095,9 @@
         !!(common_params->transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT);
     bool started_with_transient_activation = common_params->has_user_gesture;
     bool is_browser_initiated = commit_params->is_browser_initiated;
+    absl::optional<blink::scheduler::TaskAttributionId>
+        soft_navigation_heuristic_task_id =
+            commit_params->soft_navigation_heuristic_task_id;
 
     WebSecurityOrigin initiator_origin;
     if (common_params->initiator_origin)
@@ -3115,7 +3118,7 @@
     commit_status = frame_->CommitSameDocumentNavigation(
         url, load_type, item_for_history_navigation, is_client_redirect,
         started_with_transient_activation, initiator_origin,
-        is_browser_initiated);
+        is_browser_initiated, soft_navigation_heuristic_task_id);
 
     // The load of the URL can result in this frame being removed. Use a
     // WeakPtr as an easy way to detect whether this has occured. If so, this
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index c4a758a3..9faab6d 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -249,6 +249,8 @@
     "//components/network_hints/browser:browser",
     "//components/network_hints/renderer",
     "//components/network_session_configurator/common",
+    "//components/origin_trials:browser",
+    "//components/origin_trials:common",
     "//components/performance_manager",
     "//components/permissions",
     "//components/prefs",
diff --git a/content/shell/browser/DEPS b/content/shell/browser/DEPS
index 574883c..0b40568 100644
--- a/content/shell/browser/DEPS
+++ b/content/shell/browser/DEPS
@@ -6,6 +6,7 @@
   "+components/network_hints/browser",
   "+components/network_session_configurator/common",
   "+components/prefs",
+  "+components/origin_trials",
   "+components/variations",
   "+services/device/public/cpp",
   "+services/network/public",
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc
index 492880ea..0c978058 100644
--- a/content/shell/browser/shell_browser_context.cc
+++ b/content/shell/browser/shell_browser_context.cc
@@ -20,8 +20,12 @@
 #include "components/keyed_service/core/simple_factory_key.h"
 #include "components/keyed_service/core/simple_key_map.h"
 #include "components/network_session_configurator/common/network_switches.h"
+#include "components/origin_trials/browser/leveldb_persistence_provider.h"
+#include "components/origin_trials/browser/origin_trials.h"
+#include "components/origin_trials/common/features.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/origin_trials_controller_delegate.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
 #include "content/shell/browser/shell_content_browser_client.h"
@@ -33,6 +37,7 @@
 #include "content/shell/common/shell_switches.h"
 #include "content/test/mock_background_sync_controller.h"
 #include "content/test/mock_reduce_accept_language_controller_delegate.h"
+#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 
 namespace content {
 
@@ -230,4 +235,20 @@
   return reduce_accept_lang_controller_delegate_.get();
 }
 
+OriginTrialsControllerDelegate*
+ShellBrowserContext::GetOriginTrialsControllerDelegate() {
+  if (!origin_trials::features::IsPersistentOriginTrialsEnabled())
+    return nullptr;
+
+  if (!origin_trials_controller_delegate_) {
+    origin_trials_controller_delegate_ =
+        std::make_unique<origin_trials::OriginTrials>(
+            std::make_unique<origin_trials::LevelDbPersistenceProvider>(
+                GetPath(),
+                GetDefaultStoragePartition()->GetProtoDatabaseProvider()),
+            std::make_unique<blink::TrialTokenValidator>());
+  }
+  return origin_trials_controller_delegate_.get();
+}
+
 }  // namespace content
diff --git a/content/shell/browser/shell_browser_context.h b/content/shell/browser/shell_browser_context.h
index 5ba025b..37900dde 100644
--- a/content/shell/browser/shell_browser_context.h
+++ b/content/shell/browser/shell_browser_context.h
@@ -21,6 +21,7 @@
 class ContentIndexProvider;
 class ClientHintsControllerDelegate;
 class DownloadManagerDelegate;
+class OriginTrialsControllerDelegate;
 class PermissionControllerDelegate;
 class ReduceAcceptLanguageControllerDelegate;
 class ShellDownloadManagerDelegate;
@@ -71,6 +72,7 @@
   GetFederatedIdentityActiveSessionPermissionContext() override;
   ReduceAcceptLanguageControllerDelegate*
   GetReduceAcceptLanguageControllerDelegate() override;
+  OriginTrialsControllerDelegate* GetOriginTrialsControllerDelegate() override;
 
  protected:
   // Contains URLRequestContextGetter required for resource loading.
@@ -95,6 +97,8 @@
       federated_permission_context_;
   std::unique_ptr<ReduceAcceptLanguageControllerDelegate>
       reduce_accept_lang_controller_delegate_;
+  std::unique_ptr<OriginTrialsControllerDelegate>
+      origin_trials_controller_delegate_;
 
  private:
   // Performs initialization of the ShellBrowserContext while IO is still
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc
index 72fd847..6ed6a9e4 100644
--- a/content/shell/browser/shell_browser_main_parts.cc
+++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -142,6 +142,11 @@
 void ShellBrowserMainParts::InitializeBrowserContexts() {
   set_browser_context(new ShellBrowserContext(false));
   set_off_the_record_browser_context(new ShellBrowserContext(true));
+  // Persistent Origin Trials needs to be instantiated as soon as possible
+  // during browser startup, to ensure data is available prior to the first
+  // request.
+  browser_context_->GetOriginTrialsControllerDelegate();
+  off_the_record_browser_context_->GetOriginTrialsControllerDelegate();
 }
 
 void ShellBrowserMainParts::InitializeMessageLoopContext() {
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index 8e47cc2..7b895bc 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -1300,7 +1300,9 @@
 bool NavigationSimulatorImpl::SimulateRendererInitiatedStart() {
   if (session_history_offset_) {
     static_cast<NavigationControllerImpl&>(web_contents_->GetController())
-        .GoToOffsetFromRenderer(session_history_offset_, render_frame_host_);
+        .GoToOffsetFromRenderer(
+            session_history_offset_, render_frame_host_,
+            /*soft_navigation_heuristic_task_id=*/absl::nullopt);
     request_ = render_frame_host_->frame_tree_node()->navigation_request();
     return true;
   }
diff --git a/content/web_test/BUILD.gn b/content/web_test/BUILD.gn
index 19ecb36..50d99a9c 100644
--- a/content/web_test/BUILD.gn
+++ b/content/web_test/BUILD.gn
@@ -128,6 +128,8 @@
     "browser/web_test_first_device_bluetooth_chooser.h",
     "browser/web_test_javascript_dialog_manager.cc",
     "browser/web_test_javascript_dialog_manager.h",
+    "browser/web_test_origin_trial_throttle.cc",
+    "browser/web_test_origin_trial_throttle.h",
     "browser/web_test_permission_manager.cc",
     "browser/web_test_permission_manager.h",
     "browser/web_test_push_messaging_service.cc",
@@ -169,6 +171,7 @@
     "//components/download/public/background_service:public",
     "//components/download/public/common:public",
     "//components/network_session_configurator/common",
+    "//components/origin_trials:common",
     "//components/proxy_config",
     "//content/browser:for_content_tests",  # For non-component builds.
     "//content/public/browser",  # For component builds.
diff --git a/content/web_test/browser/DEPS b/content/web_test/browser/DEPS
index 69b09c5..4f72d7d2 100644
--- a/content/web_test/browser/DEPS
+++ b/content/web_test/browser/DEPS
@@ -3,6 +3,7 @@
   "+components/download",
   "+components/keyed_service/core",
   "+components/network_session_configurator/common",
+  "+components/origin_trials",
   "+components/viz/common",
   "+content/public/browser",
   "+content/public/common",
diff --git a/content/web_test/browser/web_test_content_browser_client.cc b/content/web_test/browser/web_test_content_browser_client.cc
index 7881b77..3a05abb2 100644
--- a/content/web_test/browser/web_test_content_browser_client.cc
+++ b/content/web_test/browser/web_test_content_browser_client.cc
@@ -20,6 +20,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
+#include "components/origin_trials/common/features.h"
 #include "content/public/browser/browser_child_process_observer.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -27,10 +28,12 @@
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/client_hints_controller_delegate.h"
 #include "content/public/browser/login_delegate.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/overlay_window.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "content/shell/browser/shell_content_browser_client.h"
@@ -49,6 +52,7 @@
 #include "content/web_test/browser/web_test_browser_main_parts.h"
 #include "content/web_test/browser/web_test_control_host.h"
 #include "content/web_test/browser/web_test_cookie_manager.h"
+#include "content/web_test/browser/web_test_origin_trial_throttle.h"
 #include "content/web_test/browser/web_test_permission_manager.h"
 #include "content/web_test/browser/web_test_storage_access_manager.h"
 #include "content/web_test/browser/web_test_tts_platform.h"
@@ -377,6 +381,21 @@
     WebTestControlHost::Get()->OverrideWebkitPrefs(prefs);
 }
 
+std::vector<std::unique_ptr<content::NavigationThrottle>>
+WebTestContentBrowserClient::CreateThrottlesForNavigation(
+    content::NavigationHandle* navigation_handle) {
+  std::vector<std::unique_ptr<content::NavigationThrottle>> throttles =
+      ShellContentBrowserClient::CreateThrottlesForNavigation(
+          navigation_handle);
+  if (origin_trials::features::IsPersistentOriginTrialsEnabled()) {
+    throttles.push_back(std::make_unique<WebTestOriginTrialThrottle>(
+        navigation_handle, navigation_handle->GetWebContents()
+                               ->GetBrowserContext()
+                               ->GetOriginTrialsControllerDelegate()));
+  }
+  return throttles;
+}
+
 void WebTestContentBrowserClient::AppendExtraCommandLineSwitches(
     base::CommandLine* command_line,
     int child_process_id) {
diff --git a/content/web_test/browser/web_test_content_browser_client.h b/content/web_test/browser/web_test_content_browser_client.h
index 0b77223b..55f3b2c 100644
--- a/content/web_test/browser/web_test_content_browser_client.h
+++ b/content/web_test/browser/web_test_content_browser_client.h
@@ -64,6 +64,9 @@
       RenderProcessHost* render_process_host) override;
   void OverrideWebkitPrefs(WebContents* web_contents,
                            blink::web_pref::WebPreferences* prefs) override;
+  std::vector<std::unique_ptr<content::NavigationThrottle>>
+  CreateThrottlesForNavigation(
+      content::NavigationHandle* navigation_handle) override;
   void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
                                       int child_process_id) override;
   std::unique_ptr<BrowserMainParts> CreateBrowserMainParts(
diff --git a/content/web_test/browser/web_test_origin_trial_throttle.cc b/content/web_test/browser/web_test_origin_trial_throttle.cc
new file mode 100644
index 0000000..2665d26
--- /dev/null
+++ b/content/web_test/browser/web_test_origin_trial_throttle.cc
@@ -0,0 +1,65 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/web_test/browser/web_test_origin_trial_throttle.h"
+
+#include <string>
+
+#include "base/containers/flat_set.h"
+#include "base/containers/span.h"
+#include "base/strings/string_util.h"
+#include "base/time/time.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/origin_trials_controller_delegate.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+
+namespace {
+
+const char kThrottleName[] = "WebTestOriginTrialThrottle";
+const char kWebTestOriginTrialHeaderName[] = "X-Web-Test-Enabled-Origin-Trials";
+
+}  // namespace
+
+WebTestOriginTrialThrottle::WebTestOriginTrialThrottle(
+    NavigationHandle* navigation_handle,
+    OriginTrialsControllerDelegate* delegate)
+    : NavigationThrottle(navigation_handle),
+      origin_trials_controller_delegate_(delegate) {}
+
+NavigationThrottle::ThrottleCheckResult
+WebTestOriginTrialThrottle::WillStartRequest() {
+  SetHeaderForRequest();
+  return NavigationThrottle::ThrottleAction::PROCEED;
+}
+
+NavigationThrottle::ThrottleCheckResult
+WebTestOriginTrialThrottle::WillRedirectRequest() {
+  SetHeaderForRequest();
+  return NavigationThrottle::ThrottleAction::PROCEED;
+}
+
+void WebTestOriginTrialThrottle::SetHeaderForRequest() {
+  GURL request_url = navigation_handle()->GetURL();
+  url::Origin origin = url::Origin::CreateFromNormalizedTuple(
+      request_url.scheme(), request_url.host(), request_url.EffectiveIntPort());
+
+  base::flat_set<std::string> trials;
+  if (!origin.opaque()) {
+    trials = origin_trials_controller_delegate_->GetPersistedTrialsForOrigin(
+        origin, base::Time::Now());
+  }
+  std::string header_value = base::JoinString(
+      base::span<std::string>(trials.begin(), trials.end()), ", ");
+  navigation_handle()->SetRequestHeader(kWebTestOriginTrialHeaderName,
+                                        header_value);
+}
+
+const char* WebTestOriginTrialThrottle::GetNameForLogging() {
+  return kThrottleName;
+}
+
+}  // namespace content
diff --git a/content/web_test/browser/web_test_origin_trial_throttle.h b/content/web_test/browser/web_test_origin_trial_throttle.h
new file mode 100644
index 0000000..936aa8d
--- /dev/null
+++ b/content/web_test/browser/web_test_origin_trial_throttle.h
@@ -0,0 +1,40 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_WEB_TEST_BROWSER_WEB_TEST_ORIGIN_TRIAL_THROTTLE_H_
+#define CONTENT_WEB_TEST_BROWSER_WEB_TEST_ORIGIN_TRIAL_THROTTLE_H_
+
+#include "base/memory/raw_ptr.h"
+#include "content/public/browser/navigation_throttle.h"
+
+namespace content {
+class OriginTrialsControllerDelegate;
+
+// NavigationThrottle that sets a header for testing with the names of all
+// enabled persistent origin trials.
+// This exists to support the tests in
+// third_party/blink/web_tests/http/tests/persistent-origin-trial
+// by providing an observable effect of setting a persistent origin trial.
+class WebTestOriginTrialThrottle : public NavigationThrottle {
+ public:
+  WebTestOriginTrialThrottle(NavigationHandle* navigation_handle,
+                             OriginTrialsControllerDelegate* delegate);
+  ~WebTestOriginTrialThrottle() override = default;
+
+  // NavigationThrottle implementation
+  ThrottleCheckResult WillStartRequest() override;
+  ThrottleCheckResult WillRedirectRequest() override;
+  const char* GetNameForLogging() override;
+
+ private:
+  // Helper function that set the X-Web-Test-Enabled-Origin-Trials header
+  void SetHeaderForRequest();
+
+  base::raw_ptr<OriginTrialsControllerDelegate>
+      origin_trials_controller_delegate_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_WEB_TEST_BROWSER_WEB_TEST_ORIGIN_TRIAL_THROTTLE_H_
diff --git a/extensions/browser/api/system_network/system_network_api_unittest.cc b/extensions/browser/api/system_network/system_network_api_unittest.cc
index a2c6058..8032187 100644
--- a/extensions/browser/api/system_network/system_network_api_unittest.cc
+++ b/extensions/browser/api/system_network/system_network_api_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "extensions/browser/api/system_network/system_network_api.h"
-#include "build/build_config.h"
+
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/api_unittest.h"
 #include "extensions/common/extension_builder.h"
@@ -20,13 +20,7 @@
 
 }  // namespace
 
-// TODO(crbug.com/1255187): Fails on Fuchsia running with run-test-component.
-#if BUILDFLAG(IS_FUCHSIA)
-#define MAYBE_GetNetworkInterfaces DISABLED_GetNetworkInterfaces
-#else
-#define MAYBE_GetNetworkInterfaces GetNetworkInterfaces
-#endif  // BUILDFLAG(IS_FUCHSIA)
-TEST_F(SystemNetworkApiUnitTest, MAYBE_GetNetworkInterfaces) {
+TEST_F(SystemNetworkApiUnitTest, GetNetworkInterfaces) {
   scoped_refptr<SystemNetworkGetNetworkInterfacesFunction> socket_function(
       new SystemNetworkGetNetworkInterfacesFunction());
   scoped_refptr<const Extension> empty_extension(
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index e82d4f8..40e2b0d00 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -47,6 +47,8 @@
     "//components/keyed_service/content:content",
     "//components/nacl/common:buildflags",
     "//components/network_session_configurator/common",
+    "//components/origin_trials:browser",
+    "//components/origin_trials:common",
     "//components/pref_registry",
     "//components/prefs",
     "//components/services/app_service/public/mojom",
diff --git a/extensions/shell/browser/DEPS b/extensions/shell/browser/DEPS
index 780e2c2f..63d428b 100644
--- a/extensions/shell/browser/DEPS
+++ b/extensions/shell/browser/DEPS
@@ -6,6 +6,7 @@
   "+components/nacl/browser",
   "+components/nacl/common",
   "+components/network_session_configurator/common",
+  "+components/origin_trials",
   "+components/pref_registry",
   "+components/sessions",
   "+components/update_client",
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index f301d10..7b458fce 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -382,6 +382,7 @@
     "//base",
     "//base/test:test_support",
     "//base/third_party/dynamic_annotations",
+    "//cc:test_support",
     "//cc/paint",
     "//components/viz/test:test_support",
     "//gpu/command_buffer/client:gles2_c_lib",
@@ -661,6 +662,7 @@
     "//base/test:test_support",
     "//base/third_party/dynamic_annotations",
     "//build:chromeos_buildflags",
+    "//cc:test_support",
     "//cc/paint",
     "//components/viz/common:resource_format",
     "//gpu/command_buffer/client:gles2_c_lib",
diff --git a/gpu/command_buffer/service/shared_image/DEPS b/gpu/command_buffer/service/shared_image/DEPS
index 86698d7..e9ee9ee 100644
--- a/gpu/command_buffer/service/shared_image/DEPS
+++ b/gpu/command_buffer/service/shared_image/DEPS
@@ -2,4 +2,7 @@
   "external_vk_image_backing_factory_unittest\.cc": [
     "+components/viz/common/gpu/vulkan_in_process_context_provider.h",
   ],
+  ".*_unittest\.cc": [
+    "+cc/test",
+  ],
 }
diff --git a/gpu/command_buffer/service/shared_image/gl_image_backing.cc b/gpu/command_buffer/service/shared_image/gl_image_backing.cc
index 5e688a9d..e0002e59 100644
--- a/gpu/command_buffer/service/shared_image/gl_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/gl_image_backing.cc
@@ -93,8 +93,6 @@
       alpha_type, usage, params));
 
   shared_image->passthrough_texture_ = std::move(wrapped_gl_texture);
-  shared_image->gl_texture_retained_for_legacy_mailbox_ = true;
-  shared_image->gl_texture_retain_count_ = 1;
   shared_image->image_bind_or_copy_needed_ = false;
 
   return shared_image;
@@ -127,35 +125,10 @@
 }
 
 GLImageBacking::~GLImageBacking() {
-  if (gl_texture_retained_for_legacy_mailbox_)
-    ReleaseGLTexture(have_context());
-  DCHECK_EQ(gl_texture_retain_count_, 0u);
-}
-
-void GLImageBacking::RetainGLTexture() {
-  gl_texture_retain_count_ += 1;
-  if (gl_texture_retain_count_ > 1)
-    return;
-
-  // Allocate the GL texture.
-  GLTextureImageBackingHelper::MakeTextureAndSetParameters(
-      gl_params_.target, 0 /* service_id */,
-      gl_params_.framebuffer_attachment_angle, &passthrough_texture_, nullptr);
-
-  // Set the GLImage to be initially unbound from the GL texture.
-  image_bind_or_copy_needed_ = true;
-  passthrough_texture_->SetEstimatedSize(
-      viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size(), format()));
-  passthrough_texture_->SetLevelImage(gl_params_.target, 0, image_.get());
-  passthrough_texture_->set_is_bind_pending(true);
+  ReleaseGLTexture(have_context());
 }
 
 void GLImageBacking::ReleaseGLTexture(bool have_context) {
-  DCHECK_GT(gl_texture_retain_count_, 0u);
-  gl_texture_retain_count_ -= 1;
-  if (gl_texture_retain_count_ > 0)
-    return;
-
   // If the cached promise texture is referencing the GL texture, then it needs
   // to be deleted, too.
   if (cached_promise_texture_) {
@@ -241,9 +214,6 @@
 std::unique_ptr<GLTexturePassthroughImageRepresentation>
 GLImageBacking::ProduceGLTexturePassthrough(SharedImageManager* manager,
                                             MemoryTypeTracker* tracker) {
-  // The corresponding release will be done when the returned representation is
-  // destroyed, in GLTextureImageRepresentationRelease.
-  RetainGLTexture();
   DCHECK(passthrough_texture_);
   return std::make_unique<GLTexturePassthroughGLCommonRepresentation>(
       manager, this, this, tracker, passthrough_texture_);
@@ -276,9 +246,6 @@
     scoped_refptr<SharedContextState> context_state) {
   GLTextureImageRepresentationClient* gl_client = nullptr;
   if (context_state->GrContextIsGL()) {
-    // The corresponding release will be done when the returned representation
-    // is destroyed, in GLTextureImageRepresentationRelease.
-    RetainGLTexture();
     gl_client = this;
   }
 
@@ -370,7 +337,8 @@
 }
 
 void GLImageBacking::GLTextureImageRepresentationRelease(bool has_context) {
-  ReleaseGLTexture(has_context);
+  // No action needed: This class retains the passed-in texture for its
+  // lifetime, and releases it in its destructor.
 }
 
 bool GLImageBacking::BindOrCopyImageIfNeeded() {
diff --git a/gpu/command_buffer/service/shared_image/gl_image_backing.h b/gpu/command_buffer/service/shared_image/gl_image_backing.h
index 80be5be..0c25b60 100644
--- a/gpu/command_buffer/service/shared_image/gl_image_backing.h
+++ b/gpu/command_buffer/service/shared_image/gl_image_backing.h
@@ -134,10 +134,7 @@
   bool BindOrCopyImageIfNeeded();
   bool image_bind_or_copy_needed_ = true;
 
-  void RetainGLTexture();
   void ReleaseGLTexture(bool have_context);
-  size_t gl_texture_retain_count_ = 0;
-  bool gl_texture_retained_for_legacy_mailbox_ = false;
 
   const GLTextureImageBackingHelper::InitializeGLTextureParams gl_params_;
 
diff --git a/gpu/command_buffer/service/shared_image/gl_repack_utils.cc b/gpu/command_buffer/service/shared_image/gl_repack_utils.cc
index 4f5cdd1..e00d30c3 100644
--- a/gpu/command_buffer/service/shared_image/gl_repack_utils.cc
+++ b/gpu/command_buffer/service/shared_image/gl_repack_utils.cc
@@ -62,4 +62,33 @@
   return dst_data;
 }
 
+void UnpackPixelDataWithStride(const gfx::Size& size,
+                               const std::vector<uint8_t>& src_data,
+                               size_t src_stride,
+                               SkPixmap& dst_pixmap) {
+  uint8_t* dst_data = static_cast<uint8_t*>(dst_pixmap.writable_addr());
+  size_t dst_stride = dst_pixmap.rowBytes();
+
+  DCHECK_GT(dst_stride, src_stride);
+
+  for (int y = 0; y < size.height(); ++y) {
+    memcpy(&dst_data[y * dst_stride], &src_data[y * src_stride], src_stride);
+  }
+}
+
+void SwizzleRedAndBlue(SkPixmap& pixmap) {
+  DCHECK_EQ(pixmap.info().bytesPerPixel(), 4);
+
+  uint8_t* data = static_cast<uint8_t*>(pixmap.writable_addr());
+  size_t stride = pixmap.rowBytes();
+
+  for (int y = 0; y < pixmap.height(); ++y) {
+    size_t row_offset = y * stride;
+    for (int x = 0; x < pixmap.width(); ++x) {
+      size_t pixel_offset = row_offset + x * 4;
+      std::swap(data[pixel_offset], data[pixel_offset + 2]);
+    }
+  }
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/gl_repack_utils.h b/gpu/command_buffer/service/shared_image/gl_repack_utils.h
index 3ab7c06..b944ab3 100644
--- a/gpu/command_buffer/service/shared_image/gl_repack_utils.h
+++ b/gpu/command_buffer/service/shared_image/gl_repack_utils.h
@@ -29,6 +29,18 @@
     const SkPixmap& src_pixmap,
     size_t dst_stride);
 
+// Unpacks `src_data` into `dst_pixmap`. The stride of `dst_pixmap` must be
+// larger than `src_stride`.
+GPU_GLES2_EXPORT void UnpackPixelDataWithStride(
+    const gfx::Size& size,
+    const std::vector<uint8_t>& src_data,
+    size_t src_stride,
+    SkPixmap& dst_pixmap);
+
+// Swizzles RGBA <-> BGRA / RGBX <-> BGRX or more exactly between byte 0 and 2
+// of each pixel. `pixmap` must be 4 bytes per pixel.
+GPU_GLES2_EXPORT void SwizzleRedAndBlue(SkPixmap& pixmap);
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_GL_REPACK_UTILS_H_
diff --git a/gpu/command_buffer/service/shared_image/gl_repack_utils_unittest.cc b/gpu/command_buffer/service/shared_image/gl_repack_utils_unittest.cc
index 38c39454..f98a2b2 100644
--- a/gpu/command_buffer/service/shared_image/gl_repack_utils_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/gl_repack_utils_unittest.cc
@@ -5,6 +5,8 @@
 #include "gpu/command_buffer/service/shared_image/gl_repack_utils.h"
 
 #include "base/strings/stringprintf.h"
+#include "cc/test/pixel_comparator.h"
+#include "cc/test/pixel_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -168,5 +170,50 @@
   ValidateRgbaPixelsRed(size, expected_stride, repacked_data);
 }
 
+TEST(RepackUtilsTest, UnpackStride) {
+  constexpr gfx::Size size(10, 10);
+  // RGBA stride should be 10*4 = 40 but make src bitmap stride larger.
+  constexpr size_t expected_stride = 40;
+  constexpr size_t src_stride = 48;
+
+  SkBitmap source_bitmap = MakeSolidColorBitmapWithStride(
+      size, kRGBA_8888_SkColorType, SK_ColorRED, src_stride);
+
+  auto repacked_data =
+      RepackPixelDataWithStride(size, source_bitmap.pixmap(), expected_stride);
+
+  // Result starts with green pixels.
+  SkBitmap result_bitmap = MakeSolidColorBitmapWithStride(
+      size, kRGBA_8888_SkColorType, SK_ColorGREEN, src_stride);
+
+  SkPixmap pixmap;
+  ASSERT_TRUE(result_bitmap.peekPixels(&pixmap));
+
+  // Result bitmap should have red pixels after.
+  UnpackPixelDataWithStride(size, repacked_data, expected_stride, pixmap);
+
+  EXPECT_TRUE(
+      cc::MatchesBitmap(result_bitmap, source_bitmap,
+                        cc::ExactPixelComparator(/*discard_alpha=*/false)));
+}
+
+TEST(RepackUtilsTest, SwizzleRedAndBlue) {
+  constexpr gfx::Size size(10, 10);
+  SkBitmap swizzled_bitmap =
+      MakeSolidColorBitmap(size, kRGBA_8888_SkColorType, SK_ColorRED);
+
+  SkPixmap pixmap;
+  ASSERT_TRUE(swizzled_bitmap.peekPixels(&pixmap));
+
+  SwizzleRedAndBlue(pixmap);
+
+  SkBitmap expected_bitmap =
+      MakeSolidColorBitmap(size, kRGBA_8888_SkColorType, SK_ColorBLUE);
+
+  EXPECT_TRUE(
+      cc::MatchesBitmap(swizzled_bitmap, expected_bitmap,
+                        cc::ExactPixelComparator(/*discard_alpha=*/false)));
+}
+
 }  // namespace
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc b/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc
index d1b518e40..9a73262 100644
--- a/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc
@@ -74,8 +74,9 @@
   return bits / 8;
 }
 
-bool HasFourByteAlignment(size_t stride) {
-  return (stride & 3) == 0;
+bool HasExpectedAlignment(size_t stride, viz::ResourceFormat format) {
+  const size_t alignment = format == viz::RGBA_F16 ? 7 : 3;
+  return (stride & alignment) == 0;
 }
 
 // This value can't be cached as it may change for different contexts.
@@ -84,15 +85,47 @@
          gl::g_current_gl_driver->ext.b_GL_EXT_unpack_subimage;
 }
 
+// This value can't be cached as it may change for different contexts.
+bool SupportsPackSubimage() {
+#if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_X86_FAMILY)
+  // GL_PACK_ROW_LENGTH is broken in the Android emulator. glReadPixels()
+  // modifies bytes between the last pixel in a row and the end of the stride
+  // for that row.
+  return false;
+#else
+  return gl::g_current_gl_version->is_es3_capable;
+#endif
+}
+
 }  // anonymous namespace
 
 ///////////////////////////////////////////////////////////////////////////////
 // GLTextureImageBacking
 
+bool GLTextureImageBacking::SupportsPixelReadbackWithFormat(
+    viz::SharedImageFormat format) {
+  if (!format.is_single_plane())
+    return false;
+
+  switch (format.resource_format()) {
+    case viz::ResourceFormat::RGBA_8888:
+    case viz::ResourceFormat::BGRA_8888:
+    case viz::ResourceFormat::RED_8:
+    case viz::ResourceFormat::RG_88:
+    case viz::ResourceFormat::RGBX_8888:
+    case viz::ResourceFormat::BGRX_8888:
+      return true;
+    default:
+      return false;
+  }
+}
+
 bool GLTextureImageBacking::SupportsPixelUploadWithFormat(
     viz::SharedImageFormat format) {
-  auto resource_format = format.resource_format();
-  switch (resource_format) {
+  if (!format.is_single_plane())
+    return false;
+
+  switch (format.resource_format()) {
     case viz::ResourceFormat::RGBA_8888:
     case viz::ResourceFormat::RGBA_4444:
     case viz::ResourceFormat::BGRA_8888:
@@ -210,22 +243,23 @@
   DCHECK(SupportsPixelUploadWithFormat(format()));
   DCHECK(gl::GLContext::GetCurrent());
 
+  auto resource_format = format().resource_format();
+
   const GLuint texture_id = GetGLServiceId();
   const GLenum gl_format = texture_params_.format;
   const GLenum gl_type = texture_params_.type;
   const GLenum gl_target = texture_params_.target;
 
   size_t pixmap_stride = pixmap.rowBytes();
-  DCHECK(HasFourByteAlignment(pixmap_stride));
+  DCHECK(HasExpectedAlignment(pixmap_stride, resource_format));
 
   size_t expected_stride = gfx::RowSizeForBufferFormat(
       size().width(), viz::BufferFormat(format()), /*plane=*/0);
-  DCHECK(HasFourByteAlignment(expected_stride));
+  DCHECK(HasExpectedAlignment(expected_stride, resource_format));
   DCHECK_GE(pixmap_stride, expected_stride);
 
   GLuint gl_unpack_row_length = 0;
   std::vector<uint8_t> repacked_data;
-  auto resource_format = format().resource_format();
   if (resource_format == viz::BGRX_8888 || resource_format == viz::RGBX_8888) {
     DCHECK_EQ(gl_format, static_cast<GLenum>(GL_RGB));
 
@@ -260,6 +294,115 @@
   return true;
 }
 
+bool GLTextureImageBacking::ReadbackToMemory(SkPixmap& pixmap) {
+  DCHECK(gl::GLContext::GetCurrent());
+
+  // TODO(kylechar): Ideally there would be a usage that stated readback was
+  // required so support could be verified at creation time and then asserted
+  // here instead.
+  if (!SupportsPixelReadbackWithFormat(format()))
+    return false;
+
+  viz::ResourceFormat resource_format = format().resource_format();
+
+  const GLuint texture_id = GetGLServiceId();
+  GLenum gl_format = texture_params_.format;
+  GLenum gl_type = texture_params_.type;
+
+  if (resource_format == viz::BGRX_8888 || resource_format == viz::RGBX_8888) {
+    DCHECK_EQ(gl_format, static_cast<GLenum>(GL_RGB));
+    DCHECK_EQ(gl_type, static_cast<GLenum>(GL_UNSIGNED_BYTE));
+
+    // Always readback RGBX/BGRX as RGBA/BGRA instead of RGB to avoid needing a
+    // temporary buffer.
+    gl_format = resource_format == viz::BGRX_8888 ? GL_BGRA_EXT : GL_RGBA;
+  }
+
+  gl::GLApi* api = gl::g_current_gl_context;
+  GLuint framebuffer;
+  api->glGenFramebuffersEXTFn(1, &framebuffer);
+  gl::ScopedFramebufferBinder scoped_framebuffer_binder(framebuffer);
+  // This uses GL_FRAMEBUFFER instead of GL_READ_FRAMEBUFFER as the target for
+  // GLES2 compatibility.
+  api->glFramebufferTexture2DEXTFn(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                   GL_TEXTURE_2D, texture_id, /*level=*/0);
+  DCHECK_EQ(api->glCheckFramebufferStatusEXTFn(GL_FRAMEBUFFER),
+            static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE));
+
+  bool needs_rb_swizzle = false;
+
+  // GL_RGBA + GL_UNSIGNED_BYTE are always supported. Otherwise there is a
+  // preferred format + type that can be queried and is based on what is bound
+  // to GL_READ_FRAMEBUFFER.
+  if (gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE) {
+    GLint preferred_format = 0;
+    api->glGetIntegervFn(GL_IMPLEMENTATION_COLOR_READ_FORMAT,
+                         &preferred_format);
+    GLint preferred_type = 0;
+    api->glGetIntegervFn(GL_IMPLEMENTATION_COLOR_READ_TYPE, &preferred_type);
+
+    if (gl_format != static_cast<GLenum>(preferred_format) ||
+        gl_type != static_cast<GLenum>(preferred_type)) {
+      if (resource_format == viz::BGRA_8888 ||
+          resource_format == viz::BGRX_8888) {
+        DCHECK_EQ(gl_format, static_cast<GLenum>(GL_BGRA_EXT));
+        DCHECK_EQ(gl_type, static_cast<GLenum>(GL_UNSIGNED_BYTE));
+
+        // If BGRA readback isn't support then use RGBA and swizzle.
+        gl_format = GL_RGBA;
+        needs_rb_swizzle = true;
+      } else {
+        DLOG(ERROR) << format().ToString()
+                    << " is not supported by glReadPixels()";
+        return false;
+      }
+    }
+  }
+
+  size_t pixmap_stride = pixmap.rowBytes();
+  DCHECK(HasExpectedAlignment(pixmap_stride, resource_format));
+
+  size_t expected_stride = gfx::RowSizeForBufferFormat(
+      size().width(), viz::BufferFormat(resource_format), /*plane=*/0);
+  DCHECK(HasExpectedAlignment(expected_stride, resource_format));
+  DCHECK_GE(pixmap_stride, expected_stride);
+
+  std::vector<uint8_t> unpack_buffer;
+  GLuint gl_pack_row_length = 0;
+  if (pixmap_stride > expected_stride) {
+    if (SupportsPackSubimage()) {
+      // Use GL_PACK_ROW_LENGTH to avoid temporary buffer.
+      gl_pack_row_length =
+          base::checked_cast<int>(pixmap_stride) / BytesPerPixel(format());
+    } else {
+      // If GL_PACK_ROW_LENGTH isn't supported then readback to a temporary
+      // buffer with expected stride.
+      unpack_buffer = std::vector<uint8_t>(expected_stride * size().height());
+    }
+  }
+
+  ScopedPackState scoped_pack_state(gl_pack_row_length);
+
+  void* pixels =
+      !unpack_buffer.empty() ? unpack_buffer.data() : pixmap.writable_addr();
+  api->glReadPixelsFn(0, 0, size().width(), size().height(), gl_format, gl_type,
+                      pixels);
+  DCHECK_EQ(api->glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR));
+
+  api->glDeleteFramebuffersEXTFn(1, &framebuffer);
+
+  if (!unpack_buffer.empty()) {
+    DCHECK_GT(pixmap_stride, expected_stride);
+    UnpackPixelDataWithStride(size(), unpack_buffer, expected_stride, pixmap);
+  }
+
+  if (needs_rb_swizzle) {
+    SwizzleRedAndBlue(pixmap);
+  }
+
+  return true;
+}
+
 std::unique_ptr<GLTextureImageRepresentation>
 GLTextureImageBacking::ProduceGLTexture(SharedImageManager* manager,
                                         MemoryTypeTracker* tracker) {
diff --git a/gpu/command_buffer/service/shared_image/gl_texture_image_backing.h b/gpu/command_buffer/service/shared_image/gl_texture_image_backing.h
index 60513c01..39936695 100644
--- a/gpu/command_buffer/service/shared_image/gl_texture_image_backing.h
+++ b/gpu/command_buffer/service/shared_image/gl_texture_image_backing.h
@@ -19,6 +19,7 @@
 class GLTextureImageBacking : public ClearTrackingSharedImageBacking {
  public:
   static bool SupportsPixelUploadWithFormat(viz::SharedImageFormat format);
+  static bool SupportsPixelReadbackWithFormat(viz::SharedImageFormat format);
 
   GLTextureImageBacking(const Mailbox& mailbox,
                         viz::SharedImageFormat format,
@@ -68,6 +69,7 @@
       scoped_refptr<SharedContextState> context_state) override;
   void Update(std::unique_ptr<gfx::GpuFence> in_fence) override;
   bool UploadFromMemory(const SkPixmap& pixmap) override;
+  bool ReadbackToMemory(SkPixmap& pixmap) override;
 
   bool IsPassthrough() const { return is_passthrough_; }
 
diff --git a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc
index 7abd588..547c481 100644
--- a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_factory_unittest.cc
@@ -9,6 +9,8 @@
 #include "base/bits.h"
 #include "base/command_line.h"
 #include "build/build_config.h"
+#include "cc/test/pixel_comparator.h"
+#include "cc/test/pixel_test_utils.h"
 #include "components/viz/common/resources/resource_format.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_sizes.h"
@@ -189,6 +191,9 @@
   viz::SharedImageFormat get_format() { return GetParam(); }
 };
 
+using GLTextureImageBackingFactoryWithReadbackTest =
+    GLTextureImageBackingFactoryWithUploadTest;
+
 TEST_F(GLTextureImageBackingFactoryTest, InvalidFormat) {
   auto format = viz::SharedImageFormat::SinglePlane(
       viz::ResourceFormat::YUV_420_BIPLANAR);
@@ -571,6 +576,91 @@
   EXPECT_TRUE(backing->UploadFromMemory(larger_bitmap.pixmap()));
 }
 
+TEST_P(GLTextureImageBackingFactoryWithReadbackTest, ReadbackToMemory) {
+  viz::SharedImageFormat format = get_format();
+
+  if (!IsFormatSupport(format)) {
+    GTEST_SKIP();
+  }
+
+  auto mailbox = Mailbox::GenerateForSharedImage();
+  gfx::Size size(9, 9);
+  auto color_space = gfx::ColorSpace::CreateSRGB();
+  GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
+  SkAlphaType alpha_type = kPremul_SkAlphaType;
+  uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_CPU_UPLOAD;
+  gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
+
+  bool supported =
+      backing_factory_->IsSupported(usage, format, size, /*thread_safe=*/false,
+                                    gfx::EMPTY_BUFFER, GrContextType::kGL, {});
+  ASSERT_TRUE(supported);
+
+  auto backing = backing_factory_->CreateSharedImage(
+      mailbox, format, surface_handle, size, color_space, surface_origin,
+      alpha_type, usage, false /* is_thread_safe */);
+  ASSERT_TRUE(backing);
+
+  SkColorType color_type =
+      viz::ResourceFormatToClosestSkColorType(true, format);
+
+  // Allocate a bitmap with red pixels and upload from it. RED_8 will be filled
+  // with 0xFF repeating and RG_88 will be filled with OxFF00 repeating.
+  SkBitmap bitmap;
+  SkImageInfo info =
+      SkImageInfo::Make(size.width(), size.height(), color_type, alpha_type);
+  size_t stride = base::bits::AlignUp<size_t>(info.minRowBytes(), 4);
+  bitmap.allocPixels(info, stride);
+  bitmap.eraseColor(SK_ColorRED);
+
+  EXPECT_TRUE(backing->UploadFromMemory(bitmap.pixmap()));
+
+  {
+    SkBitmap result_bitmap;
+    result_bitmap.allocPixels(info, stride);
+    SkPixmap result_pixmap;
+    ASSERT_TRUE(result_bitmap.peekPixels(&result_pixmap));
+
+    // Do readback and validate pixels match what was uploaded.
+    ASSERT_TRUE(backing->ReadbackToMemory(result_pixmap));
+    EXPECT_TRUE(cc::MatchesBitmap(result_bitmap, bitmap,
+                                  cc::ExactPixelComparator(false)));
+  }
+
+  {
+    SkBitmap result_bitmap;
+    result_bitmap.allocPixels(info, stride + 80);
+    SkPixmap result_pixmap;
+    ASSERT_TRUE(result_bitmap.peekPixels(&result_pixmap));
+
+    // Do readback into a bitmap with larger than required stride and validate
+    // pixels match what was uploaded.
+    ASSERT_TRUE(backing->ReadbackToMemory(result_pixmap));
+    EXPECT_TRUE(cc::MatchesBitmap(result_bitmap, bitmap,
+                                  cc::ExactPixelComparator(false)));
+  }
+}
+
+std::string TestParamToString(
+    const testing::TestParamInfo<viz::SharedImageFormat>& param_info) {
+  return param_info.param.ToString();
+}
+
+const auto kInitialDataFormats = ::testing::Values(
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::ETC1),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_8888),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRA_8888),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_4444),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RED_8),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RG_88),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRA_1010102),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_1010102));
+
+INSTANTIATE_TEST_SUITE_P(,
+                         GLTextureImageBackingFactoryInitialDataTest,
+                         kInitialDataFormats,
+                         TestParamToString);
+
 const auto kSharedImageFormats = ::testing::Values(
     viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_8888),
     viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRA_8888),
@@ -582,25 +672,6 @@
     viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBX_8888),
     viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRX_8888));
 
-std::string TestParamToString(
-    const testing::TestParamInfo<viz::SharedImageFormat>& param_info) {
-  return param_info.param.ToString();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    ,
-    GLTextureImageBackingFactoryInitialDataTest,
-    ::testing::Values(
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::ETC1),
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_8888),
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRA_8888),
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_4444),
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RED_8),
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RG_88),
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRA_1010102),
-        viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_1010102)),
-    TestParamToString);
-
 INSTANTIATE_TEST_SUITE_P(,
                          GLTextureImageBackingFactoryWithFormatTest,
                          kSharedImageFormats,
@@ -611,5 +682,18 @@
                          kSharedImageFormats,
                          TestParamToString);
 
+const auto kReadbackFormats = ::testing::Values(
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBA_8888),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRA_8888),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RED_8),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RG_88),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::RGBX_8888),
+    viz::SharedImageFormat::SinglePlane(viz::ResourceFormat::BGRX_8888));
+
+INSTANTIATE_TEST_SUITE_P(,
+                         GLTextureImageBackingFactoryWithReadbackTest,
+                         kReadbackFormats,
+                         TestParamToString);
+
 }  // anonymous namespace
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.cc b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.cc
index 19f059a..e8dcffe 100644
--- a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.cc
+++ b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.cc
@@ -16,6 +16,35 @@
 
 namespace gpu {
 
+ScopedPackState::ScopedPackState(int pack_row_length)
+    : api_(gl::g_current_gl_context) {
+  bool is_es3_capable = gl::g_current_gl_version->is_es3_capable;
+
+  if (is_es3_capable) {
+    // Need to unbind any GL_PIXEL_PACK_BUFFER for the nullptr in
+    // glTexImage2D to mean "no pixels" (as opposed to offset 0 in the
+    // buffer).
+    api_->glGetIntegervFn(GL_PIXEL_PACK_BUFFER_BINDING, &pack_buffer_);
+    if (pack_buffer_)
+      api_->glBindBufferFn(GL_PIXEL_PACK_BUFFER, 0);
+  }
+
+  pack_alignment_.emplace(GL_PACK_ALIGNMENT, 4);
+
+  if (is_es3_capable) {
+    pack_row_length_.emplace(GL_PACK_ROW_LENGTH, pack_row_length);
+    pack_skip_rows_.emplace(GL_PACK_SKIP_ROWS, 0);
+    pack_skip_pixels_.emplace(GL_PACK_SKIP_PIXELS, 0);
+  } else {
+    DCHECK_EQ(pack_row_length, 0);
+  }
+}
+
+ScopedPackState::~ScopedPackState() {
+  if (pack_buffer_)
+    api_->glBindBufferFn(GL_PIXEL_PACK_BUFFER, pack_buffer_);
+}
+
 ScopedUnpackState::ScopedUnpackState(bool uploading_data, int unpack_row_length)
     : api_(gl::g_current_gl_context) {
   const auto* version_info = gl::g_current_gl_version;
diff --git a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.h b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.h
index aa2e343..a581e0f 100644
--- a/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.h
+++ b/gpu/command_buffer/service/shared_image/gl_texture_image_backing_helper.h
@@ -13,7 +13,27 @@
 
 namespace gpu {
 
-// Object used to restore state around GL upload and copy.
+// Sets GL state for readback.
+class ScopedPackState {
+ public:
+  explicit ScopedPackState(int pack_row_length = 0);
+
+  ScopedPackState(const ScopedPackState&) = delete;
+  ScopedPackState& operator=(const ScopedPackState&) = delete;
+
+  ~ScopedPackState();
+
+ private:
+  const raw_ptr<gl::GLApi> api_;
+
+  GLint pack_buffer_ = 0;
+  absl::optional<gl::ScopedPixelStore> pack_alignment_;
+  absl::optional<gl::ScopedPixelStore> pack_row_length_;
+  absl::optional<gl::ScopedPixelStore> pack_skip_pixels_;
+  absl::optional<gl::ScopedPixelStore> pack_skip_rows_;
+};
+
+// Sets GL state for upload and copy.
 class ScopedUnpackState {
  public:
   explicit ScopedUnpackState(bool uploading_data, int unpack_row_length = 0);
diff --git a/infra/config/generated/builders/ci/fuchsia-arm64-rel/properties.json b/infra/config/generated/builders/ci/fuchsia-arm64-rel/properties.json
index 5d7c0c3..4780a4d 100644
--- a/infra/config/generated/builders/ci/fuchsia-arm64-rel/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-arm64-rel/properties.json
@@ -45,10 +45,6 @@
         {
           "builder": "fuchsia-arm64-rel",
           "group": "tryserver.chromium.fuchsia"
-        },
-        {
-          "builder": "fuchsia-arm64-rel-orchestrator",
-          "group": "tryserver.chromium.fuchsia"
         }
       ]
     }
diff --git a/infra/config/generated/builders/try/fuchsia-arm64-rel-orchestrator/properties.json b/infra/config/generated/builders/try/fuchsia-arm64-rel-orchestrator/properties.json
deleted file mode 100644
index 3889e0c1..0000000
--- a/infra/config/generated/builders/try/fuchsia-arm64-rel-orchestrator/properties.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
-  "$build/chromium_orchestrator": {
-    "compilator": "fuchsia-arm64-rel-compilator",
-    "compilator_watcher_git_revision": "7809a690bbd935bcb3b4d922e24cabe168aaabc8"
-  },
-  "$build/chromium_tests_builder_config": {
-    "builder_config": {
-      "builder_db": {
-        "entries": [
-          {
-            "builder_id": {
-              "bucket": "ci",
-              "builder": "fuchsia-arm64-rel",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-linux-archive",
-              "builder_group": "chromium.fuchsia",
-              "execution_mode": "COMPILE_AND_TEST",
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "mb"
-                ],
-                "build_config": "Release",
-                "config": "chromium",
-                "target_arch": "arm",
-                "target_bits": 64,
-                "target_platform": "fuchsia"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "fuchsia_arm64",
-                  "fuchsia_arm64_host"
-                ],
-                "config": "chromium"
-              }
-            }
-          }
-        ]
-      },
-      "builder_ids": [
-        {
-          "bucket": "ci",
-          "builder": "fuchsia-arm64-rel",
-          "project": "chromium"
-        }
-      ]
-    }
-  },
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "tryserver.chromium.fuchsia",
-  "recipe": "chromium/orchestrator"
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json b/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
index 07154c2..3889e0c1 100644
--- a/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
@@ -1,4 +1,8 @@
 {
+  "$build/chromium_orchestrator": {
+    "compilator": "fuchsia-arm64-rel-compilator",
+    "compilator_watcher_git_revision": "7809a690bbd935bcb3b4d922e24cabe168aaabc8"
+  },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
       "builder_db": {
@@ -43,11 +47,6 @@
       ]
     }
   },
-  "$build/goma": {
-    "enable_ats": true,
-    "rpc_extra_params": "?prod",
-    "server_host": "goma.chromium.org"
-  },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
     "grouping_keys": [
@@ -56,5 +55,5 @@
     ]
   },
   "builder_group": "tryserver.chromium.fuchsia",
-  "recipe": "chromium_trybot"
+  "recipe": "chromium/orchestrator"
 }
\ No newline at end of file
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 5261124..447f254 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -439,12 +439,6 @@
   Location filters:
   * [`//chrome/updater/.+`](https://cs.chromium.org/chromium/src/chrome/updater/)
 
-* [win7-rel](https://ci.chromium.org/p/chromium/builders/try/win7-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""win7-rel"")) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+""win7-rel""))
-
-  Location filters:
-  * [`//sandbox/win/.+`](https://cs.chromium.org/chromium/src/sandbox/win/)
-  * [`//sandbox/policy/win/.+`](https://cs.chromium.org/chromium/src/sandbox/policy/win/)
-
 * [win_optional_gpu_tests_rel](https://ci.chromium.org/p/chromium/builders/try/win_optional_gpu_tests_rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""win_optional_gpu_tests_rel"")) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+""win_optional_gpu_tests_rel""))
 
   Location filters:
diff --git a/infra/config/generated/cq-usage/full.cfg b/infra/config/generated/cq-usage/full.cfg
index d9933d1..7136893e 100644
--- a/infra/config/generated/cq-usage/full.cfg
+++ b/infra/config/generated/cq-usage/full.cfg
@@ -2310,36 +2310,6 @@
         }
       }
       builders {
-        name: "chromium/try/win7-rel"
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "sandbox/win/.+"
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "sandbox/policy/win/.+"
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "docs/.+"
-          exclude: true
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "infra/config/.+"
-          exclude: true
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "infra/config/generated/builders/try/win7-rel/.+"
-        }
-      }
-      builders {
         name: "chromium/try/win_chromium_compile_dbg_ng"
         location_filters {
           gerrit_host_regexp: ".*"
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index 95697c1..abf09f13 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -1693,10 +1693,6 @@
         includable_only: true
       }
       builders {
-        name: "chromium/try/fuchsia-arm64-rel-orchestrator"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/fuchsia-binary-size"
         location_filters {
           gerrit_host_regexp: ".*"
@@ -3850,33 +3846,7 @@
       }
       builders {
         name: "chromium/try/win7-rel"
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "sandbox/win/.+"
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "sandbox/policy/win/.+"
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "docs/.+"
-          exclude: true
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "infra/config/.+"
-          exclude: true
-        }
-        location_filters {
-          gerrit_host_regexp: ".*"
-          gerrit_project_regexp: ".*"
-          path_regexp: "infra/config/generated/builders/try/win7-rel/.+"
-        }
+        includable_only: true
       }
       builders {
         name: "chromium/try/win_archive"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index c0f8d3ee..55f6bf6 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -65899,7 +65899,7 @@
       name: "fuchsia-arm64-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:fuchsia-arm64-rel"
-      dimensions: "cores:8"
+      dimensions: "cores:2"
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-18.04"
       dimensions: "pool:luci.chromium.try"
@@ -65931,7 +65931,7 @@
         '  },'
         '  "builder_group": "tryserver.chromium.fuchsia",'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium_trybot"'
+        '  "recipe": "chromium/orchestrator"'
         '}'
       execution_timeout_secs: 14400
       expiration_secs: 7200
@@ -65943,7 +65943,7 @@
         path: "win_toolchain"
       }
       build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      service_account: "chromium-orchestrator@chops-service-accounts.iam.gserviceaccount.com"
       task_template_canary_percentage {
         value: 5
       }
@@ -66003,6 +66003,7 @@
           use_invocation_timestamp: true
         }
       }
+      description_html: "This is the orchestrator half of an orchestrator + compilator pair of builders. The compilator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/fuchsia-arm64-rel-compilator\">fuchsia-arm64-rel-compilator</a>."
     }
     builders {
       name: "fuchsia-arm64-rel-compilator"
@@ -66112,117 +66113,7 @@
           use_invocation_timestamp: true
         }
       }
-      description_html: "This is the compilator half of an orchestrator + compilator pair of builders. The orchestrator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/fuchsia-arm64-rel-orchestrator\">fuchsia-arm64-rel-orchestrator</a>."
-    }
-    builders {
-      name: "fuchsia-arm64-rel-orchestrator"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builder:fuchsia-arm64-rel-orchestrator"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/try/fuchsia-arm64-rel-orchestrator/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "tryserver.chromium.fuchsia",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium/orchestrator"'
-        '}'
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      grace_period {
-        seconds: 120
-      }
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-orchestrator@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      experiments {
-        key: "chromium_swarming.expose_merge_script_failures"
-        value: 100
-      }
-      experiments {
-        key: "enable_weetbix_queries"
-        value: 100
-      }
-      experiments {
-        key: "luci.buildbucket.omit_python2"
-        value: 0
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      experiments {
-        key: "weetbix.enable_weetbix_exonerations"
-        value: 100
-      }
-      experiments {
-        key: "weetbix.retry_weak_exonerations"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-      description_html: "This is the orchestrator half of an orchestrator + compilator pair of builders. The compilator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/fuchsia-arm64-rel-compilator\">fuchsia-arm64-rel-compilator</a>."
+      description_html: "This is the compilator half of an orchestrator + compilator pair of builders. The orchestrator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/fuchsia-arm64-rel\">fuchsia-arm64-rel</a>."
     }
     builders {
       name: "fuchsia-binary-size"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index d74e521..b65ca260 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -2669,9 +2669,6 @@
     name: "buildbucket/luci.chromium.try/fuchsia-arm64-rel-compilator"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/fuchsia-arm64-rel-orchestrator"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/fuchsia-x64-cast-receiver-rel"
   }
   builders {
@@ -16567,9 +16564,6 @@
     name: "buildbucket/luci.chromium.try/fuchsia-arm64-rel-compilator"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/fuchsia-arm64-rel-orchestrator"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/fuchsia-binary-size"
   }
   builders {
@@ -17878,9 +17872,6 @@
     name: "buildbucket/luci.chromium.try/fuchsia-arm64-rel-compilator"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/fuchsia-arm64-rel-orchestrator"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/fuchsia-binary-size"
   }
   builders {
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
index 649c9ab..45c416d 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
@@ -55,27 +55,12 @@
     ],
 )
 
-try_.builder(
-    name = "fuchsia-arm64-rel",
-    branch_selector = branches.FUCHSIA_LTS_MILESTONE,
-    builderless = not settings.is_main,
-    main_list_view = "try",
-    tryjob = try_.job(),
-    mirrors = [
-        "ci/fuchsia-arm64-rel",
-    ],
-    experiments = {
-        "enable_weetbix_queries": 100,
-        "weetbix.retry_weak_exonerations": 100,
-        "weetbix.enable_weetbix_exonerations": 100,
-    },
-)
-
 try_.orchestrator_builder(
-    name = "fuchsia-arm64-rel-orchestrator",
+    name = "fuchsia-arm64-rel",
     compilator = "fuchsia-arm64-rel-compilator",
     branch_selector = branches.FUCHSIA_LTS_MILESTONE,
     main_list_view = "try",
+    tryjob = try_.job(),
     mirrors = [
         "ci/fuchsia-arm64-rel",
     ],
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
index c28a979..76fc520 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
@@ -303,12 +303,6 @@
     goma_jobs = goma.jobs.J300,
     main_list_view = "try",
     ssd = True,
-    tryjob = try_.job(
-        location_filters = [
-            "sandbox/win/.+",
-            "sandbox/policy/win/.+",
-        ],
-    ),
 )
 
 try_.builder(
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
index 4d4fa41a8..9132de9 100644
--- a/ios/build/bots/scripts/test_runner.py
+++ b/ios/build/bots/scripts/test_runner.py
@@ -318,7 +318,9 @@
       'path_delimiter': '.',
       'seconds_since_epoch': int(time.time()),
       # This will be overwritten when the tests complete successfully.
-      'interrupted': True
+      'interrupted': True,
+      'num_failures_by_type': {},
+      'tests': {}
   }
 
 
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn
index c34167b..dbdc6d1d1 100644
--- a/ios/chrome/browser/flags/BUILD.gn
+++ b/ios/chrome/browser/flags/BUILD.gn
@@ -68,6 +68,7 @@
     "//ios/chrome/browser/ui/autofill:features",
     "//ios/chrome/browser/ui/bubble:features",
     "//ios/chrome/browser/ui/content_suggestions:feature_flags",
+    "//ios/chrome/browser/ui/credential_provider_promo:features",
     "//ios/chrome/browser/ui/default_promo:utils",
     "//ios/chrome/browser/ui/download:features",
     "//ios/chrome/browser/ui/first_run:field_trial",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 4a39c8b..a95975e 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -81,6 +81,7 @@
 #import "ios/chrome/browser/ui/autofill/features.h"
 #import "ios/chrome/browser/ui/bubble/bubble_features.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
+#import "ios/chrome/browser/ui/credential_provider_promo/features.h"
 #import "ios/chrome/browser/ui/default_promo/default_browser_utils.h"
 #import "ios/chrome/browser/ui/download/features.h"
 #import "ios/chrome/browser/ui/first_run/field_trial_constants.h"
@@ -1085,6 +1086,10 @@
      flag_descriptions::kEnableExpKitCalendarTextClassifierName,
      flag_descriptions::kEnableExpKitCalendarTextClassifierDescription,
      flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableExpKitCalendarTextClassifier)},
+    {"enable-expkit-text-classifier",
+     flag_descriptions::kEnableExpKitTextClassifierName,
+     flag_descriptions::kEnableExpKitTextClassifierDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableExpKitTextClassifier)},
     {"experience-kit-maps", flag_descriptions::kMapsExperienceKitName,
      flag_descriptions::kMapsExperienceKitDescription, flags_ui::kOsIos,
      FEATURE_WITH_PARAMS_VALUE_TYPE(kMapsExperienceKit,
@@ -1333,7 +1338,10 @@
     {"remove-crash-infobar", flag_descriptions::kRemoveCrashInfobarName,
      flag_descriptions::kRemoveCrashInfobarDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kRemoveCrashInfobar)},
-
+    {"credential-provider-extension-promo",
+     flag_descriptions::kCredentialProviderExtensionPromoName,
+     flag_descriptions::kCredentialProviderExtensionPromoDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kCredentialProviderExtensionPromo)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 26e9a24..3f5db75 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -151,6 +151,12 @@
     "When enabled, Experience Kit Calendar will use Text Classifier library in "
     "entity detection where possible.";
 
+extern const char kEnableExpKitTextClassifierName[] =
+    "Text Classifier in Experience Kit";
+extern const char kEnableExpKitTextClassifierDescription[] =
+    "When enabled, Experience Kit will use Text Classifier library in "
+    "entity detection where possible.";
+
 extern const char kMapsExperienceKitName[] = "Experience Kit Maps";
 extern const char kMapsExperienceKitDescription[] =
     "When enabled, long pressing on an address will trigger Experience Kit Maps"
@@ -173,6 +179,12 @@
     "When enabled use Crashpad to generate crash reports crash collection. "
     "When disabled use Breakpad. This flag takes two restarts to take effect";
 
+const char kCredentialProviderExtensionPromoName[] =
+    "Enable the Credential Provider Extension promo.";
+const char kCredentialProviderExtensionPromoDescription[] =
+    "When enabled, Credential Provider Extension promo will be "
+    "presented to eligible users.";
+
 const char kDefaultBrowserFullscreenPromoExperimentName[] =
     "Default Browser Fullscreen modal experiment";
 const char kDefaultBrowserFullscreenPromoExperimentDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 721e31e..1142ce7 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -128,6 +128,11 @@
 extern const char kEnableExpKitCalendarTextClassifierName[];
 extern const char kEnableExpKitCalendarTextClassifierDescription[];
 
+// Title and description for the flag to enable text classifier entity detection
+// in experience kit for different entity types.
+extern const char kEnableExpKitTextClassifierName[];
+extern const char kEnableExpKitTextClassifierDescription[];
+
 // Title and description for the flag to enable long press surrounding text.
 extern const char kLongPressSurroundingTextName[];
 extern const char kLongPressSurroundingTextDescription[];
@@ -147,6 +152,11 @@
 extern const char kCrashpadIOSName[];
 extern const char kCrashpadIOSDescription[];
 
+// Title and description for the flag to enable the Credential
+// Provider Extension promo.
+extern const char kCredentialProviderExtensionPromoName[];
+extern const char kCredentialProviderExtensionPromoDescription[];
+
 // Title and description for the flag to show a modified fullscreen modal promo
 // with a button that would send the users in the Settings.app to update the
 // default browser.
diff --git a/ios/chrome/browser/text_selection/text_classifier_model_service_factory.mm b/ios/chrome/browser/text_selection/text_classifier_model_service_factory.mm
index f8c6071..86ac1e2 100644
--- a/ios/chrome/browser/text_selection/text_classifier_model_service_factory.mm
+++ b/ios/chrome/browser/text_selection/text_classifier_model_service_factory.mm
@@ -45,7 +45,8 @@
 std::unique_ptr<KeyedService>
 TextClassifierModelServiceFactory::BuildServiceInstanceFor(
     web::BrowserState* context) const {
-  if (!base::FeatureList::IsEnabled(kEnableExpKitCalendarTextClassifier) ||
+  if ((!base::FeatureList::IsEnabled(kEnableExpKitCalendarTextClassifier) &&
+       !base::FeatureList::IsEnabled(kEnableExpKitTextClassifier)) ||
       !optimization_guide::features::IsOptimizationTargetPredictionEnabled()) {
     return nullptr;
   }
diff --git a/ios/chrome/browser/text_selection/text_selection_util.h b/ios/chrome/browser/text_selection/text_selection_util.h
index e9a51d4..1a6cbe5 100644
--- a/ios/chrome/browser/text_selection/text_selection_util.h
+++ b/ios/chrome/browser/text_selection/text_selection_util.h
@@ -11,4 +11,9 @@
 // calendar.
 BASE_DECLARE_FEATURE(kEnableExpKitCalendarTextClassifier);
 
+// Feature flag to enable Text Classifier entity detection in experience kit
+// The feature params will control which entity types are enabled for
+// detection.
+BASE_DECLARE_FEATURE(kEnableExpKitTextClassifier);
+
 #endif  // IOS_CHROME_BROWSER_TEXT_SELECTION_TEXT_SELECTION_UTIL_H_
diff --git a/ios/chrome/browser/text_selection/text_selection_util.mm b/ios/chrome/browser/text_selection/text_selection_util.mm
index c07bad1..b390aa2e 100644
--- a/ios/chrome/browser/text_selection/text_selection_util.mm
+++ b/ios/chrome/browser/text_selection/text_selection_util.mm
@@ -11,3 +11,7 @@
 BASE_FEATURE(kEnableExpKitCalendarTextClassifier,
              "EnableExpKitCalendarTextClassifier",
              base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kEnableExpKitTextClassifier,
+             "EnableExpKitTextClassifier",
+             base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn b/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn
new file mode 100644
index 0000000..81483a7
--- /dev/null
+++ b/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2022 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("features") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "features.h",
+    "features.mm",
+  ]
+  deps = [ "//base" ]
+}
diff --git a/ios/chrome/browser/ui/credential_provider_promo/features.h b/ios/chrome/browser/ui/credential_provider_promo/features.h
new file mode 100644
index 0000000..de7af74
--- /dev/null
+++ b/ios/chrome/browser/ui/credential_provider_promo/features.h
@@ -0,0 +1,16 @@
+// Copyright 2022 The Chromium Authors
+// 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_CREDENTIAL_PROVIDER_PROMO_FEATURES_H_
+#define IOS_CHROME_BROWSER_UI_CREDENTIAL_PROVIDER_PROMO_FEATURES_H_
+
+#import "base/feature_list.h"
+
+// Feature flag to enable the Credential Provider Extension Promo feature.
+BASE_DECLARE_FEATURE(kCredentialProviderExtensionPromo);
+
+// Returns true if Credential Provider Extension Promo feature is enabled.
+bool IsCredentialProviderExtensionPromoEnabled();
+
+#endif  // IOS_CHROME_BROWSER_UI_CREDENTIAL_PROVIDER_PROMO_FEATURES_H_
diff --git a/ios/chrome/browser/ui/credential_provider_promo/features.mm b/ios/chrome/browser/ui/credential_provider_promo/features.mm
new file mode 100644
index 0000000..037a902
--- /dev/null
+++ b/ios/chrome/browser/ui/credential_provider_promo/features.mm
@@ -0,0 +1,19 @@
+// Copyright 2022 The Chromium Authors
+// 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/credential_provider_promo/features.h"
+
+#import "base/feature_list.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+BASE_FEATURE(kCredentialProviderExtensionPromo,
+             "CredentialProviderExtensionPromo",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+bool IsCredentialProviderExtensionPromoEnabled() {
+  return base::FeatureList::IsEnabled(kCredentialProviderExtensionPromo);
+}
diff --git a/ios/chrome/browser/ui/price_notifications/BUILD.gn b/ios/chrome/browser/ui/price_notifications/BUILD.gn
index 738fc02..7c4d96d2 100644
--- a/ios/chrome/browser/ui/price_notifications/BUILD.gn
+++ b/ios/chrome/browser/ui/price_notifications/BUILD.gn
@@ -5,8 +5,8 @@
 source_set("price_notifications") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "price_notifications_primary_mediator.h",
-    "price_notifications_primary_mediator.mm",
+    "price_notifications_price_tracking_mediator.h",
+    "price_notifications_price_tracking_mediator.mm",
     "price_notifications_view_coordinator.h",
     "price_notifications_view_coordinator.mm",
   ]
diff --git a/ios/chrome/browser/ui/price_notifications/price_notifications_primary_mediator.h b/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.h
similarity index 88%
rename from ios/chrome/browser/ui/price_notifications/price_notifications_primary_mediator.h
rename to ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.h
index 91934af..8bfe3ee 100644
--- a/ios/chrome/browser/ui/price_notifications/price_notifications_primary_mediator.h
+++ b/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.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 IOS_CHROME_BROWSER_UI_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_PRIMARY_MEDIATOR_H_
-#define IOS_CHROME_BROWSER_UI_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_PRIMARY_MEDIATOR_H_
+#ifndef IOS_CHROME_BROWSER_UI_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_PRICE_TRACKING_MEDIATOR_H_
+#define IOS_CHROME_BROWSER_UI_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_PRICE_TRACKING_MEDIATOR_H_
 
 #import <Foundation/Foundation.h>
 #import <memory>
@@ -26,7 +26,7 @@
 class WebState;
 }  // namespace web
 
-@interface PriceNotificationsPrimaryMediator : NSObject
+@interface PriceNotificationsPriceTrackingMediator : NSObject
 
 // The designated initializer. `ShoppingService`, `BookmarkModel`,
 // `ImageDataFetcher` and `WebState` must not be nil.
@@ -43,4 +43,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_PRIMARY_MEDIATOR_H_
+#endif  // IOS_CHROME_BROWSER_UI_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_PRICE_TRACKING_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/price_notifications/price_notifications_primary_mediator.mm b/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.mm
similarity index 94%
rename from ios/chrome/browser/ui/price_notifications/price_notifications_primary_mediator.mm
rename to ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.mm
index e38e4fe..32cbff92 100644
--- a/ios/chrome/browser/ui/price_notifications/price_notifications_primary_mediator.mm
+++ b/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.mm
@@ -2,7 +2,7 @@
 // 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/price_notifications/price_notifications_primary_mediator.h"
+#import "ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.h"
 
 #import "base/strings/string_number_conversions.h"
 #import "base/strings/sys_string_conversions.h"
@@ -22,7 +22,7 @@
 using PriceNotificationItems =
     NSMutableArray<PriceNotificationsTableViewItem*>*;
 
-@interface PriceNotificationsPrimaryMediator () {
+@interface PriceNotificationsPriceTrackingMediator () {
   // The service responsible for fetching a product's image data.
   std::unique_ptr<image_fetcher::ImageDataFetcher> _imageFetcher;
 }
@@ -36,7 +36,7 @@
 
 @end
 
-@implementation PriceNotificationsPrimaryMediator
+@implementation PriceNotificationsPriceTrackingMediator
 
 - (instancetype)
     initWithShoppingService:(commerce::ShoppingService*)service
@@ -85,7 +85,7 @@
     }
   }
 
-  __weak PriceNotificationsPrimaryMediator* weakSelf = self;
+  __weak PriceNotificationsPriceTrackingMediator* weakSelf = self;
 
   self.shoppingService->GetProductInfoForUrl(
       URL, base::BindOnce(
@@ -117,7 +117,7 @@
 
   [self.consumer setTrackableItem:item currentlyTracking:NO];
 
-  __weak PriceNotificationsPrimaryMediator* weakSelf = self;
+  __weak PriceNotificationsPriceTrackingMediator* weakSelf = self;
   // Fetches the current item's trackable image.
   _imageFetcher->FetchImageData(
       productInfo->image_url,
diff --git a/ios/chrome/browser/ui/price_notifications/price_notifications_view_coordinator.mm b/ios/chrome/browser/ui/price_notifications/price_notifications_view_coordinator.mm
index e70be18..2625e5b 100644
--- a/ios/chrome/browser/ui/price_notifications/price_notifications_view_coordinator.mm
+++ b/ios/chrome/browser/ui/price_notifications/price_notifications_view_coordinator.mm
@@ -11,7 +11,7 @@
 #import "ios/chrome/browser/commerce/shopping_service_factory.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
-#import "ios/chrome/browser/ui/price_notifications/price_notifications_primary_mediator.h"
+#import "ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.h"
 #import "ios/chrome/browser/ui/price_notifications/price_notifications_table_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
@@ -33,7 +33,7 @@
 @property(nonatomic, strong)
     PriceNotificationsTableViewController* tableViewController;
 // The mediator being managed by this coordinator.
-@property(nonatomic, strong) PriceNotificationsPrimaryMediator* mediator;
+@property(nonatomic, strong) PriceNotificationsPriceTrackingMediator* mediator;
 
 @end
 
@@ -56,7 +56,7 @@
   std::unique_ptr<image_fetcher::ImageDataFetcher> imageFetcher =
       std::make_unique<image_fetcher::ImageDataFetcher>(
           self.browser->GetBrowserState()->GetSharedURLLoaderFactory());
-  self.mediator = [[PriceNotificationsPrimaryMediator alloc]
+  self.mediator = [[PriceNotificationsPriceTrackingMediator alloc]
       initWithShoppingService:shoppingService
                 bookmarkModel:bookmarkModel
                  imageFetcher:std::move(imageFetcher)
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_safe_browsing_mediator_unittest.mm b/ios/chrome/browser/ui/settings/privacy/privacy_safe_browsing_mediator_unittest.mm
index 135fc807..0e14632 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_safe_browsing_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_safe_browsing_mediator_unittest.mm
@@ -81,8 +81,6 @@
 };
 
 TEST_F(PrivacySafeBrowsingMediatorTest, TurnOnEnhancedProtection) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(safe_browsing::kEnhancedProtection);
   TableViewItem* enhanced_safe_browsing_item =
       itemWithItemType(ItemTypeSafeBrowsingEnhancedProtection);
   [mediator_ didSelectItem:enhanced_safe_browsing_item];
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
index a1d5350..089492d 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
@@ -56,8 +56,6 @@
 }
 
 struct PrivacyTableViewControllerTestConfig {
-  // Tests should run with Enhanced Protection flag enabled.
-  bool enhancedProtectionEnabled;
   // Tests should run with Third-party intents in Incognito flag enabled.
   bool thirdPartyIntentsInIncognitoEnabled;
   // Available of Incognito mode tests should run with.
@@ -93,15 +91,6 @@
               std::vector<base::test::FeatureRef>>
         enabledDisabledFeatures;
 
-    // Explicitly enable/disable Enhanced Protection flag.
-    if (GetParam().enhancedProtectionEnabled) {
-      enabledDisabledFeatures.first.push_back(
-          safe_browsing::kEnhancedProtection);
-    } else {
-      enabledDisabledFeatures.second.push_back(
-          safe_browsing::kEnhancedProtection);
-    }
-
     // Explicitly enable/disable Third-party intents in Incognito flag.
     if (GetParam().thirdPartyIntentsInIncognitoEnabled) {
       enabledDisabledFeatures.first.push_back(kIOS3PIntentsInIncognito);
@@ -186,10 +175,7 @@
   CreateController();
   CheckController();
 
-  int expectedNumberOfSections = 3;
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    expectedNumberOfSections++;
-  }
+  int expectedNumberOfSections = 4;
   if (base::FeatureList::IsEnabled(kIOS3PIntentsInIncognito)) {
     expectedNumberOfSections++;
   }
@@ -203,13 +189,11 @@
       currentSection, 0);
 
   // SafeBrowsing section.
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    currentSection++;
-    EXPECT_EQ(currentSection, NumberOfItemsInSection(1));
-    CheckTextCellTextAndDetailText(
-        l10n_util::GetNSString(IDS_IOS_PRIVACY_SAFE_BROWSING_TITLE),
-        SafeBrowsingDetailText(), 1, 0);
-  }
+  currentSection++;
+  EXPECT_EQ(1, NumberOfItemsInSection(currentSection));
+  CheckTextCellTextAndDetailText(
+      l10n_util::GetNSString(IDS_IOS_PRIVACY_SAFE_BROWSING_TITLE),
+      SafeBrowsingDetailText(), 1, 0);
 
   // WebServices section.
   currentSection++;
@@ -254,15 +238,9 @@
   }
 
   // Testing section index and text of the privacy footer.
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    CheckSectionFooter(
-        l10n_util::GetNSString(IDS_IOS_PRIVACY_GOOGLE_SERVICES_FOOTER),
-        /* section= */ expectedNumberOfSections - 1);
-  } else {
-    CheckSectionFooter(
-        l10n_util::GetNSString(IDS_IOS_PRIVACY_GOOGLE_SERVICES_FOOTER),
-        /* section= */ 0);
-  }
+  CheckSectionFooter(
+      l10n_util::GetNSString(IDS_IOS_PRIVACY_GOOGLE_SERVICES_FOOTER),
+      /* section= */ expectedNumberOfSections - 1);
 }
 
 // Tests PrivacyTableViewController sets the correct privacy footer for a
@@ -274,25 +252,16 @@
   CreateController();
   CheckController();
 
-  int expectedNumberOfSections = 3;
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    expectedNumberOfSections++;
-  }
+  int expectedNumberOfSections = 4;
   if (base::FeatureList::IsEnabled(kIOS3PIntentsInIncognito)) {
     expectedNumberOfSections++;
   }
   EXPECT_EQ(expectedNumberOfSections, NumberOfSections());
 
   // Testing section index and text of the privacy footer.
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    CheckSectionFooter(
-        l10n_util::GetNSString(IDS_IOS_PRIVACY_GOOGLE_SERVICES_FOOTER),
-        /* section= */ expectedNumberOfSections - 1);
-  } else {
-    CheckSectionFooter(
-        l10n_util::GetNSString(IDS_IOS_PRIVACY_GOOGLE_SERVICES_FOOTER),
-        /* section= */ 0);
-  }
+  CheckSectionFooter(
+      l10n_util::GetNSString(IDS_IOS_PRIVACY_GOOGLE_SERVICES_FOOTER),
+      /* section= */ expectedNumberOfSections - 1);
 }
 
 // Tests PrivacyTableViewController sets the correct privacy footer for a
@@ -305,25 +274,16 @@
   CreateController();
   CheckController();
 
-  int expectedNumberOfSections = 3;
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    expectedNumberOfSections++;
-  }
+  int expectedNumberOfSections = 4;
   if (base::FeatureList::IsEnabled(kIOS3PIntentsInIncognito)) {
     expectedNumberOfSections++;
   }
   EXPECT_EQ(expectedNumberOfSections, NumberOfSections());
 
   // Testing section index and text of the privacy footer.
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    CheckSectionFooter(
-        l10n_util::GetNSString(IDS_IOS_PRIVACY_SYNC_AND_GOOGLE_SERVICES_FOOTER),
-        /* section= */ expectedNumberOfSections - 1);
-  } else {
-    CheckSectionFooter(
-        l10n_util::GetNSString(IDS_IOS_PRIVACY_SYNC_AND_GOOGLE_SERVICES_FOOTER),
-        /* section= */ 0);
-  }
+  CheckSectionFooter(
+      l10n_util::GetNSString(IDS_IOS_PRIVACY_SYNC_AND_GOOGLE_SERVICES_FOOTER),
+      /* section= */ expectedNumberOfSections - 1);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -331,27 +291,21 @@
     PrivacyTableViewControllerTest,
     testing::Values(
         PrivacyTableViewControllerTestConfig{
-            /* enhancedProtectionEnabled= */ false,
             /* thirdPartyIntentsInIncognitoEnabled= */ false,
             /* incognitoModeAvailability= */ IncognitoModePrefs::kEnabled},
         PrivacyTableViewControllerTestConfig{
-            /* enhancedProtectionEnabled= */ true,
             /* thirdPartyIntentsInIncognitoEnabled= */ false,
             /* incognitoModeAvailability= */ IncognitoModePrefs::kEnabled},
         PrivacyTableViewControllerTestConfig{
-            /* enhancedProtectionEnabled= */ false,
             /* thirdPartyIntentsInIncognitoEnabled= */ true,
             /* incognitoModeAvailability= */ IncognitoModePrefs::kEnabled},
         PrivacyTableViewControllerTestConfig{
-            /* enhancedProtectionEnabled= */ true,
             /* thirdPartyIntentsInIncognitoEnabled= */ true,
             /* incognitoModeAvailability= */ IncognitoModePrefs::kEnabled},
         PrivacyTableViewControllerTestConfig{
-            /* enhancedProtectionEnabled= */ true,
             /* thirdPartyIntentsInIncognitoEnabled= */ true,
             /* incognitoModeAvailability= */ IncognitoModePrefs::kDisabled},
         PrivacyTableViewControllerTestConfig{
-            /* enhancedProtectionEnabled= */ true,
             /* thirdPartyIntentsInIncognitoEnabled= */ true,
             /* incognitoModeAvailability= */ IncognitoModePrefs::kForced}));
 
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
index 5dbf30ea..e1e706f 100644
--- a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
@@ -321,24 +321,19 @@
 TEST_F(SafetyCheckMediatorTest, SafeBrowsingSafeUI) {
   mediator_.safeBrowsingCheckRowState = SafeBrowsingCheckRowStateSafe;
   [mediator_ reconfigureSafeBrowsingCheckItem];
-  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
-    EXPECT_NSEQ(
-        mediator_.safeBrowsingCheckItem.detailText,
-        GetNSString(
-            IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENHANCED_PROTECTION_ENABLED_DESC));
+  EXPECT_NSEQ(
+      mediator_.safeBrowsingCheckItem.detailText,
+      GetNSString(
+          IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENHANCED_PROTECTION_ENABLED_DESC));
 
-    // Change from Enhanced Protection to Standard Protection.
-    mediator_.enhancedSafeBrowsingPreference.value = false;
-    [mediator_ reconfigureSafeBrowsingCheckItem];
-    EXPECT_NSEQ(
-        mediator_.safeBrowsingCheckItem.detailText,
-        GetNSString(
-            IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION));
-  } else {
-    EXPECT_NSEQ(
-        mediator_.safeBrowsingCheckItem.detailText,
-        GetNSString(IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED_DESC));
-  }
+  // Change from Enhanced Protection to Standard Protection.
+  mediator_.enhancedSafeBrowsingPreference.value = false;
+  [mediator_ reconfigureSafeBrowsingCheckItem];
+  EXPECT_NSEQ(
+      mediator_.safeBrowsingCheckItem.detailText,
+      GetNSString(
+          IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION));
+
   EXPECT_EQ(mediator_.safeBrowsingCheckItem.trailingImage,
             [[UIImage imageNamed:@"settings_safe_state"]
                 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]);
@@ -348,8 +343,6 @@
 // Enhanced Protection features enabled.
 TEST_F(SafetyCheckMediatorTest,
        SafeBrowsingSafeUIStandardAndEnhancedProtection) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(safe_browsing::kEnhancedProtection);
   mediator_.safeBrowsingCheckRowState = SafeBrowsingCheckRowStateSafe;
   [mediator_ reconfigureSafeBrowsingCheckItem];
   EXPECT_NSEQ(
@@ -377,12 +370,6 @@
 // Protection features enabled.
 TEST_F(SafetyCheckMediatorTest,
        SafeBrowsingSafeUIStandardAndEnhancedProtectionPhase2IOS) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      /*enabled_features=*/{safe_browsing::kEnhancedProtection,
-                            safe_browsing::kEnhancedProtectionPhase2IOS},
-      /*disabled_features=*/{});
-
   // Check UI when Safe Browsing protection choice is "Enhanced Protection".
   mediator_.safeBrowsingCheckRowState = SafeBrowsingCheckRowStateSafe;
   [mediator_ reconfigureSafeBrowsingCheckItem];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index 7420aca8..ffb37c2 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -473,10 +473,6 @@
     if (!GetFirstResponder()) {
       // It is possible to already have a first responder (for example the
       // omnibox). In that case, we don't want to mark BVC as first responder.
-      // TODO(crbug.com/1223090): Adding DCHECK below to confirm hypothesis
-      // that `-becomeFirstResponder` is crashing due to `currentBVC` not
-      // being in the view hierarchy.
-      DCHECK(self.bvcContainer.currentBVC.view.window);
       [self.bvcContainer.currentBVC becomeFirstResponder];
     }
     if (completion) {
diff --git a/ios/components/security_interstitials/safe_browsing/safe_browsing_service_unittest.mm b/ios/components/security_interstitials/safe_browsing/safe_browsing_service_unittest.mm
index c6e00ac..4fc6538 100644
--- a/ios/components/security_interstitials/safe_browsing/safe_browsing_service_unittest.mm
+++ b/ios/components/security_interstitials/safe_browsing/safe_browsing_service_unittest.mm
@@ -369,9 +369,6 @@
 
 TEST_F(SafeBrowsingServiceTest,
        RealTimeSafeAndUnsafePagesWithEnhancedProtection) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(safe_browsing::kEnhancedProtection);
-
   TestUrlCheckerClient client(safe_browsing_service_.get(),
                               browser_state_.get(), &safe_browsing_client_);
 
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index d4e1726..a63c019 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -394,11 +394,8 @@
   // If this is a error navigation, pass through.
   GURL responseURL = net::GURLWithNSURL(WKResponse.response.URL);
   if ([CRWErrorPageHelper isErrorPageFileURL:responseURL]) {
-    if (self.webStateImpl->ShouldAllowErrorPageToBeDisplayed(
-            WKResponse.response, WKResponse.forMainFrame)) {
-      handler(WKNavigationResponsePolicyAllow);
-      return;
-    }
+    handler(WKNavigationResponsePolicyAllow);
+    return;
   }
 
   if (self.pendingNavigationInfo.unsafeRedirect) {
diff --git a/ios/web/public/navigation/web_state_policy_decider.h b/ios/web/public/navigation/web_state_policy_decider.h
index 012f61e..23f97078 100644
--- a/ios/web/public/navigation/web_state_policy_decider.h
+++ b/ios/web/public/navigation/web_state_policy_decider.h
@@ -127,15 +127,6 @@
                                   PolicyDecisionCallback callback);
 
   // Asks the decider whether the navigation corresponding to `response` should
-  // be allowed to display an error page if an error occurs. Defaults to
-  // true if not overridden. This can be used to suppress error pages in certain
-  // cases such as attempting to upgrade an omnibox navigation to HTTPS. In that
-  // scenario, failed upgrade attempts (e.g. due to SSL or DNS resolution
-  // errors) should immediately fall back to HTTP without showing an error page.
-  virtual bool ShouldAllowErrorPageToBeDisplayed(NSURLResponse* response,
-                                                 bool for_main_frame);
-
-  // Asks the decider whether the navigation corresponding to `response` should
   // be allowed to continue. Defaults to PolicyDecision::Allow() if not
   // overridden. Called before WebStateObserver::DidFinishNavigation. Calls
   // `callback` with the decision.
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 a9d397c..63da42b 100644
--- a/ios/web/public/navigation/web_state_policy_decider_bridge.h
+++ b/ios/web/public/navigation/web_state_policy_decider_bridge.h
@@ -21,10 +21,6 @@
                requestInfo:(web::WebStatePolicyDecider::RequestInfo)requestInfo
            decisionHandler:(PolicyDecisionHandler)decisionHandler;
 
-// Invoked by `WebStatePolicyDeciderBridge::ShouldAllowRequest`.
-- (bool)shouldAllowErrorPageToBeDisplayed:(NSURLResponse*)response
-                             forMainFrame:(BOOL)forMainFrame;
-
 // Invoked by `WebStatePolicyDeciderBridge::ShouldAllowResponse`.
 - (void)
     decidePolicyForNavigationResponse:(NSURLResponse*)response
@@ -57,9 +53,6 @@
                            ResponseInfo response_info,
                            PolicyDecisionCallback callback) override;
 
-  bool ShouldAllowErrorPageToBeDisplayed(NSURLResponse* response,
-                                         bool for_main_frame) override;
-
  private:
   // CRWWebStatePolicyDecider which receives forwarded calls.
   __weak id<CRWWebStatePolicyDecider> decider_ = nil;
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index cd9104d..3452d7d 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -164,13 +164,6 @@
       WebStatePolicyDecider::RequestInfo request_info,
       WebStatePolicyDecider::PolicyDecisionCallback callback);
 
-  // Decides whether the navigation corresponding to `response` should
-  // be allowed to display an error page if an error occurs, by asking its
-  // policy deciders. If at least one policy decider's decision is false,
-  // returns false; otherwise returns true.
-  bool ShouldAllowErrorPageToBeDisplayed(NSURLResponse* response,
-                                         bool for_main_frame);
-
   // Decides whether the navigation corresponding to `response` should be
   // allowed to continue by asking its policy deciders, and calls `callback`
   // with the decision. Defaults to PolicyDecision::Allow(). If at least one
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 8b18f28a..6f55ca3d 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -225,12 +225,6 @@
                                       std::move(callback));
 }
 
-bool WebStateImpl::ShouldAllowErrorPageToBeDisplayed(NSURLResponse* response,
-                                                     bool for_main_frame) {
-  return RealizedState()->ShouldAllowErrorPageToBeDisplayed(response,
-                                                            for_main_frame);
-}
-
 void WebStateImpl::ShouldAllowResponse(
     NSURLResponse* response,
     WebStatePolicyDecider::ResponseInfo response_info,
diff --git a/ios/web/web_state/web_state_impl_realized_web_state.h b/ios/web/web_state/web_state_impl_realized_web_state.h
index 8b9bb279..2343ec0 100644
--- a/ios/web/web_state/web_state_impl_realized_web_state.h
+++ b/ios/web/web_state/web_state_impl_realized_web_state.h
@@ -99,8 +99,6 @@
       NSURLRequest* request,
       WebStatePolicyDecider::RequestInfo request_info,
       WebStatePolicyDecider::PolicyDecisionCallback callback);
-  bool ShouldAllowErrorPageToBeDisplayed(NSURLResponse* response,
-                                         bool for_main_frame);
   void ShouldAllowResponse(
       NSURLResponse* response,
       WebStatePolicyDecider::ResponseInfo response_info,
diff --git a/ios/web/web_state/web_state_impl_realized_web_state.mm b/ios/web/web_state/web_state_impl_realized_web_state.mm
index f61afec6..09d0383 100644
--- a/ios/web/web_state/web_state_impl_realized_web_state.mm
+++ b/ios/web/web_state/web_state_impl_realized_web_state.mm
@@ -355,18 +355,6 @@
       num_decisions_requested);
 }
 
-bool WebStateImpl::RealizedWebState::ShouldAllowErrorPageToBeDisplayed(
-    NSURLResponse* response,
-    bool for_main_frame) {
-  for (auto& policy_decider : policy_deciders()) {
-    if (!policy_decider.ShouldAllowErrorPageToBeDisplayed(response,
-                                                          for_main_frame)) {
-      return false;
-    }
-  }
-  return true;
-}
-
 void WebStateImpl::RealizedWebState::ShouldAllowResponse(
     NSURLResponse* response,
     WebStatePolicyDecider::ResponseInfo response_info,
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm
index 8c61ed7..cbeccb8 100644
--- a/ios/web/web_state/web_state_impl_unittest.mm
+++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -125,9 +125,6 @@
                void(NSURLRequest* request,
                     WebStatePolicyDecider::RequestInfo request_info,
                     WebStatePolicyDecider::PolicyDecisionCallback callback));
-
-  MOCK_METHOD2(ShouldAllowErrorPageToBeDisplayed,
-               bool(NSURLResponse* response, bool for_main_frame));
   MOCK_METHOD3(ShouldAllowResponse,
                void(NSURLResponse* response,
                     WebStatePolicyDecider::ResponseInfo response_info,
@@ -647,38 +644,6 @@
     EXPECT_TRUE(policy_decision.ShouldCancelNavigation());
   }
 
-  NSURL* error_url = [NSURL URLWithString:@"chrome://invalid"];
-  NSURLResponse* error_response =
-      [[NSURLResponse alloc] initWithURL:error_url
-                                MIMEType:@"text/html"
-                   expectedContentLength:0
-                        textEncodingName:nil];
-
-  const WebStatePolicyDecider::RequestInfo error_request_info_main_frame(
-      ui::PageTransition::PAGE_TRANSITION_LINK,
-      /*target_main_frame=*/true,
-      /*target_frame_is_cross_origin=*/false,
-      /*has_user_gesture=*/false);
-  EXPECT_CALL(decider, ShouldAllowErrorPageToBeDisplayed(error_response, true))
-      .Times(1)
-      .WillOnce(Return(true));
-  EXPECT_CALL(decider2, ShouldAllowErrorPageToBeDisplayed(error_response, true))
-      .Times(1)
-      .WillOnce(Return(true));
-  EXPECT_TRUE(
-      web_state_->ShouldAllowErrorPageToBeDisplayed(error_response, true));
-
-  // If at least one decider doesn't allow displaying error pages, web state
-  // shouldn't allow them either.
-  EXPECT_CALL(decider, ShouldAllowErrorPageToBeDisplayed(error_response, true))
-      .Times(1)
-      .WillOnce(Return(true));
-  EXPECT_CALL(decider2, ShouldAllowErrorPageToBeDisplayed(error_response, true))
-      .Times(1)
-      .WillOnce(Return(false));
-  EXPECT_FALSE(
-      web_state_->ShouldAllowErrorPageToBeDisplayed(error_response, true));
-
   EXPECT_CALL(decider, WebStateDestroyed()).Times(1);
   EXPECT_CALL(decider2, WebStateDestroyed()).Times(1);
   web_state_.reset();
diff --git a/ios/web/web_state/web_state_policy_decider.mm b/ios/web/web_state/web_state_policy_decider.mm
index 0574404..b555c66 100644
--- a/ios/web/web_state/web_state_policy_decider.mm
+++ b/ios/web/web_state/web_state_policy_decider.mm
@@ -71,12 +71,6 @@
   std::move(callback).Run(PolicyDecision::Allow());
 }
 
-bool WebStatePolicyDecider::ShouldAllowErrorPageToBeDisplayed(
-    NSURLResponse* response,
-    bool for_main_frame) {
-  return true;
-}
-
 void WebStatePolicyDecider::ShouldAllowResponse(
     NSURLResponse* response,
     ResponseInfo response_info,
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 7c8ec828..302cf816 100644
--- a/ios/web/web_state/web_state_policy_decider_bridge.mm
+++ b/ios/web/web_state/web_state_policy_decider_bridge.mm
@@ -34,17 +34,6 @@
   std::move(callback).Run(PolicyDecision::Allow());
 }
 
-bool WebStatePolicyDeciderBridge::ShouldAllowErrorPageToBeDisplayed(
-    NSURLResponse* response,
-    bool for_main_frame) {
-  if ([decider_ respondsToSelector:@selector
-                (shouldAllowErrorPageToBeDisplayed:forMainFrame:)]) {
-    return [decider_ shouldAllowErrorPageToBeDisplayed:response
-                                          forMainFrame:for_main_frame];
-  }
-  return true;
-}
-
 void WebStatePolicyDeciderBridge::ShouldAllowResponse(
     NSURLResponse* response,
     ResponseInfo response_info,
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 7177c78..1ee7988 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -39,7 +39,6 @@
     "ENABLE_HEVC_PARSER_AND_HW_DECODER=$enable_hevc_parser_and_hw_decoder",
     "ENABLE_HLS_SAMPLE_AES=$enable_hls_sample_aes",
     "ENABLE_HLS_DEMUXER=$enable_hls_demuxer",
-    "ENABLE_LIBGAV1_DECODER=$enable_libgav1_decoder",
     "ENABLE_LIBAOM=$enable_libaom",
     "ENABLE_LIBRARY_CDMS=$enable_library_cdms",
     "ENABLE_LIBVPX=$media_use_libvpx",
diff --git a/media/base/decoder.cc b/media/base/decoder.cc
index 8bd5d6af..72ac2fed 100644
--- a/media/base/decoder.cc
+++ b/media/base/decoder.cc
@@ -40,8 +40,6 @@
       return "FuchsiaVideoDecoder";
     case VideoDecoderType::kMediaCodec:
       return "MediaCodecVideoDecoder";
-    case VideoDecoderType::kGav1:
-      return "Gav1VideoDecoder";
     case VideoDecoderType::kD3D11:
       return "D3D11VideoDecoder";
     case VideoDecoderType::kVaapi:
diff --git a/media/base/decoder.h b/media/base/decoder.h
index 40e9194..2f42a39 100644
--- a/media/base/decoder.h
+++ b/media/base/decoder.h
@@ -44,13 +44,13 @@
   kDav1d = 7,       // Dav1dVideoDecoder
   kFuchsia = 8,     // FuchsiaVideoDecoder
   kMediaCodec = 9,  // MediaCodecVideoDecoder (Android)
-  kGav1 = 10,       // Gav1VideoDecoder
-  kD3D11 = 11,      // D3D11VideoDecoder
-  kVaapi = 12,      // VaapiVideoDecoder
-  kBroker = 13,     // VideoDecoderBroker (Webcodecs)
-  kVda = 14,        // VDAVideoDecoder
+  // kGav1 = 10,    // Gav1VideoDecoder. (DEPRECATED)
+  kD3D11 = 11,   // D3D11VideoDecoder
+  kVaapi = 12,   // VaapiVideoDecoder
+  kBroker = 13,  // VideoDecoderBroker (Webcodecs)
+  kVda = 14,     // VDAVideoDecoder
   // kChromeOs = 15,  // DEPRECATED, should be kVaapi or kV4L2 instead.
-  kV4L2 = 16,       // V4L2VideoDecoder
+  kV4L2 = 16,  // V4L2VideoDecoder
 
   kTesting = 17,  // Never send this to UKM, for tests only.
 
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 81443e1..4fc1aca2 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -486,11 +486,6 @@
              "FallbackAfterDecodeError",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Use Gav1VideoDecoder to decode AV1 streams.
-BASE_FEATURE(kGav1VideoDecoder,
-             "Gav1VideoDecoder",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Show toolbar button that opens dialog for controlling media sessions.
 BASE_FEATURE(kGlobalMediaControls,
              "GlobalMediaControls",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 614729ddc2..29a3ce1e 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -144,7 +144,6 @@
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kFFmpegDecodeOpaqueVP8);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kFailUrlProvisionFetcherForTesting);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kFallbackAfterDecodeError);
-MEDIA_EXPORT BASE_DECLARE_FEATURE(kGav1VideoDecoder);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kGlobalMediaControls);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kGlobalMediaControlsAutoDismiss);
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
index 69d46cb..21b2ba55 100644
--- a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
@@ -43,10 +43,6 @@
 #include "media/filters/ffmpeg_video_decoder.h"
 #endif
 
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-#include "media/filters/gav1_video_decoder.h"
-#endif
-
 namespace media {
 
 namespace {
@@ -318,18 +314,10 @@
     video_decoder = std::make_unique<VpxVideoDecoder>();
 #endif
 
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-  if (base::FeatureList::IsEnabled(kGav1VideoDecoder)) {
-    if (config.codec == cdm::kCodecAv1)
-      video_decoder.reset(new Gav1VideoDecoder(null_media_log.get()));
-  } else
-#endif  // BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-  {
 #if BUILDFLAG(ENABLE_DAV1D_DECODER)
-    if (config.codec == cdm::kCodecAv1)
-      video_decoder = std::make_unique<Dav1dVideoDecoder>(null_media_log.get());
+  if (config.codec == cdm::kCodecAv1)
+    video_decoder = std::make_unique<Dav1dVideoDecoder>(null_media_log.get());
 #endif
-  }
 
 #if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
   if (!video_decoder)
diff --git a/media/filters/BUILD.gn b/media/filters/BUILD.gn
index 73584464..f2eb201 100644
--- a/media/filters/BUILD.gn
+++ b/media/filters/BUILD.gn
@@ -154,14 +154,6 @@
     deps += [ "//third_party/dav1d" ]
   }
 
-  if (enable_libgav1_decoder) {
-    sources += [
-      "gav1_video_decoder.cc",
-      "gav1_video_decoder.h",
-    ]
-    deps += [ "//third_party/libgav1" ]
-  }
-
   if (media_use_ffmpeg) {
     if (proprietary_codecs) {
       sources += [
@@ -383,10 +375,6 @@
     sources += [ "dav1d_video_decoder_unittest.cc" ]
   }
 
-  if (enable_libgav1_decoder) {
-    sources += [ "gav1_video_decoder_unittest.cc" ]
-  }
-
   if (use_vaapi) {
     sources += [ "h264_bitstream_buffer_unittest.cc" ]
   }
diff --git a/media/filters/gav1_video_decoder.cc b/media/filters/gav1_video_decoder.cc
deleted file mode 100644
index 77508c31..0000000
--- a/media/filters/gav1_video_decoder.cc
+++ /dev/null
@@ -1,453 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/filters/gav1_video_decoder.h"
-
-#include <stdint.h>
-#include <numeric>
-
-#include "base/bits.h"
-#include "base/callback_helpers.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/system/sys_info.h"
-#include "base/task/sequenced_task_runner.h"
-#include "media/base/bind_to_current_loop.h"
-#include "media/base/limits.h"
-#include "media/base/media_log.h"
-#include "media/base/video_frame.h"
-#include "media/base/video_util.h"
-#include "third_party/libgav1/src/src/gav1/decoder.h"
-#include "third_party/libgav1/src/src/gav1/decoder_settings.h"
-#include "third_party/libgav1/src/src/gav1/frame_buffer.h"
-
-namespace media {
-
-namespace {
-
-VideoPixelFormat Libgav1ImageFormatToVideoPixelFormat(
-    const libgav1::ImageFormat libgav1_format,
-    int bitdepth) {
-  switch (libgav1_format) {
-    // Single plane monochrome images will be converted to standard 3 plane ones
-    // since Chromium doesn't support single Y plane images.
-    case libgav1::kImageFormatMonochrome400:
-    case libgav1::kImageFormatYuv420:
-      switch (bitdepth) {
-        case 8:
-          return PIXEL_FORMAT_I420;
-        case 10:
-          return PIXEL_FORMAT_YUV420P10;
-        case 12:
-          return PIXEL_FORMAT_YUV420P12;
-        default:
-          DLOG(ERROR) << "Unsupported bit depth: " << bitdepth;
-          return PIXEL_FORMAT_UNKNOWN;
-      }
-    case libgav1::kImageFormatYuv422:
-      switch (bitdepth) {
-        case 8:
-          return PIXEL_FORMAT_I422;
-        case 10:
-          return PIXEL_FORMAT_YUV422P10;
-        case 12:
-          return PIXEL_FORMAT_YUV422P12;
-        default:
-          DLOG(ERROR) << "Unsupported bit depth: " << bitdepth;
-          return PIXEL_FORMAT_UNKNOWN;
-      }
-    case libgav1::kImageFormatYuv444:
-      switch (bitdepth) {
-        case 8:
-          return PIXEL_FORMAT_I444;
-        case 10:
-          return PIXEL_FORMAT_YUV444P10;
-        case 12:
-          return PIXEL_FORMAT_YUV444P12;
-        default:
-          DLOG(ERROR) << "Unsupported bit depth: " << bitdepth;
-          return PIXEL_FORMAT_UNKNOWN;
-      }
-  }
-}
-
-int GetDecoderThreadCounts(int coded_height) {
-  // Thread counts based on currently available content. We set the number of
-  // threads to be equal to the general number of tiles for the given
-  // resolution. As of now, YouTube content has the following tile settings:
-  //   240p and below - 1 tile
-  //   360p and 480p - 2 tiles
-  //   720p - 4 tiles
-  //   1080p - 8 tiles
-  // libgav1 supports frame parallel decoding, but we do not use it (yet) since
-  // the performance for this thread configuration is good enough without it.
-  // Also, the memory usage is much lower in non-frame parallel mode. This can
-  // be revisited as performance numbers change/evolve.
-  static const int num_cores = base::SysInfo::NumberOfProcessors();
-  auto threads_by_height = [](int coded_height) {
-    if (coded_height >= 1000)
-      return 8;
-    if (coded_height >= 700)
-      return 4;
-    if (coded_height >= 300)
-      return 2;
-    return 1;
-  };
-
-  return std::min(threads_by_height(coded_height), num_cores);
-}
-
-libgav1::StatusCode GetFrameBufferImpl(void* callback_private_data,
-                                       int bitdepth,
-                                       libgav1::ImageFormat image_format,
-                                       int width,
-                                       int height,
-                                       int left_border,
-                                       int right_border,
-                                       int top_border,
-                                       int bottom_border,
-                                       int stride_alignment,
-                                       Libgav1FrameBuffer* frame_buffer) {
-  DCHECK(callback_private_data);
-  DCHECK(frame_buffer);
-  DCHECK(base::bits::IsPowerOfTwo(stride_alignment));
-  // VideoFramePool creates frames with a fixed alignment of
-  // VideoFrame::kFrameAddressAlignment. If libgav1 requests a larger
-  // alignment, it cannot be supported.
-  CHECK_LE(static_cast<size_t>(stride_alignment),
-           VideoFrame::kFrameAddressAlignment);
-
-  const VideoPixelFormat format =
-      Libgav1ImageFormatToVideoPixelFormat(image_format, bitdepth);
-  if (format == PIXEL_FORMAT_UNKNOWN)
-    return libgav1::kStatusUnimplemented;
-
-  // VideoFramePool aligns video_frame->data(i), but libgav1 needs
-  // video_frame->visible_data(i) to be aligned. To accomplish that, pad
-  // left_border to be a multiple of stride_alignment.
-  //
-  // Here is an example:
-  // width=6, height=4, left/right/top/bottom_border=2, stride_alignment=16
-  //
-  //     X*|TTTTTT|**pppppp
-  //     **|TTTTTT|**pppppp
-  //     --+------+--------
-  //     LL|YFFFFF|RRpppppp
-  //     LL|FFFFFF|RRpppppp
-  //     LL|FFFFFF|RRpppppp
-  //     LL|FFFFFF|RRpppppp
-  //     --+------+--------
-  //     **|BBBBBB|**pppppp
-  //     **|BBBBBB|**pppppp
-  //
-  // F indicates the frame proper. L, R, T, B indicate the
-  // left/right/top/bottom borders. Lowercase p indicates the padding at the
-  // end of a row. The asterisk * indicates the borders at the four corners.
-  //
-  // Libgav1 requires that the callback align the first byte of the frame
-  // proper, indicated by Y. VideoFramePool aligns the first byte of the
-  // buffer, indicated by X. To make sure the byte indicated by Y is also
-  // aligned, we need to pad left_border to be a multiple of stride_alignment.
-  left_border = base::bits::AlignUp(left_border, stride_alignment);
-  gfx::Size coded_size(left_border + width + right_border,
-                       top_border + height + bottom_border);
-  gfx::Rect visible_rect(left_border, top_border, width, height);
-
-  auto* decoder = static_cast<Gav1VideoDecoder*>(callback_private_data);
-  auto video_frame =
-      decoder->CreateVideoFrame(format, coded_size, visible_rect);
-  if (!video_frame)
-    return libgav1::kStatusInvalidArgument;
-
-  for (int i = 0; i < 3; i++) {
-    // frame_buffer->plane[i] points to the first byte of the frame proper,
-    // not the first byte of the buffer.
-    frame_buffer->plane[i] = video_frame->GetWritableVisibleData(i);
-    frame_buffer->stride[i] = video_frame->stride(i);
-  }
-  if (image_format == libgav1::kImageFormatMonochrome400) {
-    int uv_height = (height + 1) >> 1;
-    const size_t size_needed = video_frame->stride(1) * uv_height;
-    for (int i = 1; i < 3; i++) {
-      frame_buffer->plane[i] = nullptr;
-      frame_buffer->stride[i] = 0;
-      // An AV1 monochrome (grayscale) frame has no U and V planes. Set all U
-      // and V samples in video_frame to the blank value.
-      if (bitdepth == 8) {
-        constexpr uint8_t kBlankUV = 256 / 2;
-        memset(video_frame->GetWritableVisibleData(i), kBlankUV, size_needed);
-      } else {
-        const uint16_t kBlankUV = (1 << bitdepth) / 2;
-        uint16_t* data =
-            reinterpret_cast<uint16_t*>(video_frame->GetWritableVisibleData(i));
-        std::fill(data, data + size_needed / 2, kBlankUV);
-      }
-    }
-  }
-  frame_buffer->private_data = video_frame.get();
-  video_frame->AddRef();
-
-  return libgav1::kStatusOk;
-}
-
-void ReleaseFrameBufferImpl(void* callback_private_data,
-                            void* buffer_private_data) {
-  DCHECK(callback_private_data);
-  DCHECK(buffer_private_data);
-  static_cast<VideoFrame*>(buffer_private_data)->Release();
-}
-
-void ReleaseInputBufferImpl(void* callback_private_data,
-                            void* buffer_private_data) {
-  DCHECK(callback_private_data);
-  DCHECK(buffer_private_data);
-  static_cast<DecoderBuffer*>(buffer_private_data)->Release();
-}
-
-scoped_refptr<VideoFrame> FormatVideoFrame(
-    const libgav1::DecoderBuffer& buffer,
-    const VideoColorSpace& container_color_space) {
-  scoped_refptr<VideoFrame> frame =
-      static_cast<VideoFrame*>(buffer.buffer_private_data);
-  frame->set_timestamp(base::Microseconds(buffer.user_private_data));
-
-  // AV1 color space defines match ISO 23001-8:2016 via ISO/IEC 23091-4/ITU-T
-  // H.273. https://aomediacodec.github.io/av1-spec/#color-config-semantics
-  media::VideoColorSpace color_space(
-      buffer.color_primary, buffer.transfer_characteristics,
-      buffer.matrix_coefficients,
-      buffer.color_range == libgav1::kColorRangeStudio
-          ? gfx::ColorSpace::RangeID::LIMITED
-          : gfx::ColorSpace::RangeID::FULL);
-
-  // If the frame doesn't specify a color space, use the container's.
-  if (!color_space.IsSpecified())
-    color_space = container_color_space;
-
-  frame->set_color_space(color_space.ToGfxColorSpace());
-  frame->metadata().power_efficient = false;
-
-  return frame;
-}
-
-}  // namespace
-
-// static
-SupportedVideoDecoderConfigs Gav1VideoDecoder::SupportedConfigs() {
-  return {{/*profile_min=*/AV1PROFILE_PROFILE_MAIN,
-           /*profile_max=*/AV1PROFILE_PROFILE_HIGH,
-           /*coded_size_min=*/kDefaultSwDecodeSizeMin,
-           /*coded_size_max=*/kDefaultSwDecodeSizeMax,
-           /*allow_encrypted=*/false,
-           /*require_encrypted=*/false}};
-}
-
-Gav1VideoDecoder::Gav1VideoDecoder(MediaLog* media_log,
-                                   OffloadState offload_state)
-    : media_log_(media_log),
-      bind_callbacks_(offload_state == OffloadState::kNormal) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
-Gav1VideoDecoder::~Gav1VideoDecoder() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CloseDecoder();
-}
-
-VideoDecoderType Gav1VideoDecoder::GetDecoderType() const {
-  return VideoDecoderType::kGav1;
-}
-
-void Gav1VideoDecoder::Initialize(const VideoDecoderConfig& config,
-                                  bool low_delay,
-                                  CdmContext* /* cdm_context */,
-                                  InitCB init_cb,
-                                  const OutputCB& output_cb,
-                                  const WaitingCB& /* waiting_cb */) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(config.IsValidConfig());
-
-  InitCB bound_init_cb = bind_callbacks_ ? BindToCurrentLoop(std::move(init_cb))
-                                         : std::move(init_cb);
-  if (config.is_encrypted() || config.codec() != VideoCodec::kAV1) {
-    std::move(bound_init_cb)
-        .Run(DecoderStatus::Codes::kUnsupportedEncryptionMode);
-    return;
-  }
-
-  // Clear any previously initialized decoder.
-  CloseDecoder();
-
-  libgav1::DecoderSettings settings;
-  settings.threads = VideoDecoder::GetRecommendedThreadCount(
-      GetDecoderThreadCounts(config.coded_size().height()));
-  settings.get_frame_buffer = GetFrameBufferImpl;
-  settings.release_frame_buffer = ReleaseFrameBufferImpl;
-  settings.release_input_buffer = ReleaseInputBufferImpl;
-  settings.callback_private_data = this;
-
-  if (low_delay || config.is_rtc()) {
-    // The `frame_parallel` setting is false by default, so this serves more as
-    // documentation that it should be false for low delay decoding.
-    settings.frame_parallel = false;
-  }
-
-  libgav1_decoder_ = std::make_unique<libgav1::Decoder>();
-  libgav1::StatusCode status = libgav1_decoder_->Init(&settings);
-  if (status != kLibgav1StatusOk) {
-    MEDIA_LOG(ERROR, media_log_) << "libgav1::Decoder::Init() failed, "
-                                 << "status=" << status;
-    std::move(bound_init_cb).Run(DecoderStatus::Codes::kFailedToCreateDecoder);
-    return;
-  }
-
-  output_cb_ = output_cb;
-  state_ = DecoderState::kDecoding;
-  color_space_ = config.color_space_info();
-  aspect_ratio_ = config.aspect_ratio();
-  std::move(bound_init_cb).Run(DecoderStatus::Codes::kOk);
-}
-
-void Gav1VideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
-                              DecodeCB decode_cb) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(buffer);
-  DCHECK(decode_cb);
-  DCHECK(libgav1_decoder_);
-  DCHECK_NE(state_, DecoderState::kUninitialized)
-      << "Called Decode() before successful Initialize()";
-
-  DecodeCB bound_decode_cb = bind_callbacks_
-                                 ? BindToCurrentLoop(std::move(decode_cb))
-                                 : std::move(decode_cb);
-
-  if (state_ == DecoderState::kError) {
-    std::move(bound_decode_cb).Run(DecoderStatus::Codes::kFailed);
-    return;
-  }
-
-  if (!DecodeBuffer(std::move(buffer))) {
-    state_ = DecoderState::kError;
-    std::move(bound_decode_cb).Run(DecoderStatus::Codes::kFailed);
-    return;
-  }
-
-  // VideoDecoderShim expects |decode_cb| call after |output_cb_|.
-  std::move(bound_decode_cb).Run(DecoderStatus::Codes::kOk);
-}
-
-bool Gav1VideoDecoder::DecodeBuffer(scoped_refptr<DecoderBuffer> buffer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  const bool is_end_of_stream = buffer->end_of_stream();
-
-  // Used to ensure that EnqueueFrame() actually takes the packet. If we exit
-  // this function without enqueuing |buffer|, that packet will be lost. We do
-  // not have anything to enqueue at the end of stream.
-  bool enqueued = is_end_of_stream;
-
-  while (is_end_of_stream || !enqueued) {
-    // Try to enqueue the packet if it has not been enqueued already.
-    if (!enqueued) {
-      libgav1::StatusCode status = libgav1_decoder_->EnqueueFrame(
-          buffer->data(), buffer->data_size(),
-          /* user_private_data = */ buffer->timestamp().InMicroseconds(),
-          /* buffer_private_data = */ buffer.get());
-      if (status == kLibgav1StatusOk) {
-        buffer->AddRef();
-        enqueued = true;
-      } else if (status != kLibgav1StatusTryAgain) {
-        MEDIA_LOG(ERROR, media_log_)
-            << "libgav1::Decoder::EnqueueFrame failed, status=" << status
-            << " on " << buffer->AsHumanReadableString();
-        return false;
-      }
-    }
-
-    // Try to dequeue a decoded frame.
-    const libgav1::DecoderBuffer* decoded_buffer;
-    libgav1::StatusCode status =
-        libgav1_decoder_->DequeueFrame(&decoded_buffer);
-    if (status != kLibgav1StatusOk) {
-      if (status != kLibgav1StatusTryAgain &&
-          status != kLibgav1StatusNothingToDequeue) {
-        MEDIA_LOG(ERROR, media_log_)
-            << "libgav1::Decoder::DequeueFrame failed, status=" << status;
-        return false;
-      }
-
-      // We've reached end of stream and no frames are remaining to be dequeued.
-      if (is_end_of_stream && status == kLibgav1StatusNothingToDequeue) {
-        return true;
-      }
-
-      continue;
-    }
-
-    if (!decoded_buffer) {
-      // The packet did not have any displayable frames. Not an error.
-      continue;
-    }
-
-    scoped_refptr<VideoFrame> frame =
-        FormatVideoFrame(*decoded_buffer, color_space_);
-    if (!frame) {
-      MEDIA_LOG(ERROR, media_log_) << "Failed formatting VideoFrame from "
-                                   << "libgav1::DecoderBuffer";
-      return false;
-    }
-
-    output_cb_.Run(std::move(frame));
-  }
-
-  DCHECK(enqueued);
-  return true;
-}
-
-void Gav1VideoDecoder::Reset(base::OnceClosure reset_cb) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  state_ = DecoderState::kDecoding;
-
-  libgav1::StatusCode status = libgav1_decoder_->SignalEOS();
-  if (status != kLibgav1StatusOk) {
-    MEDIA_LOG(WARNING, media_log_) << "libgav1::Decoder::SignalEOS() failed, "
-                                   << "status=" << status;
-  }
-
-  if (bind_callbacks_) {
-    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE, std::move(reset_cb));
-  } else {
-    std::move(reset_cb).Run();
-  }
-}
-
-void Gav1VideoDecoder::Detach() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!bind_callbacks_);
-
-  CloseDecoder();
-
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
-scoped_refptr<VideoFrame> Gav1VideoDecoder::CreateVideoFrame(
-    VideoPixelFormat format,
-    const gfx::Size& coded_size,
-    const gfx::Rect& visible_rect) {
-  // The comment for VideoFramePool::CreateFrame() says:
-  //   The buffer for the new frame will be zero initialized.  Reused frames
-  //   will not be zero initialized.
-  // The zero initialization is necessary for FFmpeg but not for libgav1.
-  return frame_pool_.CreateFrame(format, coded_size, visible_rect,
-                                 aspect_ratio_.GetNaturalSize(visible_rect),
-                                 kNoTimestamp);
-}
-
-void Gav1VideoDecoder::CloseDecoder() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  libgav1_decoder_.reset();
-  state_ = DecoderState::kUninitialized;
-}
-
-}  // namespace media
diff --git a/media/filters/gav1_video_decoder.h b/media/filters/gav1_video_decoder.h
deleted file mode 100644
index 09677034..0000000
--- a/media/filters/gav1_video_decoder.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_FILTERS_GAV1_VIDEO_DECODER_H_
-#define MEDIA_FILTERS_GAV1_VIDEO_DECODER_H_
-
-#include <memory>
-#include <queue>
-#include <vector>
-
-#include "base/containers/queue.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/sequence_checker.h"
-#include "media/base/media_export.h"
-#include "media/base/supported_video_decoder_config.h"
-#include "media/base/video_aspect_ratio.h"
-#include "media/base/video_decoder_config.h"
-#include "media/base/video_frame_pool.h"
-#include "media/filters/offloading_video_decoder.h"
-
-namespace libgav1 {
-class Decoder;
-}  // namespace libgav1
-
-namespace media {
-class MediaLog;
-
-class MEDIA_EXPORT Gav1VideoDecoder : public OffloadableVideoDecoder {
- public:
-  static SupportedVideoDecoderConfigs SupportedConfigs();
-
-  explicit Gav1VideoDecoder(MediaLog* media_log,
-                            OffloadState offload_state = OffloadState::kNormal);
-  ~Gav1VideoDecoder() override;
-  Gav1VideoDecoder(const Gav1VideoDecoder&) = delete;
-  Gav1VideoDecoder& operator=(const Gav1VideoDecoder&) = delete;
-
-  // VideoDecoder implementation.
-  VideoDecoderType GetDecoderType() const override;
-  void Initialize(const VideoDecoderConfig& config,
-                  bool low_delay,
-                  CdmContext* cdm_context,
-                  InitCB init_cb,
-                  const OutputCB& output_cb,
-                  const WaitingCB& waiting_cb) override;
-  void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
-  void Reset(base::OnceClosure reset_cb) override;
-
-  // OffloadableVideoDecoder implementation.
-  void Detach() override;
-
-  scoped_refptr<VideoFrame> CreateVideoFrame(VideoPixelFormat format,
-                                             const gfx::Size& coded_size,
-                                             const gfx::Rect& visible_rect);
-
- private:
-  enum class DecoderState {
-    kUninitialized,
-    kDecoding,
-    kError,
-  };
-
-  void CloseDecoder();
-
-  // Invokes the decoder and calls |output_cb_| for any returned frames.
-  bool DecodeBuffer(scoped_refptr<DecoderBuffer> buffer);
-
-  // Used to report error messages to the client.
-  MediaLog* const media_log_;
-  const bool bind_callbacks_;
-
-  // Info configured in Initialize(). These are used in outputting frames.
-  VideoColorSpace color_space_;
-  VideoAspectRatio aspect_ratio_;
-
-  DecoderState state_ = DecoderState::kUninitialized;
-
-  // A decoded buffer used in libgav1 is allocated and managed by
-  // |frame_pool_|. The buffer can be reused only if libgav1's decoder doesn't
-  // use the buffer and rendering the frame is complete.
-  VideoFramePool frame_pool_;
-
-  OutputCB output_cb_;
-  std::unique_ptr<libgav1::Decoder> libgav1_decoder_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-};
-
-// Helper class for creating a Gav1VideoDecoder which will offload all AV1
-// content from the media thread.
-class OffloadingGav1VideoDecoder : public OffloadingVideoDecoder {
- public:
-  explicit OffloadingGav1VideoDecoder(MediaLog* media_log)
-      : OffloadingVideoDecoder(
-            0,
-            std::vector<VideoCodec>(1, VideoCodec::kAV1),
-            std::make_unique<Gav1VideoDecoder>(
-                media_log,
-                OffloadableVideoDecoder::OffloadState::kOffloaded)) {}
-};
-}  // namespace media
-#endif  // MEDIA_FILTERS_GAV1_VIDEO_DECODER_H_
diff --git a/media/filters/gav1_video_decoder_unittest.cc b/media/filters/gav1_video_decoder_unittest.cc
deleted file mode 100644
index 743fc28d..0000000
--- a/media/filters/gav1_video_decoder_unittest.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/hash/md5.h"
-#include "base/run_loop.h"
-#include "base/strings/string_piece.h"
-#include "base/test/task_environment.h"
-#include "build/build_config.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/limits.h"
-#include "media/base/mock_media_log.h"
-#include "media/base/test_data_util.h"
-#include "media/base/test_helpers.h"
-#include "media/base/video_frame.h"
-#include "media/ffmpeg/ffmpeg_common.h"
-#include "media/filters/gav1_video_decoder.h"
-#include "media/filters/in_memory_url_protocol.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using ::testing::_;
-
-namespace media {
-
-namespace {
-
-MATCHER(ContainsDecoderErrorLog, "") {
-  return CONTAINS_STRING(arg, "libgav1::Decoder::DequeueFrame failed");
-}
-
-// Similar to VideoFrame::HashFrameForTesting(), but uses visible_data() and
-// visible_rect() instead of data() and coded_size() to determine the region to
-// hash.
-//
-// The VideoFrame objects created by Gav1VideoDecoder have extended pixels
-// outside the visible_rect(). Those extended pixels are for libgav1 internal
-// use and are not part of the actual video frames. Unlike
-// VideoFrame::HashFrameForTesting(), this function excludes the extended pixels
-// and hashes only the actual video frames.
-void HashFrameVisibleRectForTesting(base::MD5Context* context,
-                                    const VideoFrame& frame) {
-  DCHECK(context);
-  for (size_t plane = 0; plane < VideoFrame::NumPlanes(frame.format());
-       ++plane) {
-    int rows = frame.Rows(plane, frame.format(), frame.visible_rect().height());
-    for (int row = 0; row < rows; ++row) {
-      int row_bytes =
-          frame.RowBytes(plane, frame.format(), frame.visible_rect().width());
-      base::MD5Update(context, base::StringPiece(reinterpret_cast<const char*>(
-                                                     frame.visible_data(plane) +
-                                                     frame.stride(plane) * row),
-                                                 row_bytes));
-    }
-  }
-}
-
-}  // namespace
-
-class Gav1VideoDecoderTest : public testing::Test {
- public:
-  Gav1VideoDecoderTest()
-      : decoder_(new Gav1VideoDecoder(&media_log_)),
-        i_frame_buffer_(ReadTestDataFile("av1-I-frame-320x240")) {}
-
-  Gav1VideoDecoderTest(const Gav1VideoDecoderTest&) = delete;
-  Gav1VideoDecoderTest& operator=(const Gav1VideoDecoderTest&) = delete;
-
-  ~Gav1VideoDecoderTest() override { Destroy(); }
-
-  void Initialize() {
-    InitializeWithConfig(TestVideoConfig::Normal(VideoCodec::kAV1));
-  }
-
-  void InitializeWithConfigWithResult(const VideoDecoderConfig& config,
-                                      bool success) {
-    decoder_->Initialize(config, false, nullptr,
-                         base::BindOnce(
-                             [](bool success, DecoderStatus status) {
-                               EXPECT_EQ(status.is_ok(), success);
-                             },
-                             success),
-                         base::BindRepeating(&Gav1VideoDecoderTest::FrameReady,
-                                             base::Unretained(this)),
-                         base::NullCallback());
-    base::RunLoop().RunUntilIdle();
-  }
-
-  void InitializeWithConfig(const VideoDecoderConfig& config) {
-    InitializeWithConfigWithResult(config, true);
-  }
-
-  void Reinitialize() {
-    InitializeWithConfig(TestVideoConfig::Large(VideoCodec::kAV1));
-  }
-
-  void Reset() {
-    decoder_->Reset(NewExpectedClosure());
-    base::RunLoop().RunUntilIdle();
-  }
-
-  void Destroy() {
-    decoder_.reset();
-    base::RunLoop().RunUntilIdle();
-  }
-
-  // Sets up expectations and actions to put Gav1VideoDecoder in an active
-  // decoding state.
-  void ExpectDecodingState() {
-    EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
-    ASSERT_EQ(1U, output_frames_.size());
-  }
-
-  // Sets up expectations and actions to put Gav1VideoDecoder in an end
-  // of stream state.
-  void ExpectEndOfStreamState() {
-    EXPECT_TRUE(DecodeSingleFrame(DecoderBuffer::CreateEOSBuffer()).is_ok());
-    ASSERT_FALSE(output_frames_.empty());
-  }
-
-  using InputBuffers = std::vector<scoped_refptr<DecoderBuffer>>;
-  using OutputFrames = std::vector<scoped_refptr<VideoFrame>>;
-
-  // Decodes all buffers in |input_buffers| and push all successfully decoded
-  // output frames into |output_frames|. Returns the last decode status returned
-  // by the decoder.
-  DecoderStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
-    for (auto iter = input_buffers.begin(); iter != input_buffers.end();
-         ++iter) {
-      DecoderStatus status = Decode(*iter);
-      switch (status.code()) {
-        case DecoderStatus::Codes::kOk:
-          break;
-        case DecoderStatus::Codes::kAborted:
-          NOTREACHED();
-          [[fallthrough]];
-        default:
-          DCHECK(output_frames_.empty());
-          return status;
-      }
-    }
-    return DecoderStatus::Codes::kOk;
-  }
-
-  // Decodes the single compressed frame in |buffer|.
-  DecoderStatus DecodeSingleFrame(scoped_refptr<DecoderBuffer> buffer) {
-    InputBuffers input_buffers;
-    input_buffers.push_back(std::move(buffer));
-    return DecodeMultipleFrames(input_buffers);
-  }
-
-  // Decodes |i_frame_buffer_| and then decodes the data contained in the file
-  // named |test_file_name|. This function expects both buffers to decode to
-  // frames that are the same size.
-  void DecodeIFrameThenTestFile(const std::string& test_file_name,
-                                const gfx::Size& expected_size) {
-    Initialize();
-    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
-
-    InputBuffers input_buffers;
-    input_buffers.push_back(i_frame_buffer_);
-    input_buffers.push_back(buffer);
-    input_buffers.push_back(DecoderBuffer::CreateEOSBuffer());
-
-    EXPECT_TRUE(DecodeMultipleFrames(input_buffers).is_ok());
-    ASSERT_EQ(2U, output_frames_.size());
-
-    gfx::Size original_size = TestVideoConfig::NormalCodedSize();
-    EXPECT_EQ(original_size.width(),
-              output_frames_[0]->visible_rect().size().width());
-    EXPECT_EQ(original_size.height(),
-              output_frames_[0]->visible_rect().size().height());
-    EXPECT_EQ(expected_size.width(),
-              output_frames_[1]->visible_rect().size().width());
-    EXPECT_EQ(expected_size.height(),
-              output_frames_[1]->visible_rect().size().height());
-  }
-
-  DecoderStatus Decode(scoped_refptr<DecoderBuffer> buffer) {
-    DecoderStatus status;
-    EXPECT_CALL(*this, DecodeDone(_)).WillOnce(testing::SaveArg<0>(&status));
-
-    decoder_->Decode(std::move(buffer),
-                     base::BindOnce(&Gav1VideoDecoderTest::DecodeDone,
-                                    base::Unretained(this)));
-    base::RunLoop().RunUntilIdle();
-
-    return status;
-  }
-
-  void FrameReady(scoped_refptr<VideoFrame> frame) {
-    DCHECK(!frame->metadata().end_of_stream);
-    output_frames_.push_back(std::move(frame));
-  }
-
-  std::string GetVideoFrameHash(const VideoFrame& frame) {
-    base::MD5Context md5_context;
-    base::MD5Init(&md5_context);
-    HashFrameVisibleRectForTesting(&md5_context, frame);
-    base::MD5Digest digest;
-    base::MD5Final(&digest, &md5_context);
-    return base::MD5DigestToBase16(digest);
-  }
-
-  MOCK_METHOD1(DecodeDone, void(DecoderStatus));
-
-  testing::StrictMock<MockMediaLog> media_log_;
-
-  base::test::SingleThreadTaskEnvironment task_environment_;
-  std::unique_ptr<Gav1VideoDecoder> decoder_;
-
-  scoped_refptr<DecoderBuffer> i_frame_buffer_;
-  OutputFrames output_frames_;
-};
-
-TEST_F(Gav1VideoDecoderTest, Initialize_Normal) {
-  Initialize();
-}
-
-TEST_F(Gav1VideoDecoderTest, Reinitialize_Normal) {
-  Initialize();
-  Reinitialize();
-}
-
-TEST_F(Gav1VideoDecoderTest, Reinitialize_AfterDecodeFrame) {
-  Initialize();
-  ExpectDecodingState();
-  Reinitialize();
-}
-
-TEST_F(Gav1VideoDecoderTest, Reinitialize_AfterReset) {
-  Initialize();
-  ExpectDecodingState();
-  Reset();
-  Reinitialize();
-}
-
-TEST_F(Gav1VideoDecoderTest, DecodeFrame_Normal) {
-  Initialize();
-
-  // Simulate decoding a single frame.
-  EXPECT_TRUE(DecodeSingleFrame(i_frame_buffer_).is_ok());
-  ASSERT_EQ(1U, output_frames_.size());
-
-  const auto& frame = output_frames_.front();
-  EXPECT_EQ(PIXEL_FORMAT_I420, frame->format());
-  EXPECT_EQ("589dc641b7742ffe7a2b0d4c16aa3e86", GetVideoFrameHash(*frame));
-}
-
-TEST_F(Gav1VideoDecoderTest, DecodeFrame_8bitMono) {
-  Initialize();
-  EXPECT_TRUE(
-      DecodeSingleFrame(ReadTestDataFile("av1-monochrome-I-frame-320x240-8bpp"))
-          .is_ok());
-  ASSERT_EQ(1U, output_frames_.size());
-
-  const auto& frame = output_frames_.front();
-  EXPECT_EQ(PIXEL_FORMAT_I420, frame->format());
-  EXPECT_EQ("eeba03dcc9c22c4632bf74b481db36b2", GetVideoFrameHash(*frame));
-}
-
-TEST_F(Gav1VideoDecoderTest, DecodeFrame_10bitMono) {
-  Initialize();
-  EXPECT_TRUE(DecodeSingleFrame(
-                  ReadTestDataFile("av1-monochrome-I-frame-320x240-10bpp"))
-                  .is_ok());
-  ASSERT_EQ(1U, output_frames_.size());
-
-  const auto& frame = output_frames_.front();
-  EXPECT_EQ(PIXEL_FORMAT_YUV420P10, frame->format());
-  EXPECT_EQ("026c1fed9e161f09d816ac7278458a80", GetVideoFrameHash(*frame));
-}
-
-// libgav1 does not support bit depth 12.
-TEST_F(Gav1VideoDecoderTest, DISABLED_DecodeFrame_12bitMono) {
-  Initialize();
-  EXPECT_TRUE(DecodeSingleFrame(
-                  ReadTestDataFile("av1-monochrome-I-frame-320x240-12bpp"))
-                  .is_ok());
-  ASSERT_EQ(1U, output_frames_.size());
-
-  const auto& frame = output_frames_.front();
-  EXPECT_EQ(PIXEL_FORMAT_YUV420P12, frame->format());
-  EXPECT_EQ("32115092dc00fbe86823b0b714a0f63e", GetVideoFrameHash(*frame));
-}
-
-// Decode |i_frame_buffer_| and then a frame with a larger width and verify
-// the output size was adjusted.
-TEST_F(Gav1VideoDecoderTest, DecodeFrame_LargerWidth) {
-  DecodeIFrameThenTestFile("av1-I-frame-1280x720", gfx::Size(1280, 720));
-}
-
-// Decode a VP9 frame which should trigger a decoder error.
-TEST_F(Gav1VideoDecoderTest, DecodeFrame_Error) {
-  Initialize();
-  EXPECT_MEDIA_LOG(ContainsDecoderErrorLog());
-  DecodeSingleFrame(ReadTestDataFile("vp9-I-frame-320x240"));
-}
-
-// Test resetting when decoder has initialized but not decoded.
-TEST_F(Gav1VideoDecoderTest, Reset_Initialized) {
-  Initialize();
-  Reset();
-}
-
-// Test resetting when decoder has decoded single frame.
-TEST_F(Gav1VideoDecoderTest, Reset_Decoding) {
-  Initialize();
-  ExpectDecodingState();
-  Reset();
-}
-
-// Test resetting when decoder has hit end of stream.
-TEST_F(Gav1VideoDecoderTest, Reset_EndOfStream) {
-  Initialize();
-  ExpectDecodingState();
-  ExpectEndOfStreamState();
-  Reset();
-}
-
-// Test destruction when decoder has initialized but not decoded.
-TEST_F(Gav1VideoDecoderTest, Destroy_Initialized) {
-  Initialize();
-  Destroy();
-}
-
-// Test destruction when decoder has decoded single frame.
-TEST_F(Gav1VideoDecoderTest, Destroy_Decoding) {
-  Initialize();
-  ExpectDecodingState();
-  Destroy();
-}
-
-// Test destruction when decoder has hit end of stream.
-TEST_F(Gav1VideoDecoderTest, Destroy_EndOfStream) {
-  Initialize();
-  ExpectDecodingState();
-  ExpectEndOfStreamState();
-  Destroy();
-}
-
-TEST_F(Gav1VideoDecoderTest, FrameValidAfterPoolDestruction) {
-  Initialize();
-  Decode(i_frame_buffer_);
-  Destroy();
-
-  ASSERT_FALSE(output_frames_.empty());
-
-  // Write to the Y plane. The memory tools should detect a
-  // use-after-free if the storage was actually removed by pool destruction.
-  memset(output_frames_.front()->writable_data(VideoFrame::kYPlane), 0xff,
-         output_frames_.front()->rows(VideoFrame::kYPlane) *
-             output_frames_.front()->stride(VideoFrame::kYPlane));
-}
-
-}  // namespace media
diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn
index 75c124c8..71c7d5d 100644
--- a/media/gpu/v4l2/BUILD.gn
+++ b/media/gpu/v4l2/BUILD.gn
@@ -126,7 +126,7 @@
   }
 
   # TODO(b/243970152): update use_libgav1_parser flag
-  if (enable_libgav1_decoder || use_libgav1_parser) {
+  if (use_libgav1_parser) {
     deps += [ "//third_party/libgav1:libgav1" ]
   }
 }
@@ -193,7 +193,7 @@
     "//media/parsers",
   ]
 
-  if (enable_libgav1_decoder || use_libgav1_parser) {
+  if (use_libgav1_parser) {
     deps += [ "//third_party/libgav1:libgav1" ]
   }
 }
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
index d74c341..1d59512 100644
--- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
@@ -648,11 +648,13 @@
 }
 
 size_t V4L2StatelessVideoDecoderBackend::GetNumOUTPUTQueueBuffers() const {
-  // Some H.264 test vectors (CAPCM*1_Sand_E.h264) need 16 reference frames.
+  // Some H.264 test vectors (CAPCM*1_Sand_E.h264) need 16 reference frames; add
+  // one to calculate the number of OUTPUT buffers, to account for the frame
+  // being decoded.
   // TODO(b/249325255): reduce this number to e.g. 8 or even less when it does
   // not artificially limit the size of the CAPTURE (decoded video frames)
   // queue.
-  constexpr size_t kNumInputBuffers = 16;
+  constexpr size_t kNumInputBuffers = 16 + 1;
   return kNumInputBuffers;
 }
 
diff --git a/media/gpu/video_decode_accelerator_tests.cc b/media/gpu/video_decode_accelerator_tests.cc
index 712b8230..7894b7a 100644
--- a/media/gpu/video_decode_accelerator_tests.cc
+++ b/media/gpu/video_decode_accelerator_tests.cc
@@ -17,6 +17,7 @@
 #include "media/base/test_data_util.h"
 #include "media/base/video_decoder_config.h"
 #include "media/base/video_transformation.h"
+#include "media/filters/dav1d_video_decoder.h"
 #include "media/gpu/test/video.h"
 #include "media/gpu/test/video_frame_file_writer.h"
 #include "media/gpu/test/video_frame_validator.h"
@@ -28,12 +29,6 @@
 #include "media/media_buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if BUILDFLAG(ENABLE_DAV1D_DECODER)
-#include "media/filters/dav1d_video_decoder.h"
-#elif BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-#include "media/filters/gav1_video_decoder.h"
-#endif
-
 namespace media {
 namespace test {
 
@@ -203,11 +198,8 @@
       LOG(ERROR) << "Frame validation by SSIM is allowed for AV1 streams only";
       return false;
     }
-#if BUILDFLAG(ENABLE_DAV1D_DECODER)
+
     Dav1dVideoDecoder decoder(
-#elif BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-    Gav1VideoDecoder decoder(
-#endif
         /*media_log=*/nullptr,
         OffloadableVideoDecoder::OffloadState::kOffloaded);
     VideoDecoderConfig decoder_config(
diff --git a/media/media_options.gni b/media/media_options.gni
index cfe0648..afdaf0c 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -104,7 +104,7 @@
 declare_args() {
   # If overriding this to false, possibly via its component values,
   # `enable_libaom` should likely also be overriddent to false.
-  enable_av1_decoder = enable_dav1d_decoder || enable_libgav1_decoder
+  enable_av1_decoder = enable_dav1d_decoder
 
   # Enable HEVC/H265 demuxing. Actual decoding must be provided by the
   # platform.
diff --git a/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h b/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h
index 74ce7e1e..325d42c 100644
--- a/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h
+++ b/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h
@@ -1137,7 +1137,6 @@
       case ::media::VideoDecoderType::kDav1d:
       case ::media::VideoDecoderType::kFuchsia:
       case ::media::VideoDecoderType::kMediaCodec:
-      case ::media::VideoDecoderType::kGav1:
       case ::media::VideoDecoderType::kD3D11:
       case ::media::VideoDecoderType::kBroker:
         return media::stable::mojom::VideoDecoderType::kUnknown;
diff --git a/media/renderers/default_decoder_factory.cc b/media/renderers/default_decoder_factory.cc
index 3ed218de..45a8304 100644
--- a/media/renderers/default_decoder_factory.cc
+++ b/media/renderers/default_decoder_factory.cc
@@ -42,10 +42,6 @@
 #include "media/filters/vpx_video_decoder.h"
 #endif
 
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-#include "media/filters/gav1_video_decoder.h"
-#endif
-
 namespace media {
 
 DefaultDecoderFactory::DefaultDecoderFactory(
@@ -121,18 +117,10 @@
   video_decoders->push_back(std::make_unique<OffloadingVpxVideoDecoder>());
 #endif
 
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-  if (base::FeatureList::IsEnabled(kGav1VideoDecoder)) {
-    video_decoders->push_back(
-        std::make_unique<OffloadingGav1VideoDecoder>(media_log));
-  } else
-#endif  // BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-  {
 #if BUILDFLAG(ENABLE_DAV1D_DECODER)
-    video_decoders->push_back(
-        std::make_unique<OffloadingDav1dVideoDecoder>(media_log));
+  video_decoders->push_back(
+      std::make_unique<OffloadingDav1dVideoDecoder>(media_log));
 #endif
-  }
 
 #if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
   video_decoders->push_back(std::make_unique<FFmpegVideoDecoder>(media_log));
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index 55d2d782..fdba15ac 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -44,10 +44,6 @@
 #include "media/filters/vpx_video_decoder.h"
 #endif
 
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-#include "media/filters/gav1_video_decoder.h"
-#endif
-
 using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::AtLeast;
@@ -74,18 +70,10 @@
   video_decoders.push_back(std::make_unique<OffloadingVpxVideoDecoder>());
 #endif
 
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-  if (base::FeatureList::IsEnabled(kGav1VideoDecoder)) {
-    video_decoders.push_back(
-        std::make_unique<OffloadingGav1VideoDecoder>(media_log));
-  } else
-#endif  // BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-  {
 #if BUILDFLAG(ENABLE_DAV1D_DECODER)
-    video_decoders.push_back(
-        std::make_unique<OffloadingDav1dVideoDecoder>(media_log));
+  video_decoders.push_back(
+      std::make_unique<OffloadingDav1dVideoDecoder>(media_log));
 #endif
-  }
 
 #if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
   video_decoders.push_back(std::make_unique<FFmpegVideoDecoder>(media_log));
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc
index b72bd5b..fa3e7435 100644
--- a/media/video/software_video_encoder_test.cc
+++ b/media/video/software_video_encoder_test.cc
@@ -50,10 +50,6 @@
 #include "media/filters/dav1d_video_decoder.h"
 #endif
 
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-#include "media/filters/gav1_video_decoder.h"
-#endif
-
 namespace media {
 
 struct SwVideoTestParams {
@@ -100,16 +96,9 @@
       decoder_ = std::make_unique<VpxVideoDecoder>();
 #endif
     } else if (codec_ == VideoCodec::kAV1) {
-#if BUILDFLAG(ENABLE_LIBGAV1_DECODER)
-      if (base::FeatureList::IsEnabled(kGav1VideoDecoder)) {
-        decoder_ = std::make_unique<Gav1VideoDecoder>(&media_log_);
-      } else
-#endif
-      {
 #if BUILDFLAG(ENABLE_DAV1D_DECODER)
-        decoder_ = std::make_unique<Dav1dVideoDecoder>(&media_log_);
+      decoder_ = std::make_unique<Dav1dVideoDecoder>(&media_log_);
 #endif
-      }
     }
 
     EXPECT_NE(decoder_, nullptr);
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index aba123f..1d0c571 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@
 #   hash function for preloaded entries again (we have already done so once).
 #
 
-# Last updated: 2022-11-16 12:54 UTC
+# Last updated: 2022-11-17 12:56 UTC
 PinsListTimestamp
-1668603290
+1668689801
 
 TestSPKI
 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 3b739b7..8248d8a 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -212,8 +212,6 @@
 
 #define SK_SUPPORT_LEGACY_AAA_CHOICE
 
-#define SK_LEGACY_RECT_DASHING_BUG
-
 #define SK_SUPPORT_LEGACY_DRAWLOOPER
 
 #define SK_SUPPORT_LEGACY_DITHER
diff --git a/testing/buildbot/chromium.updater.json b/testing/buildbot/chromium.updater.json
index 9b11491..b0243b9 100644
--- a/testing/buildbot/chromium.updater.json
+++ b/testing/buildbot/chromium.updater.json
@@ -5,6 +5,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -28,6 +29,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -56,6 +58,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -79,6 +82,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -107,6 +111,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -130,6 +135,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -158,6 +164,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -181,6 +188,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -209,6 +217,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -232,6 +241,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -260,6 +270,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -283,6 +294,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -311,6 +323,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -334,6 +347,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -362,6 +376,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -385,6 +400,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -413,6 +429,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -436,6 +453,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -464,6 +482,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -487,6 +506,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -515,6 +535,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -540,6 +561,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -569,6 +591,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -594,6 +617,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -623,6 +647,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000",
@@ -649,6 +674,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -677,6 +703,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -702,6 +729,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -731,6 +759,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000",
@@ -757,6 +786,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -785,6 +815,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -810,6 +841,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -839,6 +871,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -863,6 +896,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -891,6 +925,7 @@
     "gtest_tests": [
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
@@ -915,6 +950,7 @@
       },
       {
         "args": [
+          "--gtest_shuffle",
           "--test-launcher-timeout=90000",
           "--ui-test-action-max-timeout=45000",
           "--ui-test-action-timeout=40000"
diff --git a/testing/buildbot/filters/android.emulator_n.gl_tests.filter b/testing/buildbot/filters/android.emulator_n.gl_tests.filter
index 6774a80..b40f143 100644
--- a/testing/buildbot/filters/android.emulator_n.gl_tests.filter
+++ b/testing/buildbot/filters/android.emulator_n.gl_tests.filter
@@ -9,9 +9,5 @@
 # https://crbug.com/1342713
 -GLBGRAMipMapTest.GenerateMipmapsSucceeds
 
-# TODO(crbug.com/1368355)
--Service/GLTextureImageBackingFactoryTest.Basic/AllowPassthrough_BGRA_8888
--Service/GLTextureImageBackingFactoryTest.Basic/DisallowPassthrough_BGRA_8888
--GLTextureImageBackingFactoryTest.Basic/BGRA_8888
--GLTextureImageBackingFactoryWithFormatTest.Basic/BGRA_8888
--GLTextureImageBackingFactoryWithUploadTest.UploadFromMemory/BGRA_8888
+# https://crbug.com/1342713: GL_BGRA_EXT is broken in Android emulator.
+-GLTextureImageBackingFactory*/BGRA_8888
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 4632c9b4..97f58db 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4848,6 +4848,7 @@
     'updater_gtests_mac': {
       'updater_tests': {
         'args': [
+          '--gtest_shuffle',
           # Timeouts based on empirical observations of test runtimes, 2021-07.
           '--test-launcher-timeout=90000',
           '--ui-test-action-max-timeout=45000',
@@ -4856,6 +4857,7 @@
       },
       'updater_tests_system': {
         'args': [
+          '--gtest_shuffle',
           # Timeouts based on empirical observations of test runtimes, 2021-07.
           '--test-launcher-timeout=90000',
           '--ui-test-action-max-timeout=45000',
@@ -4875,6 +4877,7 @@
     'updater_gtests_win': {
       'updater_tests': {
         'args': [
+          '--gtest_shuffle',
           # Timeouts based on empirical observations of test runtimes, 2021-07.
           '--test-launcher-timeout=90000',
           '--ui-test-action-max-timeout=45000',
@@ -4883,6 +4886,7 @@
       },
       'updater_tests_system': {
         'args': [
+          '--gtest_shuffle',
           # Timeouts based on empirical observations of test runtimes, 2021-07.
           '--test-launcher-timeout=90000',
           '--ui-test-action-max-timeout=45000',
@@ -4901,6 +4905,7 @@
     'updater_gtests_win_uac': {
       'updater_tests_system': {
         'args': [
+          '--gtest_shuffle',
           # Timeouts based on empirical observations of test runtimes, 2021-07.
           '--test-launcher-timeout=90000',
           '--ui-test-action-max-timeout=45000',
@@ -4917,6 +4922,7 @@
       },
       'updater_tests_win_uac': {
         'args': [
+          '--gtest_shuffle',
           # Timeouts based on empirical observations of test runtimes, 2021-07.
           '--test-launcher-timeout=90000',
           '--ui-test-action-max-timeout=45000',
diff --git a/third_party/android_sdk/README.chromium b/third_party/android_sdk/README.chromium
index a8ae4c90..1804f73 100644
--- a/third_party/android_sdk/README.chromium
+++ b/third_party/android_sdk/README.chromium
@@ -34,7 +34,7 @@
 * Adding new sdk packages:
   * Prepare the CIPD yaml files for packages in the cipd/ directory.
   * Add them to android-sdk-packager buildbucket configuation file:
-    infra/config/subprojects/chromium/master-only/ci.star
+    infra/config/subprojects/chromium/ci/chromium.packager.star
   * Submit the changes into gerrit (See crrev.com/c/2241994 as a reference)
   * Follow the update instructions to get a build from the CI builder.
 * Updating this file:
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index be2007a9..1596c6548 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1467,7 +1467,7 @@
 // Allow access to WebSQL in non-secure contexts.
 BASE_FEATURE(kWebSQLNonSecureContextAccess,
              "WebSQLNonSecureContextAccess",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 BASE_FEATURE(kFileSystemUrlNavigation,
              "FileSystemUrlNavigation",
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index cab2900..71b3132 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -1153,6 +1153,19 @@
       ]
       traits_headers = [ "//third_party/blink/public/common/messaging/message_port_descriptor_mojom_traits.h" ]
     },
+    {
+      types = [
+        {
+          mojom = "blink.mojom.TaskAttributionId"
+          cpp = "::blink::scheduler::TaskAttributionId"
+          move_only = true
+        },
+      ]
+      traits_headers = [
+        "//third_party/blink/public/common/scheduler/task_attribution_id.h",
+      ]
+      traits_private_headers = [ "//third_party/blink/public/common/messaging/task_attribution_id_mojom_traits.h" ]
+    },
   ]
 
   cpp_typemaps = [
@@ -1197,16 +1210,6 @@
       ]
       traits_private_headers = [ "//third_party/blink/public/common/messaging/transferable_message_mojom_traits.h" ]
     },
-    {
-      types = [
-        {
-          mojom = "blink.mojom.TaskAttributionId"
-          cpp = "::blink::scheduler::TaskAttributionId"
-          move_only = true
-        },
-      ]
-      traits_private_headers = [ "//third_party/blink/public/common/messaging/task_attribution_id_mojom_traits.h" ]
-    },
   ]
   cpp_typemaps += shared_cpp_typemaps
 
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index ebe58f3..32d8bd71 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -46,6 +46,7 @@
 import "third_party/blink/public/mojom/input/scroll_direction.mojom";
 import "third_party/blink/public/mojom/loader/referrer.mojom";
 import "third_party/blink/public/mojom/messaging/delegated_capability.mojom";
+import "third_party/blink/public/mojom/messaging/task_attribution_id.mojom";
 import "third_party/blink/public/mojom/messaging/transferable_message.mojom";
 import "third_party/blink/public/mojom/navigation/navigation_api_history_entry_arrays.mojom";
 import "third_party/blink/public/mojom/opengraph/metadata.mojom";
@@ -320,8 +321,12 @@
   // Tells the browser to navigate back or forward in session history by
   // the given offset (relative to the current position in session
   // history). |has_user_gesture| tells whether or not this is the consequence
-  // of a user action.
-  GoToEntryAtOffset(int32 offset, bool has_user_gesture);
+  // of a user action. |soft_navigation_heuristics_task_id| is the task ID of
+  // the initiator of the navigation, if any. It is restricted to same-document
+  // main-frame navigation initiated by the top-level document.
+  GoToEntryAtOffset(int32 offset,
+                    bool has_user_gesture,
+                    TaskAttributionId? soft_navigation_heuristics_task_id);
 
   // Tells the browser to navigate back or forward in session history to the
   // history entry associated with |key|. |key| is a renderer-generated random
diff --git a/third_party/blink/public/mojom/navigation/navigation_params.mojom b/third_party/blink/public/mojom/navigation/navigation_params.mojom
index 493e7cd..727099f 100644
--- a/third_party/blink/public/mojom/navigation/navigation_params.mojom
+++ b/third_party/blink/public/mojom/navigation/navigation_params.mojom
@@ -22,6 +22,7 @@
 import "third_party/blink/public/mojom/frame/frame_policy.mojom";
 import "third_party/blink/public/mojom/loader/mixed_content.mojom";
 import "third_party/blink/public/mojom/loader/referrer.mojom";
+import "third_party/blink/public/mojom/messaging/task_attribution_id.mojom";
 import "third_party/blink/public/mojom/navigation/navigation_api_history_entry_arrays.mojom";
 import "third_party/blink/public/mojom/navigation/navigation_policy.mojom";
 import "third_party/blink/public/mojom/navigation/prefetched_signed_exchange_info.mojom";
@@ -523,4 +524,9 @@
   // transitions when navigating between same-origin Documents.
   // See https://drafts.csswg.org/css-view-transitions-1/ for details.
   blink.mojom.ViewTransitionState? view_transition_state;
+
+  // If any, the task ID of the initiator of the navigation. This is restricted
+  // to same-document main-frame navigation initiated by the top-level document.
+  // Used by SoftNavigationHeuristics to trace back the chain of events.
+  TaskAttributionId? soft_navigation_heuristic_task_id;
 };
diff --git a/third_party/blink/public/web/web_navigation_control.h b/third_party/blink/public/web/web_navigation_control.h
index 7a7232f..bf7e962 100644
--- a/third_party/blink/public/web/web_navigation_control.h
+++ b/third_party/blink/public/web/web_navigation_control.h
@@ -19,6 +19,9 @@
 class WebURL;
 struct WebNavigationInfo;
 struct WebNavigationParams;
+namespace scheduler {
+class TaskAttributionId;
+}  // namespace scheduler
 
 // This interface gives control to navigation-related functionality of
 // WebLocalFrame. It is separated from WebLocalFrame to give precise control
@@ -54,7 +57,9 @@
       bool is_client_redirect,
       bool has_transient_user_activation,
       const WebSecurityOrigin& initiator_origin,
-      bool is_browser_initiated) = 0;
+      bool is_browser_initiated,
+      absl::optional<scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id) = 0;
 
   // Override the normal rules that determine whether the frame is on the
   // initial empty document or not. Used to propagate state when this frame has
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
index 7f653be..b02279d 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
@@ -533,7 +533,9 @@
     kValidHttp = 6,
     kValidHttps = 7,
     kValidDataURL = 8,
-    kValidOtherProtocol = 9,
+    kValidFileURL = 9,
+    kValidBlob = 10,
+    kValidOtherProtocol = 11,
 
     kMaxValue = kValidOtherProtocol
   };
@@ -587,12 +589,15 @@
   auto protocol_type = WasmStreamingInputType::kNoURL;
   if (const KURL* kurl = response->GetResponse()->Url()) {
     String protocol = kurl->Protocol();
-    // Http and https can be cached; we expect most other protocols to be
-    // "data". Thus track those three protocols.
+    // Http and https can be cached; also track other protocols we expect in
+    // Wasm streaming. If {kValidOtherProtocol} spikes, we should add more enum
+    // values.
     protocol_type = protocol == "http"    ? WasmStreamingInputType::kValidHttp
                     : protocol == "https" ? WasmStreamingInputType::kValidHttps
-                    : protocol == "data"
-                        ? WasmStreamingInputType::kValidDataURL
+                    : protocol == "data" ? WasmStreamingInputType::kValidDataURL
+                    : protocol == "file" ? WasmStreamingInputType::kValidFileURL
+                    : protocol == "blob"
+                        ? WasmStreamingInputType::kValidBlob
                         : WasmStreamingInputType::kValidOtherProtocol;
   }
   base::UmaHistogramEnumeration("V8.WasmStreamingInputType", protocol_type);
diff --git a/third_party/blink/renderer/build/scripts/core/css/css_properties.py b/third_party/blink/renderer/build/scripts/core/css/css_properties.py
index acea01e..26f53d2 100755
--- a/third_party/blink/renderer/build/scripts/core/css/css_properties.py
+++ b/third_party/blink/renderer/build/scripts/core/css/css_properties.py
@@ -127,6 +127,28 @@
         super(PropertyBase, self).__init__()
 
     @property
+    def namespace(self):
+        """The namespace for the generated CSSProperty subclass."""
+        if self.is_shorthand:
+            return 'css_shorthand'
+        # Otherwise, 'self' is a longhand, or a descriptor (which also ends up
+        # in the css_longhand namespace).
+        return 'css_longhand'
+
+    @property
+    def classname(self):
+        """The name of the generated CSSProperty subclass."""
+        return self.name.to_upper_camel_case()
+
+    @property
+    def is_longhand(self):
+        return self.is_property and not self.longhands
+
+    @property
+    def is_shorthand(self):
+        return self.is_property and self.longhands
+
+    @property
     def is_internal(self):
         return self.name.original.startswith('-internal-')
 
@@ -368,10 +390,6 @@
         name = property_.name
         property_.property_id = id_for_css_property(name)
         property_.enum_key = enum_key_for_css_property(name)
-        property_.is_shorthand = \
-                property_.is_property and bool(property_.longhands)
-        property_.is_longhand = \
-                property_.is_property and not property_.is_shorthand
         method_name = property_.name_for_methods
         if not method_name:
             method_name = name.to_upper_camel_case().replace('Webkit', '')
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py b/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py
index 454aaa82..cb68ee0 100755
--- a/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py
+++ b/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_instances.py
@@ -6,18 +6,8 @@
 import json5_generator
 import template_expander
 
-from collections import namedtuple
 from core.css import css_properties
 
-
-class PropertyClassData(
-        namedtuple(
-            'PropertyClassData',
-            'enum_key,enum_value,property_id,classname,namespace_group,filename'
-        )):
-    pass
-
-
 class CSSPropertyInstancesWriter(json5_generator.Writer):
     def __init__(self, json5_file_paths, output_dir):
         super(CSSPropertyInstancesWriter, self).__init__([], output_dir)
@@ -38,45 +28,19 @@
 
         self._css_properties = css_properties.CSSProperties(json5_file_paths)
 
-        properties = self._css_properties.longhands + self._css_properties.shorthands
-        aliases = self._css_properties.aliases
+        self._properties = self._css_properties.longhands + self._css_properties.shorthands
+        self._aliases = self._css_properties.aliases
 
-        # Lists of PropertyClassData.
-        self._property_classes_by_id = list(map(self.get_class, properties))
-        self._alias_classes_by_id = list(map(self.get_class, aliases))
-
-        # Sort by enum value.
-        self._property_classes_by_id.sort(key=lambda t: t.enum_value)
-        self._alias_classes_by_id.sort(key=lambda t: t.enum_value)
-
-    def get_class(self, property_):
-        """Gets the automatically
-        generated class name for a property.
-        Args:
-            property_: A single property from CSSProperties.properties()
-        Returns:
-            The name to use for the property class.
-        """
-        namespace_group = 'Shorthand' if property_.longhands else 'Longhand'
-        return PropertyClassData(
-            enum_key=property_.enum_key,
-            enum_value=property_.enum_value,
-            property_id=property_.property_id,
-            classname=property_.name.to_upper_camel_case(),
-            namespace_group=namespace_group,
-            filename=property_.name.to_snake_case())
-
-    @property
-    def css_properties(self):
-        return self._css_properties
+        self._properties.sort(key=lambda t: t.enum_value)
+        self._aliases.sort(key=lambda t: t.enum_value)
 
     @template_expander.use_jinja(
         'core/css/properties/templates/css_property_instances.h.tmpl')
     def generate_property_instances_header(self):
         return {
             'input_files': self._input_files,
-            'property_classes_by_property_id': self._property_classes_by_id,
-            'alias_classes_by_property_id': self._alias_classes_by_id,
+            'properties': self._properties,
+            'aliases': self._aliases,
         }
 
     @template_expander.use_jinja(
@@ -84,8 +48,8 @@
     def generate_property_instances_implementation(self):
         return {
             'input_files': self._input_files,
-            'property_classes_by_property_id': self._property_classes_by_id,
-            'alias_classes_by_property_id': self._alias_classes_by_id,
+            'properties': self._properties,
+            'aliases': self._aliases,
         }
 
 
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl
index c727bd56..13ebd565 100644
--- a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.cc.tmpl
@@ -15,18 +15,18 @@
 namespace blink {
 namespace {
 
-{% for _, _, property_id, classname, namespace_group, _ in property_classes_by_property_id %}
-static constexpr css_{{namespace_group.lower()}}::{{classname}} property_{{property_id.lower()}};
+{% for property in properties %}
+static constexpr {{property.namespace}}::{{property.classname}} property_{{property.property_id.lower()}};
 {% endfor %}
-{% for _, _, property_id, classname, namespace_group, _ in alias_classes_by_property_id %}
-static constexpr css_{{namespace_group.lower()}}::{{classname}} property_{{property_id.lower()}};
+{% for property in aliases %}
+static constexpr {{property.namespace}}::{{property.classname}} property_{{property.property_id.lower()}};
 {% endfor %}
 
 } // namespace
 
-{% for property_class_data in property_classes_by_property_id %}
-const CSSProperty& Get{{property_class_data.property_id}}() {
-  return property_{{property_class_data.property_id.lower()}};
+{% for property in properties %}
+const CSSProperty& Get{{property.property_id}}() {
+  return property_{{property.property_id.lower()}};
 }
 {% endfor %}
 
@@ -34,9 +34,9 @@
   DCHECK_GT(id, kLastCSSProperty);  // last property id
   DCHECK_LE(id, kLastUnresolvedCSSProperty);  // last unresolved property id
   switch (id) {
-    {% for property_class_data in alias_classes_by_property_id %}
-    case CSSPropertyID::{{property_class_data.enum_key}}:
-      return &property_{{property_class_data.property_id.lower()}};
+    {% for property in aliases %}
+    case CSSPropertyID::{{property.enum_key}}:
+      return &property_{{property.property_id.lower()}};
     {% endfor %}
     default:
       NOTREACHED();
@@ -47,8 +47,8 @@
 const CSSUnresolvedProperty* const kPropertyClasses[] = {
   nullptr,  // kInvalid.
   nullptr,  // kVariable.
-  {% for property_class_data in property_classes_by_property_id %}
-  &property_{{property_class_data.property_id.lower()}},  // {{property_class_data.property_id}}
+  {% for property in properties %}
+  &property_{{property.property_id.lower()}},  // {{property.property_id}}
   {% endfor %}
 };
 
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.h.tmpl b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.h.tmpl
index 44145873..002078d 100644
--- a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_instances.h.tmpl
@@ -18,8 +18,8 @@
 
 const CSSUnresolvedProperty* GetAliasPropertyInternal(CSSPropertyID);
 
-{% for property_class_data in property_classes_by_property_id %}
-CORE_EXPORT const CSSProperty& Get{{property_class_data.property_id}}();
+{% for property in properties %}
+CORE_EXPORT const CSSProperty& Get{{property.property_id}}();
 {% endfor %}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/dom_exception.cc b/third_party/blink/renderer/core/dom/dom_exception.cc
index 9eca533..3d96217 100644
--- a/third_party/blink/renderer/core/dom/dom_exception.cc
+++ b/third_party/blink/renderer/core/dom/dom_exception.cc
@@ -127,6 +127,8 @@
     {DOMExceptionCode::kNotAllowedError, "NotAllowedError",
      "The request is not allowed by the user agent or the platform in the "
      "current context."},
+    {DOMExceptionCode::kOptOutError, "OptOutError",
+     "The user opted out of the process."},
 
     // DOMError (obsolete, not DOMException) defined in File system (obsolete).
     // https://www.w3.org/TR/2012/WD-file-system-api-20120417/
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index ebd12aad..381b1e080 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -2484,24 +2484,27 @@
   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
       item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
       ClientRedirectPolicy::kNotClientRedirect,
-      false /* has_transient_user_activation */, nullptr /* initiator_origin */,
-      false /* is_synchronously_committed */,
+      /*has_transient_user_activation=*/false, /*initiator_origin=*/nullptr,
+      /*is_synchronously_committed=*/false,
       mojom::blink::TriggeringEventInfo::kNotFromEvent,
-      true /* is_browser_initiated */);
+      /*is_browser_initiated=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
       item2->Url(), WebFrameLoadType::kBackForward, item2.Get(),
       ClientRedirectPolicy::kNotClientRedirect,
-      false /* has_transient_user_activation */, nullptr /* initiator_origin */,
-      false /* is_synchronously_committed */,
+      /*has_transient_user_activation=*/false, /*initiator_origin=*/nullptr,
+      /*is_synchronously_committed=*/false,
       mojom::blink::TriggeringEventInfo::kNotFromEvent,
-      true /* is_browser_initiated */);
+      /*is_browser_initiated=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
       item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
       ClientRedirectPolicy::kNotClientRedirect,
-      false /* has_transient_user_activation */, nullptr /* initiator_origin */,
-      false /* is_synchronously_committed */,
+      /*has_transient_user_activation=*/false, /*initiator_origin=*/nullptr,
+      /*is_synchronously_committed=*/false,
       mojom::blink::TriggeringEventInfo::kNotFromEvent,
-      true /* is_browser_initiated */);
+      /*is_browser_initiated=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
       DocumentUpdateReason::kTest);
 
@@ -2520,18 +2523,20 @@
   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
       item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
       ClientRedirectPolicy::kNotClientRedirect,
-      false /* has_transient_user_activation */, nullptr /* initiator_origin */,
-      false /* is_synchronously_committed */,
+      /*has_transient_user_activation=*/false, /*initiator_origin=*/nullptr,
+      /*is_synchronously_committed=*/false,
       mojom::blink::TriggeringEventInfo::kNotFromEvent,
-      true /* is_browser_initiated */);
+      /*is_browser_initiated=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
 
   main_frame_local->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
       item3->Url(), WebFrameLoadType::kBackForward, item3.Get(),
       ClientRedirectPolicy::kNotClientRedirect,
-      false /* has_transient_user_activation */, nullptr /* initiator_origin */,
-      false /* is_synchronously_committed */,
+      /*has_transient_user_activation=*/false, /*initiator_origin=*/nullptr,
+      /*is_synchronously_committed=*/false,
       mojom::blink::TriggeringEventInfo::kNotFromEvent,
-      true /* is_browser_initiated */);
+      /*is_browser_initiated=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   // The scroll offset is only applied via invoking the anchor via the main
   // lifecycle, or a forced layout.
   // TODO(chrishtr): At the moment, WebLocalFrameImpl::GetScrollOffset() does
diff --git a/third_party/blink/renderer/core/frame/history.cc b/third_party/blink/renderer/core/frame/history.cc
index bf413f0..bba55ca 100644
--- a/third_party/blink/renderer/core/frame/history.cc
+++ b/third_party/blink/renderer/core/frame/history.cc
@@ -44,6 +44,7 @@
 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
@@ -226,8 +227,15 @@
     // navigation is committed.
     ReportURLChange(window, script_state,
                     /*url=*/String(""));
+    // Pass the current task ID so it'd be set as the parent task for the future
+    // popstate event.
+    auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
+    absl::optional<scheduler::TaskAttributionId> task_id;
+    if (tracker && script_state->World().IsMainWorld()) {
+      task_id = tracker->RunningTaskAttributionId(script_state);
+    }
     DCHECK(frame->Client());
-    if (frame->Client()->NavigateBackForward(delta)) {
+    if (frame->Client()->NavigateBackForward(delta, task_id)) {
       if (Page* page = frame->GetPage())
         page->HistoryNavigationVirtualTimePauser().PauseVirtualTime();
     }
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 409b6fb..af7732d8 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -921,8 +921,24 @@
 }
 
 void LocalDOMWindow::DispatchPopstateEvent(
-    scoped_refptr<SerializedScriptValue> state_object) {
+    scoped_refptr<SerializedScriptValue> state_object,
+    absl::optional<scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   DCHECK(GetFrame());
+  // This unique_ptr maintains the TaskScope alive for the lifetime of the
+  // method.
+  std::unique_ptr<scheduler::TaskAttributionTracker::TaskScope>
+      task_attribution_scope;
+  if (soft_navigation_heuristics_task_id) {
+    ScriptState* script_state = ToScriptStateForMainWorld(GetFrame());
+    DCHECK(ThreadScheduler::Current());
+    auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
+    if (script_state && tracker) {
+      task_attribution_scope = tracker->CreateTaskScope(
+          script_state, soft_navigation_heuristics_task_id,
+          scheduler::TaskAttributionTracker::TaskScopeType::kPopState);
+    }
+  }
   DispatchEvent(*PopStateEvent::Create(std::move(state_object), history()));
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index b8a26ca..6b79bec0 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -35,6 +35,7 @@
 #include "third_party/blink/public/common/frame/fullscreen_request_token.h"
 #include "third_party/blink/public/common/frame/payment_request_token.h"
 #include "third_party/blink/public/common/metrics/post_message_counter.h"
+#include "third_party/blink/public/common/scheduler/task_attribution_id.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -415,7 +416,9 @@
   void EnqueueDocumentEvent(Event&, TaskType);
   void EnqueueNonPersistedPageshowEvent();
   void EnqueueHashchangeEvent(const String& old_url, const String& new_url);
-  void DispatchPopstateEvent(scoped_refptr<SerializedScriptValue>);
+  void DispatchPopstateEvent(scoped_refptr<SerializedScriptValue>,
+                             absl::optional<scheduler::TaskAttributionId>
+                                 soft_navigation_heuristics_task_id);
   void DispatchWindowLoadEvent();
   void DocumentWasClosed();
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 4c1364e1..248df0e 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -112,6 +112,10 @@
 struct Impression;
 struct MobileFriendliness;
 
+namespace scheduler {
+class TaskAttributionId;
+}  // namespace scheduler
+
 class CORE_EXPORT LocalFrameClient : public FrameClient {
  public:
   ~LocalFrameClient() override = default;
@@ -183,7 +187,10 @@
   virtual void DidStartLoading() = 0;
   virtual void DidStopLoading() = 0;
 
-  virtual bool NavigateBackForward(int offset) const = 0;
+  virtual bool NavigateBackForward(
+      int offset,
+      absl::optional<scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id) const = 0;
 
   virtual void DidDispatchPingLoader(const KURL&) = 0;
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index b311c95..860023bd 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -40,6 +40,7 @@
 #include "mojo/public/cpp/bindings/type_converter.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "third_party/blink/public/common/permissions_policy/permissions_policy.h"
+#include "third_party/blink/public/common/scheduler/task_attribution_id.h"
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
@@ -684,7 +685,10 @@
     web_frame_->Client()->DidStopLoading();
 }
 
-bool LocalFrameClientImpl::NavigateBackForward(int offset) const {
+bool LocalFrameClientImpl::NavigateBackForward(
+    int offset,
+    absl::optional<scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) const {
   WebViewImpl* webview = web_frame_->ViewImpl();
   DCHECK(webview->Client());
   DCHECK(web_frame_->Client());
@@ -698,7 +702,7 @@
   bool has_user_gesture =
       LocalFrame::HasTransientUserActivation(web_frame_->GetFrame());
   web_frame_->GetFrame()->GetLocalFrameHostRemote().GoToEntryAtOffset(
-      offset, has_user_gesture);
+      offset, has_user_gesture, soft_navigation_heuristics_task_id);
   return true;
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index bd5effa..8e634ec 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -140,7 +140,10 @@
   void DispatchWillSendSubmitEvent(HTMLFormElement*) override;
   void DidStartLoading() override;
   void DidStopLoading() override;
-  bool NavigateBackForward(int offset) const override;
+  bool NavigateBackForward(
+      int offset,
+      absl::optional<scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id) const override;
   void DidDispatchPingLoader(const KURL&) override;
   void DidChangePerformanceTiming() override;
   void DidObserveInputDelay(base::TimeDelta) override;
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
index d9a0d5c..3171bdb9 100644
--- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -119,8 +119,7 @@
                                                  ukm::UkmRecorder* recorder)
     : source_id_(source_id),
       recorder_(recorder),
-      clock_(base::DefaultTickClock::GetInstance()),
-      event_name_("Blink.UpdateTime") {
+      clock_(base::DefaultTickClock::GetInstance()) {
   // All of these are assumed to have one entry per sub-metric.
   DCHECK_EQ(std::size(absolute_metric_records_), metrics_data().size());
   DCHECK_EQ(std::size(current_sample_.sub_metrics_counts),
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
index ef0ab5b51..e84ec22 100644
--- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
+++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -388,7 +388,6 @@
   const base::TickClock* clock_;
 
   // Event and metric data
-  const char* const event_name_;
   AbsoluteMetricRecord primary_metric_;
   std::array<AbsoluteMetricRecord, kCount> absolute_metric_records_;
 
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index ace2bde..7df9683 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -8112,7 +8112,8 @@
       false /* has_transient_user_activation */, /*initiator_origin=*/nullptr,
       /*is_synchronously_committed=*/false,
       mojom::blink::TriggeringEventInfo::kNotFromEvent,
-      true /* is_browser_initiated */);
+      /*is_browser_initiated=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   EXPECT_EQ(kWebBackForwardCommit, client.LastCommitType());
 }
 
@@ -13450,8 +13451,10 @@
       ToKURL("about:blank"), nullptr,
       mojom::blink::SameDocumentNavigationType::kHistoryApi, message,
       WebFrameLoadType::kReplaceCurrentItem,
-      frame->DomWindow()->GetSecurityOrigin(), false /* is_browser_initiated */,
-      true /* is_synchronously_committed */);
+      frame->DomWindow()->GetSecurityOrigin(),
+      /*is_browser_initiated=*/false,
+      /*is_synchronously_committed=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   // The bucket index corresponds to the definition of
   // |SinglePageAppNavigationType|.
   tester.ExpectBucketCount(histogramName,
@@ -13460,15 +13463,19 @@
       ToKURL("about:blank"), MakeGarbageCollected<HistoryItem>(),
       mojom::blink::SameDocumentNavigationType::kFragment, message,
       WebFrameLoadType::kBackForward, frame->DomWindow()->GetSecurityOrigin(),
-      false /* is_browser_initiated */, true /* is_synchronously_committed */);
+      /*is_browser_initiated=*/false,
+      /*is_synchronously_committed=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   tester.ExpectBucketCount(histogramName,
                            kSPANavTypeSameDocumentBackwardOrForward, 1);
   document_loader.UpdateForSameDocumentNavigation(
       ToKURL("about:blank"), nullptr,
       mojom::blink::SameDocumentNavigationType::kFragment, message,
       WebFrameLoadType::kReplaceCurrentItem,
-      frame->DomWindow()->GetSecurityOrigin(), false /* is_browser_initiated */,
-      true /* is_synchronously_committed */);
+      frame->DomWindow()->GetSecurityOrigin(),
+      /*is_browser_initiated=*/false,
+      /*is_synchronously_committed=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
   tester.ExpectBucketCount(histogramName, kSPANavTypeOtherFragmentNavigation,
                            1);
   // mojom::blink::SameDocumentNavigationType::kHistoryApi and
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index c99f8b32..ef22f42 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2660,7 +2660,9 @@
     bool is_client_redirect,
     bool has_transient_user_activation,
     const WebSecurityOrigin& initiator_origin,
-    bool is_browser_initiated) {
+    bool is_browser_initiated,
+    absl::optional<scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   DCHECK(GetFrame());
   DCHECK(!url.ProtocolIs("javascript"));
 
@@ -2671,7 +2673,8 @@
                          : ClientRedirectPolicy::kNotClientRedirect,
       has_transient_user_activation, initiator_origin.Get(),
       /*is_synchronously_committed=*/false,
-      mojom::blink::TriggeringEventInfo::kNotFromEvent, is_browser_initiated);
+      mojom::blink::TriggeringEventInfo::kNotFromEvent, is_browser_initiated,
+      soft_navigation_heuristics_task_id);
 }
 
 bool WebLocalFrameImpl::IsLoading() const {
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 928dc0cd..cc6ffed3 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -376,7 +376,9 @@
       bool is_client_redirect,
       bool has_transient_user_activation,
       const WebSecurityOrigin& initiator_origin,
-      bool is_browser_initiated) override;
+      bool is_browser_initiated,
+      absl::optional<scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id) override;
   void SetIsNotOnInitialEmptyDocument() override;
   bool IsOnInitialEmptyDocument() override;
   void WillPotentiallyStartNavigation(const WebURL&) const override;
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc b/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
index 2d8a61b..d2071ebe 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
@@ -320,9 +320,10 @@
   main_frame->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
       item1->Url(), WebFrameLoadType::kBackForward, item1.Get(),
       ClientRedirectPolicy::kNotClientRedirect,
-      false /* has_transient_user_activation */, nullptr /* initiator_origin */,
-      false /* is_synchronously_committed */,
-      mojom::blink::TriggeringEventInfo::kNotFromEvent, is_browser_initiated);
+      /*has_transient_user_activation=*/false, /*initiator_origin=*/nullptr,
+      /*is_synchronously_committed=*/false,
+      mojom::blink::TriggeringEventInfo::kNotFromEvent, is_browser_initiated,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
 
   Compositor().BeginFrame();
   test::RunPendingTasks();
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
index 2edf151..ebc00133 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -260,7 +260,7 @@
   // items, we could end up with an incorrect static position.
   if (UNLIKELY(InvolvedInBlockFragmentation(container_builder_))) {
     should_process_block_end = !container_builder_.DidBreakSelf() &&
-                               !container_builder_.HasChildBreakInside();
+                               !container_builder_.ShouldBreakInside();
     if (should_process_block_end) {
       // Recompute the total block size in case |total_intrinsic_block_size_|
       // changed as a result of fragmentation.
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index e8edb9a..d0c89f0 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -3535,7 +3535,7 @@
   bool should_process_block_end = true;
   if (UNLIKELY(InvolvedInBlockFragmentation(container_builder_))) {
     should_process_block_end = !container_builder_.DidBreakSelf() &&
-                               !container_builder_.HasChildBreakInside();
+                               !container_builder_.ShouldBreakInside();
   }
 
   const auto& node = Node();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index bda074726..ec0f303 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -656,7 +656,8 @@
       DCHECK(!container_builder_.FoundColumnSpanner());
       DCHECK(!IsBreakInside(To<NGBlockBreakToken>(child_break_token)));
 
-      if (container_builder_.HasChildBreakInside()) {
+      if (ConstraintSpace().IsPastBreak() ||
+          container_builder_.HasInsertedChildBreak()) {
         // Something broke inside (typically in a parallel flow, or we wouldn't
         // be here). Before we can handle the spanner, we need to finish what
         // comes before it.
@@ -2777,6 +2778,15 @@
     SetupSpaceBuilderForFragmentation(
         ConstraintSpace(), child, fragmentainer_offset_delta, &builder,
         is_new_fc, container_builder_.RequiresContentBeforeBreaking());
+
+    // If there's a child break inside (typically in a parallel flow, or we
+    // would have finished layout by now), we need to produce more
+    // fragmentainers, before we can insert any column spanners, so that
+    // everything that is supposed to come before the spanner actually ends up
+    // there.
+    if (ConstraintSpace().IsPastBreak() ||
+        container_builder_.HasInsertedChildBreak())
+      builder.SetIsPastBreak();
   }
 
   return builder.ToConstraintSpace();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 22de5be..f3333a7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -542,7 +542,7 @@
     if (!break_token_) {
       if (last_inline_break_token_)
         child_break_tokens_.push_back(std::move(last_inline_break_token_));
-      if (DidBreakSelf() || HasChildBreakInside())
+      if (DidBreakSelf() || ShouldBreakInside())
         break_token_ = NGBlockBreakToken::Create(this);
     }
 
@@ -700,7 +700,7 @@
 #if DCHECK_IS_ON()
 
 void NGBoxFragmentBuilder::CheckNoBlockFragmentation() const {
-  DCHECK(!HasChildBreakInside());
+  DCHECK(!ShouldBreakInside());
   DCHECK(!HasInflowChildBreakInside());
   DCHECK(!DidBreakSelf());
   DCHECK(!has_forced_break_);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 2d57fac..9557194 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -343,22 +343,31 @@
     return previous_break_token_;
   }
 
-  // Return true if we need to break before or inside any child, doesn't matter
-  // if it's in-flow or not. As long as there are only breaks in parallel flows,
-  // we may continue layout, but when we're done, we'll need to create a break
+  // Return true if a break has been inserted, doesn't matter if it's in the
+  // same flow or not. As long as there are only breaks in parallel flows, we
+  // may continue layout, but when we're done, we'll need to create a break
   // token for this fragment nevertheless, so that we re-enter, descend and
   // resume at the broken children in the next fragmentainer.
-  bool HasChildBreakInside() const {
-    if (!child_break_tokens_.empty()) {
-      for (const NGBreakToken* child_token : child_break_tokens_) {
-        const auto* block_child_token =
-            DynamicTo<NGBlockBreakToken>(child_token);
-        if (!block_child_token || !block_child_token->IsRepeated())
-          return true;
-      }
+  bool HasInsertedChildBreak() const {
+    if (child_break_tokens_.empty())
+      return false;
+    for (const NGBreakToken* child_token : child_break_tokens_) {
+      const auto* block_child_token = DynamicTo<NGBlockBreakToken>(child_token);
+      if (!block_child_token || !block_child_token->IsRepeated())
+        return true;
     }
-    // Inline nodes produce a "finished" trailing break token even if we don't
-    // need to block-fragment.
+    return false;
+  }
+
+  // Return true if we need to break inside this node, the way things are
+  // currently looking. This should only be called at the end of layout, right
+  // before creating a fragment.
+  bool ShouldBreakInside() const {
+    if (HasInsertedChildBreak())
+      return true;
+    // If there's an outgoing inline break-token at this point, and we're about
+    // to finish layout, it means that inline layout needs to continue in the
+    // next fragmentianer.
     if (last_inline_break_token_)
       return true;
     // Grid layout doesn't insert break before tokens, and instead set this bit
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 277eb8c..31241b2 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -580,6 +580,12 @@
     return HasRareData() && rare_data_->is_in_column_bfc;
   }
 
+  // True if there's a preceding break in the current fragmentainer (typically a
+  // break in a parallel flow, or we wouldn't attempt to keep laying out).
+  bool IsPastBreak() const {
+    return HasRareData() && rare_data_->is_past_break;
+  }
+
   // Return true if we would be at least our intrinsic block-size.
   //
   // During fragmentation we may have a stretch block-size (or similar) set,
@@ -890,6 +896,7 @@
           is_inside_balanced_columns(false),
           should_ignore_forced_breaks(false),
           is_in_column_bfc(false),
+          is_past_break(false),
           min_block_size_should_encompass_intrinsic_size(false),
           has_override_min_max_block_sizes(false),
           min_break_appeal(kBreakAppealLastResort),
@@ -922,6 +929,7 @@
           is_inside_balanced_columns(other.is_inside_balanced_columns),
           should_ignore_forced_breaks(other.should_ignore_forced_breaks),
           is_in_column_bfc(other.is_in_column_bfc),
+          is_past_break(other.is_past_break),
           min_block_size_should_encompass_intrinsic_size(
               other.min_block_size_should_encompass_intrinsic_size),
           has_override_min_max_block_sizes(
@@ -1006,6 +1014,7 @@
           is_inside_balanced_columns != other.is_inside_balanced_columns ||
           should_ignore_forced_breaks != other.should_ignore_forced_breaks ||
           is_in_column_bfc != other.is_in_column_bfc ||
+          is_past_break != other.is_past_break ||
           min_break_appeal != other.min_break_appeal ||
           propagate_child_break_values != other.propagate_child_break_values ||
           should_repeat != other.should_repeat ||
@@ -1043,7 +1052,7 @@
           block_direction_fragmentation_type != kFragmentNone ||
           is_block_fragmentation_forced_off ||
           requires_content_before_breaking || is_inside_balanced_columns ||
-          should_ignore_forced_breaks || is_in_column_bfc ||
+          should_ignore_forced_breaks || is_in_column_bfc || is_past_break ||
           min_break_appeal != kBreakAppealLastResort ||
           propagate_child_break_values || is_at_fragmentainer_start ||
           should_repeat || is_inside_repeatable_content)
@@ -1334,6 +1343,7 @@
     unsigned is_inside_balanced_columns : 1;
     unsigned should_ignore_forced_breaks : 1;
     unsigned is_in_column_bfc : 1;
+    unsigned is_past_break : 1;
     unsigned min_block_size_should_encompass_intrinsic_size : 1;
     unsigned has_override_min_max_block_sizes : 1;
     unsigned min_break_appeal : kNGBreakAppealBitsNeeded;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index f17a31b..247cb9c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -250,6 +250,8 @@
 
   void SetIsInColumnBfc() { space_.EnsureRareData()->is_in_column_bfc = true; }
 
+  void SetIsPastBreak() { space_.EnsureRareData()->is_past_break = true; }
+
   void SetMinBlockSizeShouldEncompassIntrinsicSize() {
     space_.EnsureRareData()->min_block_size_should_encompass_intrinsic_size =
         true;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index 0567157..fcd17cc9 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -532,12 +532,12 @@
     return NGBreakStatus::kContinue;
   }
 
-  if (builder->HasChildBreakInside()) {
-    // We broke before or inside one of our children. Even if we fit within the
-    // remaining space, and even if the child involved in the break were to be
-    // in a parallel flow, we still need to prepare a break token for this node,
-    // so that we can resume layout of its broken or unstarted children in the
-    // next fragmentainer.
+  if (builder->ShouldBreakInside()) {
+    // We need to break before or inside one of our children (or have already
+    // done so). Even if we fit within the remaining space, and even if the
+    // child involved in the break were to be in a parallel flow, we still need
+    // to prepare a break token for this node, so that we can resume layout of
+    // its broken or unstarted children in the next fragmentainer.
     //
     // If we're at the end of the node, we need to mark the outgoing break token
     // as such. This is a way for the parent algorithm to determine whether we
@@ -564,8 +564,7 @@
       // at the end. If block-size is unconstrained (or at least allowed to grow
       // a bit more), we're only at the end if no in-flow content inside broke.
       if (!was_broken_by_child || builder->IsKnownToFitInFragmentainer()) {
-        if (node.HasNonVisibleBlockOverflow() &&
-            builder->HasChildBreakInside()) {
+        if (node.HasNonVisibleBlockOverflow() && builder->ShouldBreakInside()) {
           // We have reached the end of a fragmentable node that clips overflow
           // in the block direction. If something broke inside at this point, we
           // need to relayout without fragmentation, so that we don't generate
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 2cfb632..2aec75c 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -818,7 +818,7 @@
   UpdateForSameDocumentNavigation(
       new_url, history_item, same_document_navigation_type, std::move(data),
       type, frame_->DomWindow()->GetSecurityOrigin(), is_browser_initiated,
-      is_synchronously_committed);
+      is_synchronously_committed, absl::nullopt);
 }
 
 void DocumentLoader::UpdateForSameDocumentNavigation(
@@ -829,7 +829,9 @@
     WebFrameLoadType type,
     const SecurityOrigin* initiator_origin,
     bool is_browser_initiated,
-    bool is_synchronously_committed) {
+    bool is_synchronously_committed,
+    absl::optional<scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   DCHECK_EQ(IsBackForwardLoadType(type), !!history_item);
 
   if (frame_->IsMainFrame() && type == WebFrameLoadType::kBackForward) {
@@ -945,7 +947,8 @@
       scoped_refptr<SerializedScriptValue> state_object =
           history_item ? history_item->StateObject()
                        : SerializedScriptValue::NullValue();
-      frame_->DomWindow()->DispatchPopstateEvent(std::move(state_object));
+      frame_->DomWindow()->DispatchPopstateEvent(
+          std::move(state_object), soft_navigation_heuristics_task_id);
     }
   }
 }
@@ -1393,7 +1396,9 @@
     const SecurityOrigin* initiator_origin,
     bool is_synchronously_committed,
     mojom::blink::TriggeringEventInfo triggering_event_info,
-    bool is_browser_initiated) {
+    bool is_browser_initiated,
+    absl::optional<scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   DCHECK(!IsReloadLoadType(frame_load_type));
   DCHECK(frame_->GetDocument());
   DCHECK(!is_browser_initiated || !is_synchronously_committed);
@@ -1476,7 +1481,8 @@
                 WrapPersistent(history_item), same_document_navigation_type,
                 client_redirect_policy, has_transient_user_activation,
                 WTF::RetainedRef(initiator_origin), is_browser_initiated,
-                is_synchronously_committed, triggering_event_info));
+                is_synchronously_committed, triggering_event_info,
+                soft_navigation_heuristics_task_id));
   } else {
     // Treat a navigation to the same url as replacing only if it did not
     // originate from a cross-origin iframe. If |is_synchronously_committed| is
@@ -1488,8 +1494,8 @@
     CommitSameDocumentNavigationInternal(
         url, frame_load_type, history_item, same_document_navigation_type,
         client_redirect_policy, has_transient_user_activation, initiator_origin,
-        is_browser_initiated, is_synchronously_committed,
-        triggering_event_info);
+        is_browser_initiated, is_synchronously_committed, triggering_event_info,
+        soft_navigation_heuristics_task_id);
   }
   return mojom::CommitResult::Ok;
 }
@@ -1504,7 +1510,9 @@
     const SecurityOrigin* initiator_origin,
     bool is_browser_initiated,
     bool is_synchronously_committed,
-    mojom::blink::TriggeringEventInfo triggering_event_info) {
+    mojom::blink::TriggeringEventInfo triggering_event_info,
+    absl::optional<scheduler::TaskAttributionId>
+        soft_navigation_heuristics_task_id) {
   // If this function was scheduled to run asynchronously, this DocumentLoader
   // might have been detached before the task ran.
   if (!frame_)
@@ -1558,7 +1566,7 @@
   UpdateForSameDocumentNavigation(
       url, history_item, same_document_navigation_type, nullptr,
       frame_load_type, initiator_origin, is_browser_initiated,
-      is_synchronously_committed);
+      is_synchronously_committed, soft_navigation_heuristics_task_id);
   if (!frame_)
     return;
 
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index a8dae2c..9e53223a 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -109,9 +109,12 @@
 class SubresourceFilter;
 class WebServiceWorkerNetworkProvider;
 
+namespace scheduler {
+class TaskAttributionId;
+}  // namespace scheduler
 namespace mojom {
 enum class CommitResult : int32_t;
-}
+}  // namespace mojom
 
 namespace {
 struct SameSizeAsDocumentLoader;
@@ -232,14 +235,17 @@
 
   // |is_synchronously_committed| is described in comment for
   // CommitSameDocumentNavigation.
-  void UpdateForSameDocumentNavigation(const KURL&,
-                                       HistoryItem*,
-                                       mojom::blink::SameDocumentNavigationType,
-                                       scoped_refptr<SerializedScriptValue>,
-                                       WebFrameLoadType,
-                                       const SecurityOrigin* initiator_origin,
-                                       bool is_browser_initiated,
-                                       bool is_synchronously_committed);
+  void UpdateForSameDocumentNavigation(
+      const KURL&,
+      HistoryItem*,
+      mojom::blink::SameDocumentNavigationType,
+      scoped_refptr<SerializedScriptValue>,
+      WebFrameLoadType,
+      const SecurityOrigin* initiator_origin,
+      bool is_browser_initiated,
+      bool is_synchronously_committed,
+      absl::optional<scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id);
 
   const ResourceResponse& GetResponse() const { return response_; }
 
@@ -287,7 +293,9 @@
       const SecurityOrigin* initiator_origin,
       bool is_synchronously_committed,
       mojom::blink::TriggeringEventInfo,
-      bool is_browser_initiated);
+      bool is_browser_initiated,
+      absl::optional<scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id);
 
   void SetDefersLoading(LoaderFreezeMode);
 
@@ -506,7 +514,9 @@
       const SecurityOrigin* initiator_origin,
       bool is_browser_initiated,
       bool is_synchronously_committed,
-      mojom::blink::TriggeringEventInfo);
+      mojom::blink::TriggeringEventInfo,
+      absl::optional<scheduler::TaskAttributionId>
+          soft_navigation_heuristics_task_id);
 
   // Use these method only where it's guaranteed that |m_frame| hasn't been
   // cleared.
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index f876e56..ae991172 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -39,6 +39,7 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/common/input/web_menu_source_type.h"
+#include "third_party/blink/public/common/scheduler/task_attribution_id.h"
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom-blink.h"
 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
@@ -328,7 +329,11 @@
 
   void TransitionToCommittedForNewPage() override {}
 
-  bool NavigateBackForward(int offset) const override { return false; }
+  bool NavigateBackForward(
+      int offset,
+      absl::optional<scheduler::TaskAttributionId>) const override {
+    return false;
+  }
   void DidDispatchPingLoader(const KURL&) override {}
   void SelectorMatchChanged(const Vector<String>&,
                             const Vector<String>&) override {}
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index fc698cfa8..590994f 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -680,7 +680,8 @@
                                       IsOnInitialEmptyDocument()),
         resource_request.HasUserGesture(), origin_window->GetSecurityOrigin(),
         /*is_synchronously_committed=*/true, request.GetTriggeringEventInfo(),
-        false /* is_browser_initiated */);
+        /*is_browser_initiated=*/false,
+        /*soft_navigation_heuristics_task_id=*/absl::nullopt);
     return;
   }
 
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
index 4d0e1a8..fbc613f9 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -25,6 +25,7 @@
 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
 #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/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "ui/gfx/geometry/size.h"
 #include "v8/include/v8.h"
@@ -691,6 +692,12 @@
   return Url().ProtocolIsData();
 }
 
+AtomicString ImageResourceContent::MediaType() const {
+  if (!image_)
+    return AtomicString();
+  return AtomicString(image_->FilenameExtension());
+}
+
 base::TimeTicks ImageResourceContent::LoadResponseEnd() const {
   return info_->LoadResponseEnd();
 }
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.h b/third_party/blink/renderer/core/loader/resource/image_resource_content.h
index 5e38e14..09e1524 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_content.h
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.h
@@ -136,6 +136,7 @@
   // Redirecting methods to Resource.
   const KURL& Url() const override;
   bool IsDataUrl() const override;
+  AtomicString MediaType() const override;
   base::TimeTicks LoadResponseEnd() const;
   bool IsAccessAllowed() const;
   const ResourceResponse& GetResponse() const;
diff --git a/third_party/blink/renderer/core/loader/resource/video_timing.h b/third_party/blink/renderer/core/loader/resource/video_timing.h
index ff744ea8..3b20c26 100644
--- a/third_party/blink/renderer/core/loader/resource/video_timing.h
+++ b/third_party/blink/renderer/core/loader/resource/video_timing.h
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/loader/fetch/media_timing.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
 namespace blink {
 
@@ -25,6 +26,7 @@
   const KURL& Url() const override { return url_; }
   // TODO: Detect data URLs in video elements.
   bool IsDataUrl() const override { return false; }
+  AtomicString MediaType() const override { return AtomicString("video"); }
 
   void SetIsSufficientContentLoadedForPaint() override { is_loaded_ = true; }
   bool IsSufficientContentLoadedForPaint() const override { return is_loaded_; }
diff --git a/third_party/blink/renderer/core/navigation_api/navigation_api_test.cc b/third_party/blink/renderer/core/navigation_api/navigation_api_test.cc
index 8cfba50..bef09df 100644
--- a/third_party/blink/renderer/core/navigation_api/navigation_api_test.cc
+++ b/third_party/blink/renderer/core/navigation_api/navigation_api_test.cc
@@ -76,10 +76,11 @@
   auto result = frame_loader.GetDocumentLoader()->CommitSameDocumentNavigation(
       item->Url(), WebFrameLoadType::kBackForward, item,
       ClientRedirectPolicy::kNotClientRedirect,
-      false /* has_transient_user_activation */, nullptr /* initiator_origin */,
-      false /* is_synchronously_committed */,
+      /*has_transient_user_activation=*/false, /*initiator_origin=*/nullptr,
+      /*is_synchronously_committed=*/false,
       mojom::blink::TriggeringEventInfo::kNotFromEvent,
-      true /* is_browser_initiated */);
+      /*is_browser_initiated=*/true,
+      /*soft_navigation_heuristics_task_id=*/absl::nullopt);
 
   EXPECT_EQ(result, mojom::blink::CommitResult::Ok);
 }
diff --git a/third_party/blink/renderer/core/paint/image_painter.cc b/third_party/blink/renderer/core/paint/image_painter.cc
index 8e9efbba..4dabe74 100644
--- a/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/third_party/blink/renderer/core/paint/image_painter.cc
@@ -86,8 +86,8 @@
   }
   return ImagePaintTimingInfo(PaintTimingDetector::NotifyImagePaint(
       layout_image, image.Size(), *image_content,
-      context.GetPaintController().CurrentPaintChunkProperties(), image_border,
-      image_content->GetImage()->FilenameExtension()));
+      context.GetPaintController().CurrentPaintChunkProperties(),
+      image_border));
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/paint/svg_image_painter.cc b/third_party/blink/renderer/core/paint/svg_image_painter.cc
index 96f75a6..ed3a221c 100644
--- a/third_party/blink/renderer/core/paint/svg_image_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_image_painter.cc
@@ -34,8 +34,8 @@
     const gfx::Rect& image_border) {
   return ImagePaintTimingInfo(PaintTimingDetector::NotifyImagePaint(
       layout_image, image.Size(), *image_content,
-      context.GetPaintController().CurrentPaintChunkProperties(), image_border,
-      image_content->GetImage()->FilenameExtension()));
+      context.GetPaintController().CurrentPaintChunkProperties(),
+      image_border));
 }
 }  // namespace
 
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
index 4404384..8e0255b 100644
--- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
@@ -294,8 +294,7 @@
     const MediaTiming& media_timing,
     const PropertyTreeStateOrAlias& current_paint_chunk_properties,
     const StyleFetchedImage* style_image,
-    const gfx::Rect& image_border,
-    const String& media_type) {
+    const gfx::Rect& image_border) {
   Node* node = object.GetNode();
 
   if (!node)
@@ -321,7 +320,7 @@
           image_border, mapped_visual_rect, intrinsic_size,
           current_paint_chunk_properties, object, media_timing);
       records_manager_.MaybeUpdateLargestIgnoredImage(
-          record_id, rect_size, media_type, image_border, mapped_visual_rect);
+          record_id, rect_size, image_border, mapped_visual_rect);
     }
     return false;
   }
@@ -365,7 +364,7 @@
                    : 0.0;
 
   bool added_pending = records_manager_.RecordFirstPaintAndReturnIsPending(
-      record_id, rect_size, media_type, image_border, mapped_visual_rect, bpp);
+      record_id, rect_size, image_border, mapped_visual_rect, bpp);
   if (!added_pending)
     return false;
 
@@ -523,14 +522,13 @@
 void ImageRecordsManager::MaybeUpdateLargestIgnoredImage(
     const RecordId& record_id,
     const uint64_t& visual_size,
-    const String& media_type,
     const gfx::Rect& frame_visual_rect,
     const gfx::RectF& root_visual_rect) {
   if (visual_size && (!largest_ignored_image_ ||
                       visual_size > largest_ignored_image_->recorded_size)) {
     largest_ignored_image_ =
         CreateImageRecord(*record_id.first, record_id.second, visual_size,
-                          media_type, frame_visual_rect, root_visual_rect);
+                          frame_visual_rect, root_visual_rect);
     largest_ignored_image_->load_time = base::TimeTicks::Now();
   }
 }
@@ -538,7 +536,6 @@
 bool ImageRecordsManager::RecordFirstPaintAndReturnIsPending(
     const RecordId& record_id,
     const uint64_t& visual_size,
-    const String& media_type,
     const gfx::Rect& frame_visual_rect,
     const gfx::RectF& root_visual_rect,
     double bpp) {
@@ -561,7 +558,7 @@
 
   std::unique_ptr<ImageRecord> record =
       CreateImageRecord(*record_id.first, record_id.second, visual_size,
-                        media_type, frame_visual_rect, root_visual_rect);
+                        frame_visual_rect, root_visual_rect);
   size_ordered_set_.insert(record->AsWeakPtr());
   pending_images_.insert(record_id, std::move(record));
   return true;
@@ -571,15 +568,13 @@
     const LayoutObject& object,
     const MediaTiming* media_timing,
     const uint64_t& visual_size,
-    const String& media_type,
     const gfx::Rect& frame_visual_rect,
     const gfx::RectF& root_visual_rect) {
   DCHECK_GT(visual_size, 0u);
   Node* node = object.GetNode();
   DOMNodeId node_id = DOMNodeIds::IdForNode(node);
   std::unique_ptr<ImageRecord> record = std::make_unique<ImageRecord>(
-      node_id, media_timing, visual_size, media_type, frame_visual_rect,
-      root_visual_rect);
+      node_id, media_timing, visual_size, frame_visual_rect, root_visual_rect);
   return record;
 }
 
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
index 08e693c..5255000 100644
--- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
@@ -38,13 +38,11 @@
   ImageRecord(DOMNodeId new_node_id,
               const MediaTiming* new_media_timing,
               uint64_t new_recorded_size,
-              const String& media_type,
               const gfx::Rect& frame_visual_rect,
               const gfx::RectF& root_visual_rect)
       : node_id(new_node_id),
         media_timing(new_media_timing),
-        recorded_size(new_recorded_size),
-        media_type_(media_type) {
+        recorded_size(new_recorded_size) {
     static unsigned next_insertion_index_ = 1;
     insertion_index = next_insertion_index_++;
     if (PaintTimingVisualizer::IsTracingEnabled()) {
@@ -85,10 +83,6 @@
   // Images that come from origin-dirty styles should have some limitations on
   // what they report.
   bool origin_clean = true;
-
-  // The string representation of the type of the decoded content as returned
-  // by Image::FilenameExtension().
-  String media_type_;
 };
 
 typedef std::pair<const LayoutObject*, const MediaTiming*> RecordId;
@@ -131,7 +125,6 @@
   // Returns whether an image was added to |pending_images_|.
   bool RecordFirstPaintAndReturnIsPending(const RecordId& record_id,
                                           const uint64_t& visual_size,
-                                          const String& media_type,
                                           const gfx::Rect& frame_visual_rect,
                                           const gfx::RectF& root_visual_rect,
                                           double bpp);
@@ -165,7 +158,6 @@
   // larger size.
   void MaybeUpdateLargestIgnoredImage(const RecordId&,
                                       const uint64_t& visual_size,
-                                      const String& media_type,
                                       const gfx::Rect& frame_visual_rect,
                                       const gfx::RectF& root_visual_rect);
   void ReportLargestIgnoredImage(unsigned current_frame_index);
@@ -184,7 +176,6 @@
       const LayoutObject& object,
       const MediaTiming* media_timing,
       const uint64_t& visual_size,
-      const String& media_type,
       const gfx::Rect& frame_visual_rect,
       const gfx::RectF& root_visual_rect);
   inline void QueueToMeasurePaintTime(const RecordId& record_id,
@@ -273,8 +264,7 @@
                    const MediaTiming&,
                    const PropertyTreeStateOrAlias& current_paint_properties,
                    const StyleFetchedImage*,
-                   const gfx::Rect& image_border,
-                   const String& media_type);
+                   const gfx::Rect& image_border);
   void NotifyImageFinished(const LayoutObject&, const MediaTiming*);
   void OnPaintFinished();
   void NotifyImageRemoved(const LayoutObject&, const MediaTiming*);
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
index 0be550b..64c9455 100644
--- a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
@@ -66,12 +66,12 @@
 }
 
 LargestContentfulPaintType GetLargestContentfulPaintTypeFromString(
-    const String& type_string) {
+    const AtomicString& type_string) {
   if (type_string.empty())
     return LargestContentfulPaintType::kNone;
 
   using LargestContentfulPaintTypeMap =
-      HashMap<String, LargestContentfulPaintType>;
+      HashMap<AtomicString, LargestContentfulPaintType>;
 
   DEFINE_STATIC_LOCAL(LargestContentfulPaintTypeMap,
                       largest_contentful_paint_type_map,
@@ -161,8 +161,7 @@
 
   return image_paint_timing_detector.RecordImage(
       *object, image.Size(), *cached_image, current_paint_chunk_properties,
-      &style_image, image_border,
-      cached_image->GetImage()->FilenameExtension());
+      &style_image, image_border);
 }
 
 // static
@@ -171,8 +170,7 @@
     const gfx::Size& intrinsic_size,
     const MediaTiming& media_timing,
     const PropertyTreeStateOrAlias& current_paint_chunk_properties,
-    const gfx::Rect& image_border,
-    const String& media_type) {
+    const gfx::Rect& image_border) {
   if (IgnorePaintTimingScope::ShouldIgnore())
     return false;
   LocalFrameView* frame_view = object.GetFrameView();
@@ -185,7 +183,7 @@
 
   return image_paint_timing_detector.RecordImage(
       object, intrinsic_size, media_timing, current_paint_chunk_properties,
-      nullptr, image_border, media_type);
+      nullptr, image_border);
 }
 
 void PaintTimingDetector::NotifyImageFinished(const LayoutObject& object,
@@ -324,7 +322,8 @@
 
       // Set specific type of the image.
       lcp_details_.largest_contentful_paint_type_ |=
-          GetLargestContentfulPaintTypeFromString(image_record->media_type_);
+          GetLargestContentfulPaintTypeFromString(
+              image_record->media_timing->MediaType());
 
       // Set DataURI type.
       if (image_record->media_timing->IsDataUrl()) {
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h
index 79c4781..16d05c1 100644
--- a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.h
@@ -154,8 +154,7 @@
       const gfx::Size& intrinsic_size,
       const MediaTiming& media_timing,
       const PropertyTreeStateOrAlias& current_paint_chunk_properties,
-      const gfx::Rect& image_border,
-      const String& media_type = "");
+      const gfx::Rect& image_border);
   inline static void NotifyTextPaint(const gfx::Rect& text_visual_rect);
 
   void NotifyImageFinished(const LayoutObject&, const MediaTiming*);
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
index e1cdddf..01ff4b57 100644
--- a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
+++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
@@ -100,8 +100,10 @@
 
 void FakeLocalFrameHost::DispatchLoad() {}
 
-void FakeLocalFrameHost::GoToEntryAtOffset(int32_t offset,
-                                           bool has_user_gesture) {}
+void FakeLocalFrameHost::GoToEntryAtOffset(
+    int32_t offset,
+    bool has_user_gesture,
+    absl::optional<blink::scheduler::TaskAttributionId>) {}
 
 void FakeLocalFrameHost::UpdateTitle(
     const WTF::String& title,
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.h b/third_party/blink/renderer/core/testing/fake_local_frame_host.h
index 856e3db3..05f4842 100644
--- a/third_party/blink/renderer/core/testing/fake_local_frame_host.h
+++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.h
@@ -72,7 +72,10 @@
   void DidChangeLoadProgress(double load_progress) override;
   void DidFinishLoad(const KURL& validated_url) override;
   void DispatchLoad() override;
-  void GoToEntryAtOffset(int32_t offset, bool has_user_gesture) override;
+  void GoToEntryAtOffset(
+      int32_t offset,
+      bool has_user_gesture,
+      absl::optional<blink::scheduler::TaskAttributionId>) override;
   void NavigateToNavigationApiKey(const WTF::String& key,
                                   bool has_user_gesture) override {}
   void UpdateTitle(const WTF::String& title,
diff --git a/third_party/blink/renderer/core/view_transition/view_transition.h b/third_party/blink/renderer/core/view_transition/view_transition.h
index b9319ef..0e4e6a3 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition.h
+++ b/third_party/blink/renderer/core/view_transition/view_transition.h
@@ -171,6 +171,12 @@
     return creation_type_ == CreationType::kForSnapshot;
   }
 
+  // Returns true if this object was created for transitions in the same
+  // Document via document.startViewTransition(...).
+  bool IsCreatedViaScriptAPI() const {
+    return creation_type_ == CreationType::kScript;
+  }
+
   // Notifies before the compositor associated with this frame will initiate a
   // lifecycle update.
   void WillBeginMainFrame();
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc b/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
index 71ca2674..af36d31 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
@@ -51,9 +51,9 @@
     Document& document,
     V8ViewTransitionCallback* callback,
     ExceptionState& exception_state) {
-  // TODO(khushalsagar): Script initiates a transition request during
-  // navigation?
-  if (transition_ && transition_->IsForNavigationSnapshot())
+  // Disallow script initiated transitions during a navigation initiated
+  // transition.
+  if (transition_ && !transition_->IsCreatedViaScriptAPI())
     return nullptr;
 
   if (transition_)
@@ -70,6 +70,7 @@
 void ViewTransitionSupplement::SnapshotDocumentForNavigation(
     Document& document,
     ViewTransition::ViewTransitionStateCallback callback) {
+  DCHECK(RuntimeEnabledFeatures::ViewTransitionOnNavigationEnabled());
   auto* supplement = From(document);
   supplement->StartTransition(document, std::move(callback));
 }
@@ -78,7 +79,9 @@
     Document& document,
     ViewTransition::ViewTransitionStateCallback callback) {
   if (transition_) {
-    DCHECK(!transition_->IsForNavigationSnapshot());
+    // We may have a transition which was created to animate to this Document at
+    // this point if another navigation starts before the animations finish.
+    DCHECK(transition_->IsForNavigationSnapshot());
     transition_->skipTransition();
   }
   DCHECK(!transition_)
@@ -92,6 +95,7 @@
 void ViewTransitionSupplement::CreateFromSnapshotForNavigation(
     Document& document,
     ViewTransitionState transition_state) {
+  DCHECK(RuntimeEnabledFeatures::ViewTransitionOnNavigationEnabled());
   auto* supplement = From(document);
   supplement->StartTransition(document, std::move(transition_state));
 }
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index aa2b0df..08ec862 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -1541,7 +1541,7 @@
       break;
 
     case PaymentErrorReason::USER_OPT_OUT:
-      exception_code = DOMExceptionCode::kAbortError;
+      exception_code = DOMExceptionCode::kOptOutError;
       break;
 
     case PaymentErrorReason::UNKNOWN:
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_error_util.cc b/third_party/blink/renderer/modules/peerconnection/rtc_error_util.cc
index 1622361..dd9473c 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_error_util.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_error_util.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
 
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_error.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 
@@ -29,8 +30,12 @@
     case webrtc::RTCErrorType::UNSUPPORTED_OPERATION:
     case webrtc::RTCErrorType::RESOURCE_EXHAUSTED:
     case webrtc::RTCErrorType::INTERNAL_ERROR:
-      return MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kOperationError, error.message());
+      if (error.error_detail() == webrtc::RTCErrorDetailType::NONE) {
+        return MakeGarbageCollected<DOMException>(
+            DOMExceptionCode::kOperationError, error.message());
+      } else {
+        return MakeGarbageCollected<RTCError>(error);
+      }
     case webrtc::RTCErrorType::INVALID_STATE:
       return MakeGarbageCollected<DOMException>(
           DOMExceptionCode::kInvalidStateError, error.message());
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc
index 08e6b33..438ad29b 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc
@@ -393,19 +393,15 @@
       webrtc::RtpParameters parameters,
       CrossThreadOnceFunction<void(webrtc::RTCError)> callback) {
     DCHECK(signaling_task_runner_->BelongsToCurrentThread());
-    webrtc::RTCError result = webrtc_sender_->SetParameters(parameters);
-    PostCrossThreadTask(
-        *main_task_runner_.get(), FROM_HERE,
-        CrossThreadBindOnce(
-            &RTCRtpSenderImpl::RTCRtpSenderInternal::SetParametersCallback,
-            WrapRefCounted(this), std::move(result), std::move(callback)));
-  }
 
-  void SetParametersCallback(
-      webrtc::RTCError result,
-      CrossThreadOnceFunction<void(webrtc::RTCError)> callback) {
-    DCHECK(main_task_runner_->BelongsToCurrentThread());
-    std::move(callback).Run(std::move(result));
+    webrtc_sender_->SetParametersAsync(
+        parameters,
+        [callback = std::move(callback),
+         task_runner = main_task_runner_](webrtc::RTCError error) mutable {
+          PostCrossThreadTask(
+              *task_runner.get(), FROM_HERE,
+              CrossThreadBindOnce(std::move(callback), std::move(error)));
+        });
   }
 
   void SetStreamsOnSignalingThread(const Vector<String>& stream_ids) {
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
index e3ad90b..3679561f 100644
--- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
+++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
@@ -41,6 +41,8 @@
       return ProtoType::TASK_SCOPE_SCRIPT_EXECUTION;
     case TaskAttributionTracker::TaskScopeType::kPostMessage:
       return ProtoType::TASK_SCOPE_POST_MESSAGE;
+    case TaskAttributionTracker::TaskScopeType::kPopState:
+      return ProtoType::TASK_SCOPE_POP_STATE;
   }
 }
 
diff --git a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc
index 27f8e8eea..10681888 100644
--- a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc
+++ b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc
@@ -81,11 +81,10 @@
   OpenWebDatabaseInWindow("http://example.test:0/", "first_party/empty.html",
                           scope.GetExceptionState());
   EXPECT_TRUE(scope.GetExceptionState().HadException());
-  // Insufficient state exists to actually open a database, but this error
-  // means it was tried.
+  // This error means the database opening was rejected.
   EXPECT_TRUE(scope.GetExceptionState().HadException());
   EXPECT_EQ(scope.GetExceptionState().Code(),
-            static_cast<int>(DOMExceptionCode::kInvalidStateError));
+            static_cast<int>(DOMExceptionCode::kSecurityError));
 }
 
 TEST(DOMWindowWebDatabaseTest, WebSQLNonSecureContextFeatureOff) {
diff --git a/third_party/blink/renderer/platform/bindings/exception_code.h b/third_party/blink/renderer/platform/bindings/exception_code.h
index 32a2914..596eb2e 100644
--- a/third_party/blink/renderer/platform/bindings/exception_code.h
+++ b/third_party/blink/renderer/platform/bindings/exception_code.h
@@ -89,6 +89,7 @@
   kVersionError,
   kOperationError,
   kNotAllowedError,
+  kOptOutError,
 
   // The rest of entries are defined out of scope of Web IDL.
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/media_timing.h b/third_party/blink/renderer/platform/loader/fetch/media_timing.h
index fd67187..9da1c24 100644
--- a/third_party/blink/renderer/platform/loader/fetch/media_timing.h
+++ b/third_party/blink/renderer/platform/loader/fetch/media_timing.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
 
@@ -53,6 +54,10 @@
   virtual absl::optional<WebURLRequest::Priority> RequestPriority() const = 0;
 
   virtual bool IsDataUrl() const = 0;
+
+  // Returns the type. For images it would be the specific types like jpg etc.
+  // For video, it would be video.
+  virtual AtomicString MediaType() const = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
index 2b7a1388..03da704e 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -452,13 +452,16 @@
 }  // namespace
 
 namespace features {
+// Make RTCVideoEncoder::Encode() asynchronous.
+BASE_FEATURE(kWebRtcEncoderAsyncEncode,
+             "WebRtcEncoderAsyncEncode",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Fallback from hardware encoder (if available) to software, for WebRTC
 // screensharing that uses temporal scalability.
 BASE_FEATURE(kWebRtcScreenshareSwEncoding,
              "WebRtcScreenshareSwEncoding",
              base::FEATURE_DISABLED_BY_DEFAULT);
-
 }  // namespace features
 
 // This private class of RTCVideoEncoder does the actual work of communicating
@@ -478,6 +481,7 @@
        webrtc::VideoCodecType video_codec_type,
        webrtc::VideoContentType video_content_type,
        UpdateEncoderInfoCallback update_encoder_info_callback,
+       base::RepeatingClosure execute_software_fallback,
        base::WeakPtr<Impl>& weak_this_for_client);
 
   ~Impl() override;
@@ -599,9 +603,9 @@
   // matching.
   bool failed_timestamp_match_{false};
 
-  // Next input frame chunk. Since there is at most one next frame chunk, a
-  // single-element queue is sufficient.
-  absl::optional<FrameChunk> next_frame_chunk_;
+  // The pending frames to be encoded with the boolean representing whether the
+  // frame must be encoded keyframe.
+  WTF::Deque<FrameChunk> pending_frames_;
 
   // Frame sizes.
   gfx::Size input_frame_coded_size_;
@@ -643,6 +647,9 @@
 
   UpdateEncoderInfoCallback update_encoder_info_callback_;
 
+  // Calling this causes a software encoder fallback.
+  base::RepeatingClosure execute_software_fallback_;
+
   // The reslutions of active spatial layer, only used when |Vp9Metadata| is
   // contained in |BitstreamBufferMetadata|. it will be updated when key frame
   // is produced.
@@ -678,11 +685,13 @@
     webrtc::VideoCodecType video_codec_type,
     webrtc::VideoContentType video_content_type,
     UpdateEncoderInfoCallback update_encoder_info_callback,
+    base::RepeatingClosure execute_software_fallback,
     base::WeakPtr<Impl>& weak_this_for_client)
     : gpu_factories_(gpu_factories),
       video_codec_type_(video_codec_type),
       video_content_type_(video_content_type),
-      update_encoder_info_callback_(std::move(update_encoder_info_callback)) {
+      update_encoder_info_callback_(std::move(update_encoder_info_callback)),
+      execute_software_fallback_(std::move(execute_software_fallback)) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 
   preferred_pixel_formats_ = {webrtc::VideoFrameBuffer::Type::kI420};
@@ -804,7 +813,6 @@
                frame_chunk.timestamp);
   DVLOG(3) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!next_frame_chunk_);
 
   if (status_ != WEBRTC_VIDEO_CODEC_OK) {
     encode_event.Set(status_);
@@ -837,20 +845,22 @@
     encode_event.Signal();
     return;
   }
-  next_frame_chunk_.emplace(std::move(frame_chunk));
+
   async_encode_event_ = ScopedSignaledValue(std::move(encode_event));
 
-  // If |use_native_input_| is true, then we always queue the frame to the
-  // encoder since no intermediate buffer is needed in RTCVideoEncoder.
   if (use_native_input_) {
-    EncodeOneFrameWithNativeInput(std::move(*next_frame_chunk_));
-    next_frame_chunk_.reset();
+    DCHECK(pending_frames_.empty());
+    EncodeOneFrameWithNativeInput(std::move(frame_chunk));
     return;
   }
 
-  if (!input_buffers_free_.empty()) {
-    EncodeOneFrame(std::move(*next_frame_chunk_));
-    next_frame_chunk_.reset();
+  pending_frames_.push_back(std::move(frame_chunk));
+  // When |input_buffers_free_| is empty, EncodeOneFrame() for the frame in
+  // |pending_frames_| will be invoked from InputBufferReleased().
+  while (!pending_frames_.empty() && !input_buffers_free_.empty()) {
+    auto chunk = std::move(pending_frames_.front());
+    pending_frames_.pop_front();
+    EncodeOneFrame(std::move(chunk));
   }
 }
 
@@ -1230,6 +1240,8 @@
 
   async_init_event_.SetAndReset(retval);
   async_encode_event_.SetAndReset(retval);
+
+  execute_software_fallback_.Run();
 }
 
 RTCVideoEncoder::Impl::~Impl() {
@@ -1514,9 +1526,11 @@
   DCHECK_GE(index, 0);
   DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
   input_buffers_free_.push_back(index);
-  if (next_frame_chunk_) {
-    EncodeOneFrame(std::move(*next_frame_chunk_));
-    next_frame_chunk_.reset();
+
+  while (!pending_frames_.empty() && !input_buffers_free_.empty()) {
+    auto chunk = std::move(pending_frames_.front());
+    pending_frames_.pop_front();
+    EncodeOneFrame(std::move(chunk));
   }
 }
 
@@ -1603,15 +1617,20 @@
   if (impl_)
     Release();
 
+  has_error_ = false;
+
   Impl::UpdateEncoderInfoCallback update_encoder_info_callback =
       media::BindToCurrentLoop(
           base::BindRepeating(&RTCVideoEncoder::UpdateEncoderInfo, weak_this_));
+  base::RepeatingClosure execute_software_fallback = media::BindToCurrentLoop(
+      base::BindRepeating(&RTCVideoEncoder::SetError, weak_this_));
+
   impl_ = std::make_unique<Impl>(
       gpu_factories_, ProfileToWebRtcVideoCodecType(profile_),
       (codec_settings->mode == webrtc::VideoCodecMode::kScreensharing)
           ? webrtc::VideoContentType::SCREENSHARE
           : webrtc::VideoContentType::UNSPECIFIED,
-      update_encoder_info_callback, weak_impl_);
+      update_encoder_info_callback, execute_software_fallback, weak_impl_);
 
   std::vector<media::VideoEncodeAccelerator::Config::SpatialLayer>
       spatial_layers;
@@ -1660,24 +1679,34 @@
     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
   }
 
+  if (has_error_)
+    return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+
   const bool want_key_frame =
       frame_types && frame_types->size() &&
       frame_types->front() == webrtc::VideoFrameType::kVideoFrameKey;
-  base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
-  base::WaitableEvent encode_waiter(
-      base::WaitableEvent::ResetPolicy::MANUAL,
-      base::WaitableEvent::InitialState::NOT_SIGNALED);
-  int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
-  PostCrossThreadTask(
-      *gpu_task_runner_.get(), FROM_HERE,
-      CrossThreadBindOnce(&RTCVideoEncoder::Impl::Enqueue, weak_impl_,
-                          FrameChunk(input_image, want_key_frame),
-                          SignaledValue(&encode_waiter, &encode_retval)));
-
-  // webrtc::VideoEncoder expects this call to be synchronous.
-  encode_waiter.Wait();
-  DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval;
-  return encode_retval;
+  if (base::FeatureList::IsEnabled(features::kWebRtcEncoderAsyncEncode)) {
+    PostCrossThreadTask(
+        *gpu_task_runner_.get(), FROM_HERE,
+        CrossThreadBindOnce(&RTCVideoEncoder::Impl::Enqueue, weak_impl_,
+                            FrameChunk(input_image, want_key_frame),
+                            SignaledValue()));
+    return WEBRTC_VIDEO_CODEC_OK;
+  } else {
+    base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
+    base::WaitableEvent encode_waiter(
+        base::WaitableEvent::ResetPolicy::MANUAL,
+        base::WaitableEvent::InitialState::NOT_SIGNALED);
+    int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+    PostCrossThreadTask(
+        *gpu_task_runner_.get(), FROM_HERE,
+        CrossThreadBindOnce(&RTCVideoEncoder::Impl::Enqueue, weak_impl_,
+                            FrameChunk(input_image, want_key_frame),
+                            SignaledValue(&encode_waiter, &encode_retval)));
+    encode_waiter.Wait();
+    DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval;
+    return encode_retval;
+  }
 }
 
 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
@@ -1743,6 +1772,9 @@
     return;
   }
 
+  if (has_error_)
+    return;
+
   PostCrossThreadTask(
       *gpu_task_runner_.get(), FROM_HERE,
       CrossThreadBindOnce(
@@ -1791,6 +1823,14 @@
                                                preferred_pixel_formats.end());
 }
 
+void RTCVideoEncoder::SetError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(webrtc_sequence_checker_);
+  has_error_ = true;
+
+  if (error_callback_for_testing_)
+    std::move(error_callback_for_testing_).Run();
+}
+
 // static
 bool RTCVideoEncoder::Vp9HwSupportForSpatialLayers() {
 #if defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_CHROMEOS)
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h
index 53c4320b..528d9995 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h
@@ -17,6 +17,7 @@
 #include "base/synchronization/lock.h"
 #include "media/base/video_decoder_config.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/webrtc/api/video/video_bitrate_allocation.h"
 #include "third_party/webrtc/modules/video_coding/include/video_codec_interface.h"
 #include "ui/gfx/geometry/size.h"
@@ -33,6 +34,7 @@
 namespace blink {
 
 namespace features {
+PLATFORM_EXPORT BASE_DECLARE_FEATURE(kWebRtcEncoderAsyncEncode);
 PLATFORM_EXPORT BASE_DECLARE_FEATURE(kWebRtcScreenshareSwEncoding);
 }
 
@@ -70,6 +72,11 @@
   // Returns true if there's VP9 HW support for spatial layers.
   static bool Vp9HwSupportForSpatialLayers();
 
+  void SetErrorCallbackForTesting(
+      WTF::CrossThreadOnceClosure error_callback_for_testing) {
+    error_callback_for_testing_ = std::move(error_callback_for_testing);
+  }
+
  private:
   class Impl;
   friend class RTCVideoEncoder::Impl;
@@ -77,6 +84,7 @@
   void UpdateEncoderInfo(
       media::VideoEncoderInfo encoder_info,
       std::vector<webrtc::VideoFrameBuffer::Type> preferred_pixel_formats);
+  void SetError();
 
   const media::VideoCodecProfile profile_;
 
@@ -100,6 +108,11 @@
   // The sequence on which the webrtc::VideoEncoder functions are executed.
   SEQUENCE_CHECKER(webrtc_sequence_checker_);
 
+  bool has_error_ GUARDED_BY_CONTEXT(webrtc_sequence_checker_){false};
+
+  // Execute in SetError(). This can be valid only in testing.
+  WTF::CrossThreadOnceClosure error_callback_for_testing_;
+
   // The RTCVideoEncoder::Impl that does all the work.
   std::unique_ptr<Impl> impl_;
 
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
index 24a117a..a233fc9 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
@@ -23,6 +23,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.h"
 #include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/libyuv/include/libyuv/planar_functions.h"
 #include "third_party/webrtc/api/video/i420_buffer.h"
 #include "third_party/webrtc/api/video_codecs/video_encoder.h"
@@ -181,6 +182,20 @@
     waiter.Wait();
     return result;
   }
+  void SetErrorWaiter(base::WaitableEvent* error_waiter) {
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](RTCVideoEncoder* rtc_video_encoder,
+               base::WaitableEvent* waiter) {
+              rtc_video_encoder->SetErrorCallbackForTesting(CrossThreadBindOnce(
+                  [](base::WaitableEvent* waiter) { waiter->Signal(); },
+                  CrossThreadUnretained(waiter)));
+            },
+            rtc_video_encoder_.get(), error_waiter));
+    return;
+  }
+
   void SetRates(
       const webrtc::VideoEncoder::RateControlParameters& parameters) override {
     base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::MANUAL,
@@ -223,20 +238,12 @@
 };
 }  // anonymous namespace
 
-class RTCVideoEncoderTest
-    : public ::testing::TestWithParam<webrtc::VideoCodecType> {
+class RTCVideoEncoderTest {
  public:
   RTCVideoEncoderTest()
       : encoder_thread_("vea_thread"),
         mock_gpu_factories_(
-            new media::MockGpuVideoAcceleratorFactories(nullptr)),
-        idle_waiter_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-                     base::WaitableEvent::InitialState::NOT_SIGNALED) {
-#if defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_CHROMEOS)
-    // TODO(crbug.com/1186051): remove once enabled by default.
-    feature_list_.InitAndEnableFeature(media::kVaapiVp9kSVCHWEncoding);
-#endif
-  }
+            new media::MockGpuVideoAcceleratorFactories(nullptr)) {}
 
   media::MockVideoEncodeAccelerator* ExpectCreateInitAndDestroyVEA(
       bool vea_used) {
@@ -256,7 +263,7 @@
     return mock_vea;
   }
 
-  void SetUp() override {
+  void SetUp() {
     DVLOG(3) << __func__;
     ASSERT_TRUE(encoder_thread_.Start());
 
@@ -264,7 +271,7 @@
         .WillRepeatedly(Return(encoder_thread_.task_runner()));
   }
 
-  void TearDown() override {
+  void TearDown() {
     DVLOG(3) << __func__;
     EXPECT_TRUE(encoder_thread_.IsRunning());
     RunUntilIdle();
@@ -276,10 +283,7 @@
 
   void RunUntilIdle() {
     DVLOG(3) << __func__;
-    encoder_thread_.task_runner()->PostTask(
-        FROM_HERE, base::BindOnce(&base::WaitableEvent::Signal,
-                                  base::Unretained(&idle_waiter_)));
-    idle_waiter_.Wait();
+    encoder_thread_.FlushForTesting();
   }
 
   void CreateEncoder(webrtc::VideoCodecType codec_type, bool vea_used = true) {
@@ -539,12 +543,20 @@
   base::test::TaskEnvironment task_environment_;
   std::unique_ptr<media::MockGpuVideoAcceleratorFactories> mock_gpu_factories_;
   std::unique_ptr<EncodedImageCallbackWrapper> callback_wrapper_;
-  base::WaitableEvent idle_waiter_;
   size_t num_spatial_layers_;
-  base::test::ScopedFeatureList feature_list_;
 };
 
-TEST_P(RTCVideoEncoderTest, CreateAndInitSucceeds) {
+class RTCVideoEncoderInitTest
+    : public RTCVideoEncoderTest,
+      public ::testing::TestWithParam<webrtc::VideoCodecType> {
+ public:
+  RTCVideoEncoderInitTest() = default;
+  ~RTCVideoEncoderInitTest() override = default;
+  void SetUp() override { RTCVideoEncoderTest::SetUp(); }
+  void TearDown() override { RTCVideoEncoderTest::TearDown(); }
+};
+
+TEST_P(RTCVideoEncoderInitTest, CreateAndInitSucceeds) {
   const webrtc::VideoCodecType codec_type = GetParam();
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -553,7 +565,7 @@
             rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
 }
 
-TEST_P(RTCVideoEncoderTest, RepeatedInitSucceeds) {
+TEST_P(RTCVideoEncoderInitTest, RepeatedInitSucceeds) {
   const webrtc::VideoCodecType codec_type = GetParam();
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -565,7 +577,7 @@
             rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
 }
 
-TEST_P(RTCVideoEncoderTest, CreateAndInitSucceedsForTemporalLayer) {
+TEST_P(RTCVideoEncoderInitTest, CreateAndInitSucceedsForTemporalLayer) {
   const webrtc::VideoCodecType codec_type = GetParam();
   if (codec_type == webrtc::kVideoCodecVP8)
     GTEST_SKIP() << "VP8 temporal layer encoding is not supported";
@@ -580,12 +592,33 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(CodecProfiles,
-                         RTCVideoEncoderTest,
+                         RTCVideoEncoderInitTest,
                          Values(webrtc::kVideoCodecH264,
                                 webrtc::kVideoCodecVP8,
                                 webrtc::kVideoCodecVP9));
 
-TEST_F(RTCVideoEncoderTest, H264SoftwareFallbackForOddSize) {
+class RTCVideoEncoderEncodeTest : public RTCVideoEncoderTest,
+                                  public ::testing::TestWithParam<bool> {
+ public:
+  RTCVideoEncoderEncodeTest() {
+    if (GetParam())
+      feature_list_.InitAndEnableFeature(features::kWebRtcEncoderAsyncEncode);
+  }
+
+  ~RTCVideoEncoderEncodeTest() override = default;
+  void SetUp() override { RTCVideoEncoderTest::SetUp(); }
+  void TearDown() override { RTCVideoEncoderTest::TearDown(); }
+
+ protected:
+  bool AsyncEncodingIsEnabled() const {
+    return base::FeatureList::IsEnabled(features::kWebRtcEncoderAsyncEncode);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_P(RTCVideoEncoderEncodeTest, H264SoftwareFallbackForOddSize) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecH264;
   CreateEncoder(codec_type, false);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -598,7 +631,7 @@
     mock_vea_->Destroy();
 }
 
-TEST_F(RTCVideoEncoderTest, VP8CreateAndInitSucceedsForOddSize) {
+TEST_P(RTCVideoEncoderEncodeTest, VP8CreateAndInitSucceedsForOddSize) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -608,7 +641,7 @@
             rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings));
 }
 
-TEST_F(RTCVideoEncoderTest, VP9CreateAndInitSucceedsForOddSize) {
+TEST_P(RTCVideoEncoderEncodeTest, VP9CreateAndInitSucceedsForOddSize) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP9;
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -620,7 +653,7 @@
 
 // Checks that WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE is returned when there is
 // platform error.
-TEST_F(RTCVideoEncoderTest, SoftwareFallbackAfterError) {
+TEST_P(RTCVideoEncoderEncodeTest, SoftwareFallbackAfterError) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -642,6 +675,10 @@
       webrtc::I420Buffer::Create(kInputFrameWidth, kInputFrameHeight);
   FillFrameBuffer(buffer);
   std::vector<webrtc::VideoFrameType> frame_types;
+  base::WaitableEvent error_waiter(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  rtc_encoder_->SetErrorWaiter(&error_waiter);
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
             rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
                                      .set_video_frame_buffer(buffer)
@@ -650,8 +687,7 @@
                                      .set_rotation(webrtc::kVideoRotation_0)
                                      .build(),
                                  &frame_types));
-  RunUntilIdle();
-
+  error_waiter.Wait();
   // Expect the next frame to return SW fallback.
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE,
             rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
@@ -663,7 +699,7 @@
                                  &frame_types));
 }
 
-TEST_F(RTCVideoEncoderTest, SoftwareFallbackOnBadEncodeInput) {
+TEST_P(RTCVideoEncoderEncodeTest, SoftwareFallbackOnBadEncodeInput) {
   // Make RTCVideoEncoder expect native input.
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kVideoCaptureUseGpuMemoryBuffer);
@@ -683,8 +719,27 @@
           frame, std::vector<scoped_refptr<media::VideoFrame>>(),
           new WebRtcVideoFrameAdapter::SharedResources(nullptr)));
   std::vector<webrtc::VideoFrameType> frame_types;
+
   // Expect SW fallback because the frame isn't a GpuMemoryBuffer-based frame.
-  EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE,
+  if (!AsyncEncodingIsEnabled()) {
+    EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE,
+              rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+                                       .set_video_frame_buffer(frame_adapter)
+                                       .set_timestamp_rtp(1000)
+                                       .set_timestamp_us(2000)
+                                       .set_rotation(webrtc::kVideoRotation_0)
+                                       .build(),
+                                   &frame_types));
+    return;
+  }
+
+  // The frame type check is done in media thread asynchronously. The error is
+  // reported in the second Encode callback.
+  base::WaitableEvent error_waiter(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  rtc_encoder_->SetErrorWaiter(&error_waiter);
+  EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
             rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
                                      .set_video_frame_buffer(frame_adapter)
                                      .set_timestamp_rtp(1000)
@@ -692,9 +747,18 @@
                                      .set_rotation(webrtc::kVideoRotation_0)
                                      .build(),
                                  &frame_types));
+  error_waiter.Wait();
+  EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE,
+            rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+                                     .set_video_frame_buffer(frame_adapter)
+                                     .set_timestamp_rtp(2000)
+                                     .set_timestamp_us(3000)
+                                     .set_rotation(webrtc::kVideoRotation_0)
+                                     .build(),
+                                 &frame_types));
 }
 
-TEST_F(RTCVideoEncoderTest, EncodeScaledFrame) {
+TEST_P(RTCVideoEncoderEncodeTest, EncodeScaledFrame) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -731,7 +795,7 @@
             rtc_encoder_->Encode(rtc_frame, &frame_types));
 }
 
-TEST_F(RTCVideoEncoderTest, PreserveTimestamps) {
+TEST_P(RTCVideoEncoderEncodeTest, PreserveTimestamps) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -761,7 +825,7 @@
             rtc_encoder_->Encode(rtc_frame, &frame_types));
 }
 
-TEST_F(RTCVideoEncoderTest, AcceptsRepeatedWrappedMediaVideoFrame) {
+TEST_P(RTCVideoEncoderEncodeTest, AcceptsRepeatedWrappedMediaVideoFrame) {
   // Ensure encoder is accepting subsequent frames with the same timestamp in
   // the wrapped media::VideoFrame.
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
@@ -795,7 +859,7 @@
                                  &frame_types));
 }
 
-TEST_F(RTCVideoEncoderTest, EncodeVP9TemporalLayer) {
+TEST_P(RTCVideoEncoderEncodeTest, EncodeVP9TemporalLayer) {
   webrtc::VideoCodec tl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
                                                  /*num_spatial_layers=*/1);
   CreateEncoder(tl_codec.codecType);
@@ -825,7 +889,7 @@
   }
 }
 
-TEST_F(RTCVideoEncoderTest, InitializeWithTooHighBitrateFails) {
+TEST_P(RTCVideoEncoderEncodeTest, InitializeWithTooHighBitrateFails) {
   // We expect initialization to fail. We do not want a mock video encoder, as
   // it will not be successfully attached to the rtc_encoder_. So we do not call
   // CreateEncoder, but instead CreateEncoderWithoutVea.
@@ -844,7 +908,7 @@
 // support spatial SVC encoding.
 
 // http://crbug.com/1226875
-TEST_F(RTCVideoEncoderTest, EncodeSpatialLayer) {
+TEST_P(RTCVideoEncoderEncodeTest, EncodeSpatialLayer) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP9;
   CreateEncoder(codec_type);
   webrtc::VideoCodec sl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
@@ -900,9 +964,10 @@
                                        .build(),
                                    &frame_types));
   }
+  RunUntilIdle();
 }
 
-TEST_F(RTCVideoEncoderTest, CreateAndInitVP9ThreeLayerSvc) {
+TEST_P(RTCVideoEncoderEncodeTest, CreateAndInitVP9ThreeLayerSvc) {
   webrtc::VideoCodec tl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
                                                  /*num_spatial_layers=*/3);
   CreateEncoder(tl_codec.codecType);
@@ -921,7 +986,7 @@
                       Field(&SpatialLayer::height, kInputFrameHeight)))));
 }
 
-TEST_F(RTCVideoEncoderTest, CreateAndInitVP9SvcSinglecast) {
+TEST_P(RTCVideoEncoderEncodeTest, CreateAndInitVP9SvcSinglecast) {
   webrtc::VideoCodec tl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
                                                  /*num_spatial_layers=*/3);
   tl_codec.spatialLayers[1].active = false;
@@ -937,7 +1002,7 @@
                         Field(&SpatialLayer::height, kInputFrameHeight / 4)))));
 }
 
-TEST_F(RTCVideoEncoderTest,
+TEST_P(RTCVideoEncoderEncodeTest,
        CreateAndInitVP9SvcSinglecastWithoutTemporalLayers) {
   webrtc::VideoCodec tl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
                                                  /*num_spatial_layers=*/3);
@@ -952,7 +1017,7 @@
   EXPECT_THAT(config_->spatial_layers, IsEmpty());
 }
 
-TEST_F(RTCVideoEncoderTest, RaiseErrorOnMissingEndOfPicture) {
+TEST_P(RTCVideoEncoderEncodeTest, RaiseErrorOnMissingEndOfPicture) {
   webrtc::VideoCodec tl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
                                                  /*num_spatial_layers=*/2);
   tl_codec.VP9()->numberOfTemporalLayers = 1;
@@ -985,7 +1050,25 @@
   FillFrameBuffer(buffer);
   std::vector<webrtc::VideoFrameType> frame_types{
       webrtc::VideoFrameType::kVideoFrameKey};
-  EXPECT_NE(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+  if (!AsyncEncodingIsEnabled()) {
+    EXPECT_NE(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+                                       .set_video_frame_buffer(buffer)
+                                       .set_timestamp_rtp(0)
+                                       .set_timestamp_us(0)
+                                       .set_rotation(webrtc::kVideoRotation_0)
+                                       .build(),
+                                   &frame_types),
+              WEBRTC_VIDEO_CODEC_OK);
+    return;
+  }
+
+  // BitstreamBufferReady() is called after the first Encode() returns.
+  // The error is reported on the second call.
+  base::WaitableEvent error_waiter(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  rtc_encoder_->SetErrorWaiter(&error_waiter);
+  EXPECT_EQ(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
                                      .set_video_frame_buffer(buffer)
                                      .set_timestamp_rtp(0)
                                      .set_timestamp_us(0)
@@ -993,9 +1076,18 @@
                                      .build(),
                                  &frame_types),
             WEBRTC_VIDEO_CODEC_OK);
+  error_waiter.Wait();
+  EXPECT_EQ(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+                                     .set_video_frame_buffer(buffer)
+                                     .set_timestamp_rtp(0)
+                                     .set_timestamp_us(0)
+                                     .set_rotation(webrtc::kVideoRotation_0)
+                                     .build(),
+                                 &frame_types),
+            WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE);
 }
 
-TEST_F(RTCVideoEncoderTest, RaiseErrorOnMismatchingResolutions) {
+TEST_P(RTCVideoEncoderEncodeTest, RaiseErrorOnMismatchingResolutions) {
   webrtc::VideoCodec tl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
                                                  /*num_spatial_layers=*/2);
   tl_codec.VP9()->numberOfTemporalLayers = 1;
@@ -1022,7 +1114,26 @@
   FillFrameBuffer(buffer);
   std::vector<webrtc::VideoFrameType> frame_types{
       webrtc::VideoFrameType::kVideoFrameKey};
-  EXPECT_NE(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+
+  if (!AsyncEncodingIsEnabled()) {
+    EXPECT_NE(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+                                       .set_video_frame_buffer(buffer)
+                                       .set_timestamp_rtp(0)
+                                       .set_timestamp_us(0)
+                                       .set_rotation(webrtc::kVideoRotation_0)
+                                       .build(),
+                                   &frame_types),
+              WEBRTC_VIDEO_CODEC_OK);
+    return;
+  }
+
+  // BitstreamBufferReady() is called after the first Encode() returns.
+  // The error is reported on the second call.
+  base::WaitableEvent error_waiter(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  rtc_encoder_->SetErrorWaiter(&error_waiter);
+  EXPECT_EQ(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
                                      .set_video_frame_buffer(buffer)
                                      .set_timestamp_rtp(0)
                                      .set_timestamp_us(0)
@@ -1030,9 +1141,18 @@
                                      .build(),
                                  &frame_types),
             WEBRTC_VIDEO_CODEC_OK);
+  error_waiter.Wait();
+  EXPECT_EQ(rtc_encoder_->Encode(webrtc::VideoFrame::Builder()
+                                     .set_video_frame_buffer(buffer)
+                                     .set_timestamp_rtp(0)
+                                     .set_timestamp_us(0)
+                                     .set_rotation(webrtc::kVideoRotation_0)
+                                     .build(),
+                                 &frame_types),
+            WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE);
 }
 
-TEST_F(RTCVideoEncoderTest, SpatialLayerTurnedOffAndOnAgain) {
+TEST_P(RTCVideoEncoderEncodeTest, SpatialLayerTurnedOffAndOnAgain) {
   webrtc::VideoCodec tl_codec = GetSVCLayerCodec(webrtc::kVideoCodecVP9,
                                                  /*num_spatial_layers=*/2);
   tl_codec.VP9()->numberOfTemporalLayers = 1;
@@ -1073,6 +1193,7 @@
                                      .build(),
                                  &frame_types),
             WEBRTC_VIDEO_CODEC_OK);
+  RunUntilIdle();
 
   // Sind bitrate allocation disabling the second spatial layer.
   webrtc::VideoBitrateAllocation bitrate_allocation;
@@ -1098,6 +1219,7 @@
                                      .build(),
                                  &frame_types),
             WEBRTC_VIDEO_CODEC_OK);
+  RunUntilIdle();
 
   // Re-enable the top layer.
   bitrate_allocation.SetBitrate(1, 0, 500000);
@@ -1126,11 +1248,12 @@
                                      .build(),
                                  &frame_types),
             WEBRTC_VIDEO_CODEC_OK);
+  RunUntilIdle();
 }
 
 #endif  // defined(ARCH_CPU_X86_FAMILY) && BUILDFLAG(IS_CHROMEOS_ASH)
 
-TEST_F(RTCVideoEncoderTest, EncodeFrameWithAdapter) {
+TEST_P(RTCVideoEncoderEncodeTest, EncodeFrameWithAdapter) {
   const webrtc::VideoCodecType codec_type = webrtc::kVideoCodecVP8;
   CreateEncoder(codec_type);
   webrtc::VideoCodec codec = GetDefaultCodec();
@@ -1179,4 +1302,8 @@
                                  &frame_types));
 }
 
+INSTANTIATE_TEST_SUITE_P(SyncAndAsynEncoding,
+                         RTCVideoEncoderEncodeTest,
+                         Values(false, true));
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
index 529bdaa..683eb7c5 100644
--- a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
+++ b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
@@ -35,6 +35,7 @@
     kScheduledAction,
     kScriptExecution,
     kPostMessage,
+    kPopState,
   };
 
   // A class maintaining the scope of the current task. Keeping it alive ensures
diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc
index f45c36c..a7dd02b 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.cc
+++ b/third_party/blink/renderer/platform/widget/widget_base.cc
@@ -898,8 +898,14 @@
   if (ShouldRecordBeginMainFrameMetrics()) {
     raf_aligned_input_start_time = base::TimeTicks::Now();
   }
+
+  auto weak_this = weak_ptr_factory_.GetWeakPtr();
   widget_input_handler_manager_->input_event_queue()->DispatchRafAlignedInput(
       frame_time);
+  // DispatchRafAlignedInput could have detached the frame.
+  if (!weak_this)
+    return;
+
   if (ShouldRecordBeginMainFrameMetrics()) {
     client_->RecordDispatchRafAlignedInputTime(raf_aligned_input_start_time);
   }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 5093ef0..165bc37 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -4628,11 +4628,6 @@
 crbug.com/1088007 virtual/gpu/fast/canvas/OffscreenCanvasClearRect.html [ Failure Pass ]
 crbug.com/1088007 virtual/gpu/fast/canvas/OffscreenCanvasClearRectPartial.html [ Failure Pass ]
 
-# Sheriff 2020-06-03
-crbug.com/1349215 [ Mac11 ] external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Timeout ]
-crbug.com/1349215 [ Mac10.15 ] external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Timeout ]
-crbug.com/1349215 [ Mac12 ] external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Timeout ]
-
 # Sheriff 2020-06-09
 crbug.com/1093003 [ Mac ] external/wpt/html/rendering/replaced-elements/embedded-content/cross-domain-iframe.sub.html [ Failure Pass ]
 
@@ -6922,11 +6917,11 @@
 crbug.com/1207146 virtual/force-eager/external/wpt/measure-memory/main-frame-and-worker.https.window.html [ Failure Pass ]
 
 crbug.com/1385413 [ Win ] media/controls/overflow-menu-pointer-selection.html [ Failure Pass ]
-crbug.com/1385413 media/controls/text-track-menu-pointer-selection.html [ Failure Pass Timeout Skip ]
+crbug.com/1385413 media/controls/text-track-menu-pointer-selection.html [ Failure Pass Skip Timeout ]
 
 # Sheriff 2022-11-17
 crbug.com/1385642 [ Linux ] external/wpt/css/css-values/calc-in-media-queries-with-mixed-units.html [ Skip Failure Pass Timeout ]
-crbug.com/1385676 external/wpt/screen-capture/getdisplaymedia.https.html [ Skip Timeout ]
 crbug.com/1385681 external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html [ Failure Pass ]
 crbug.com/1372166 fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html [ Failure Pass ]
 crbug.com/1385497 http/tests/inspector-protocol/tracing/page-load-metrics.js [ Failure Pass ]
+crbug.com/1349215 external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Skip Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index a83f17d..196c2dc6 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1492,5 +1492,11 @@
       "external/wpt/mediacapture-streams/parallel-capture-requests.https.html"
     ],
     "args": ["--enable-features=SplitUserMediaQueues"]
+  },
+  {
+    "prefix": "enable-persistent-origin-trials",
+    "platforms": ["Linux", "Mac", "Win"],
+    "bases": [ "http/tests/persistent-origin-trials/" ],
+    "args": ["--enable-features=PersistentOriginTrials"]
   }
 ]
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 437e878..4e41510 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
@@ -257526,6 +257526,16 @@
    }
   },
   "support": {
+   ".cache": {
+    "gitignore2.json": [
+     "48531bf5259e9c30432667063666c4f8751d0452",
+     []
+    ],
+    "mtime.json": [
+     "711bf7895fb57e893c5a72563560d9a102da8e4d",
+     []
+    ]
+   },
    ".gitignore": [
     "d93e645d547894b50149d3726de2654957b6e06f",
     []
@@ -316720,6 +316730,10 @@
       "afbc38724a948f0ccda43812b2d445a6d344e141",
       []
      ],
+     "cssom-getPropertyValue-common-checks-expected.txt": [
+      "7dc527c588063c123b96d477780303c91cd70d48",
+      []
+     ],
      "cssstyledeclaration-cssfontrule.tentative-expected.txt": [
       "3c086eba4b94d008892cbbe3b1b07cda02014efb",
       []
@@ -374178,7 +374192,7 @@
      []
     ],
     "RTCConfiguration-iceServers-expected.txt": [
-     "c333f28867d5e5430064213aaeee4cbcf978315a",
+     "dceb1eea00e83ce54abf2c6583c56ccc01928a99",
      []
     ],
     "RTCConfiguration-iceServers.html.ini": [
@@ -422260,7 +422274,7 @@
        ]
       ],
       "font-variant-valid.html": [
-       "921498d738e030ea2a2fe1e424b9d391e2b69a1b",
+       "19d858189a9dcf3cf6ebf48b564d8752657043a8",
        [
         null,
         {}
@@ -442683,6 +442697,13 @@
        {}
       ]
      ],
+     "cssom-getPropertyValue-common-checks.html": [
+      "29ca39a88a659bc5a60b3464617235dd30e9d42d",
+      [
+       null,
+       {}
+      ]
+     ],
      "cssom-pagerule.html": [
       "c7604eba338083a2d0a4cd942e5d6aaee18e8d78",
       [
@@ -517012,7 +517033,7 @@
     "semantics": {
      "disabled-elements": {
       "disabled-event-dispatch.tentative.html": [
-       "1728adb11e1ae3aa44b37ca63838b8d0aa24ce02",
+       "66b12b417160ed3e3c9186971043f56bea7b7670",
        [
         null,
         {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-valid.html
index 921498d7..19d8581 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-variant-valid.html
@@ -95,12 +95,12 @@
                  ' ordinal slashed-zero jis78 full-width ruby sub');
 
 test_valid_value('font-variant',
-                 'super proportional-width jis83 stacked-fractions' +
-                 ' tabular-nums oldstyle-nums historical-forms all-small-caps no-contextual' +
-                 ' no-historical-ligatures no-discretionary-ligatures no-common-ligatures',
-                 'no-common-ligatures no-discretionary-ligatures no-historical-ligatures' +
-                 ' no-contextual all-small-caps historical-forms oldstyle-nums tabular-nums' +
-                 ' stacked-fractions jis83 proportional-width super');
+  'super proportional-width jis83 stacked-fractions tabular-nums oldstyle-nums historical-forms all-small-caps no-contextual no-historical-ligatures no-discretionary-ligatures no-common-ligatures',
+  [
+    'no-common-ligatures no-discretionary-ligatures no-historical-ligatures no-contextual all-small-caps historical-forms oldstyle-nums tabular-nums stacked-fractions jis83 proportional-width super',
+    'no-contextual no-historical-ligatures no-discretionary-ligatures no-common-ligatures all-small-caps historical-forms stacked-fractions tabular-nums oldstyle-nums jis83 proportional-width super'
+  ]
+);
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/spanner-after-parallel-flow.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/spanner-after-parallel-flow.html
new file mode 100644
index 0000000..4ed0914
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/spanner-after-parallel-flow.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1383978">
+<div style="columns:5; height:10px;">
+  <div style="height:0;">
+    <div style="contain:size; height:20px;"></div>
+    <div style="contain:size; height:20px;"></div>
+    <div></div>
+    <div style="break-before:column;"></div>
+  </div>
+  <div>
+    <div style="contain:size; height:20px;"></div>
+    <div style="contain:size; height:20px;"></div>
+    <div style="column-span:all;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-001.html
new file mode 100644
index 0000000..124f0116
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-001.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-multicol-1/#spanning-columns">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1383916">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:2; width:100px; gap:0; orphans:1; widows:1; background:red;">
+  <div style="float:left; width:50px; height:180px; background:green;"></div>
+  <div>
+    <div style="column-span:all; height:10px; background:green;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-002.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-002.html
new file mode 100644
index 0000000..3a8bac5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-002.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-multicol-1/#spanning-columns">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1383916">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:2; width:100px; gap:0; orphans:1; widows:1; background:red;">
+  <div style="float:left; width:50px; height:180px; background:green;"></div>
+  <div>
+    <div>
+      <div style="column-span:all; height:10px; background:green;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-003.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-003.html
new file mode 100644
index 0000000..8016205
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-003.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-multicol-1/#spanning-columns">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1383916">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:2; width:100px; gap:0; orphans:1; widows:1; background:red;">
+  <div style="float:left; width:50px; height:180px; background:green;"></div>
+  <span>
+    <div style="column-span:all; height:10px; background:green;"></div>
+  </span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-004.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-004.html
new file mode 100644
index 0000000..00d4e0d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-child-after-parallel-flow-004.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-multicol-1/#spanning-columns">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1383916">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:2; width:100px; gap:0; orphans:1; widows:1; background:red;">
+  <div style="height:0;">
+    <div style="height:90px; background:green;"></div>
+    <div style="break-before:column; height:90px; background:green;"></div>
+  </div>
+  <span>
+    <div style="column-span:all; height:10px; background:green;"></div>
+  </span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/cssom-getPropertyValue-common-checks-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/cssom-getPropertyValue-common-checks-expected.txt
new file mode 100644
index 0000000..7dc527c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/cssom-getPropertyValue-common-checks-expected.txt
@@ -0,0 +1,14 @@
+This is a testharness.js-based test.
+PASS All properties can serialize 'initial'
+FAIL All properties (except 'all') can serialize their initial value (computed) assert_array_equals: lengths differ, expected array ["all"] length 1, got ["all", ["background-repeat-x", ""], ["background-repeat-y", ""], ["grid", "none / none / none / row / auto / auto"], ["grid-template", "none / none / none"], ["page-orientation", ""], ["size", ""], ["view-timeline", ""]] length 8
+FAIL All properties (except 'all') can serialize their initial value (specified) assert_array_equals: lengths differ, expected array [] length 0, got [["grid-column-gap", "normal", ""], ["grid-gap", "normal normal", ""], ["grid-row-gap", "normal", ""]] length 3
+PASS All shorthands can serialize their longhands set to 'initial'
+FAIL All shorthands can serialize their longhands set to their initial value assert_array_equals: lengths differ, expected array [] length 0, got [["border", ""], ["grid-gap", ""]] length 2
+PASS All aliases can serialize target property set to 'initial'
+FAIL All aliases can serialize target property set to its initial value assert_array_equals: lengths differ, expected array [] length 0, got [["grid-column-gap", ""], ["grid-row-gap", ""]] length 2
+PASS Can't serialize shorthand when longhands are set to different css-wide keywords
+PASS Can't serialize shorthand when longhands have different priority
+PASS Can't serialize shorthand set to 'initial' when some longhand is missing
+PASS Can't serialize shorthand set to initial value when some longhand is missing
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/cssom-getPropertyValue-common-checks.html b/third_party/blink/web_tests/external/wpt/css/cssom/cssom-getPropertyValue-common-checks.html
new file mode 100644
index 0000000..29ca39a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/cssom-getPropertyValue-common-checks.html
@@ -0,0 +1,225 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Common serialization checks for all properties</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue">
+
+<div id="element"></div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+const element = document.getElementById("element");
+const { style } = element;
+const computedStyle = getComputedStyle(element);
+const cssProperties = new Set();
+const cssShorthands = new Map();
+const cssShorthandsForLonghand = new Map();
+const cssLonghands = new Set();
+const cssAliases = new Map();
+const initialValues = new Map();
+
+setup(function() {
+  for (let obj = style; obj; obj = Reflect.getPrototypeOf(obj)) {
+    for (let name of Object.getOwnPropertyNames(obj)) {
+      const property = name.replace(/[A-Z]/g, c => "-" + c.toLowerCase());
+      if (CSS.supports(property, "initial")) {
+        cssProperties.add(property);
+      }
+    }
+  }
+  for (let property of cssProperties) {
+    style.cssText = "";
+    style.setProperty(property, "initial");
+    if (style.length > 1) {
+      cssShorthands.set(property, [...style]);
+      for (let longhand of style) {
+        if (cssShorthandsForLonghand.has(longhand)) {
+          cssShorthandsForLonghand.get(longhand).add(property);
+        } else {
+          cssShorthandsForLonghand.set(longhand, new Set([property]));
+        }
+      }
+    } else if (style.length === 1) {
+      if (property === style[0]) {
+        cssLonghands.add(property);
+      } else {
+        cssAliases.set(property, style[0]);
+      }
+    }
+  }
+});
+
+test(function() {
+  const bad = [];
+  for (let property of cssProperties) {
+    style.cssText = "";
+    style.setProperty(property, "initial");
+    const result = style.getPropertyValue(property);
+    if (result !== "initial") {
+      bad.push([property, result]);
+    }
+  }
+  assert_array_equals(bad, []);
+}, "All properties can serialize 'initial'");
+
+test(function() {
+  for (let longhand of cssLonghands) {
+    element.style.setProperty(longhand, "initial");
+  }
+  const bad = [];
+  for (let property of cssProperties) {
+    const result = computedStyle.getPropertyValue(property);
+    if (CSS.supports(property, result)) {
+      initialValues.set(property, result);
+    } else if (property === "all") {
+      bad.push("all");
+    } else {
+      bad.push([property, result]);
+    }
+  }
+  assert_array_equals(bad, ["all"]);
+}, "All properties (except 'all') can serialize their initial value (computed)");
+
+test(function() {
+  const bad = [];
+  for (let [property, value] of initialValues) {
+    style.cssText = "";
+    style.setProperty(property, value);
+    const result = style.getPropertyValue(property);
+    if (!CSS.supports(property, result)) {
+      bad.push([property, value, result]);
+    }
+  }
+  assert_array_equals(bad, []);
+}, "All properties (except 'all') can serialize their initial value (specified)");
+
+test(function() {
+  const bad = [];
+  for (let [shorthand, longhands] of cssShorthands) {
+    style.cssText = "";
+    for (let longhand of longhands) {
+      style.setProperty(longhand, "initial");
+    }
+    const result = style.getPropertyValue(shorthand);
+    if (result !== "initial") {
+      bad.push([shorthand, result]);
+    }
+  }
+  assert_array_equals(bad, []);
+}, "All shorthands can serialize their longhands set to 'initial'");
+
+test(function() {
+  const bad = [];
+  outerloop:
+  for (let [shorthand, longhands] of cssShorthands) {
+    style.cssText = "";
+    for (let longhand of longhands) {
+      if (!initialValues.has(longhand)) {
+        continue outerloop;
+      }
+      style.setProperty(longhand, initialValues.get(longhand));
+    }
+    const result = style.getPropertyValue(shorthand);
+    if (!CSS.supports(shorthand, result)) {
+      bad.push([shorthand, result]);
+    }
+  }
+  assert_array_equals(bad, []);
+}, "All shorthands can serialize their longhands set to their initial value");
+
+test(function() {
+  const bad = [];
+  for (let [alias, target] of cssAliases) {
+    style.cssText = "";
+    style.setProperty(target, "initial");
+    const result = style.getPropertyValue(alias);
+    if (result !== "initial") {
+      bad.push([alias, result]);
+    }
+  }
+  assert_array_equals(bad, []);
+}, "All aliases can serialize target property set to 'initial'");
+
+test(function() {
+  const bad = [];
+  for (let [alias, target] of cssAliases) {
+    if (!initialValues.has(target)) {
+      continue;
+    }
+    style.cssText = "";
+    style.setProperty(target, initialValues.get(target));
+    const result = style.getPropertyValue(alias);
+    if (!CSS.supports(alias, result)) {
+      bad.push([alias, result]);
+    }
+  }
+  assert_array_equals(bad, []);
+}, "All aliases can serialize target property set to its initial value");
+
+test(function() {
+  const bad = [];
+  for (let [shorthand, longhands] of cssShorthands) {
+    for (let longhand of longhands) {
+      style.cssText = "";
+      style.setProperty(shorthand, "initial");
+      style.setProperty(longhand, "inherit");
+      const result = style.getPropertyValue(shorthand);
+      if (result !== "") {
+        bad.push([shorthand, longhand, result]);
+      }
+    }
+  }
+  assert_array_equals(bad, []);
+}, "Can't serialize shorthand when longhands are set to different css-wide keywords");
+
+test(function() {
+  const bad = [];
+  for (let [shorthand, longhands] of cssShorthands) {
+    for (let longhand of longhands) {
+      style.cssText = "";
+      style.setProperty(shorthand, "initial");
+      style.setProperty(longhand, "initial", "important");
+      const result = style.getPropertyValue(shorthand);
+      if (result !== "") {
+        bad.push([shorthand, longhand, result]);
+      }
+    }
+  }
+  assert_array_equals(bad, []);
+}, "Can't serialize shorthand when longhands have different priority");
+
+test(function() {
+  const bad = [];
+  for (let [shorthand, longhands] of cssShorthands) {
+    for (let longhand of longhands) {
+      style.cssText = "";
+      style.setProperty(shorthand, "initial");
+      style.removeProperty(longhand);
+      const result = style.getPropertyValue(shorthand);
+      if (result !== "") {
+        bad.push([shorthand, longhand, result]);
+      }
+    }
+  }
+  assert_array_equals(bad, []);
+}, "Can't serialize shorthand set to 'initial' when some longhand is missing");
+
+test(function() {
+  const bad = [];
+  for (let [shorthand, longhands] of cssShorthands) {
+    if (initialValues.has(shorthand)) {
+      for (let longhand of longhands) {
+        style.cssText = "";
+        style.setProperty(shorthand, initialValues.get(shorthand));
+        style.removeProperty(longhand);
+        const result = style.getPropertyValue(shorthand);
+        if (result !== "") {
+          bad.push([shorthand, longhand, result]);
+        }
+      }
+    }
+  }
+  assert_array_equals(bad, []);
+}, "Can't serialize shorthand set to initial value when some longhand is missing");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html
index 1728adb1..66b12b4 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html
@@ -18,31 +18,31 @@
 <script>
 ['mousedown', 'mouseup', 'pointerdown', 'pointerup', 'click'].forEach(eventName => {
   [true, false].forEach(clickChildElement => {
-    promise_test(async () => {
+    promise_test(async t => {
       const parentShouldReceiveEvents = eventName.startsWith('pointer');
       let parentReceivedEvent = false;
-      targetparent.addEventListener(eventName, () => {
+      targetparent.addEventListener(eventName, t.step_func(() => {
         if (parentShouldReceiveEvents) {
           parentReceivedEvent = true;
         } else {
           assert_unreached(`parent element should not receive ${eventName} events.`);
         }
-      });
+      }));
 
       const targetShouldReceiveEvents = eventName.startsWith('pointer');
       let targetReceivedEvent = false;
-      target.addEventListener(eventName, () => {
+      target.addEventListener(eventName, t.step_func(() => {
         if (targetShouldReceiveEvents) {
           targetReceivedEvent = true;
         } else {
           assert_unreached(`target element should not receive ${eventName} events.`);
         }
-      });
+      }));
 
       let childReceivedEvent = false;
-      targetchild.addEventListener(eventName, () => {
+      targetchild.addEventListener(eventName, t.step_func(() => {
         childReceivedEvent = true;
-      });
+      }));
 
       await test_driver.click(clickChildElement ? targetchild : target);
 
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
index 5fc0b68..651b377 100644
--- a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
@@ -1,8 +1,8 @@
 This is a testharness.js-based test.
-Found 60 tests; 59 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 60 tests; 58 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS getDisplayMedia in navigator.mediaDevices
 FAIL getDisplayMedia() must require user activation assert_unreached: Should have rejected: getDisplayMedia should have returned an already-rejected promise. Reached unreachable code
-PASS getDisplayMedia() must adhere to frameRate if set
+FAIL getDisplayMedia() must adhere to frameRate if set assert_greater_than_equal: expected a number greater than or equal to 2.5 but got NaN
 PASS getDisplayMedia({"video":true}) must succeed with video
 PASS getDisplayMedia({"video":true,"audio":false}) must succeed with video
 PASS getDisplayMedia({"video":{}}) must succeed with video
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
index 989835af..d2229e11 100644
--- a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
+++ b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
@@ -40,7 +40,7 @@
   const v = document.getElementById('display');
   v.autoplay = true;
   // work around firefox bug 1586505, orthogonal to what's being tested
-  const frames = () => v.getVideoPlaybackQuality()?.totalVideoFrames ?? v.mozPaintedFrames;
+  const frames = () => v.getVideoPlaybackQuality()?.totalVideoFrames || v.mozPaintedFrames;
   const target_rate = 5;
   const stream = await getDisplayMedia({video: {width:160, frameRate: target_rate}});
   t.add_cleanup(() => stopTracks(stream));
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html
index f9f8cdec..8fc159d 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html
@@ -19,7 +19,7 @@
     testNavigationApiNotDetected(
       "Aborted navigate event is not a soft navigation",
       e => {
-        timestamps[counter]["clickEventStart"] = performance.now();
+        timestamps[counter]["eventStart"] = performance.now();
         e.intercept({handler: async () => {
           await addImageToMain();
           main.appendChild(img);
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-rejected.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-rejected.tentative.html
index 7d3e9e3..bcc0451d 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-rejected.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-rejected.tentative.html
@@ -16,7 +16,7 @@
   <script>
     const link = document.getElementById("link");
     testNavigationApi("Test intercepted and rejected navigate event", e => {
-        timestamps[counter]["clickEventStart"] = performance.now();
+        timestamps[counter]["eventStart"] = performance.now();
         e.intercept({handler: async () => {
           await addImageToMain();
           throw new Error("This navigation handler rejected");
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api.tentative.html
index 3ad16dd9..c4f2786c 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api.tentative.html
@@ -16,7 +16,7 @@
   <script>
     const link = document.getElementById("link");
     testNavigationApi("Test soft navigation with the Navigation API", e => {
-        timestamps[counter]["clickEventStart"] = performance.now();
+        timestamps[counter]["eventStart"] = performance.now();
         e.intercept({handler: async () => {
           await addImageToMain();
           main.appendChild(img);
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/popstate.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/popstate.tentative.html
new file mode 100644
index 0000000..60a5ff72
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/popstate.tentative.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Detect simple soft navigation.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/soft-navigation-helper.js"></script>
+</head>
+<body>
+  <main id=main>
+    <div>
+      <a id=link>Click me!</a>
+    </div>
+  </main>
+  <script>
+    // Push state twice, so that history.back() will trigger a popstate event,
+    // when the first push state is restored.
+    history.pushState({}, "", "foobar.html");
+    history.pushState({}, "", "another_one.html");
+
+    const link = document.getElementById("link");
+    link.addEventListener("click", () => history.back());
+    testSoftNavigation({
+      addContent: () => {
+        // Add the content to the main element
+        const main = document.getElementById("main");
+        main.removeChild(document.getElementsByTagName("div")[0]);
+        const div = document.createElement("div");
+        const text = document.createTextNode("Lorem ipsum");
+        div.appendChild(text);
+        div.style="font-size: 3em";
+        main.appendChild(div);
+      },
+      link: link,
+      testName: "A soft navigation that uses a same-document initiated popstate"
+        + " event is recognized by SoftNavigationHeuristics",
+      eventType: "popstate"});
+  </script>
+</body>
+</html>
+
+
+
+
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js
index 1bef2c2..cefe915 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js
@@ -17,9 +17,10 @@
                                                    () => {});
       const testName = options.testName;
       const pushUrl = readValue(options.pushUrl, true);
+      const eventType = readValue(options.eventType, "click");
       promise_test(async t => {
         const preClickLcp = await getLcpEntries();
-        setClickEvent(t, link, pushState, addContent, pushUrl);
+        setEvent(t, link, pushState, addContent, pushUrl, eventType);
         for (let i = 0; i < clicks; ++i) {
           clicked = false;
           click(link);
@@ -101,9 +102,10 @@
   });
 };
 
-const setClickEvent = (t, link, pushState, addContent, pushUrl) => {
-  link.addEventListener("click", async e => {
-    timestamps[counter]["clickEventStart"] = performance.now();
+const setEvent = (t, button, pushState, addContent, pushUrl, eventType) => {
+  const eventObject = (eventType == "click") ? button : window;
+  eventObject.addEventListener(eventType, async e => {
+    timestamps[counter]["eventStart"] = performance.now();
     // Jump through a task, to ensure task tracking is working properly.
     await new Promise(r => t.step_timeout(r, 0));
 
@@ -148,8 +150,8 @@
     const entryTimestamp = entry.startTime;
     assert_less_than_equal(timestamps[i]["syncPostClick"], entryTimestamp);
     assert_greater_than_equal(
-        timestamps[i]['clickEventStart'], entryTimestamp,
-        'Click event start timestamp matches');
+        timestamps[i]['eventStart'], entryTimestamp,
+        'Event start timestamp matches');
     assert_not_equals(entry.navigationId,
                       performance.getEntriesByType("navigation")[0].navigationId,
                       "The navigation ID was incremented");
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
new file mode 100644
index 0000000..18767b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS share() is disabled by default 'self' by permissions policy for cross-origin iframes
+PASS share() is disabled explicitly by permissions policy for cross-origin iframe
+PASS share() not allowed, as only allowed to share with self
+PASS canShare() not allowed to share by default permissions policy cross-origin
+FAIL canShare() is allowed by permissions policy to share cross-origin on a particular origin assert_equals: Expected true, is it can now share on https://web-platform.test:8444. expected true but got false
+PASS canShare() with self
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..9b5e3a2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL PersistentOriginTrial using Critical header assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..664288a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+FAIL PersistentInChild assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..62deff42
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS PersistentOriginTrial using Critical header
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..6d4a956
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+PASS PersistentInChild
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
new file mode 100644
index 0000000..18767b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS share() is disabled by default 'self' by permissions policy for cross-origin iframes
+PASS share() is disabled explicitly by permissions policy for cross-origin iframe
+PASS share() not allowed, as only allowed to share with self
+PASS canShare() not allowed to share by default permissions policy cross-origin
+FAIL canShare() is allowed by permissions policy to share cross-origin on a particular origin assert_equals: Expected true, is it can now share on https://web-platform.test:8444. expected true but got false
+PASS canShare() with self
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..62deff42
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS PersistentOriginTrial using Critical header
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..6d4a956
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+PASS PersistentInChild
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/transforms/svg-vs-css-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/transforms/svg-vs-css-expected.png
index ec983df1..7bcd05f3 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/transforms/svg-vs-css-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/transforms/svg-vs-css-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/web-sql-issue-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/web-sql-issue-expected.txt
deleted file mode 100644
index 9b32692..0000000
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/web-sql-issue-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Tests that deprecation issues are reported
-Inspector issue: {
-    issue : {
-        code : DeprecationIssue
-        details : {
-            deprecationIssueDetails : {
-                affectedFrame : {
-                    frameId : <string>
-                }
-                sourceCodeLocation : {
-                    columnNumber : 8
-                    lineNumber : 0
-                    scriptId : <string>
-                    url : 
-                }
-                type : OpenWebDatabaseInsecureContext
-            }
-        }
-    }
-}
-
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/web-sql-issue.js b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/web-sql-issue.js
deleted file mode 100644
index 6e491d5..0000000
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/web-sql-issue.js
+++ /dev/null
@@ -1,13 +0,0 @@
-(async function(testRunner) {
-  const {session, dp} = await testRunner.startURL(
-      'http://devtools.test:8000/inspector-protocol/resources/empty.html',
-      `Tests that deprecation issues are reported`);
-
-  await dp.Audits.enable();
-  const promise = dp.Audits.onceIssueAdded();
-  session.evaluate('window.openDatabase(\'testdb\', \'1.0\', \'\', 1)');
-
-  const result = await promise;
-  testRunner.log(result.params, 'Inspector issue: ');
-  testRunner.completeTest();
-})
diff --git a/third_party/blink/web_tests/http/tests/persistent-origin-trials/critical-origin-trial.https.php b/third_party/blink/web_tests/http/tests/persistent-origin-trials/critical-origin-trial.https.php
new file mode 100644
index 0000000..8e9f280
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/persistent-origin-trials/critical-origin-trial.https.php
@@ -0,0 +1,21 @@
+<?php
+// Token for FrobulatePersistent
+$ORIGIN_TRIAL_TOKEN = "A7eQahvlWGVqTPZ/Rpyq3p+Lw+CZaKPs8POfJ7SURAykNb7kG6+xv4I3O4E03VALwnxZJy4aB83PX5q5yseoSQEAAABceyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6ODQ0MyIsICJmZWF0dXJlIjogIkZyb2J1bGF0ZVBlcnNpc3RlbnQiLCAiZXhwaXJ5IjogMjAwMDAwMDAwMH0=";
+header("Origin-Trial: ". $ORIGIN_TRIAL_TOKEN);
+header("Critical-Origin-Trial: FrobulatePersistent");
+$headers = getallheaders();
+$trials = $headers['X-Web-Test-Enabled-Origin-Trials'];
+?>
+<!DOCTYPE html>
+<title>Test that the Critical-Origin-Trial header enables the request header</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+    test(function(){
+        assert_equals("<?php echo($trials)?>", "FrobulatePersistent");
+        this.add_cleanup(function() {
+            window.open("support/cleanup.https.html");
+        });
+    }, "PersistentOriginTrial using Critical header");
+</script>
diff --git a/third_party/blink/web_tests/http/tests/persistent-origin-trials/support/cleanup.https.html b/third_party/blink/web_tests/http/tests/persistent-origin-trials/support/cleanup.https.html
new file mode 100644
index 0000000..d2f5890
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/persistent-origin-trials/support/cleanup.https.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<!--
+    This file exists to allow for a navigation to the test origin
+    without setting any Origin-Trial headers.
+-->
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/persistent-origin-trials/window-origin-trial.https.php b/third_party/blink/web_tests/http/tests/persistent-origin-trials/window-origin-trial.https.php
new file mode 100644
index 0000000..e420cfa
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/persistent-origin-trials/window-origin-trial.https.php
@@ -0,0 +1,51 @@
+<?php
+// Token for FrobulatePersistent
+$ORIGIN_TRIAL_TOKEN = "A7eQahvlWGVqTPZ/Rpyq3p+Lw+CZaKPs8POfJ7SURAykNb7kG6+xv4I3O4E03VALwnxZJy4aB83PX5q5yseoSQEAAABceyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6ODQ0MyIsICJmZWF0dXJlIjogIkZyb2J1bGF0ZVBlcnNpc3RlbnQiLCAiZXhwaXJ5IjogMjAwMDAwMDAwMH0=";
+header("Origin-Trial: ". $ORIGIN_TRIAL_TOKEN);
+$headers = getallheaders();
+$trials = $headers['X-Web-Test-Enabled-Origin-Trials'];
+
+$child = $_REQUEST['child'] == "true";
+
+if (!$child) {
+// Main page
+?>
+<!DOCTYPE html>
+<title>Test that navigations in a new window enables persistent origin trials</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+    test(
+        () => {
+            // Ensure that the test state is reset, by checking that the first
+            // load does not have an enabled persistent trial.
+            assert_equals("<?php echo($trials)?>", "");
+        }, "TestPrimaryPageHasNoTrial");
+    // Navigate to the same domain, and check that the trial header is set
+    var child_window = window.open("window-origin-trial.https.php?child=true");
+    fetch_tests_from_window(child_window);
+  </script>
+<?php
+// End main page
+} else {
+// Child page
+?>
+<!DOCTYPE html>
+<title>Test that navigations in a new window enables persistent origin trials</title>
+<script src="/resources/testharness.js"></script>
+<body>
+<script>
+    test(function() {
+        // In the child, assert that the header is now applied without any
+        // redirects
+        assert_equals("<?php echo($trials)?>", "FrobulatePersistent");
+
+        this.add_cleanup(function() {
+            window.open("support/cleanup.https.html");
+        });
+    }, "PersistentInChild");
+</script>
+<?php
+// End child page
+}
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..9b5e3a2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL PersistentOriginTrial using Critical header assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..664288a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+FAIL PersistentInChild assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/generic/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..62deff42
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS PersistentOriginTrial using Critical header
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/generic/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..6d4a956
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+PASS PersistentInChild
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/linux/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..9b5e3a2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL PersistentOriginTrial using Critical header assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/linux/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..664288a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+FAIL PersistentInChild assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/svg/transforms/svg-css-transforms-expected.png b/third_party/blink/web_tests/platform/linux/svg/transforms/svg-css-transforms-expected.png
index 014acf5..d5d57d1 100644
--- a/third_party/blink/web_tests/platform/linux/svg/transforms/svg-css-transforms-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/transforms/svg-css-transforms-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/transforms/svg-vs-css-expected.png b/third_party/blink/web_tests/platform/linux/transforms/svg-vs-css-expected.png
index b9e79aeb..b8913228f 100644
--- a/third_party/blink/web_tests/platform/linux/transforms/svg-vs-css-expected.png
+++ b/third_party/blink/web_tests/platform/linux/transforms/svg-vs-css-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..62deff42
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS PersistentOriginTrial using Critical header
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..6d4a956
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+PASS PersistentInChild
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/mac/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..9b5e3a2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL PersistentOriginTrial using Critical header assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/mac/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..664288a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+FAIL PersistentInChild assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/svg/transforms/svg-css-transforms-expected.png b/third_party/blink/web_tests/platform/mac/svg/transforms/svg-css-transforms-expected.png
index cb4c7dd..61336fe 100644
--- a/third_party/blink/web_tests/platform/mac/svg/transforms/svg-css-transforms-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/transforms/svg-css-transforms-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/transforms/svg-vs-css-expected.png b/third_party/blink/web_tests/platform/mac/transforms/svg-vs-css-expected.png
index a582eb03..1243f213 100644
--- a/third_party/blink/web_tests/platform/mac/transforms/svg-vs-css-expected.png
+++ b/third_party/blink/web_tests/platform/mac/transforms/svg-vs-css-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..62deff42
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS PersistentOriginTrial using Critical header
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..6d4a956
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+PASS PersistentInChild
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/svg/transforms/svg-css-transforms-expected.png b/third_party/blink/web_tests/platform/win/svg/transforms/svg-css-transforms-expected.png
index 7303be2e..8cda910 100644
--- a/third_party/blink/web_tests/platform/win/svg/transforms/svg-css-transforms-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/transforms/svg-css-transforms-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/transforms/svg-vs-css-expected.png b/third_party/blink/web_tests/platform/win/transforms/svg-vs-css-expected.png
index 2047d89..49aa43d 100644
--- a/third_party/blink/web_tests/platform/win/transforms/svg-vs-css-expected.png
+++ b/third_party/blink/web_tests/platform/win/transforms/svg-vs-css-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/win10/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..9b5e3a2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL PersistentOriginTrial using Critical header assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win10/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/win10/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..664288a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+FAIL PersistentInChild assert_equals: expected "FrobulatePersistent" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win10/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/win10/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
new file mode 100644
index 0000000..62deff42
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/critical-origin-trial.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS PersistentOriginTrial using Critical header
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win10/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt b/third_party/blink/web_tests/platform/win10/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
new file mode 100644
index 0000000..6d4a956
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/virtual/enable-persistent-origin-trials/http/tests/persistent-origin-trials/window-origin-trial.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS TestPrimaryPageHasNoTrial
+PASS PersistentInChild
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/enable-persistent-origin-trials/README.md b/third_party/blink/web_tests/virtual/enable-persistent-origin-trials/README.md
new file mode 100644
index 0000000..dfe13100
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/enable-persistent-origin-trials/README.md
@@ -0,0 +1,9 @@
+This directory contains a test suite for an expansion of the Origin Trials
+framework to include persistent trials, which is currently undergoing Finch
+roll-out in M109.
+
+Since the `PersistentOriginTrials` flag is disabled by default for now, this
+virtual test suite exist to run tests with the flag enabled.
+
+This virtual test suite will be removed once the `PersistentOriginTrials` flag
+is enabled by default.
diff --git a/third_party/libavif/BUILD.gn b/third_party/libavif/BUILD.gn
index 6d0ffdc..3e1bb489 100644
--- a/third_party/libavif/BUILD.gn
+++ b/third_party/libavif/BUILD.gn
@@ -38,10 +38,4 @@
     defines += [ "AVIF_CODEC_DAV1D" ]
     deps += [ "//third_party/dav1d" ]
   }
-
-  if (enable_libgav1_decoder) {
-    sources += [ "src/src/codec_libgav1.c" ]
-    defines += [ "AVIF_CODEC_LIBGAV1" ]
-    deps += [ "//third_party/libgav1" ]
-  }
 }
diff --git a/third_party/libgav1/BUILD.gn b/third_party/libgav1/BUILD.gn
index 2c06864..78f53e8 100644
--- a/third_party/libgav1/BUILD.gn
+++ b/third_party/libgav1/BUILD.gn
@@ -39,7 +39,8 @@
   }
 }
 
-if (enable_libgav1_decoder || use_libgav1_parser) {
+# TODO(b/259317395): Add source_set for parsing only.
+if (use_libgav1_parser) {
   # Separate from libgav1 because utils/constants.cc and dsp/constants.cc
   # generate the same object file, constants.o.
   source_set("libgav1_utils") {
diff --git a/third_party/libgav1/options.gni b/third_party/libgav1/options.gni
index 8474dfd..0aab011 100644
--- a/third_party/libgav1/options.gni
+++ b/third_party/libgav1/options.gni
@@ -6,13 +6,8 @@
 import("//build/config/gclient_args.gni")
 
 declare_args() {
-  # Enable libgav1 decoder.
-  # TODO(b/179825724): enable on LaCrOS.
-  enable_libgav1_decoder =
-      is_chromeos_ash && (target_cpu == "arm" || target_cpu == "arm64")
   use_libgav1_parser =
       (is_chromeos || is_linux || is_win) &&
-      (target_cpu == "x86" || target_cpu == "x64" ||
-      target_cpu == "arm" || target_cpu == "arm64" ||
-      target_cpu == "ppc64")
+      (target_cpu == "x86" || target_cpu == "x64" || target_cpu == "arm" ||
+       target_cpu == "arm64" || target_cpu == "ppc64")
 }
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 320600c8..149a395 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -184,9 +184,10 @@
 
   Needs to be called from inside the git repository dir."""
   git_exe = 'git.bat' if sys.platform.startswith('win') else 'git'
-  return subprocess.check_output(
-      [git_exe, 'describe', '--long', '--abbrev=8', commit],
-      universal_newlines=True).rstrip()
+  return subprocess.check_output([
+      git_exe, 'describe', '--long', '--abbrev=8', '--match=*llvmorg-*-init',
+      commit
+  ], universal_newlines=True).rstrip()
 
 
 def AddCMakeToPath(args):
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ca0bf33..b33a4f5 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -61264,6 +61264,7 @@
   <int value="-122458532" label="FilesExtractArchive:enabled"/>
   <int value="-121563330" label="SecurePaymentConfirmationBrowser:disabled"/>
   <int value="-120521482" label="DirectManipulationStylus:enabled"/>
+  <int value="-120430245" label="EnableExpKitTextClassifier:enabled"/>
   <int value="-120091289" label="CrostiniAppSearch:enabled"/>
   <int value="-119841719" label="ThreadingOptimizationsOnIo:disabled"/>
   <int value="-119055644" label="GenericSensor:enabled"/>
@@ -64389,6 +64390,7 @@
   <int value="1766676896" label="affiliation-based-matching:disabled"/>
   <int value="1767218791" label="TouchDragAndContextMenu:enabled"/>
   <int value="1767411597" label="DisallowUnsafeHttpDownloads:enabled"/>
+  <int value="1768173143" label="EnableExpKitTextClassifier:disabled"/>
   <int value="1768759000" label="AutofillProfileServerValidation:disabled"/>
   <int value="1769483213" label="AudioUrl:disabled"/>
   <int value="1770189877" label="ConfirmNtpSuggestionRemovals:enabled"/>
@@ -105396,7 +105398,9 @@
   <int value="6" label="kValidHttp"/>
   <int value="7" label="kValidHttps"/>
   <int value="8" label="kValidDataURL"/>
-  <int value="9" label="kValidOtherProtocol"/>
+  <int value="9" label="kValidFileURL"/>
+  <int value="10" label="kValidBlob"/>
+  <int value="11" label="kValidOtherProtocol"/>
 </enum>
 
 <enum name="WaylandTimingEvent">
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index cf35fca..6b8789c 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -1010,22 +1010,6 @@
   </summary>
 </histogram>
 
-<histogram name="TabManager.BackgroundTabOpening.SwitchToTab"
-    enum="TabLoadingState" expires_after="M79">
-  <owner>chrisha@chromium.org</owner>
-  <summary>
-    The loading state of a tab at the time the user switches to it during a
-    background tab opening session (the duration of time from when the browser
-    starts to open background tabs until the time the browser has finished
-    loading those tabs or otherwise decided to stop loading them). The metric is
-    only recorded when a tab is switched to from another tab within the same
-    tabstrip. As a result, the case when switching between different windows is
-    not included, either between two tabs in different browser windows, or when
-    switching to a different application and switching back to the browser. The
-    metric is not recorded when the session overlaps with session restore.
-  </summary>
-</histogram>
-
 <histogram name="TabManager.BackgroundTabOpening.TabCount" units="tabs"
     expires_after="M79">
   <owner>chrisha@chromium.org</owner>
@@ -1175,27 +1159,6 @@
 </histogram>
 
 <histogram
-    name="TabManager.Experimental.BackgroundTabOpening.TabSwitchLoadTime.UntilTabIsLoaded"
-    units="ms" expires_after="M79">
-  <owner>chrisha@chromium.org</owner>
-  <summary>
-    The tab load time of a tab that is switched to during a background tab
-    opening session (the duration of time from when the browser starts to open
-    background tabs until the time the browser has finished loading those tabs
-    or otherwise decided to stop loading them). Tab load time is defined as the
-    time between when the user switches to a backround tab, and the time when
-    that tab finishes loading in the foreground. If the user switches away
-    before the tab finishes loading, a metric will not be recorded unless the
-    user switches back, in which case the tab load time is measured from that
-    point in time. The metric is only recorded when a tab is switched to from
-    another tab within the same tabstrip. As a result, the initial forground tab
-    is not included in this metric since it was not switched to from another
-    tab. The metric is not recorded when the session overlaps with session
-    restore.
-  </summary>
-</histogram>
-
-<histogram
     name="TabManager.Experimental.SessionRestore.ForegroundTab.FirstContentfulPaint"
     units="ms" expires_after="M79">
   <owner>chrisha@chromium.org</owner>
@@ -1296,25 +1259,6 @@
   </summary>
 </histogram>
 
-<histogram name="TabManager.SessionRestore.SwitchToTab" enum="TabLoadingState"
-    expires_after="M79">
-  <owner>chrisha@chromium.org</owner>
-  <summary>
-    The loading state of a tab at the time the user switched to it during a
-    session restore. The metric is only recorded when a tab is switched to from
-    another tab within the same tabstrip. As a result, there are two cases where
-    tabs are not included. The first case is when the initial forground tab is
-    shown, since it was not switched to from another tab. The second case is
-    when switching between different windows, either between two tabs in
-    different browser windows, or when switching to a different application and
-    switching back to the browser. The metric is only recorded when session
-    restore is actively loading tabs, which ends when either all tabs have been
-    loaded and their pages rendered, or tab loading needs to be deferred in
-    cases where the system is under memory pressure. The metric is not recorded
-    when the session overlaps with background tab opening session.
-  </summary>
-</histogram>
-
 <histogram name="TabManager.TabRanker.Result" enum="TabManagerTabRankerResult"
     expires_after="M85">
   <owner>michaelpg@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/variations/histograms.xml b/tools/metrics/histograms/metadata/variations/histograms.xml
index 77009f5..7a6c33e 100644
--- a/tools/metrics/histograms/metadata/variations/histograms.xml
+++ b/tools/metrics/histograms/metadata/variations/histograms.xml
@@ -281,9 +281,9 @@
 </histogram>
 
 <histogram name="Variations.PolicyRestriction"
-    enum="VariationsRestrictionPolicyValues" expires_after="2022-04-30">
-  <owner>pastarmovj@chromium.org</owner>
+    enum="VariationsRestrictionPolicyValues" expires_after="2023-06-30">
   <owner>ydago@chromium.org</owner>
+  <owner>pastarmovj@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
     Records the restrictions on how experiment variations are applied on the
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 29aa641a..15b05b1 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -20407,6 +20407,9 @@
 
 <event name="TabManager.Experimental.BackgroundTabOpening.TabSwitchLoadStopped"
     singular="True">
+  <obsolete>
+    Removed 11/2022 because it wasn't actively used.
+  </obsolete>
   <owner>zhenw@chromium.org</owner>
   <summary>
     Collects data when a tab is switched to from another tab and then finishes
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index ffcf85d..c16b35c 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,15 +6,15 @@
         },
         "win": {
             "hash": "bb2cc045bbee68ad3cd3daed827075285572fe49",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/cd8caf2a15c6ecd393ff7add162f6e3af681d0a3/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/a3e39a91c2d5d61394a314c8b042d07660e8743d/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "mac": {
-            "hash": "08e3f8126405ba583ce845a3af5ef631f2cf68b3",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/b25d8d9bb1d5aca92d98c17acabd5a8e208e74ad/trace_processor_shell"
+            "hash": "d85de527c577d68968139c64a9185e6b00750c8d",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/9fcb4a22e876f62e6e197d03000ee955d26c4bf4/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "92318bea34f5c9beec69d2d826a9a92ec9d3cdcd",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "7e4cc10d0a4b47b170771988b6800e9438ad73cf",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/cd8caf2a15c6ecd393ff7add162f6e3af681d0a3/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/9fcb4a22e876f62e6e197d03000ee955d26c4bf4/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h
index 4a9b362..febdc99 100644
--- a/ui/accessibility/ax_node.h
+++ b/ui/accessibility/ax_node.h
@@ -426,6 +426,10 @@
 
   ax::mojom::NameFrom GetNameFrom() const { return data().GetNameFrom(); }
 
+  ax::mojom::DescriptionFrom GetDescriptionFrom() const {
+    return data().GetDescriptionFrom();
+  }
+
   ax::mojom::InvalidState GetInvalidState() const {
     return data().GetInvalidState();
   }
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.cc b/ui/accessibility/platform/ax_platform_node_delegate.cc
index f155cd4be..c3ee2e8 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate.cc
@@ -5,11 +5,13 @@
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 
 #include "base/containers/fixed_flat_set.h"
+#include "base/notreached.h"
+#include "ui/accessibility/ax_selection.h"
 #include "ui/accessibility/platform/ax_platform_tree_manager.h"
 
 namespace ui {
 
-AXPlatformNodeDelegate::AXPlatformNodeDelegate() = default;
+AXPlatformNodeDelegate::AXPlatformNodeDelegate() : node_(nullptr) {}
 
 AXPlatformNodeDelegate::AXPlatformNodeDelegate(ui::AXNode* node) : node_(node) {
   DCHECK(node);
@@ -31,6 +33,262 @@
   return AXTreeManager::FromID(GetTreeData().tree_id);
 }
 
+const AXTreeData& AXPlatformNodeDelegate::GetTreeData() const {
+  if (node_) {
+    DCHECK(node_->tree())
+        << "All nodes should be owned by an accessibility tree.\n"
+        << *node_;
+    return node_->tree()->data();
+  }
+
+  static base::NoDestructor<AXTreeData> empty_data;
+  return *empty_data;
+}
+
+ax::mojom::Role AXPlatformNodeDelegate::GetRole() const {
+  // Getting the role is generally the result of an accessibility API call, so
+  // we should reset the auto-disable accessibility code.
+  EnableGlobalAccessibilityModeOnApiUsage();
+  if (node_)
+    return node_->GetRole();
+  return GetData().role;
+}
+
+bool AXPlatformNodeDelegate::HasBoolAttribute(
+    ax::mojom::BoolAttribute attribute) const {
+  if (node_)
+    return node_->HasBoolAttribute(attribute);
+  return GetData().HasBoolAttribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetBoolAttribute(
+    ax::mojom::BoolAttribute attribute) const {
+  if (node_)
+    return node_->GetBoolAttribute(attribute);
+  return GetData().GetBoolAttribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetBoolAttribute(
+    ax::mojom::BoolAttribute attribute,
+    bool* value) const {
+  if (node_)
+    return node_->GetBoolAttribute(attribute, value);
+  return GetData().GetBoolAttribute(attribute, value);
+}
+
+bool AXPlatformNodeDelegate::HasFloatAttribute(
+    ax::mojom::FloatAttribute attribute) const {
+  if (node_)
+    return node_->HasFloatAttribute(attribute);
+  return GetData().HasFloatAttribute(attribute);
+}
+
+float AXPlatformNodeDelegate::GetFloatAttribute(
+    ax::mojom::FloatAttribute attribute) const {
+  if (node_)
+    return node_->GetFloatAttribute(attribute);
+  return GetData().GetFloatAttribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetFloatAttribute(
+    ax::mojom::FloatAttribute attribute,
+    float* value) const {
+  if (node_)
+    return node_->GetFloatAttribute(attribute, value);
+  return GetData().GetFloatAttribute(attribute, value);
+}
+
+const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+AXPlatformNodeDelegate::GetIntAttributes() const {
+  if (node_)
+    return node_->GetIntAttributes();
+  return GetData().int_attributes;
+}
+
+bool AXPlatformNodeDelegate::HasIntAttribute(
+    ax::mojom::IntAttribute attribute) const {
+  if (node_)
+    return node_->HasIntAttribute(attribute);
+  return GetData().HasIntAttribute(attribute);
+}
+
+int AXPlatformNodeDelegate::GetIntAttribute(
+    ax::mojom::IntAttribute attribute) const {
+  if (node_)
+    return node_->GetIntAttribute(attribute);
+  return GetData().GetIntAttribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetIntAttribute(ax::mojom::IntAttribute attribute,
+                                             int* value) const {
+  if (node_)
+    return node_->GetIntAttribute(attribute, value);
+  return GetData().GetIntAttribute(attribute, value);
+}
+
+const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
+AXPlatformNodeDelegate::GetStringAttributes() const {
+  if (node_)
+    return node_->GetStringAttributes();
+  return GetData().string_attributes;
+}
+
+bool AXPlatformNodeDelegate::HasStringAttribute(
+    ax::mojom::StringAttribute attribute) const {
+  if (node_)
+    return node_->HasStringAttribute(attribute);
+  return GetData().HasStringAttribute(attribute);
+}
+
+const std::string& AXPlatformNodeDelegate::GetStringAttribute(
+    ax::mojom::StringAttribute attribute) const {
+  if (node_)
+    return node_->GetStringAttribute(attribute);
+  return GetData().GetStringAttribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetStringAttribute(
+    ax::mojom::StringAttribute attribute,
+    std::string* value) const {
+  if (node_)
+    return node_->GetStringAttribute(attribute, value);
+  return GetData().GetStringAttribute(attribute, value);
+}
+
+std::u16string AXPlatformNodeDelegate::GetString16Attribute(
+    ax::mojom::StringAttribute attribute) const {
+  if (node_)
+    return node_->GetString16Attribute(attribute);
+  return GetData().GetString16Attribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetString16Attribute(
+    ax::mojom::StringAttribute attribute,
+    std::u16string* value) const {
+  if (node_)
+    return node_->GetString16Attribute(attribute, value);
+  return GetData().GetString16Attribute(attribute, value);
+}
+
+const std::string& AXPlatformNodeDelegate::GetInheritedStringAttribute(
+    ax::mojom::StringAttribute attribute) const {
+  if (node_)
+    return node_->GetInheritedStringAttribute(attribute);
+
+  NOTIMPLEMENTED();
+  return GetData().GetStringAttribute(attribute);
+}
+
+std::u16string AXPlatformNodeDelegate::GetInheritedString16Attribute(
+    ax::mojom::StringAttribute attribute) const {
+  if (node_)
+    return node_->GetInheritedString16Attribute(attribute);
+
+  NOTIMPLEMENTED();
+  return GetData().GetString16Attribute(attribute);
+}
+
+const std::vector<std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+AXPlatformNodeDelegate::GetIntListAttributes() const {
+  if (node_)
+    return node_->GetIntListAttributes();
+  return GetData().intlist_attributes;
+}
+
+bool AXPlatformNodeDelegate::HasIntListAttribute(
+    ax::mojom::IntListAttribute attribute) const {
+  if (node_)
+    return node_->HasIntListAttribute(attribute);
+  return GetData().HasIntListAttribute(attribute);
+}
+
+const std::vector<int32_t>& AXPlatformNodeDelegate::GetIntListAttribute(
+    ax::mojom::IntListAttribute attribute) const {
+  if (node_)
+    return node_->GetIntListAttribute(attribute);
+  return GetData().GetIntListAttribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetIntListAttribute(
+    ax::mojom::IntListAttribute attribute,
+    std::vector<int32_t>* value) const {
+  if (node_)
+    return node_->GetIntListAttribute(attribute, value);
+  return GetData().GetIntListAttribute(attribute, value);
+}
+
+bool AXPlatformNodeDelegate::HasStringListAttribute(
+    ax::mojom::StringListAttribute attribute) const {
+  if (node_)
+    return node_->HasStringListAttribute(attribute);
+  return GetData().HasStringListAttribute(attribute);
+}
+
+const std::vector<std::string>& AXPlatformNodeDelegate::GetStringListAttribute(
+    ax::mojom::StringListAttribute attribute) const {
+  if (node_)
+    return node_->GetStringListAttribute(attribute);
+  return GetData().GetStringListAttribute(attribute);
+}
+
+bool AXPlatformNodeDelegate::GetStringListAttribute(
+    ax::mojom::StringListAttribute attribute,
+    std::vector<std::string>* value) const {
+  if (node_)
+    return node_->GetStringListAttribute(attribute, value);
+  return GetData().GetStringListAttribute(attribute, value);
+}
+
+bool AXPlatformNodeDelegate::HasHtmlAttribute(const char* attribute) const {
+  if (node_)
+    return node_->HasHtmlAttribute(attribute);
+  return GetData().HasHtmlAttribute(attribute);
+}
+
+const base::StringPairs& AXPlatformNodeDelegate::GetHtmlAttributes() const {
+  if (node_)
+    return node_->GetHtmlAttributes();
+  return GetData().html_attributes;
+}
+
+bool AXPlatformNodeDelegate::GetHtmlAttribute(const char* attribute,
+                                              std::string* value) const {
+  if (node_)
+    return node_->GetHtmlAttribute(attribute, value);
+  return GetData().GetHtmlAttribute(attribute, value);
+}
+
+bool AXPlatformNodeDelegate::GetHtmlAttribute(const char* attribute,
+                                              std::u16string* value) const {
+  if (node_)
+    return node_->GetHtmlAttribute(attribute, value);
+  return GetData().GetHtmlAttribute(attribute, value);
+}
+
+AXTextAttributes AXPlatformNodeDelegate::GetTextAttributes() const {
+  if (node_)
+    return node_->GetTextAttributes();
+  return GetData().GetTextAttributes();
+}
+
+bool AXPlatformNodeDelegate::HasState(ax::mojom::State state) const {
+  if (node_)
+    return node_->HasState(state);
+  return GetData().HasState(state);
+}
+
+ax::mojom::State AXPlatformNodeDelegate::GetState() const {
+  if (node_)
+    return node_->GetState();
+  return static_cast<ax::mojom::State>(GetData().state);
+}
+
+bool AXPlatformNodeDelegate::HasAction(ax::mojom::Action action) const {
+  if (node_)
+    return node_->HasAction(action);
+  return GetData().HasAction(action);
+}
+
 gfx::Rect AXPlatformNodeDelegate::GetClippedScreenBoundsRect(
     AXOffscreenResult* offscreen_result) const {
   return GetBoundsRect(AXCoordinateSystem::kScreenDIPs,
@@ -101,4 +359,240 @@
   return supported_actions;
 }
 
+bool AXPlatformNodeDelegate::HasTextStyle(
+    ax::mojom::TextStyle text_style) const {
+  if (node_)
+    return node_->HasTextStyle(text_style);
+  return GetData().HasTextStyle(text_style);
+}
+
+ax::mojom::NameFrom AXPlatformNodeDelegate::GetNameFrom() const {
+  if (node_)
+    return node_->GetNameFrom();
+  return GetData().GetNameFrom();
+}
+
+ax::mojom::DescriptionFrom AXPlatformNodeDelegate::GetDescriptionFrom() const {
+  if (node_)
+    return node_->GetDescriptionFrom();
+  return GetData().GetDescriptionFrom();
+}
+
+const AXSelection AXPlatformNodeDelegate::GetUnignoredSelection() const {
+  if (node_)
+    return node_->GetUnignoredSelection();
+
+  NOTIMPLEMENTED();
+  return AXSelection();
+}
+
+bool AXPlatformNodeDelegate::IsLeaf() const {
+  if (node_)
+    return node_->IsLeaf();
+  return !GetChildCount();
+}
+
+bool AXPlatformNodeDelegate::IsInvisibleOrIgnored() const {
+  if (node_)
+    return node_->IsInvisibleOrIgnored();
+  return IsIgnored() || GetData().IsInvisible();
+}
+
+const std::string& AXPlatformNodeDelegate::GetName() const {
+  if (node_)
+    return node()->GetNameUTF8();
+  return GetStringAttribute(ax::mojom::StringAttribute::kName);
+}
+
+bool AXPlatformNodeDelegate::IsTable() const {
+  if (node_)
+    return node_->IsTable();
+  return ui::IsTableLike(GetRole());
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableRowCount() const {
+  if (node_)
+    return node_->GetTableRowCount();
+  return GetIntAttribute(ax::mojom::IntAttribute::kTableRowCount);
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableColCount() const {
+  if (node_)
+    return node_->GetTableColCount();
+  return GetIntAttribute(ax::mojom::IntAttribute::kTableColumnCount);
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellCount() const {
+  if (node_)
+    return node_->GetTableCellCount();
+  return absl::nullopt;
+}
+
+absl::optional<bool> AXPlatformNodeDelegate::GetTableHasColumnOrRowHeaderNode()
+    const {
+  if (node_)
+    return node_->GetTableHasColumnOrRowHeaderNode();
+  return absl::nullopt;
+}
+
+std::vector<int32_t> AXPlatformNodeDelegate::GetColHeaderNodeIds() const {
+  if (node_)
+    return node_->GetTableColHeaderNodeIds();
+  return {};
+}
+
+std::vector<int32_t> AXPlatformNodeDelegate::GetColHeaderNodeIds(
+    int col_index) const {
+  if (node_)
+    return node_->GetTableColHeaderNodeIds(col_index);
+  return {};
+}
+
+std::vector<int32_t> AXPlatformNodeDelegate::GetRowHeaderNodeIds() const {
+  if (node_)
+    return node_->GetTableCellRowHeaderNodeIds();
+  return {};
+}
+
+std::vector<int32_t> AXPlatformNodeDelegate::GetRowHeaderNodeIds(
+    int row_index) const {
+  if (node_)
+    return node_->GetTableRowHeaderNodeIds(row_index);
+  return {};
+}
+
+bool AXPlatformNodeDelegate::IsTableRow() const {
+  if (node_)
+    return node_->IsTableRow();
+  return ui::IsTableRow(GetRole());
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableRowRowIndex() const {
+  if (node_)
+    return node_->GetTableRowRowIndex();
+  return GetIntAttribute(ax::mojom::IntAttribute::kTableRowIndex);
+}
+
+bool AXPlatformNodeDelegate::IsTableCellOrHeader() const {
+  if (node_)
+    return node_->IsTableCellOrHeader();
+  return ui::IsCellOrTableHeader(GetRole());
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellIndex() const {
+  if (node_)
+    return node_->GetTableCellIndex();
+  return absl::nullopt;
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellColIndex() const {
+  if (node_)
+    return node_->GetTableCellColIndex();
+  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex);
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellRowIndex() const {
+  if (node_)
+    return node_->GetTableCellRowIndex();
+  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex);
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellColSpan() const {
+  if (node_)
+    return node_->GetTableCellColSpan();
+  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan);
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellRowSpan() const {
+  if (node_)
+    return node_->GetTableCellRowSpan();
+  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowSpan);
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellAriaColIndex() const {
+  if (node_)
+    return node_->GetTableCellAriaColIndex();
+  if (HasIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex))
+    return GetIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex);
+  return absl::nullopt;
+}
+
+absl::optional<int> AXPlatformNodeDelegate::GetTableCellAriaRowIndex() const {
+  if (node_)
+    return node_->GetTableCellAriaRowIndex();
+  if (HasIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex))
+    return GetIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex);
+  return absl::nullopt;
+}
+
+absl::optional<int32_t> AXPlatformNodeDelegate::GetCellId(int row_index,
+                                                          int col_index) const {
+  if (node_) {
+    AXNode* cell = node()->GetTableCellFromCoords(row_index, col_index);
+    if (!cell)
+      return absl::nullopt;
+    return cell->id();
+  }
+  return absl::nullopt;
+}
+
+absl::optional<int32_t> AXPlatformNodeDelegate::CellIndexToId(
+    int cell_index) const {
+  if (node_) {
+    ui::AXNode* cell = node()->GetTableCellFromIndex(cell_index);
+    if (!cell)
+      return absl::nullopt;
+    return cell->id();
+  }
+  return absl::nullopt;
+}
+
+bool AXPlatformNodeDelegate::IsCellOrHeaderOfAriaGrid() const {
+  if (node_)
+    return node_->IsCellOrHeaderOfAriaGrid();
+  return false;
+}
+
+bool AXPlatformNodeDelegate::IsOrderedSetItem() const {
+  if (node_)
+    return node_->IsOrderedSetItem();
+  return false;
+}
+
+bool AXPlatformNodeDelegate::IsOrderedSet() const {
+  if (node_)
+    return node_->IsOrderedSet();
+  return false;
+}
+
+SkColor AXPlatformNodeDelegate::GetColor() const {
+  if (node_)
+    return node_->ComputeColor();
+  return SK_ColorBLACK;
+}
+
+SkColor AXPlatformNodeDelegate::GetBackgroundColor() const {
+  if (node_)
+    return node_->ComputeBackgroundColor();
+  return SK_ColorWHITE;
+}
+
+bool AXPlatformNodeDelegate::IsReadOnlySupported() const {
+  if (node_)
+    return node_->IsReadOnlySupported();
+  return false;
+}
+
+bool AXPlatformNodeDelegate::IsReadOnlyOrDisabled() const {
+  if (node_)
+    return node_->IsReadOnlyOrDisabled();
+  return false;
+}
+
+std::string AXPlatformNodeDelegate::GetLanguage() const {
+  if (node_)
+    return node_->GetLanguage();
+  return std::string();
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index 7510229..62afbdf 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -102,8 +102,8 @@
   // missing or erroneous information too.
   virtual const AXNodeData& GetData() const = 0;
 
-  // Get the accessibility tree data for this node.
-  virtual const AXTreeData& GetTreeData() const = 0;
+  // Get some extra data about the accessibility tree that contains this node.
+  virtual const AXTreeData& GetTreeData() const;
 
   // Accessing accessibility attributes:
   //
@@ -120,69 +120,60 @@
   // attribute is not present. In addition, strings can be returned as
   // either std::string or std::u16string, for convenience.
 
-  virtual ax::mojom::Role GetRole() const = 0;
-  virtual bool HasBoolAttribute(ax::mojom::BoolAttribute attribute) const = 0;
-  virtual bool GetBoolAttribute(ax::mojom::BoolAttribute attribute) const = 0;
-  virtual bool GetBoolAttribute(ax::mojom::BoolAttribute attribute,
-                                bool* value) const = 0;
-  virtual bool HasFloatAttribute(ax::mojom::FloatAttribute attribute) const = 0;
-  virtual float GetFloatAttribute(
-      ax::mojom::FloatAttribute attribute) const = 0;
-  virtual bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
-                                 float* value) const = 0;
-  virtual const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
-  GetIntAttributes() const = 0;
-  virtual bool HasIntAttribute(ax::mojom::IntAttribute attribute) const = 0;
-  virtual int GetIntAttribute(ax::mojom::IntAttribute attribute) const = 0;
-  virtual bool GetIntAttribute(ax::mojom::IntAttribute attribute,
-                               int* value) const = 0;
-  virtual const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
-  GetStringAttributes() const = 0;
-  virtual bool HasStringAttribute(
-      ax::mojom::StringAttribute attribute) const = 0;
-  virtual const std::string& GetStringAttribute(
-      ax::mojom::StringAttribute attribute) const = 0;
-  virtual bool GetStringAttribute(ax::mojom::StringAttribute attribute,
-                                  std::string* value) const = 0;
-  virtual std::u16string GetString16Attribute(
-      ax::mojom::StringAttribute attribute) const = 0;
-  virtual bool GetString16Attribute(ax::mojom::StringAttribute attribute,
-                                    std::u16string* value) const = 0;
-  virtual const std::string& GetInheritedStringAttribute(
-      ax::mojom::StringAttribute attribute) const = 0;
-  virtual std::u16string GetInheritedString16Attribute(
-      ax::mojom::StringAttribute attribute) const = 0;
-  virtual const std::vector<
+  ax::mojom::Role GetRole() const;
+  bool HasBoolAttribute(ax::mojom::BoolAttribute attribute) const;
+  bool GetBoolAttribute(ax::mojom::BoolAttribute attribute) const;
+  bool GetBoolAttribute(ax::mojom::BoolAttribute attribute, bool* value) const;
+  bool HasFloatAttribute(ax::mojom::FloatAttribute attribute) const;
+  float GetFloatAttribute(ax::mojom::FloatAttribute attribute) const;
+  bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
+                         float* value) const;
+  const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+  GetIntAttributes() const;
+  bool HasIntAttribute(ax::mojom::IntAttribute attribute) const;
+  int GetIntAttribute(ax::mojom::IntAttribute attribute) const;
+  bool GetIntAttribute(ax::mojom::IntAttribute attribute, int* value) const;
+  const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
+  GetStringAttributes() const;
+  bool HasStringAttribute(ax::mojom::StringAttribute attribute) const;
+  const std::string& GetStringAttribute(
+      ax::mojom::StringAttribute attribute) const;
+  bool GetStringAttribute(ax::mojom::StringAttribute attribute,
+                          std::string* value) const;
+  std::u16string GetString16Attribute(
+      ax::mojom::StringAttribute attribute) const;
+  bool GetString16Attribute(ax::mojom::StringAttribute attribute,
+                            std::u16string* value) const;
+  const std::string& GetInheritedStringAttribute(
+      ax::mojom::StringAttribute attribute) const;
+  std::u16string GetInheritedString16Attribute(
+      ax::mojom::StringAttribute attribute) const;
+  const std::vector<
       std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
-  GetIntListAttributes() const = 0;
-  virtual bool HasIntListAttribute(
-      ax::mojom::IntListAttribute attribute) const = 0;
-  virtual const std::vector<int32_t>& GetIntListAttribute(
-      ax::mojom::IntListAttribute attribute) const = 0;
-  virtual bool GetIntListAttribute(ax::mojom::IntListAttribute attribute,
-                                   std::vector<int32_t>* value) const = 0;
-  virtual bool HasStringListAttribute(
-      ax::mojom::StringListAttribute attribute) const = 0;
-  virtual const std::vector<std::string>& GetStringListAttribute(
-      ax::mojom::StringListAttribute attribute) const = 0;
-  virtual bool GetStringListAttribute(
-      ax::mojom::StringListAttribute attribute,
-      std::vector<std::string>* value) const = 0;
-  virtual bool HasHtmlAttribute(const char* attribute) const = 0;
-  virtual const base::StringPairs& GetHtmlAttributes() const = 0;
-  virtual bool GetHtmlAttribute(const char* attribute,
-                                std::string* value) const = 0;
-  virtual bool GetHtmlAttribute(const char* attribute,
-                                std::u16string* value) const = 0;
-  virtual AXTextAttributes GetTextAttributes() const = 0;
-  virtual bool HasState(ax::mojom::State state) const = 0;
-  virtual ax::mojom::State GetState() const = 0;
-  virtual bool HasAction(ax::mojom::Action action) const = 0;
+  GetIntListAttributes() const;
+  bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const;
+  const std::vector<int32_t>& GetIntListAttribute(
+      ax::mojom::IntListAttribute attribute) const;
+  bool GetIntListAttribute(ax::mojom::IntListAttribute attribute,
+                           std::vector<int32_t>* value) const;
+  bool HasStringListAttribute(ax::mojom::StringListAttribute attribute) const;
+  const std::vector<std::string>& GetStringListAttribute(
+      ax::mojom::StringListAttribute attribute) const;
+  bool GetStringListAttribute(ax::mojom::StringListAttribute attribute,
+                              std::vector<std::string>* value) const;
+  bool HasHtmlAttribute(const char* attribute) const;
+  const base::StringPairs& GetHtmlAttributes() const;
+  bool GetHtmlAttribute(const char* attribute, std::string* value) const;
+  bool GetHtmlAttribute(const char* attribute, std::u16string* value) const;
+  AXTextAttributes GetTextAttributes() const;
+  bool HasState(ax::mojom::State state) const;
+  ax::mojom::State GetState() const;
+  bool HasAction(ax::mojom::Action action) const;
   bool HasDefaultActionVerb() const;
   std::vector<ax::mojom::Action> GetSupportedActions() const;
-  virtual bool HasTextStyle(ax::mojom::TextStyle text_style) const = 0;
-  virtual ax::mojom::NameFrom GetNameFrom() const = 0;
-  virtual ax::mojom::DescriptionFrom GetDescriptionFrom() const = 0;
+  bool HasTextStyle(ax::mojom::TextStyle text_style) const;
+  ax::mojom::NameFrom GetNameFrom() const;
+  ax::mojom::DescriptionFrom GetDescriptionFrom() const;
 
   // Returns the text of this node and all descendant nodes; including text
   // found in embedded objects.
@@ -200,7 +191,7 @@
   virtual std::u16string GetValueForControl() const = 0;
 
   // See `AXNode::GetUnignoredSelection`.
-  virtual const AXSelection GetUnignoredSelection() const = 0;
+  virtual const AXSelection GetUnignoredSelection() const;
 
   // Creates a text position rooted at this object if it's a leaf node, or a
   // tree position otherwise.
@@ -293,11 +284,11 @@
   // Returns true if this is a leaf node, meaning all its
   // children should not be exposed to any platform's native accessibility
   // layer.
-  virtual bool IsLeaf() const = 0;
+  virtual bool IsLeaf() const;
 
   // Returns true if this node is invisible or ignored. (Only relevant for
   // accessibility trees that support ignored nodes.)
-  virtual bool IsInvisibleOrIgnored() const = 0;
+  virtual bool IsInvisibleOrIgnored() const;
 
   // Returns true if this node is focused.
   virtual bool IsFocused() const = 0;
@@ -351,8 +342,10 @@
   virtual std::unique_ptr<AXPlatformNodeDelegate::ChildIterator>
   ChildrenEnd() = 0;
 
-  // Returns the accessible name for the node.
-  virtual const std::string& GetName() const = 0;
+  // Returns the accessible name for this node. This could either be derived
+  // from visible text, such as the node's contents or an associated label, or
+  // be manually set by the node's owner, e.g. via an aria-label in HTML.
+  const std::string& GetName() const;
 
   // Returns the accessible description for the node.
   // An accessible description gives more information about the node in
@@ -466,10 +459,10 @@
   virtual bool IsWebContent() const = 0;
 
   // Get whether this node can be marked as read-only.
-  virtual bool IsReadOnlySupported() const = 0;
+  virtual bool IsReadOnlySupported() const;
 
   // Get whether this node is marked as read-only or is disabled.
-  virtual bool IsReadOnlyOrDisabled() const = 0;
+  virtual bool IsReadOnlyOrDisabled() const;
 
   // See `AXNode::HasVisibleCaretOrSelection`.
   virtual bool HasVisibleCaretOrSelection() const = 0;
@@ -531,58 +524,61 @@
   //
   // Returns empty string if no appropriate language was found or if this node
   // uses the default interface language.
-  virtual std::string GetLanguage() const = 0;
+  std::string GetLanguage() const;
 
   //
-  // Tables. All of these should be called on a node that's a table-like
+  // Tables. All of these should be called on a node that has a table-like
   // role, otherwise they return nullopt.
   //
-  virtual bool IsTable() const = 0;
-  virtual absl::optional<int> GetTableColCount() const = 0;
-  virtual absl::optional<int> GetTableRowCount() const = 0;
+  bool IsTable() const;
+  virtual absl::optional<int> GetTableColCount() const;
+  virtual absl::optional<int> GetTableRowCount() const;
   virtual absl::optional<int> GetTableAriaColCount() const = 0;
   virtual absl::optional<int> GetTableAriaRowCount() const = 0;
-  virtual absl::optional<int> GetTableCellCount() const = 0;
-  virtual absl::optional<bool> GetTableHasColumnOrRowHeaderNode() const = 0;
-  virtual std::vector<int32_t> GetColHeaderNodeIds() const = 0;
-  virtual std::vector<int32_t> GetColHeaderNodeIds(int col_index) const = 0;
-  virtual std::vector<int32_t> GetRowHeaderNodeIds() const = 0;
-  virtual std::vector<int32_t> GetRowHeaderNodeIds(int row_index) const = 0;
+  virtual absl::optional<int> GetTableCellCount() const;
+  virtual absl::optional<bool> GetTableHasColumnOrRowHeaderNode() const;
+  virtual std::vector<int32_t> GetColHeaderNodeIds() const;
+  virtual std::vector<int32_t> GetColHeaderNodeIds(int col_index) const;
+  virtual std::vector<int32_t> GetRowHeaderNodeIds() const;
+  virtual std::vector<int32_t> GetRowHeaderNodeIds(int row_index) const;
   virtual AXPlatformNode* GetTableCaption() const = 0;
 
-  // Table row-like nodes.
-  virtual bool IsTableRow() const = 0;
-  virtual absl::optional<int> GetTableRowRowIndex() const = 0;
+  //
+  // Nodes with a table row-like role.
+  //
+  virtual bool IsTableRow() const;
+  virtual absl::optional<int> GetTableRowRowIndex() const;
 
-  // Table cell-like nodes.
-  virtual bool IsTableCellOrHeader() const = 0;
-  virtual absl::optional<int> GetTableCellIndex() const = 0;
-  virtual absl::optional<int> GetTableCellColIndex() const = 0;
-  virtual absl::optional<int> GetTableCellRowIndex() const = 0;
-  virtual absl::optional<int> GetTableCellColSpan() const = 0;
-  virtual absl::optional<int> GetTableCellRowSpan() const = 0;
-  virtual absl::optional<int> GetTableCellAriaColIndex() const = 0;
-  virtual absl::optional<int> GetTableCellAriaRowIndex() const = 0;
-  virtual absl::optional<int32_t> GetCellId(int row_index,
-                                            int col_index) const = 0;
-  virtual absl::optional<int32_t> CellIndexToId(int cell_index) const = 0;
+  //
+  // Nodes with a table cell-like role.
+  //
+  virtual bool IsTableCellOrHeader() const;
+  virtual absl::optional<int> GetTableCellIndex() const;
+  virtual absl::optional<int> GetTableCellColIndex() const;
+  virtual absl::optional<int> GetTableCellRowIndex() const;
+  virtual absl::optional<int> GetTableCellColSpan() const;
+  virtual absl::optional<int> GetTableCellRowSpan() const;
+  virtual absl::optional<int> GetTableCellAriaColIndex() const;
+  virtual absl::optional<int> GetTableCellAriaRowIndex() const;
+  virtual absl::optional<int32_t> GetCellId(int row_index, int col_index) const;
+  virtual absl::optional<int32_t> CellIndexToId(int cell_index) const;
 
   // Returns true if this node is a cell or a row/column header in an ARIA grid
   // or treegrid.
-  virtual bool IsCellOrHeaderOfAriaGrid() const = 0;
+  virtual bool IsCellOrHeaderOfAriaGrid() const;
 
   // See `AXNode::IsRootWebAreaForPresentationalIframe()`.
   virtual bool IsRootWebAreaForPresentationalIframe() const = 0;
 
   // Ordered-set-like and item-like nodes.
-  virtual bool IsOrderedSetItem() const = 0;
-  virtual bool IsOrderedSet() const = 0;
+  virtual bool IsOrderedSetItem() const;
+  virtual bool IsOrderedSet() const;
   virtual absl::optional<int> GetPosInSet() const = 0;
   virtual absl::optional<int> GetSetSize() const = 0;
 
   // Computed colors, taking blending into account.
-  virtual SkColor GetColor() const = 0;
-  virtual SkColor GetBackgroundColor() const = 0;
+  virtual SkColor GetColor() const;
+  virtual SkColor GetBackgroundColor() const;
 
   //
   // Events.
@@ -640,6 +636,8 @@
 
   virtual std::string SubtreeToStringHelper(size_t level) = 0;
 
+  virtual void EnableGlobalAccessibilityModeOnApiUsage() const {}
+
  private:
   // The underlying node. This could change during the lifetime of this object
   // if this object has been reparented, i.e. moved to another part of the tree.
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index 7008aa5..3564a6c 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -28,198 +28,6 @@
   return *empty_data;
 }
 
-const AXTreeData& AXPlatformNodeDelegateBase::GetTreeData() const {
-  static base::NoDestructor<AXTreeData> empty_data;
-  return *empty_data;
-}
-
-ax::mojom::Role AXPlatformNodeDelegateBase::GetRole() const {
-  return GetData().role;
-}
-
-bool AXPlatformNodeDelegateBase::HasBoolAttribute(
-    ax::mojom::BoolAttribute attribute) const {
-  return GetData().HasBoolAttribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetBoolAttribute(
-    ax::mojom::BoolAttribute attribute) const {
-  return GetData().GetBoolAttribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetBoolAttribute(
-    ax::mojom::BoolAttribute attribute,
-    bool* value) const {
-  return GetData().GetBoolAttribute(attribute, value);
-}
-
-bool AXPlatformNodeDelegateBase::HasFloatAttribute(
-    ax::mojom::FloatAttribute attribute) const {
-  return GetData().HasFloatAttribute(attribute);
-}
-
-float AXPlatformNodeDelegateBase::GetFloatAttribute(
-    ax::mojom::FloatAttribute attribute) const {
-  return GetData().GetFloatAttribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetFloatAttribute(
-    ax::mojom::FloatAttribute attribute,
-    float* value) const {
-  return GetData().GetFloatAttribute(attribute, value);
-}
-
-const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
-AXPlatformNodeDelegateBase::GetIntAttributes() const {
-  return GetData().int_attributes;
-}
-
-bool AXPlatformNodeDelegateBase::HasIntAttribute(
-    ax::mojom::IntAttribute attribute) const {
-  return GetData().HasIntAttribute(attribute);
-}
-
-int AXPlatformNodeDelegateBase::GetIntAttribute(
-    ax::mojom::IntAttribute attribute) const {
-  return GetData().GetIntAttribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetIntAttribute(
-    ax::mojom::IntAttribute attribute,
-    int* value) const {
-  return GetData().GetIntAttribute(attribute, value);
-}
-
-const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
-AXPlatformNodeDelegateBase::GetStringAttributes() const {
-  return GetData().string_attributes;
-}
-
-bool AXPlatformNodeDelegateBase::HasStringAttribute(
-    ax::mojom::StringAttribute attribute) const {
-  return GetData().HasStringAttribute(attribute);
-}
-
-const std::string& AXPlatformNodeDelegateBase::GetStringAttribute(
-    ax::mojom::StringAttribute attribute) const {
-  return GetData().GetStringAttribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetStringAttribute(
-    ax::mojom::StringAttribute attribute,
-    std::string* value) const {
-  return GetData().GetStringAttribute(attribute, value);
-}
-
-std::u16string AXPlatformNodeDelegateBase::GetString16Attribute(
-    ax::mojom::StringAttribute attribute) const {
-  return GetData().GetString16Attribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetString16Attribute(
-    ax::mojom::StringAttribute attribute,
-    std::u16string* value) const {
-  return GetData().GetString16Attribute(attribute, value);
-}
-
-const std::string& AXPlatformNodeDelegateBase::GetInheritedStringAttribute(
-    ax::mojom::StringAttribute attribute) const {
-  NOTIMPLEMENTED();
-  return GetData().GetStringAttribute(attribute);
-}
-
-std::u16string AXPlatformNodeDelegateBase::GetInheritedString16Attribute(
-    ax::mojom::StringAttribute attribute) const {
-  NOTIMPLEMENTED();
-  return GetData().GetString16Attribute(attribute);
-}
-
-const std::vector<std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
-AXPlatformNodeDelegateBase::GetIntListAttributes() const {
-  return GetData().intlist_attributes;
-}
-
-bool AXPlatformNodeDelegateBase::HasIntListAttribute(
-    ax::mojom::IntListAttribute attribute) const {
-  return GetData().HasIntListAttribute(attribute);
-}
-
-const std::vector<int32_t>& AXPlatformNodeDelegateBase::GetIntListAttribute(
-    ax::mojom::IntListAttribute attribute) const {
-  return GetData().GetIntListAttribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetIntListAttribute(
-    ax::mojom::IntListAttribute attribute,
-    std::vector<int32_t>* value) const {
-  return GetData().GetIntListAttribute(attribute, value);
-}
-
-bool AXPlatformNodeDelegateBase::HasStringListAttribute(
-    ax::mojom::StringListAttribute attribute) const {
-  return GetData().HasStringListAttribute(attribute);
-}
-
-const std::vector<std::string>&
-AXPlatformNodeDelegateBase::GetStringListAttribute(
-    ax::mojom::StringListAttribute attribute) const {
-  return GetData().GetStringListAttribute(attribute);
-}
-
-bool AXPlatformNodeDelegateBase::GetStringListAttribute(
-    ax::mojom::StringListAttribute attribute,
-    std::vector<std::string>* value) const {
-  return GetData().GetStringListAttribute(attribute, value);
-}
-
-bool AXPlatformNodeDelegateBase::HasHtmlAttribute(const char* attribute) const {
-  return GetData().HasHtmlAttribute(attribute);
-}
-
-const base::StringPairs& AXPlatformNodeDelegateBase::GetHtmlAttributes() const {
-  return GetData().html_attributes;
-}
-
-bool AXPlatformNodeDelegateBase::GetHtmlAttribute(const char* attribute,
-                                                  std::string* value) const {
-  return GetData().GetHtmlAttribute(attribute, value);
-}
-
-bool AXPlatformNodeDelegateBase::GetHtmlAttribute(const char* attribute,
-                                                  std::u16string* value) const {
-  return GetData().GetHtmlAttribute(attribute, value);
-}
-
-AXTextAttributes AXPlatformNodeDelegateBase::GetTextAttributes() const {
-  return GetData().GetTextAttributes();
-}
-
-bool AXPlatformNodeDelegateBase::HasState(ax::mojom::State state) const {
-  return GetData().HasState(state);
-}
-
-ax::mojom::State AXPlatformNodeDelegateBase::GetState() const {
-  return static_cast<ax::mojom::State>(GetData().state);
-}
-
-bool AXPlatformNodeDelegateBase::HasAction(ax::mojom::Action action) const {
-  return GetData().HasAction(action);
-}
-
-bool AXPlatformNodeDelegateBase::HasTextStyle(
-    ax::mojom::TextStyle text_style) const {
-  return GetData().HasTextStyle(text_style);
-}
-
-ax::mojom::NameFrom AXPlatformNodeDelegateBase::GetNameFrom() const {
-  return GetData().GetNameFrom();
-}
-
-ax::mojom::DescriptionFrom AXPlatformNodeDelegateBase::GetDescriptionFrom()
-    const {
-  return GetData().GetDescriptionFrom();
-}
-
 std::u16string AXPlatformNodeDelegateBase::GetTextContentUTF16() const {
   // Unlike in web content The "kValue" attribute always takes precedence,
   // because we assume that users of this base class, such as Views controls,
@@ -267,11 +75,6 @@
   return value;
 }
 
-const AXSelection AXPlatformNodeDelegateBase::GetUnignoredSelection() const {
-  NOTIMPLEMENTED();
-  return AXSelection();
-}
-
 AXNodePosition::AXPositionInstance AXPlatformNodeDelegateBase::CreatePositionAt(
     int offset,
     ax::mojom::TextAffinity affinity) const {
@@ -360,10 +163,6 @@
   return parent->IsChildOfLeaf();
 }
 
-bool AXPlatformNodeDelegateBase::IsLeaf() const {
-  return !GetChildCount();
-}
-
 bool AXPlatformNodeDelegateBase::IsFocused() const {
   return false;
 }
@@ -379,10 +178,6 @@
          HasState(ax::mojom::State::kIgnored);
 }
 
-bool AXPlatformNodeDelegateBase::IsInvisibleOrIgnored() const {
-  return IsIgnored() || GetData().IsInvisible();
-}
-
 bool AXPlatformNodeDelegateBase::IsToplevelBrowserWindow() {
   return false;
 }
@@ -560,10 +355,6 @@
   return std::make_unique<ChildIteratorBase>(this, GetChildCount());
 }
 
-const std::string& AXPlatformNodeDelegateBase::GetName() const {
-  return GetStringAttribute(ax::mojom::StringAttribute::kName);
-}
-
 const std::string& AXPlatformNodeDelegateBase::GetDescription() const {
   return GetStringAttribute(ax::mojom::StringAttribute::kDescription);
 }
@@ -654,18 +445,6 @@
   return gfx::kNullAcceleratedWidget;
 }
 
-bool AXPlatformNodeDelegateBase::IsTable() const {
-  return ui::IsTableLike(GetRole());
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableRowCount() const {
-  return GetIntAttribute(ax::mojom::IntAttribute::kTableRowCount);
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableColCount() const {
-  return GetIntAttribute(ax::mojom::IntAttribute::kTableColumnCount);
-}
-
 absl::optional<int> AXPlatformNodeDelegateBase::GetTableAriaColCount() const {
   int aria_column_count;
   if (!GetIntAttribute(ax::mojom::IntAttribute::kAriaColumnCount,
@@ -684,102 +463,10 @@
   return aria_row_count;
 }
 
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellCount() const {
-  return absl::nullopt;
-}
-
-absl::optional<bool>
-AXPlatformNodeDelegateBase::GetTableHasColumnOrRowHeaderNode() const {
-  return absl::nullopt;
-}
-
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetColHeaderNodeIds() const {
-  return {};
-}
-
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetColHeaderNodeIds(
-    int col_index) const {
-  return {};
-}
-
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetRowHeaderNodeIds() const {
-  return {};
-}
-
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetRowHeaderNodeIds(
-    int row_index) const {
-  return {};
-}
-
 AXPlatformNode* AXPlatformNodeDelegateBase::GetTableCaption() const {
   return nullptr;
 }
 
-bool AXPlatformNodeDelegateBase::IsTableRow() const {
-  return ui::IsTableRow(GetRole());
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableRowRowIndex() const {
-  return GetIntAttribute(ax::mojom::IntAttribute::kTableRowIndex);
-}
-
-bool AXPlatformNodeDelegateBase::IsTableCellOrHeader() const {
-  return ui::IsCellOrTableHeader(GetRole());
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellColIndex() const {
-  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex);
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellRowIndex() const {
-  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex);
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellColSpan() const {
-  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan);
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellRowSpan() const {
-  return GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowSpan);
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellAriaColIndex()
-    const {
-  if (HasIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex)) {
-    return GetIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex);
-  }
-
-  return absl::nullopt;
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellAriaRowIndex()
-    const {
-  if (HasIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex)) {
-    return GetIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex);
-  }
-
-  return absl::nullopt;
-}
-
-absl::optional<int32_t> AXPlatformNodeDelegateBase::GetCellId(
-    int row_index,
-    int col_index) const {
-  return absl::nullopt;
-}
-
-absl::optional<int> AXPlatformNodeDelegateBase::GetTableCellIndex() const {
-  return absl::nullopt;
-}
-
-absl::optional<int32_t> AXPlatformNodeDelegateBase::CellIndexToId(
-    int cell_index) const {
-  return absl::nullopt;
-}
-
-bool AXPlatformNodeDelegateBase::IsCellOrHeaderOfAriaGrid() const {
-  return false;
-}
-
 bool AXPlatformNodeDelegateBase::IsRootWebAreaForPresentationalIframe() const {
   if (!ui::IsPlatformDocument(GetRole()))
     return false;
@@ -789,14 +476,6 @@
   return parent->GetRole() == ax::mojom::Role::kIframePresentational;
 }
 
-bool AXPlatformNodeDelegateBase::IsOrderedSetItem() const {
-  return false;
-}
-
-bool AXPlatformNodeDelegateBase::IsOrderedSet() const {
-  return false;
-}
-
 absl::optional<int> AXPlatformNodeDelegateBase::GetPosInSet() const {
   return absl::nullopt;
 }
@@ -805,14 +484,6 @@
   return absl::nullopt;
 }
 
-SkColor AXPlatformNodeDelegateBase::GetColor() const {
-  return SK_ColorBLACK;
-}
-
-SkColor AXPlatformNodeDelegateBase::GetBackgroundColor() const {
-  return SK_ColorWHITE;
-}
-
 bool AXPlatformNodeDelegateBase::AccessibilityPerformAction(
     const ui::AXActionData& data) {
   return false;
@@ -878,14 +549,6 @@
   return false;
 }
 
-bool AXPlatformNodeDelegateBase::IsReadOnlySupported() const {
-  return false;
-}
-
-bool AXPlatformNodeDelegateBase::IsReadOnlyOrDisabled() const {
-  return false;
-}
-
 bool AXPlatformNodeDelegateBase::HasVisibleCaretOrSelection() const {
   return IsDescendantOfAtomicTextField();
 }
@@ -966,10 +629,6 @@
   return {};
 }
 
-std::string AXPlatformNodeDelegateBase::GetLanguage() const {
-  return std::string();
-}
-
 AXPlatformNodeDelegate* AXPlatformNodeDelegateBase::GetParentDelegate() const {
   AXPlatformNode* parent_node =
       ui::AXPlatformNode::FromNativeViewAccessible(GetParent());
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h
index 3b12fdfc..bf0fbbb3 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -38,68 +38,8 @@
 
   // `AXPlatformNodeDelegate` implementation.
   const AXNodeData& GetData() const override;
-  const AXTreeData& GetTreeData() const override;
-  ax::mojom::Role GetRole() const override;
-  bool HasBoolAttribute(ax::mojom::BoolAttribute attribute) const override;
-  bool GetBoolAttribute(ax::mojom::BoolAttribute attribute) const override;
-  bool GetBoolAttribute(ax::mojom::BoolAttribute attribute,
-                        bool* value) const override;
-  bool HasFloatAttribute(ax::mojom::FloatAttribute attribute) const override;
-  float GetFloatAttribute(ax::mojom::FloatAttribute attribute) const override;
-  bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
-                         float* value) const override;
-  const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
-  GetIntAttributes() const override;
-  bool HasIntAttribute(ax::mojom::IntAttribute attribute) const override;
-  int GetIntAttribute(ax::mojom::IntAttribute attribute) const override;
-  bool GetIntAttribute(ax::mojom::IntAttribute attribute,
-                       int* value) const override;
-  const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
-  GetStringAttributes() const override;
-  bool HasStringAttribute(ax::mojom::StringAttribute attribute) const override;
-  const std::string& GetStringAttribute(
-      ax::mojom::StringAttribute attribute) const override;
-  bool GetStringAttribute(ax::mojom::StringAttribute attribute,
-                          std::string* value) const override;
-  std::u16string GetString16Attribute(
-      ax::mojom::StringAttribute attribute) const override;
-  bool GetString16Attribute(ax::mojom::StringAttribute attribute,
-                            std::u16string* value) const override;
-  const std::string& GetInheritedStringAttribute(
-      ax::mojom::StringAttribute attribute) const override;
-  std::u16string GetInheritedString16Attribute(
-      ax::mojom::StringAttribute attribute) const override;
-  const std::vector<
-      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
-  GetIntListAttributes() const override;
-  bool HasIntListAttribute(
-      ax::mojom::IntListAttribute attribute) const override;
-  const std::vector<int32_t>& GetIntListAttribute(
-      ax::mojom::IntListAttribute attribute) const override;
-  bool GetIntListAttribute(ax::mojom::IntListAttribute attribute,
-                           std::vector<int32_t>* value) const override;
-  bool HasStringListAttribute(
-      ax::mojom::StringListAttribute attribute) const override;
-  const std::vector<std::string>& GetStringListAttribute(
-      ax::mojom::StringListAttribute attribute) const override;
-  bool GetStringListAttribute(ax::mojom::StringListAttribute attribute,
-                              std::vector<std::string>* value) const override;
-  bool HasHtmlAttribute(const char* attribute) const override;
-  const base::StringPairs& GetHtmlAttributes() const override;
-  bool GetHtmlAttribute(const char* attribute,
-                        std::string* value) const override;
-  bool GetHtmlAttribute(const char* attribute,
-                        std::u16string* value) const override;
-  AXTextAttributes GetTextAttributes() const override;
-  bool HasState(ax::mojom::State state) const override;
-  ax::mojom::State GetState() const override;
-  bool HasAction(ax::mojom::Action action) const override;
-  bool HasTextStyle(ax::mojom::TextStyle text_style) const override;
-  ax::mojom::NameFrom GetNameFrom() const override;
-  ax::mojom::DescriptionFrom GetDescriptionFrom() const override;
   std::u16string GetTextContentUTF16() const override;
   std::u16string GetValueForControl() const override;
-  const AXSelection GetUnignoredSelection() const override;
 
   AXNodePosition::AXPositionInstance CreatePositionAt(
       int offset,
@@ -140,7 +80,6 @@
   bool IsChildOfLeaf() const override;
   bool IsDescendantOfAtomicTextField() const override;
   bool IsPlatformDocument() const override;
-  bool IsLeaf() const override;
   bool IsFocused() const override;
   bool IsToplevelBrowserWindow() override;
   gfx::NativeViewAccessible GetLowestPlatformAncestor() const override;
@@ -170,7 +109,6 @@
       override;
   std::unique_ptr<AXPlatformNodeDelegate::ChildIterator> ChildrenEnd() override;
 
-  const std::string& GetName() const override;
   const std::string& GetDescription() const override;
   std::u16string GetHypertext() const override;
   const std::map<int, int>& GetHypertextOffsetToHyperlinkChildIndex()
@@ -223,9 +161,6 @@
   // Returns true if this node is ignored.
   bool IsIgnored() const override;
 
-  // Returns true if this node is invisible or ignored.
-  bool IsInvisibleOrIgnored() const override;
-
   // Get whether this node is a minimized window.
   bool IsMinimized() const override;
   bool IsText() const override;
@@ -233,12 +168,6 @@
   // Get whether this node is in web content.
   bool IsWebContent() const override;
 
-  // Get whether this node can be marked as read-only.
-  bool IsReadOnlySupported() const override;
-
-  // Get whether this node is marked as read-only or is disabled.
-  bool IsReadOnlyOrDisabled() const override;
-
   // Returns true if the caret or selection is visible on this object.
   bool HasVisibleCaretOrSelection() const override;
 
@@ -283,54 +212,21 @@
       ui::AXPlatformNodeDelegate* start,
       ui::AXPlatformNodeDelegate* end) override;
 
-  std::string GetLanguage() const override;
-
   //
   // Tables. All of these should be called on a node that's a table-like
   // role, otherwise they return nullopt.
   //
-  bool IsTable() const override;
-  absl::optional<int> GetTableColCount() const override;
-  absl::optional<int> GetTableRowCount() const override;
   absl::optional<int> GetTableAriaColCount() const override;
   absl::optional<int> GetTableAriaRowCount() const override;
-  absl::optional<int> GetTableCellCount() const override;
-  absl::optional<bool> GetTableHasColumnOrRowHeaderNode() const override;
-  std::vector<int32_t> GetColHeaderNodeIds() const override;
-  std::vector<int32_t> GetColHeaderNodeIds(int col_index) const override;
-  std::vector<int32_t> GetRowHeaderNodeIds() const override;
-  std::vector<int32_t> GetRowHeaderNodeIds(int row_index) const override;
   AXPlatformNode* GetTableCaption() const override;
 
-  // Table row-like nodes.
-  bool IsTableRow() const override;
-  absl::optional<int> GetTableRowRowIndex() const override;
-
   // Table cell-like nodes.
-  bool IsTableCellOrHeader() const override;
-  absl::optional<int> GetTableCellIndex() const override;
-  absl::optional<int> GetTableCellColIndex() const override;
-  absl::optional<int> GetTableCellRowIndex() const override;
-  absl::optional<int> GetTableCellColSpan() const override;
-  absl::optional<int> GetTableCellRowSpan() const override;
-  absl::optional<int> GetTableCellAriaColIndex() const override;
-  absl::optional<int> GetTableCellAriaRowIndex() const override;
-  absl::optional<int32_t> GetCellId(int row_index,
-                                    int col_index) const override;
-  absl::optional<int32_t> CellIndexToId(int cell_index) const override;
-  bool IsCellOrHeaderOfAriaGrid() const override;
   bool IsRootWebAreaForPresentationalIframe() const override;
 
   // Ordered-set-like and item-like nodes.
-  bool IsOrderedSetItem() const override;
-  bool IsOrderedSet() const override;
   absl::optional<int> GetPosInSet() const override;
   absl::optional<int> GetSetSize() const override;
 
-  // Computed colors, taking blending into account.
-  SkColor GetColor() const override;
-  SkColor GetBackgroundColor() const override;
-
   //
   // Events.
   //
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 1630b0e1..7aba1582d 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -466,10 +466,6 @@
   tree_->UpdateDataForTesting(new_tree_data);
 }
 
-bool TestAXNodeWrapper::IsTable() const {
-  return node_->IsTable();
-}
-
 absl::optional<int> TestAXNodeWrapper::GetTableRowCount() const {
   return node_->GetTableRowCount();
 }
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h
index d3f136f..5c80d90e 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -111,7 +111,6 @@
   AXPlatformNode* GetFromTreeIDAndNodeID(const ui::AXTreeID& ax_tree_id,
                                          int32_t id) override;
   absl::optional<size_t> GetIndexInParent() override;
-  bool IsTable() const override;
   absl::optional<int> GetTableRowCount() const override;
   absl::optional<int> GetTableColCount() const override;
   absl::optional<int> GetTableAriaColCount() const override;
diff --git a/ui/base/wayland/BUILD.gn b/ui/base/wayland/BUILD.gn
index 8f1c950..4b852ca 100644
--- a/ui/base/wayland/BUILD.gn
+++ b/ui/base/wayland/BUILD.gn
@@ -67,13 +67,24 @@
   ]
 }
 
+source_set("wayland_display_util") {
+  sources = [
+    "wayland_display_util.cc",
+    "wayland_display_util.h",
+  ]
+}
+
 source_set("unittests") {
   testonly = true
 
-  sources = [ "wayland_input_types_unittest.cc" ]
+  sources = [
+    "wayland_display_util_unittest.cc",
+    "wayland_input_types_unittest.cc",
+  ]
 
   deps = [
     ":wayland_client_input_types",
+    ":wayland_display_util",
     ":wayland_server_input_types",
     "//testing/gtest",
     "//ui/base/ime:text_input_types",
diff --git a/ui/base/wayland/wayland_display_util.cc b/ui/base/wayland/wayland_display_util.cc
new file mode 100644
index 0000000..0509ff48
--- /dev/null
+++ b/ui/base/wayland/wayland_display_util.cc
@@ -0,0 +1,19 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/wayland/wayland_display_util.h"
+
+namespace ui::wayland {
+
+WaylandDisplayIdPair ToWaylandDisplayIdPair(int64_t display_id) {
+  return {static_cast<uint32_t>(display_id >> 32),
+          static_cast<uint32_t>(display_id)};
+}
+
+int64_t FromWaylandDisplayIdPair(WaylandDisplayIdPair&& display_id_pair) {
+  return static_cast<int64_t>(display_id_pair.high) << 32 |
+         static_cast<int64_t>(display_id_pair.low);
+}
+
+}  // namespace ui::wayland
diff --git a/ui/base/wayland/wayland_display_util.h b/ui/base/wayland/wayland_display_util.h
new file mode 100644
index 0000000..8354f167
--- /dev/null
+++ b/ui/base/wayland/wayland_display_util.h
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_WAYLAND_WAYLAND_DISPLAY_UTIL_H_
+#define UI_BASE_WAYLAND_WAYLAND_DISPLAY_UTIL_H_
+
+#include <cstdint>
+
+namespace ui::wayland {
+
+struct WaylandDisplayIdPair {
+  uint32_t high;
+  uint32_t low;
+};
+
+// Convert int64_t display id into pair of uint32_t.
+WaylandDisplayIdPair ToWaylandDisplayIdPair(int64_t display_id);
+
+// Convert pair of uint32_t into display id int64_t.
+int64_t FromWaylandDisplayIdPair(WaylandDisplayIdPair&& display_id_pair);
+
+}  // namespace ui::wayland
+
+#endif
diff --git a/ui/base/wayland/wayland_display_util_unittest.cc b/ui/base/wayland/wayland_display_util_unittest.cc
new file mode 100644
index 0000000..ac50b69
--- /dev/null
+++ b/ui/base/wayland/wayland_display_util_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/wayland/wayland_display_util.h"
+
+namespace ui::wayland {
+
+TEST(WaylandDisplayUtilTest, Basic) {
+  const int64_t kTestIds[] = {
+      std::numeric_limits<int64_t>::min(),
+      std::numeric_limits<int64_t>::min() + 1,
+      static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1,
+      std::numeric_limits<int32_t>::min(),
+      std::numeric_limits<int32_t>::min() + 1,
+      -1,
+      0,
+      1,
+      std::numeric_limits<int32_t>::max() - 1,
+      std::numeric_limits<int32_t>::max(),
+      static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1,
+      std::numeric_limits<int64_t>::max() - 1,
+      std::numeric_limits<int64_t>::max()};
+
+  for (int64_t id : kTestIds) {
+    auto pair = ToWaylandDisplayIdPair(id);
+    EXPECT_EQ(id, FromWaylandDisplayIdPair({pair.high, pair.low}));
+  }
+}
+
+}  // namespace ui::wayland
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index e090333b..1a4c84d 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -281,6 +281,7 @@
     "//ui/base/ime/linux",
     "//ui/base/wayland:color_manager_util",
     "//ui/base/wayland:wayland_client_input_types",
+    "//ui/base/wayland:wayland_display_util",
     "//ui/display",
     "//ui/display/util:gpu_info_util",
     "//ui/display/util:util",
diff --git a/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc b/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc
index 6c92c32..b520db32 100644
--- a/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc
+++ b/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc
@@ -13,7 +13,10 @@
 
 #include "base/files/scoped_file.h"
 #include "base/strings/stringprintf.h"
-#include "ui/gfx/linux/scoped_gbm_device.h"
+
+#if defined(WAYLAND_GBM)
+#include "ui/gfx/linux/scoped_gbm_device.h"  // nogncheck
+#endif
 
 namespace ui {
 
@@ -59,11 +62,13 @@
     if (drm_fd.get() < 0)
       continue;
 
+#if defined(WAYLAND_GBM)
     // In case the first node /dev/dri/renderD128 can be opened but fails to
     // create gbm device on certain driver (E.g. PowerVR). Skip such paths.
     ScopedGbmDevice device(gbm_create_device(drm_fd.get()));
     if (!device)
       continue;
+#endif
 
     drm_render_node_path_ = base::FilePath(dri_render_node);
     break;
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index 72c8c9a..97104c1 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -25,17 +25,20 @@
 #if defined(WAYLAND_GBM)
 #include "ui/gfx/linux/gbm_wrapper.h"  // nogncheck
 #include "ui/ozone/platform/wayland/gpu/drm_render_node_handle.h"
-#include "ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.h"
 #endif
 
 namespace ui {
 
-WaylandBufferManagerGpu::WaylandBufferManagerGpu() {
+WaylandBufferManagerGpu::WaylandBufferManagerGpu()
+    : WaylandBufferManagerGpu(base::FilePath()) {}
+
+WaylandBufferManagerGpu::WaylandBufferManagerGpu(
+    const base::FilePath& drm_node_path) {
 #if defined(WAYLAND_GBM)
   // The path_finder and the handle do syscalls, which are permitted before
   // the sandbox entry. After the gpu enters the sandbox, they fail. Thus,
-  // open the handle early and store it.
-  OpenAndStoreDrmRenderNodeFd();
+  // we get node path from the platform instance and get a handle for that here.
+  OpenAndStoreDrmRenderNodeFd(drm_node_path);
 #endif
 
   // The WaylandBufferManagerGpu takes the task runner where it was created.
@@ -411,16 +414,10 @@
 }
 
 #if defined(WAYLAND_GBM)
-void WaylandBufferManagerGpu::OpenAndStoreDrmRenderNodeFd() {
-  DrmRenderNodePathFinder path_finder;
-  const base::FilePath drm_node_path = path_finder.GetDrmRenderNodePath();
-  if (drm_node_path.empty()) {
-    LOG(WARNING) << "Failed to find drm render node path.";
-    return;
-  }
-
+void WaylandBufferManagerGpu::OpenAndStoreDrmRenderNodeFd(
+    const base::FilePath& drm_node_path) {
   DrmRenderNodeHandle handle;
-  if (!handle.Initialize(drm_node_path)) {
+  if (drm_node_path.empty() || !handle.Initialize(drm_node_path)) {
     LOG(WARNING) << "Failed to initialize drm render node handle.";
     return;
   }
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
index f8ae26b..82ebd696 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "base/callback_forward.h"
+#include "base/files/file_path.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
@@ -40,6 +41,7 @@
 class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
  public:
   WaylandBufferManagerGpu();
+  explicit WaylandBufferManagerGpu(const base::FilePath& drm_node_path);
   WaylandBufferManagerGpu(const WaylandBufferManagerGpu&) = delete;
   WaylandBufferManagerGpu& operator=(const WaylandBufferManagerGpu&) = delete;
 
@@ -230,9 +232,9 @@
   void DestroyBufferTask(uint32_t buffer_id);
 
 #if defined(WAYLAND_GBM)
-  // Finds drm render node, opens it and stores the handle into
+  // Uses |drm_node_path| to open the handle and store it into
   // |drm_render_node_fd|.
-  void OpenAndStoreDrmRenderNodeFd();
+  void OpenAndStoreDrmRenderNodeFd(const base::FilePath& drm_node_path);
   // Used by the gbm_device for self creation.
   base::ScopedFD drm_render_node_fd_;
   // A DRM render node based gbm device.
diff --git a/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc b/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc
index 60065836..5454edf 100644
--- a/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc
@@ -35,7 +35,9 @@
 // to sync will hang.  That is why we run "bare" lambdas in all tests of this
 // suite instead of using `PostToServerAndWait()`: that helper syncs the
 // connection after running the server task.  Due to the same reason we disable
-// the sync on the test tear down.
+// the sync on the test tear down.  To ensure that the error message is caught
+// by the crash reporter, we wait until idle in the end of each test before
+// checking the crash key value.
 class WaylandEventWatcherTest : public WaylandTest {
  public:
   WaylandEventWatcherTest() : WaylandTest(TestServerMode::kAsync) {}
@@ -81,6 +83,8 @@
                                kTestErrorString.c_str());
       }));
 
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(text, crash_reporter::GetCrashKeyValue("wayland_error"));
 }
 
@@ -101,6 +105,8 @@
         wl_resource_post_no_memory(xdg_surface);
       }));
 
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(expected_error_code,
             crash_reporter::GetCrashKeyValue("wayland_error"));
 }
@@ -116,6 +122,8 @@
         wl_client_post_no_memory(server->client());
       }));
 
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(expected_error_code,
             crash_reporter::GetCrashKeyValue("wayland_error"));
 }
@@ -133,6 +141,8 @@
                                             kError.c_str());
       }));
 
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(expected_error_code,
             crash_reporter::GetCrashKeyValue("wayland_error"));
 }
@@ -148,6 +158,8 @@
                                             "stub error");
       }));
 
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(kTestWaylandCompositor,
             crash_reporter::GetCrashKeyValue("wayland_compositor"));
 }
@@ -161,6 +173,8 @@
                                             "stub error");
       }));
 
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ("Unknown", crash_reporter::GetCrashKeyValue("wayland_compositor"));
 }
 
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_output.cc b/ui/ozone/platform/wayland/host/wayland_zaura_output.cc
index 9468535..d07638114 100644
--- a/ui/ozone/platform/wayland/host/wayland_zaura_output.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_output.cc
@@ -8,6 +8,7 @@
 
 #include "base/check.h"
 #include "base/logging.h"
+#include "ui/base/wayland/wayland_display_util.h"
 
 namespace ui {
 
@@ -66,8 +67,8 @@
                                      uint32_t display_id_hi,
                                      uint32_t display_id_lo) {
   if (auto* aura_output = static_cast<WaylandZAuraOutput*>(data)) {
-    aura_output->display_id_ = static_cast<int64_t>(display_id_hi) << 32 |
-                               static_cast<int64_t>(display_id_lo);
+    aura_output->display_id_ =
+        ui::wayland::FromWaylandDisplayIdPair({display_id_hi, display_id_lo});
   }
 }
 
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 0228a265d..04b443d 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -259,7 +259,13 @@
   }
 
   void InitializeGPU(const InitParams& args) override {
-    buffer_manager_ = std::make_unique<WaylandBufferManagerGpu>();
+    base::FilePath drm_node_path;
+#if defined(WAYLAND_GBM)
+    drm_node_path = path_finder_.GetDrmRenderNodePath();
+    if (drm_node_path.empty())
+      LOG(WARNING) << "Failed to find drm render node path.";
+#endif
+    buffer_manager_ = std::make_unique<WaylandBufferManagerGpu>(drm_node_path);
     surface_factory_ = std::make_unique<WaylandSurfaceFactory>(
         connection_.get(), buffer_manager_.get());
     overlay_manager_ =
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 7aaca113..192f0bb 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1715,7 +1715,7 @@
   if (should_do_learning_.has_value())
     return should_do_learning_.value();
 
-  NOTIMPLEMENTED_LOG_ONCE() << "A Textfield does not support ShouldDoLearning";
+  NOTIMPLEMENTED_LOG_ONCE();
   DVLOG(1) << "This Textfield instance does not support ShouldDoLearning";
   return false;
 }
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index 6e79f007..7c48764 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -459,9 +459,10 @@
 }
 
 TEST_F(DesktopNativeWidgetAuraWithNoDelegateTest, OnGestureEventTest) {
-  ui::GestureEvent move(0, 0, 0, ui::EventTimeForNow(),
-                        ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
-  static_cast<ui::EventHandler*>(desktop_native_widget)->OnGestureEvent(&move);
+  ui::GestureEvent gesture(0, 0, 0, ui::EventTimeForNow(),
+                           ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
+  static_cast<ui::EventHandler*>(desktop_native_widget)
+      ->OnGestureEvent(&gesture);
 }
 
 TEST_F(DesktopNativeWidgetAuraWithNoDelegateTest, OnHostMovedInPixelsTest) {
diff --git a/ui/views/widget/native_widget_aura_unittest.cc b/ui/views/widget/native_widget_aura_unittest.cc
index 355e5cd..d51ddcf6 100644
--- a/ui/views/widget/native_widget_aura_unittest.cc
+++ b/ui/views/widget/native_widget_aura_unittest.cc
@@ -909,7 +909,7 @@
     params.ownership = views::Widget::InitParams::CLIENT_OWNS_WIDGET;
     params.native_widget = native_widget;
     widget->Init(std::move(params));
-
+    widget->Show();
     // Widget will create a DefaultWidgetDelegate if no delegates are provided.
     // Call Widget::OnNativeWidgetDestroyed() to destroy
     // the WidgetDelegate properly.
@@ -959,11 +959,23 @@
   native_widget->OnBoundsChanged(gfx::Rect(), gfx::Rect());
 }
 
+TEST_F(NativeWidgetAuraWithNoDelegateTest, OnGestureEventTest) {
+  ui::GestureEvent gesture(0, 0, 0, ui::EventTimeForNow(),
+                           ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
+  native_widget->OnGestureEvent(&gesture);
+}
+
 TEST_F(NativeWidgetAuraWithNoDelegateTest, OnKeyEventTest) {
   ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_0, ui::EF_NONE);
   native_widget->OnKeyEvent(&key);
 }
 
+TEST_F(NativeWidgetAuraWithNoDelegateTest, OnMouseEventTest) {
+  ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
+                      ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  native_widget->OnMouseEvent(&move);
+}
+
 TEST_F(NativeWidgetAuraWithNoDelegateTest, OnPaintTest) {
   native_widget->OnPaint(ui::PaintContext(nullptr, 0, gfx::Rect(), false));
 }
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts b/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts
index cbe40d4..44d87b43 100644
--- a/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts
+++ b/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts
@@ -45,9 +45,10 @@
          */
         private helpBubbleControllerById_: Map<string, HelpBubbleController> =
             new Map();
-        private listenerIds_: number[] = [];
+        private helpBubbleListenerIds_: number[] = [];
         private helpBubbleAnchorObserver_: IntersectionObserver|null = null;
-        private dismissedEventTracker_: EventTracker = new EventTracker();
+        private helBubbleDismissedEventTracker_: EventTracker =
+            new EventTracker();
 
         constructor(...args: any[]) {
           super(...args);
@@ -62,7 +63,7 @@
           super.connectedCallback();
 
           const router = this.helpBubbleCallbackRouter_;
-          this.listenerIds_.push(
+          this.helpBubbleListenerIds_.push(
               router.showHelpBubble.addListener(
                   this.onShowHelpBubble_.bind(this)),
               router.toggleFocusForAccessibility.addListener(
@@ -89,10 +90,10 @@
         override disconnectedCallback() {
           super.disconnectedCallback();
 
-          for (const listenerId of this.listenerIds_) {
+          for (const listenerId of this.helpBubbleListenerIds_) {
             this.helpBubbleCallbackRouter_.removeListener(listenerId);
           }
-          this.listenerIds_ = [];
+          this.helpBubbleListenerIds_ = [];
           assert(this.helpBubbleAnchorObserver_);
           this.helpBubbleAnchorObserver_.disconnect();
           this.helpBubbleAnchorObserver_ = null;
@@ -189,10 +190,10 @@
           assert(this.canShowHelpBubble(controller), 'Can\'t show help bubble');
           const bubble = controller.createBubble(params);
 
-          this.dismissedEventTracker_.add(
+          this.helBubbleDismissedEventTracker_.add(
               bubble, HELP_BUBBLE_DISMISSED_EVENT,
               this.onHelpBubbleDismissed_.bind(this));
-          this.dismissedEventTracker_.add(
+          this.helBubbleDismissedEventTracker_.add(
               bubble, HELP_BUBBLE_TIMED_OUT_EVENT,
               this.onHelpBubbleTimedOut_.bind(this));
 
@@ -210,9 +211,9 @@
             return false;
           }
 
-          this.dismissedEventTracker_.remove(
+          this.helBubbleDismissedEventTracker_.remove(
               bubble.getElement()!, HELP_BUBBLE_DISMISSED_EVENT);
-          this.dismissedEventTracker_.remove(
+          this.helBubbleDismissedEventTracker_.remove(
               bubble.getElement()!, HELP_BUBBLE_TIMED_OUT_EVENT);
 
           bubble.hide();
diff --git a/ui/webui/resources/cr_components/history_clusters/cluster.html b/ui/webui/resources/cr_components/history_clusters/cluster.html
index cdd057a..f877d74 100644
--- a/ui/webui/resources/cr_components/history_clusters/cluster.html
+++ b/ui/webui/resources/cr_components/history_clusters/cluster.html
@@ -8,6 +8,7 @@
   }
 
   :host([in-side-panel_]) {
+    --cr-icon-button-margin-start: 8px;
     padding-bottom: 0;
     padding-top: 8px;
   }
@@ -64,6 +65,7 @@
   :host([in-side-panel_]) #label {
     font-size: .875rem;  /* 14px */
     line-height: calc(10/7); /* 20px */
+    margin-inline-end: 16px;
   }
 
   :host([in-side-panel_]) .timestamp {
@@ -136,11 +138,8 @@
     on-open-all-visits="onOpenAllVisits_"
     on-remove-all-visits="onRemoveAllVisits_"
     on-remove-visit="onRemoveVisit_">
-  <!-- In the side panel the label and timestamp should be stacked on the
-       left, while outside the side panel the timestamp and the menu should
-       be side by side on the right. -->
   <div class="label-row">
-    <span id="label" class="label"></span>
+    <span id="label" class="truncate"></span>
     <img is="cr-auto-img" auto-src="[[imageUrl_]]">
     <div class="debug-info">[[cluster.debugInfo]]</div>
     <div class="timestamp-and-menu">
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
index 021a1d27d..e7d47e70 100644
--- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
+++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
@@ -96,6 +96,10 @@
         padding: 16px 20px;
       }
 
+      :host([hide-backdrop]) dialog::backdrop {
+        opacity: 0;
+      }
+
       @media (prefers-color-scheme: dark) {
         :host ::slotted([slot=footer]) {
           border-top-color: var(--cr-separator-color);