diff --git a/DEPS b/DEPS
index 79c2e15..55e7235 100644
--- a/DEPS
+++ b/DEPS
@@ -307,7 +307,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': '2f18b71d0e10a430beb1ec31560e6e2828ec096a',
+  'angle_revision': '649514930e65cb7a9baa489092431010df5e8b4a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -315,7 +315,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'a4646686ab9486809befa1570e0f6849dfa57d48',
+  'pdfium_revision': 'b6457bcccc5c86ac7159f957fa8dbea3d5e13f49',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -411,7 +411,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '5602ae03628ac1ae4ba8d265ac1979abea42d6ba',
+  'dawn_revision': '168d54a050758eb88e25757111b850bb1e97ed90',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1572,7 +1572,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '682a9b98153aec09a8df5d129561a604cd409d68',
+    'ceeb89e0f8224ca96ca05598cf0cfc1a7b652963',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1802,7 +1802,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/error_prone',
-               'version': 'RiplT9oTSE0lQHviAF6FMk5P9863t0-WHcl2te12hi0C',
+               'version': 'KOECi08Fw4fRTVXkKocxg94coB-e_dlcHRokC21yxyoC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1824,7 +1824,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/lint',
-               'version': '3bWjs4NjBtTIXoWH03nPx8c--ehZzlDkL8PUE_GaPKUC',
+               'version': 'Ddt_nMFT2APf615MrUZPaZpe-MqZSNrJmk8s9ud-f3gC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1835,7 +1835,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': 'AFWUMAcwcd0L1DG2-ib4ghtQYFsCvZjWuQkhuTJl4ToC',
+               'version': 'JcTHGCKOl5tWhax5LSv_vf5dQV14RZdPF9xSRKU76JgC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2114,7 +2114,7 @@
 
   # Used for embedded builds. CrOS & Linux use the system version.
   'src/third_party/fontconfig/src': {
-      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + 'f71f39e7da6bccfb5a803a4adcdfe88d382a6eab',
+      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + 'c527fe1452d469e5fa1a211180dd40bcdb79fb2a',
       'condition': 'checkout_linux',
   },
 
@@ -2310,7 +2310,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/kotlin_stdlib',
-              'version': 'E405j4iATVcDLLGq9LbG61CRuyD0rs08XuMkg_GCJAwC',
+              'version': 'tLtdnQg608nJL86aqaHDj7zYXia6baxVWj0T0AvFGeYC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2926,16 +2926,16 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@17fd4e2e0ff9c2de2dc9a251d4c2b7832f7735f5',
-  'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@05cfcc1613c28c1274036f53616d66324f7cd383',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4e2ba677d4d655a0b0d69b596f1c076ee0d4b516',
+  'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@21b4e37133868b3a50ef15fc027ecd6d3a52c875',
   'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3',
   'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@2a611a970fdbc41ac2e3e328802aed9985352dca',
-  'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@dab29fb163948c142b33f0176eb8baa086fa5df3',
+  'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@422150b405c2ac2e05e51a19defabb232efd9187',
   'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@b39ab380a44b6c8df462c34e976ea9ce2d2c336b',
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@dc6786e527cf8cefd244318f546b3b2ec26e84f4',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@d671923090e4dc74c0ebdb10c6e09fa0826e1fe9',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@54c9baf20802a13279e23fa4cb0528dd5cf16064',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@d004bbbbeb7e1bfe79533522af631bacec407ad2',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@7cee394fda75d7b33d52b06b9e637abeb23c991c',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -3113,7 +3113,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'rX2MqHAspksu1vGKKUlrz5wgKpSn4cqRCdwp1-2SWQsC',
+        'version': 'm10SwGuuVH0QFwZe_Lc87HLp_-6nS0sUMUa-P7wuElMC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3124,7 +3124,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'GzCoW3LSnAHDe97i96XMweS4tzQIRWALYBZgEu1OBHgC',
+        'version': 'b8W8bh4rI2sAAObZO4i-kD1gZ2_CeelZ2RyB1vHD0dwC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4766,7 +4766,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'ca30afba1f3ceed05b486665b6cbaf3dfd7afd99',
+        '60004bd65ffb1bcc3552545311cc10870ea99e4c',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index 5cfce0c..f8c82d1 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -65,6 +65,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "base/not_fatal_until.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/pickle.h"
 #include "base/supports_user_data.h"
diff --git a/android_webview/browser/aw_permission_manager.cc b/android_webview/browser/aw_permission_manager.cc
index 28cb6d5..7d83fa6 100644
--- a/android_webview/browser/aw_permission_manager.cc
+++ b/android_webview/browser/aw_permission_manager.cc
@@ -20,6 +20,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/sequence_checker.h"
 #include "base/task/thread_pool.h"
diff --git a/ash/app_list/test_app_list_client.cc b/ash/app_list/test_app_list_client.cc
index 912e9840..f64c9a3 100644
--- a/ash/app_list/test_app_list_client.cc
+++ b/ash/app_list/test_app_list_client.cc
@@ -11,6 +11,7 @@
 #include "ash/public/cpp/app_list/app_list_controller.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "chromeos/ash/services/assistant/public/cpp/features.h"
diff --git a/ash/assistant/ui/logo_view/logo_view_impl.cc b/ash/assistant/ui/logo_view/logo_view_impl.cc
index bcd0c58..86cb573 100644
--- a/ash/assistant/ui/logo_view/logo_view_impl.cc
+++ b/ash/assistant/ui/logo_view/logo_view_impl.cc
@@ -9,7 +9,7 @@
 #include "ash/assistant/ui/logo_view/shape/shape.h"
 #include "base/check.h"
 #include "base/containers/adapters.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chromeos/assistant/internal/logo_view/logo_model/dot.h"
 #include "chromeos/assistant/internal/logo_view/logo_view_constants.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index 59f27d1..18d4e02 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -33,6 +33,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/login/ui/access_code_input.cc b/ash/login/ui/access_code_input.cc
index 26dc6b7..1b81a58 100644
--- a/ash/login/ui/access_code_input.cc
+++ b/ash/login/ui/access_code_input.cc
@@ -9,6 +9,7 @@
 
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/system_textfield.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/ash/system/input_device_settings/pref_handlers/stylus_pref_handler_impl.cc b/ash/system/input_device_settings/pref_handlers/stylus_pref_handler_impl.cc
index 8d7bb46..1f34da20 100644
--- a/ash/system/input_device_settings/pref_handlers/stylus_pref_handler_impl.cc
+++ b/ash/system/input_device_settings/pref_handlers/stylus_pref_handler_impl.cc
@@ -5,7 +5,7 @@
 #include "ash/system/input_device_settings/pref_handlers/stylus_pref_handler_impl.h"
 
 #include "ash/public/mojom/input_device_settings.mojom-forward.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "components/prefs/pref_service.h"
 
 namespace ash {
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index e95c156f..d94fede 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -42,6 +42,7 @@
 #include "ash/wm/desks/templates/saved_desk_test_helper.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/system/sys_info.h"
 #include "base/system/system_monitor.h"
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index dc8d8df..812d8a2 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -45,6 +45,7 @@
 #include "base/debug/crash_logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/types/cxx23_to_underlying.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/base/chromeos_ui_constants.h"
diff --git a/base/android/pre_freeze_background_memory_trimmer.cc b/base/android/pre_freeze_background_memory_trimmer.cc
index 5f6fae7..31f6e71 100644
--- a/base/android/pre_freeze_background_memory_trimmer.cc
+++ b/base/android/pre_freeze_background_memory_trimmer.cc
@@ -119,29 +119,6 @@
   return after_value < before_value ? before_value - after_value : 0;
 }
 
-bool IsMadvisePageoutSupported() {
-  static bool supported = []() -> bool {
-#if defined(MADV_PAGEOUT)
-    // To determine if MADV_PAGEOUT is supported we will try calling it with an
-    // invalid memory area.
-    // madvise(2) first checks the mode first, returning -EINVAL if it's
-    // unknown. Next, it will always return 0 for a zero length VMA before
-    // validating if it's mapped.
-    // So, in this case, we can test for support with any page aligned address
-    // with a zero length.
-    int res =
-        madvise(reinterpret_cast<void*>(base::GetPageSize()), 0, MADV_PAGEOUT);
-    if (res < 0 && errno == -EINVAL)
-      return false;
-    PLOG_IF(ERROR, res < 0) << "Unexpected return from madvise";
-    if (res == 0)
-      return true;
-#endif
-    return false;
-  }();
-  return supported;
-}
-
 }  // namespace
 
 PreFreezeBackgroundMemoryTrimmer::PreFreezeBackgroundMemoryTrimmer()
@@ -445,101 +422,6 @@
   metrics_.erase(metrics_.begin() + index);
 }
 
-void SelfCompactionManager::MaybePostCompactionTask(
-    std::unique_ptr<CompactionState> state,
-    scoped_refptr<CompactionMetric> metric) {
-  TRACE_EVENT0("base", "MaybePostCompactionTask");
-  // Compaction is taking too long, so cancel it. This happens in practice in
-  // the field sometimes, according to UMA data.
-  if (TimeoutExceeded()) {
-    MaybeCancelCompaction(CompactCancellationReason::kTimeout);
-    // We do not return here, despite the fact that we will not be doing any
-    // more compaction, in order to run |FinishCompaction| below.
-  }
-
-  if (ShouldContinueCompaction(*state) && !state->regions_.empty()) {
-    auto task_runner = state->task_runner_;
-    task_runner->PostDelayedTask(
-        FROM_HERE,
-        // |base::Unretained| is safe here because we never destroy |this|.
-        base::BindOnce(&SelfCompactionManager::CompactionTask,
-                       base::Unretained(this), std::move(state),
-                       std::move(metric)),
-        GetDelayBetweenCompaction());
-  } else {
-    FinishCompaction(std::move(state), std::move(metric));
-  }
-}
-
-void SelfCompactionManager::CompactionTask(
-    std::unique_ptr<CompactionState> state,
-    scoped_refptr<CompactionMetric> metric) {
-  if (!ShouldContinueCompaction(*state)) {
-    return;
-  }
-
-  TRACE_EVENT0("base", "CompactionTask");
-
-  CompactMemory(&state->regions_, state->max_bytes_);
-
-  MaybePostCompactionTask(std::move(state), std::move(metric));
-}
-
-void SelfCompactionManager::MaybeRunOnSelfCompactCallback() {
-  if (on_self_compact_callback_) {
-    on_self_compact_callback_.Run();
-  }
-}
-
-void SelfCompactionManager::StartCompaction(
-    std::unique_ptr<CompactionState> state) {
-  scoped_refptr<CompactionMetric> metric;
-  {
-    base::AutoLock locker(lock());
-    compaction_last_started_ = base::TimeTicks::Now();
-    metric = state->MakeCompactionMetric(compaction_last_started_);
-    TRACE_EVENT0("base", "StartCompaction");
-    base::trace_event::EmitNamedTrigger("start-self-compaction");
-    process_compacted_metadata_.emplace(
-        "PreFreezeBackgroundMemoryTrimmer.ProcessCompacted",
-        /*is_compacted=*/1, base::SampleMetadataScope::kProcess);
-    MaybeRunOnSelfCompactCallback();
-  }
-  metric->RecordBeforeMetrics();
-  MaybePostCompactionTask(std::move(state), std::move(metric));
-}
-
-void SelfCompactionManager::FinishCompaction(
-    std::unique_ptr<CompactionState> state,
-    scoped_refptr<CompactionMetric> metric) {
-  TRACE_EVENT0("base", "FinishCompaction");
-  {
-    base::AutoLock locker(lock());
-    compaction_last_finished_ = base::TimeTicks::Now();
-  }
-  if (ShouldContinueCompaction(*state)) {
-    metric->RecordDelayedMetrics();
-    base::AutoLock locker(lock());
-    metric->RecordTimeMetrics(compaction_last_finished_,
-                              compaction_last_cancelled_);
-  }
-}
-
-void SelfCompactionManager::MaybeCancelCompactionInternal(
-    CompactCancellationReason cancellation_reason) {
-  // Check for the last time cancelled here in order to avoid recording this
-  // metric multiple times. Also, only record this metric if a compaction is
-  // currently running.
-  if (compaction_last_cancelled_ < compaction_last_triggered_ &&
-      compaction_last_finished_ < compaction_last_triggered_) {
-    UmaHistogramEnumeration(
-        "Memory.RunningOrSelfCompact.Renderer.Cancellation.Reason",
-        cancellation_reason);
-  }
-  compaction_last_finished_ = compaction_last_cancelled_ =
-      base::TimeTicks::Now();
-}
-
 SelfCompactionManager::CompactionState::CompactionState(
     scoped_refptr<SequencedTaskRunner> task_runner,
     base::TimeTicks triggered_at,
@@ -566,20 +448,6 @@
   UmaHistogramEnumeration(GetMetricName("ReadProcMaps"), did_read_proc_maps);
 }
 
-void SelfCompactionManager::OnTriggerCompact(
-    std::unique_ptr<CompactionState> state) {
-  if (state->IsFeatureEnabled()) {
-    PreFreezeBackgroundMemoryTrimmer::Instance().RunPreFreezeTasks();
-  }
-  const auto delay_after_pre_freeze_tasks =
-      state->GetDelayAfterPreFreezeTasks();
-  const auto task_runner = state->task_runner_;
-  task_runner->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&SelfCompactionManager::CompactSelf, std::move(state)),
-      delay_after_pre_freeze_tasks);
-}
-
 // static
 void PreFreezeBackgroundMemoryTrimmer::OnPreFreeze() {
   // If we have scheduled a self compaction task, cancel it, since App Freezer
@@ -825,24 +693,4 @@
                           last_finished - last_cancelled);
 }
 
-SelfCompactionManager::SelfCompactionManager() = default;
-
-// static
-SelfCompactionManager& SelfCompactionManager::Instance() {
-  static base::NoDestructor<SelfCompactionManager> instance;
-  return *instance;
-}
-
-// static
-bool SelfCompactionManager::CompactionIsSupported() {
-  return IsMadvisePageoutSupported();
-}
-
-void SelfCompactionManager::MaybeCancelCompaction(
-    base::android::CompactCancellationReason cancellation_reason) {
-  base::AutoLock locker(lock());
-  Instance().process_compacted_metadata_.reset();
-  Instance().MaybeCancelCompactionInternal(cancellation_reason);
-}
-
 }  // namespace base::android
diff --git a/base/android/self_compaction_manager.cc b/base/android/self_compaction_manager.cc
index 0f441a5..433f77e 100644
--- a/base/android/self_compaction_manager.cc
+++ b/base/android/self_compaction_manager.cc
@@ -8,11 +8,14 @@
 
 #include "base/feature_list.h"
 #include "base/logging.h"
+#include "base/memory/page_size.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/rand_util.h"
 #include "base/strings/strcat.h"
 #include "base/task/thread_pool.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/trace_event/named_trigger.h"  // no-presubmit-check
 #include "base/trace_event/trace_event.h"
 
 namespace base::android {
@@ -48,6 +51,29 @@
 
 namespace {
 
+bool IsMadvisePageoutSupported() {
+  static bool supported = []() -> bool {
+#if defined(MADV_PAGEOUT)
+    // To determine if MADV_PAGEOUT is supported we will try calling it with an
+    // invalid memory area.
+    // madvise(2) first checks the mode first, returning -EINVAL if it's
+    // unknown. Next, it will always return 0 for a zero length VMA before
+    // validating if it's mapped.
+    // So, in this case, we can test for support with any page aligned address
+    // with a zero length.
+    int res =
+        madvise(reinterpret_cast<void*>(base::GetPageSize()), 0, MADV_PAGEOUT);
+    if (res < 0 && errno == -EINVAL)
+      return false;
+    PLOG_IF(ERROR, res < 0) << "Unexpected return from madvise";
+    if (res == 0)
+      return true;
+#endif
+    return false;
+  }();
+  return supported;
+}
+
 // Based on UMA data, >99.5% of the compaction should take < 6s, so 10s should
 // be more than enough.
 constexpr base::TimeDelta kCompactionTimeout = base::Seconds(10);
@@ -132,6 +158,14 @@
 
 }  // namespace
 
+SelfCompactionManager::SelfCompactionManager() = default;
+
+// static
+SelfCompactionManager& SelfCompactionManager::Instance() {
+  static base::NoDestructor<SelfCompactionManager> instance;
+  return *instance;
+}
+
 // static
 void SelfCompactionManager::SetOnStartSelfCompactionCallback(
     base::RepeatingCallback<void(void)> callback) {
@@ -153,6 +187,11 @@
 }
 
 // static
+bool SelfCompactionManager::CompactionIsSupported() {
+  return IsMadvisePageoutSupported();
+}
+
+// static
 bool SelfCompactionManager::ShouldContinueCompaction(
     base::TimeTicks compaction_triggered_at) {
   base::AutoLock locker(lock());
@@ -166,6 +205,34 @@
   return base::Milliseconds(base::RandInt(100, 300));
 }
 
+void SelfCompactionManager::MaybeRunOnSelfCompactCallback() {
+  if (on_self_compact_callback_) {
+    on_self_compact_callback_.Run();
+  }
+}
+
+void SelfCompactionManager::MaybeCancelCompaction(
+    base::android::CompactCancellationReason cancellation_reason) {
+  base::AutoLock locker(lock());
+  Instance().process_compacted_metadata_.reset();
+  Instance().MaybeCancelCompactionInternal(cancellation_reason);
+}
+
+void SelfCompactionManager::MaybeCancelCompactionInternal(
+    CompactCancellationReason cancellation_reason) {
+  // Check for the last time cancelled here in order to avoid recording this
+  // metric multiple times. Also, only record this metric if a compaction is
+  // currently running.
+  if (compaction_last_cancelled_ < compaction_last_triggered_ &&
+      compaction_last_finished_ < compaction_last_triggered_) {
+    UmaHistogramEnumeration(
+        "Memory.RunningOrSelfCompact.Renderer.Cancellation.Reason",
+        cancellation_reason);
+  }
+  compaction_last_finished_ = compaction_last_cancelled_ =
+      base::TimeTicks::Now();
+}
+
 // static
 void SelfCompactionManager::OnRunningCompact() {
   TRACE_EVENT0("base", "OnRunningCompact");
@@ -184,6 +251,20 @@
   Instance().OnTriggerCompact<SelfCompactionState>(std::move(task_runner));
 }
 
+void SelfCompactionManager::OnTriggerCompact(
+    std::unique_ptr<CompactionState> state) {
+  if (state->IsFeatureEnabled()) {
+    PreFreezeBackgroundMemoryTrimmer::Instance().RunPreFreezeTasks();
+  }
+  const auto delay_after_pre_freeze_tasks =
+      state->GetDelayAfterPreFreezeTasks();
+  const auto task_runner = state->task_runner_;
+  task_runner->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&SelfCompactionManager::CompactSelf, std::move(state)),
+      delay_after_pre_freeze_tasks);
+}
+
 template <class State>
 void SelfCompactionManager::OnTriggerCompact(
     scoped_refptr<SequencedTaskRunner> task_runner) {
@@ -194,6 +275,80 @@
   OnTriggerCompact(std::move(state));
 }
 
+void SelfCompactionManager::StartCompaction(
+    std::unique_ptr<CompactionState> state) {
+  scoped_refptr<CompactionMetric> metric;
+  {
+    base::AutoLock locker(lock());
+    compaction_last_started_ = base::TimeTicks::Now();
+    metric = state->MakeCompactionMetric(compaction_last_started_);
+    TRACE_EVENT0("base", "StartCompaction");
+    base::trace_event::EmitNamedTrigger("start-self-compaction");
+    process_compacted_metadata_.emplace(
+        "PreFreezeBackgroundMemoryTrimmer.ProcessCompacted",
+        /*is_compacted=*/1, base::SampleMetadataScope::kProcess);
+    MaybeRunOnSelfCompactCallback();
+  }
+  metric->RecordBeforeMetrics();
+  MaybePostCompactionTask(std::move(state), std::move(metric));
+}
+
+void SelfCompactionManager::MaybePostCompactionTask(
+    std::unique_ptr<CompactionState> state,
+    scoped_refptr<CompactionMetric> metric) {
+  TRACE_EVENT0("base", "MaybePostCompactionTask");
+  // Compaction is taking too long, so cancel it. This happens in practice in
+  // the field sometimes, according to UMA data.
+  if (TimeoutExceeded()) {
+    MaybeCancelCompaction(CompactCancellationReason::kTimeout);
+    // We do not return here, despite the fact that we will not be doing any
+    // more compaction, in order to run |FinishCompaction| below.
+  }
+
+  if (ShouldContinueCompaction(*state) && !state->regions_.empty()) {
+    auto task_runner = state->task_runner_;
+    task_runner->PostDelayedTask(
+        FROM_HERE,
+        // |base::Unretained| is safe here because we never destroy |this|.
+        base::BindOnce(&SelfCompactionManager::CompactionTask,
+                       base::Unretained(this), std::move(state),
+                       std::move(metric)),
+        GetDelayBetweenCompaction());
+  } else {
+    FinishCompaction(std::move(state), std::move(metric));
+  }
+}
+
+void SelfCompactionManager::CompactionTask(
+    std::unique_ptr<CompactionState> state,
+    scoped_refptr<CompactionMetric> metric) {
+  if (!ShouldContinueCompaction(*state)) {
+    return;
+  }
+
+  TRACE_EVENT0("base", "CompactionTask");
+
+  CompactMemory(&state->regions_, state->max_bytes_);
+
+  MaybePostCompactionTask(std::move(state), std::move(metric));
+}
+
+void SelfCompactionManager::FinishCompaction(
+    std::unique_ptr<CompactionState> state,
+    scoped_refptr<CompactionMetric> metric) {
+  TRACE_EVENT0("base", "FinishCompaction");
+  {
+    base::AutoLock locker(lock());
+    compaction_last_finished_ = base::TimeTicks::Now();
+  }
+  if (ShouldContinueCompaction(*state)) {
+    metric->RecordDelayedMetrics();
+    base::AutoLock locker(lock());
+    metric->RecordTimeMetrics(compaction_last_finished_,
+                              compaction_last_cancelled_);
+  }
+}
+
 // static
 void SelfCompactionManager::CompactSelf(
     std::unique_ptr<CompactionState> state) {
diff --git a/base/features.cc b/base/features.cc
index f52cf7c8..a5c96cba 100644
--- a/base/features.cc
+++ b/base/features.cc
@@ -4,6 +4,8 @@
 
 #include "base/features.h"
 
+#include <atomic>
+
 #include "base/files/file_path.h"
 #include "base/task/sequence_manager/sequence_manager_impl.h"
 #include "base/threading/platform_thread.h"
@@ -35,6 +37,16 @@
 
 namespace base::features {
 
+namespace {
+
+// An atomic is used because this can be queried racily by a thread checking if
+// an optimization is enabled and a thread initializing this from the
+// FeatureList. All operations use std::memory_order_relaxed because there are
+// no dependent memory operations.
+std::atomic_bool g_is_reduce_ppms_enabled{false};
+
+}  // namespace
+
 // Alphabetical:
 
 // Controls caching within BASE_FEATURE_PARAM(). This is feature-controlled
@@ -128,8 +140,15 @@
              FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_ANDROID)
 
+bool IsReducePPMsEnabled() {
+  return g_is_reduce_ppms_enabled.load(std::memory_order_relaxed);
+}
+
 void Init(EmitThreadControllerProfilerMetadata
               emit_thread_controller_profiler_metadata) {
+  g_is_reduce_ppms_enabled.store(FeatureList::IsEnabled(kReducePPMs),
+                                 std::memory_order_relaxed);
+
   sequence_manager::internal::SequenceManagerImpl::InitializeFeatures();
   sequence_manager::internal::ThreadController::InitializeFeatures(
       emit_thread_controller_profiler_metadata);
diff --git a/base/features.h b/base/features.h
index 617593b..6d13f4a 100644
--- a/base/features.h
+++ b/base/features.h
@@ -50,6 +50,12 @@
                                        kBackgroundThreadPoolFieldTrialConfig);
 #endif
 
+// Whether the ReducePPMs feature is enabled. Unlike
+// `FeatureList::IsEnabled(base::features::kReducePPMs)`, this can be called
+// racily with initializing the FeatureList (although the return value might not
+// reflect the state of the feature in the FeatureList in that case).
+BASE_EXPORT bool IsReducePPMsEnabled();
+
 // Policy for emitting profiler metadata from `ThreadController`.
 enum class EmitThreadControllerProfilerMetadata {
   // Always emit metadata.
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index aa4fbd4..cdaf805 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -9,6 +9,8 @@
 
 #include "base/files/file.h"
 
+#include "base/notimplemented.h"
+
 // The only 32-bit platform that uses this file is Android. On Android APIs
 // >= 21, this standard define is the right way to express that you want a
 // 64-bit offset in struct stat, and the stat64 struct and functions aren't
diff --git a/base/test/test_file_util_linux.cc b/base/test/test_file_util_linux.cc
index f8e283b..0bfeb30c 100644
--- a/base/test/test_file_util_linux.cc
+++ b/base/test/test_file_util_linux.cc
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc
index 21721c9..9a9639ca 100644
--- a/cc/metrics/dropped_frame_counter.cc
+++ b/cc/metrics/dropped_frame_counter.cc
@@ -250,18 +250,6 @@
 
 void DroppedFrameCounter::ReportFramesOnEveryFrameForUI() {
   DCHECK(report_for_ui_);
-
-  if (!sliding_window_current_percent_dropped_) {
-    return;
-  }
-
-  auto* recorder = CustomMetricRecorder::Get();
-  if (!recorder) {
-    return;
-  }
-
-  recorder->ReportPercentDroppedFramesInOneSecondWindow2(
-      *sliding_window_current_percent_dropped_);
 }
 
 void DroppedFrameCounter::SetUkmSmoothnessDestination(
diff --git a/cc/metrics/dropped_frame_counter_unittest.cc b/cc/metrics/dropped_frame_counter_unittest.cc
index dc89351..36d15bf 100644
--- a/cc/metrics/dropped_frame_counter_unittest.cc
+++ b/cc/metrics/dropped_frame_counter_unittest.cc
@@ -628,40 +628,6 @@
   EXPECT_EQ(dropped_frame_counter_->total_smoothness_dropped(), 3u);
 }
 
-TEST_F(DroppedFrameCounterTest, ReportOnEveryFrameForUI) {
-  constexpr auto kInterval = base::Milliseconds(10);
-  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
-  static_assert(
-      kFps % 5 == 0,
-      "kFps must be a multiple of 5 because this test depends on it.");
-  SetInterval(kInterval);
-
-  dropped_frame_counter_->EnableReportForUI();
-  TestCustomMetricsRecorder recorder;
-
-  // 4 seconds with 20% dropped frames.
-  SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
-
-  // Recorded (kFps * 3) samples of 20% dropped frame percentage. Only 3 seconds
-  // of frames reported because there is no reports for the very 1st second.
-  // Off-by-one introduced by FrameSorter refactor.
-  // We have inverted the order in which we call DFC::AddSortedFrame and
-  // DFC::OnEndFrame, meaning that DFC's sliding_window_current_percent_dropped_
-  // is set after OnEndFrame has been called at the 1s second threshold.
-  // Therefore, we expect one less call to the frame recorder.
-  EXPECT_EQ(recorder.report_count(), (kFps * 3) - 1);
-  EXPECT_FLOAT_EQ(recorder.last_percent_dropped_frames(), 20.0f);
-
-  recorder.Reset();
-
-  // 4 seconds with 0 dropped frames.
-  SimulateFrameSequence({false, false, false, false, false}, (kFps / 5) * 4);
-
-  // Recorded (kFps * 4) samples of 0% dropped frame percentage.
-  EXPECT_EQ(recorder.report_count(), kFps * 4);
-  EXPECT_FLOAT_EQ(recorder.last_percent_dropped_frames(), 0.0f);
-}
-
 class DroppedFrameCounterLegacyMetricsTest : public DroppedFrameCounterTest {
  public:
   DroppedFrameCounterLegacyMetricsTest();
@@ -680,35 +646,5 @@
   frame_sorter_.AddObserver(dropped_frame_counter_.get());
 }
 
-TEST_F(DroppedFrameCounterLegacyMetricsTest, DoesNotReportLegacyMetrics) {
-  constexpr auto kInterval = base::Milliseconds(10);
-  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
-  static_assert(
-      kFps % 5 == 0,
-      "kFps must be a multiple of 5 because this test depends on it.");
-  SetInterval(kInterval);
-
-  dropped_frame_counter_->EnableReportForUI();
-  TestCustomMetricsRecorder recorder;
-
-  // 5 seconds with 20% dropped frames.
-  SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 6);
-  // We have inverted the order in which we call DFC::AddSortedFrame and
-  // DFC::OnEndFrame, meaning that DFC's sliding_window_current_percent_dropped_
-  // is set after OnEndFrame has been called at the 1s second threshold.
-  // Therefore, we expect one less call to the frame recorder.
-  EXPECT_EQ(recorder.report_count(), (5 * kFps) - 1);
-
-  // The following metrics should report data.
-  // Average calculation
-  EXPECT_GT(dropped_frame_counter_->total_smoothness_dropped(), 0.0);
-  // Median calculation
-  EXPECT_GT(PercentDroppedFrameMedian(), 0.0);
-  // Compositor-focused median calculation
-  EXPECT_GT(dropped_frame_counter_->SlidingWindowMedianPercentDropped(
-                SmoothnessStrategy::kCompositorFocusedStrategy),
-            0.0);
-}
-
 }  // namespace
 }  // namespace cc
diff --git a/cc/metrics/frame_sorter.cc b/cc/metrics/frame_sorter.cc
index 1d5f3a80..62ad1801 100644
--- a/cc/metrics/frame_sorter.cc
+++ b/cc/metrics/frame_sorter.cc
@@ -4,12 +4,19 @@
 
 #include "cc/metrics/frame_sorter.h"
 
+#include <algorithm>
 #include <cstddef>
+#include <cstdint>
 #include <utility>
 
+#include "cc/metrics/custom_metrics_recorder.h"
 #include "cc/metrics/frame_info.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
 
 namespace cc {
+namespace {
+const base::TimeDelta kDefaultSlidingWindowInterval = base::Seconds(1);
+}  // namespace
 
 using FrameState = FrameSorter::FrameState;
 
@@ -104,6 +111,13 @@
   if (!frame_states_.count(args.frame_id))
     return;
 
+  if (report_for_ui_) {
+    sliding_window_.emplace(args, frame_info);
+    if (frame_info.IsDroppedAffectingSmoothness()) {
+      DCHECK_GE(dropped_frame_count_in_window_ + 1, 0u);
+      dropped_frame_count_in_window_ += 1;
+    }
+  }
   const auto f = frame_infos_.find(args.frame_id);
   if (f != frame_infos_.end()) {
     f->second.MergeWith(frame_info);
@@ -139,6 +153,28 @@
         << args.frame_id.ToString()
         << pending_frames_.front().frame_id.ToString();
   }
+
+  // Report frames on every frame for UI. This needs to happen after
+  // `FrameSorter::AddFrameResult` so that the current ending frame is included
+  // in the sliding window.
+  if (report_for_ui_) {
+    auto* recorder = CustomMetricRecorder::Get();
+    if (sliding_window_current_percent_dropped_ && recorder) {
+      recorder->ReportPercentDroppedFramesInOneSecondWindow2(
+          *sliding_window_current_percent_dropped_);
+    }
+
+    if (ComputeCurrentWindowSize() < kDefaultSlidingWindowInterval) {
+      return;
+    }
+    DCHECK_GE(dropped_frame_count_in_window_, 0u);
+    DCHECK_GE(sliding_window_.size(), dropped_frame_count_in_window_);
+
+    while (ComputeCurrentWindowSize() > kDefaultSlidingWindowInterval) {
+      PopSlidingWindow(args);
+    }
+    DCHECK(!sliding_window_.empty());
+  }
 }
 
 bool FrameSorter::IsAlreadyReportedDropped(const viz::BeginFrameId& id) const {
@@ -170,6 +206,9 @@
   if (reset_fcp) {
     first_contentful_paint_received_ = false;
   }
+  sliding_window_ = {};
+  sliding_window_current_percent_dropped_.reset();
+  dropped_frame_count_in_window_ = 0;
 }
 
 void FrameSorter::FlushFrames() {
@@ -210,4 +249,45 @@
   first_contentful_paint_received_ = true;
 }
 
+base::TimeDelta FrameSorter::ComputeCurrentWindowSize() const {
+  if (sliding_window_.empty()) {
+    return {};
+  }
+  return sliding_window_.back().first.frame_time +
+         sliding_window_.back().first.interval -
+         sliding_window_.front().first.frame_time;
+}
+
+void FrameSorter::PopSlidingWindow(const viz::BeginFrameArgs& args) {
+  const auto removed_args = sliding_window_.front().first;
+  const auto removed_frame_info = sliding_window_.front().second;
+  if (removed_frame_info.IsDroppedAffectingSmoothness()) {
+    DCHECK_GE(dropped_frame_count_in_window_ - 1, 0u);
+    dropped_frame_count_in_window_ -= 1;
+  }
+  sliding_window_.pop();
+  if (sliding_window_.empty()) {
+    return;
+  }
+
+  // Don't count the newest element if it is outside the current window.
+  const auto newest_was_dropped =
+      sliding_window_.back().second.IsDroppedAffectingSmoothness();
+
+  uint32_t invalidated_frames = 0;
+  if (ComputeCurrentWindowSize() > kDefaultSlidingWindowInterval &&
+      newest_was_dropped) {
+    invalidated_frames++;
+  }
+
+  uint32_t dropped = dropped_frame_count_in_window_ - invalidated_frames;
+  auto total_frames_in_window = kDefaultSlidingWindowInterval / args.interval;
+  const double percent_dropped_frame =
+      std::min((dropped * 100.0) / total_frames_in_window, 100.0);
+  sliding_window_current_percent_dropped_ = percent_dropped_frame;
+}
+void FrameSorter::EnableReportForUI() {
+  report_for_ui_ = true;
+}
+
 }  // namespace cc
diff --git a/cc/metrics/frame_sorter.h b/cc/metrics/frame_sorter.h
index dbe159c..418d035b 100644
--- a/cc/metrics/frame_sorter.h
+++ b/cc/metrics/frame_sorter.h
@@ -9,6 +9,8 @@
 
 #include <map>
 #include <optional>
+#include <queue>
+#include <utility>
 #include <vector>
 
 #include "base/containers/circular_deque.h"
@@ -96,8 +98,14 @@
     return first_contentful_paint_received_;
   }
 
+  // Enable dropped frame report for ui::Compositor..
+  void EnableReportForUI();
+
  private:
   void FlushFrames();
+  base::TimeDelta ComputeCurrentWindowSize() const;
+  void PopSlidingWindow(const viz::BeginFrameArgs& args);
+  std::queue<std::pair<const viz::BeginFrameArgs, FrameInfo>> sliding_window_;
 
   const uint64_t kPendingFramesMaxSize = 300u;
 
@@ -120,6 +128,9 @@
 
   std::optional<uint64_t> current_source_id_;
   bool first_contentful_paint_received_ = false;
+  bool report_for_ui_ = false;
+  std::optional<double> sliding_window_current_percent_dropped_;
+  uint32_t dropped_frame_count_in_window_ = 0;
 };
 
 }  // namespace cc
diff --git a/cc/metrics/frame_sorter_unittest.cc b/cc/metrics/frame_sorter_unittest.cc
index cadc893f..522208a 100644
--- a/cc/metrics/frame_sorter_unittest.cc
+++ b/cc/metrics/frame_sorter_unittest.cc
@@ -9,13 +9,45 @@
 #include <vector>
 
 #include "base/functional/bind.h"
+#include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "cc/metrics/custom_metrics_recorder.h"
 #include "cc/metrics/frame_info.h"
 #include "cc/test/fake_frame_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
 
+class TestCustomMetricsRecorder : public CustomMetricRecorder {
+ public:
+  TestCustomMetricsRecorder() = default;
+  ~TestCustomMetricsRecorder() override = default;
+
+  // CustomMetricRecorder:
+  void ReportPercentDroppedFramesInOneSecondWindow2(double percent) override {
+    ++report_count_;
+    last_percent_dropped_frames_ = percent;
+  }
+  void ReportEventLatency(
+      std::vector<EventLatencyTracker::LatencyData> latencies) override {}
+
+  void Reset() {
+    report_count_ = 0u;
+    last_percent_dropped_frames_ = 0;
+  }
+
+  int report_count() const { return report_count_; }
+
+  double last_percent_dropped_frames() const {
+    return last_percent_dropped_frames_;
+  }
+
+ private:
+  int report_count_ = 0u;
+  double last_percent_dropped_frames_ = 0;
+};
+
 // Test class for FrameSorter
 class FrameSorterTest : public testing::Test, FrameSorterObserver {
  public:
@@ -27,11 +59,12 @@
 
   viz::BeginFrameArgs GetNextFrameArgs() {
     uint64_t sequence_number = next_frame_sequence_number_++;
+    last_begin_frame_time_ += base::Milliseconds(250);
     return viz::BeginFrameArgs::Create(
         BEGINFRAME_FROM_HERE, next_frame_source_id_, sequence_number,
         last_begin_frame_time_,
-        last_begin_frame_time_ + viz::BeginFrameArgs::DefaultInterval(),
-        viz::BeginFrameArgs::DefaultInterval(), viz::BeginFrameArgs::NORMAL);
+        last_begin_frame_time_ + base::Milliseconds(250),
+        base::Milliseconds(250), viz::BeginFrameArgs::NORMAL);
   }
 
   void IncreaseSourceId() {
@@ -118,6 +151,7 @@
       result_index++;
     }
   }
+  FrameSorter frame_sorter_;
 
  private:
   void AddSortedFrame(const viz::BeginFrameArgs& args,
@@ -125,7 +159,6 @@
     sorted_frames_.emplace_back(args, frame.IsDroppedAffectingSmoothness());
   }
 
-  FrameSorter frame_sorter_;
   std::vector<std::pair<const viz::BeginFrameArgs, bool>> sorted_frames_;
   base::TimeTicks last_begin_frame_time_ = base::TimeTicks::Now();
   uint64_t next_frame_source_id_ = 0;
@@ -211,4 +244,24 @@
   ValidateResults(expected_results);
 }
 
+TEST_F(FrameSorterTest, ReportOnEveryFrameForUI) {
+  // 1 dropped frame in the first window of 4 frames, which will be accounted
+  // for over the first second of monitoring.
+  // We need to present two additional frames in order to (1) assign the
+  // sliding_window_current_percent_dropped_ value and (2) print it in the
+  // recorder.
+  std::vector<std::string> queries = {"S0", "S1", "P0", "S2", "P2", "S3",
+                                      "P1", "D3", "S4", "P4", "S5", "D5"};
+
+  frame_sorter_.EnableReportForUI();
+  TestCustomMetricsRecorder recorder;
+
+  SimulateQueries(queries);
+  // Should report 1 report count because we only had one window > the default
+  // interval of 1s.
+  EXPECT_EQ(recorder.report_count(), 1);
+  EXPECT_EQ(recorder.last_percent_dropped_frames(),
+            25.0f);  // 1 of 4 frames dropped in the first window.
+}
+
 }  // namespace cc
diff --git a/cc/paint/skia_paint_canvas.cc b/cc/paint/skia_paint_canvas.cc
index 2b412ad..ddcad418 100644
--- a/cc/paint/skia_paint_canvas.cc
+++ b/cc/paint/skia_paint_canvas.cc
@@ -10,7 +10,7 @@
 
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/paint/display_item_list.h"
 #include "cc/paint/paint_filter.h"
diff --git a/cc/paint/skottie_wrapper_impl.cc b/cc/paint/skottie_wrapper_impl.cc
index 2a5d8cfce..e545b79 100644
--- a/cc/paint/skottie_wrapper_impl.cc
+++ b/cc/paint/skottie_wrapper_impl.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/paint/skottie_wrapper.h"
-
 #include <functional>
 #include <memory>
 #include <string_view>
@@ -15,11 +13,12 @@
 #include "base/functional/callback.h"
 #include "base/hash/hash.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/paint/skottie_mru_resource_provider.h"
+#include "cc/paint/skottie_wrapper.h"
 #include "skia/ext/font_utils.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkFontMgr.h"
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index f3a9a3de..15de1aa 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -677,7 +677,8 @@
 
  private:
   raw_ptr<TestHooks> hooks_;
-  raw_ptr<TaskRunnerProvider> task_runner_provider_;
+  raw_ptr<TaskRunnerProvider, AcrossTasksDanglingUntriaged>
+      task_runner_provider_;
 };
 
 LayerTreeTest::LayerTreeTest(viz::RendererType renderer_type)
@@ -1297,22 +1298,6 @@
 }
 
 void LayerTreeTest::DestroyLayerTreeHost() {
-  // The `LayerTreeFrameSink` must be released before the LayerTreeHost as some
-  // subclasses, such as `TestLayerTreeFrameSink` hold onto pointers to
-  // `LayerTreeTestLayerTreeFrameSinkClient` and other objects, such as
-  // `TestCompositorFrameSinkSupport` (which also references the task runner and
-  // client), which will trigger dangling ptr warnings if destroyed in the wrong
-  // order.
-  if (layer_tree_host_) {
-    // Forcing the LayerTreeHost to be !visible to avoid triggering the DCHECK
-    // in ReleaseLayerTreeFrameSink.
-    layer_tree_host_->SetVisible(false);
-    layer_tree_host_->ReleaseLayerTreeFrameSink();
-  }
-  // References the TaskRunnerProvider owned by LayerTreeHost so must be
-  // cleaned up first to avoid being a dangling ptr.
-  layer_tree_frame_sink_client_ = nullptr;
-
   if (layer_tree_host_ && layer_tree_host_->root_layer())
     layer_tree_host_->root_layer()->SetLayerTreeHost(nullptr);
   layer_tree_host_ = nullptr;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 4e85450..66acd867 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -524,6 +524,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
     dropped_frame_counter_.EnableReportForUI();
+    frame_sorter_.EnableReportForUI();
     frame_trackers_.StartSequence(
         FrameSequenceTrackerType::kCompositorAnimation);
 #endif  // BUILDFLAG(IS_CHROMEOS)
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 0aad897..7fd8ffac 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -1432,7 +1432,6 @@
         ui_resource2_ = nullptr;
         ui_resource3_ = nullptr;
         EndTest();
-        test_ended_ = true;
         break;
       case 4:
         NOTREACHED();
@@ -1440,12 +1439,6 @@
   }
 
   void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
-    // LayerTreeTest will change the visibility of the tree to false as part of
-    // tearing down the LayerTreeHost. sii_ and other resources will already be
-    // destroyed.
-    if (test_ended_) {
-      return;
-    }
     if (!visible) {
       // All resources should have been evicted.
       ASSERT_EQ(0u, sii_->shared_image_count());
@@ -1531,7 +1524,6 @@
  private:
   std::unique_ptr<FakeScopedUIResource> ui_resource2_;
   std::unique_ptr<FakeScopedUIResource> ui_resource3_;
-  bool test_ended_ = false;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction);
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index b4340002..2a984b3a 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -12,7 +12,7 @@
 
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/profiler/sample_metadata.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/trace_event/trace_event.h"
diff --git a/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected b/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected
index 353f1b0..fbd1a06 100644
--- a/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_64_32_public_bundle__chrome.AndroidManifest.expected
@@ -831,13 +831,6 @@
       </intent-filter>  # DIFF-ANCHOR: 4ed161a4
       <meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info"/>
     </receiver>  # DIFF-ANCHOR: a0d83ae5
-    <receiver  # DIFF-ANCHOR: 2f1fe689
-        android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$PhoneUnlockedReceiver"
-        android:exported="true">
-      <intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
-        <action android:name="android.intent.action.USER_PRESENT"/>
-      </intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
-    </receiver>  # DIFF-ANCHOR: 2f1fe689
     <receiver  # DIFF-ANCHOR: 124ac9a1
         android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$TapReceiver"
         android:exported="false">
diff --git a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
index 5f2df15..23e100a 100644
--- a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
@@ -786,13 +786,6 @@
       </intent-filter>  # DIFF-ANCHOR: 4ed161a4
       <meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info"/>
     </receiver>  # DIFF-ANCHOR: a0d83ae5
-    <receiver  # DIFF-ANCHOR: 2f1fe689
-        android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$PhoneUnlockedReceiver"
-        android:exported="true">
-      <intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
-        <action android:name="android.intent.action.USER_PRESENT"/>
-      </intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
-    </receiver>  # DIFF-ANCHOR: 2f1fe689
     <receiver  # DIFF-ANCHOR: 124ac9a1
         android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$TapReceiver"
         android:exported="false">
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
index 3c4231b..23ec8db4 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -2079,8 +2079,7 @@
         // make sure that the color of navigation bar is changed by dialog scrim.
         // Skip if Chrome is drawing edge to edge as navigation bar will stay transparent.
         Resources resources = cta.getResources();
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1
-                || !resources.getBoolean(R.bool.window_light_navigation_bar)
+        if (!resources.getBoolean(R.bool.window_light_navigation_bar)
                 || isTablet(cta)
                 || cta.getTabModelSelectorSupplier().get().isIncognitoBrandedModelSelected()) {
             return;
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java
index a48eb02..e69acb4 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java
@@ -287,18 +287,14 @@
     @UiThreadTest
     public void testSetTint() {
         ColorStateList tint = ThemeUtils.getThemedToolbarIconTint(sActivity, true);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            assertNotEquals(tint, mBackButton.getImageTintList());
-            assertNotEquals(tint, mNewTabButton.getImageTintList());
-        }
+        assertNotEquals(tint, mBackButton.getImageTintList());
+        assertNotEquals(tint, mNewTabButton.getImageTintList());
         assertNotEquals(tint, mTitleTextView.getTextColors());
 
         mModel.set(TabGridDialogProperties.TINT, tint);
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            assertEquals(tint, mBackButton.getImageTintList());
-            assertEquals(tint, mNewTabButton.getImageTintList());
-        }
+        assertEquals(tint, mBackButton.getImageTintList());
+        assertEquals(tint, mNewTabButton.getImageTintList());
         assertEquals(tint, mTitleTextView.getTextColors());
     }
 
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java
index 2e38764..9dfc995 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java
@@ -20,7 +20,6 @@
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabModelTabCount;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount;
 
-import android.os.Build;
 import android.os.Build.VERSION_CODES;
 
 import androidx.test.filters.LargeTest;
@@ -80,8 +79,7 @@
 
     @After
     public void tearDown() throws Exception {
-        // On Android N this throws an exception because of legacy multi window.
-        if (mCta2 != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+        if (mCta2 != null) {
             ApplicationTestUtils.finishActivity(mCta2);
         }
         if (mCta1 != null) {
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index c261000..15d2c2a9 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -11,7 +11,6 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
@@ -963,9 +962,7 @@
 
             // Work around https://crbug.com/943873 where default focus highlight shows up after
             // toggling dark mode.
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                view.setDefaultFocusHighlightEnabled(false);
-            }
+            view.setDefaultFocusHighlightEnabled(false);
             if (mOverScrollDisabled) {
                 view.setOverScrollMode(View.OVER_SCROLL_NEVER);
             }
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index f8815b4..40da3e5f 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -468,12 +468,6 @@
             android:excludeFromRecents="true"
             android:exported="false" />
 
-        <receiver android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$PhoneUnlockedReceiver" android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.USER_PRESENT" />
-            </intent-filter>
-        </receiver>
-
         <!-- Phishing Protection related -->
         <receiver android:name="org.chromium.chrome.browser.safe_browsing.PasswordProtectionBroadcastReceiver"
         android:exported="true"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
index a7841a7..02c2eb17 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
@@ -28,7 +28,6 @@
 import androidx.annotation.ColorInt;
 import androidx.annotation.IntDef;
 import androidx.annotation.LayoutRes;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.StyleRes;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.app.AppCompatActivity;
@@ -153,9 +152,7 @@
         }
         // If ClassLoader was corrected by SplitCompatAppComponentFactory, also need to correct
         // the reference in the associated Context.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            BundleUtils.checkContextClassLoader(newBase, this);
-        }
+        BundleUtils.checkContextClassLoader(newBase, this);
 
         mServiceTracingProxyProvider = ServiceTracingProxyProvider.create(newBase);
 
@@ -314,7 +311,6 @@
     }
 
     @Override
-    @RequiresApi(Build.VERSION_CODES.O)
     public void onMultiWindowModeChanged(boolean inMultiWindowMode, Configuration configuration) {
         super.onMultiWindowModeChanged(inMultiWindowMode, configuration);
         onMultiWindowModeChanged(inMultiWindowMode);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
index 6eea2d79..cd3f417 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser;
 
-
-import android.os.Build;
 import android.os.Looper;
 import android.os.StrictMode;
 import android.text.TextUtils;
@@ -99,14 +97,8 @@
                 .detectLeakedRegistrationObjects()
                 .detectLeakedSqlLiteObjects();
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            // Introduced in O.
-            vmPolicy.detectContentUriWithoutPermission();
-        }
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            // Introduced in Q.
-            vmPolicy.detectCredentialProtectedWhileLocked().detectImplicitDirectBoot();
-        }
+        vmPolicy.detectContentUriWithoutPermission();
+        vmPolicy.detectCredentialProtectedWhileLocked().detectImplicitDirectBoot();
 
         // File URI leak detection, has false positives when file URI intents are passed between
         // Chrome activities in separate processes. See http://crbug.com/508282#c11.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 768ffca9..e390edd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -33,7 +33,6 @@
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleObserver;
@@ -4240,10 +4239,7 @@
      *
      * @param isIncognito Whether the shortcut or action created a new incognito tab.
      */
-    @RequiresApi(Build.VERSION_CODES.N_MR1)
     private void reportNewTabShortcutUsed(boolean isIncognito) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return;
-
         ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
         shortcutManager.reportShortcutUsed(
                 isIncognito ? "new-incognito-tab-shortcut" : "new-tab-shortcut");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java
index c7f49dbc..189bfbb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java
@@ -54,7 +54,6 @@
             @NonNull Supplier<CompositorViewHolder> compositorViewHolderSupplier,
             @NonNull Supplier<ModalDialogManager> modalDialogManagerSupplier,
             @NonNull Supplier<ManualFillingComponent> manualFillingComponentSupplier,
-            boolean activityTopResumedSupported,
             @NonNull IntentRequestTracker intentRequestTracker,
             @NonNull InsetObserver insetObserver) {
         this(
@@ -63,7 +62,7 @@
                 modalDialogManagerSupplier,
                 sKeyboardVisibilityDelegateFactory.create(
                         new WeakReference<>(activity), manualFillingComponentSupplier),
-                activityTopResumedSupported,
+                /* activityTopResumedSupported= */ true,
                 intentRequestTracker,
                 insetObserver);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java
index 670b6bb..e1a64c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java
@@ -10,10 +10,8 @@
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager;
 import android.graphics.drawable.Icon;
-import android.os.Build;
 import android.os.Bundle;
 
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ResettersForTesting;
@@ -73,8 +71,6 @@
      * @param profile The profile used to check whether incognito mode is enabled.
      */
     public static void updateIncognitoShortcut(Context context, Profile profile) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return;
-
         SharedPreferencesManager preferences = ChromeSharedPreferences.getInstance();
         boolean incognitoEnabled = IncognitoUtils.isIncognitoModeEnabled(profile);
         boolean incognitoShortcutAdded =
@@ -98,11 +94,11 @@
 
     /**
      * Adds a "New incognito tab" dynamic launcher shortcut.
+     *
      * @param context The context used to retrieve the system {@link ShortcutManager}.
      * @return True if adding the shortcut has succeeded. False if the call fails due to rate
-     *         limiting. See {@link ShortcutManager#addDynamicShortcuts}.
+     *     limiting. See {@link ShortcutManager#addDynamicShortcuts}.
      */
-    @RequiresApi(Build.VERSION_CODES.N_MR1)
     private static boolean addIncognitoLauncherShortcut(Context context) {
         Intent intent = new Intent(LauncherShortcutActivity.ACTION_OPEN_NEW_INCOGNITO_TAB);
         intent.setPackage(context.getPackageName());
@@ -125,9 +121,9 @@
 
     /**
      * Removes the dynamic "New incognito tab" launcher shortcut.
+     *
      * @param context The context used to retrieve the system {@link ShortcutManager}.
      */
-    @RequiresApi(Build.VERSION_CODES.N_MR1)
     private static void removeIncognitoLauncherShortcut(Context context) {
         List<String> shortcutList = new ArrayList<>();
         shortcutList.add(DYNAMIC_OPEN_NEW_INCOGNITO_TAB_ID);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SnackbarActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/SnackbarActivity.java
index fd5756e..409a439 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SnackbarActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SnackbarActivity.java
@@ -4,11 +4,9 @@
 
 package org.chromium.chrome.browser;
 
-import android.os.Build;
 import android.os.Bundle;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 
 import androidx.annotation.CallSuper;
 
@@ -31,9 +29,6 @@
     @Override
     protected void onCreateInternal(Bundle savedInstanceState) {
         super.onCreateInternal(savedInstanceState);
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
-            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-        }
         // TODO(crbug.com/399495650): Add render tests for snackbar padding in edge-to-edge mode.
         mSnackbarManager = new SnackbarManager(this, getContentView(), null);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 89bcd12..a58a7bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -34,7 +34,6 @@
 import androidx.annotation.CallSuper;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ActivityState;
@@ -462,15 +461,11 @@
 
     @Override
     protected ActivityWindowAndroid createWindowAndroid() {
-        // Multi-resume feature is from Android 10.
-        // https://source.android.com/docs/core/display/multi_display/multi-resume
-        boolean activityTopResumedSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
         return new ChromeWindow(
                 /* activity= */ this,
                 mCompositorViewHolderSupplier,
                 getModalDialogManagerSupplier(),
                 mManualFillingComponentSupplier,
-                activityTopResumedSupported,
                 getIntentRequestTracker(),
                 getInsetObserver());
     }
@@ -1039,24 +1034,10 @@
         }
     }
 
-    private boolean useWindowFocusForVisibility() {
-        return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q;
-    }
-
     @Override
     public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
 
-        if (useWindowFocusForVisibility()) {
-            if (hasFocus) {
-                onActivityShown();
-            } else {
-                if (ApplicationStatus.getStateForActivity(this) == ActivityState.STOPPED) {
-                    onActivityHidden();
-                }
-            }
-        }
-
         Clipboard.getInstance().onWindowFocusChanged(hasFocus);
     }
 
@@ -1240,7 +1221,6 @@
      * is kept up-to-date.
      */
     @Override
-    @RequiresApi(api = Build.VERSION_CODES.O)
     public void onPictureInPictureModeChanged(boolean inPicture, Configuration newConfig) {
         super.onPictureInPictureModeChanged(inPicture, newConfig);
         Log.i(
@@ -1438,9 +1418,7 @@
         }
         super.onStart();
 
-        if (!useWindowFocusForVisibility()) {
-            onActivityShown();
-        }
+        onActivityShown();
 
         if (mPartnerBrowserRefreshNeeded) {
             mPartnerBrowserRefreshNeeded = false;
@@ -1506,11 +1484,7 @@
     public void onStop() {
         super.onStop();
 
-        if (useWindowFocusForVisibility()) {
-            if (!hasWindowFocus()) onActivityHidden();
-        } else {
-            onActivityHidden();
-        }
+        onActivityHidden();
 
         // We want to refresh partner browser provider every onStart().
         mPartnerBrowserRefreshNeeded = true;
@@ -2791,14 +2765,11 @@
             // This is a workaround for crbug.com/1236981. Doing nothing here is better than
             // crashing. We assert, which will be stripped in builds that get shipped to users.
             Log.e(TAG, "crbug.com/1236981", e);
-            String extraInfo = "";
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                extraInfo = " inflated from layout ID #" + v.getSourceLayoutResId();
-            }
             assert false
                     : "View "
                             + v.toString()
-                            + extraInfo
+                            + " inflated from layout ID #"
+                            + v.getSourceLayoutResId()
                             + " was not a ControlContainer. "
                             + " If you can reproduce, post in crbug.com/1236981";
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkActivity.java
index 75088ae..9e0bb10 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkActivity.java
@@ -4,11 +4,14 @@
 
 package org.chromium.chrome.browser.app.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.ComponentName;
 import android.content.Intent;
 import android.text.TextUtils;
 
 import org.chromium.base.IntentUtils;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.SnackbarActivity;
@@ -35,6 +38,7 @@
  * only be shown on phones; on tablet the bookmark UI is shown inside of a tab (see {@link
  * BookmarkPage}).
  */
+@NullMarked
 public class BookmarkActivity extends SnackbarActivity {
     public static final int EDIT_BOOKMARK_REQUEST_CODE = 14;
     public static final String INTENT_VISIT_BOOKMARK_ID = "BookmarkEditActivity.VisitBookmarkId";
@@ -79,19 +83,19 @@
         }
 
         if (mBookmarkOpener != null) {
-            mBookmarkOpener.destroy();
             mBookmarkOpener = null;
         }
     }
 
     @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
         if (requestCode == EDIT_BOOKMARK_REQUEST_CODE && resultCode == RESULT_OK) {
+            assumeNonNull(data);
             BookmarkId bookmarkId =
                     BookmarkId.getBookmarkIdFromString(
                             data.getStringExtra(INTENT_VISIT_BOOKMARK_ID));
-            mBookmarkManagerCoordinator.openBookmark(bookmarkId);
+            assumeNonNull(mBookmarkManagerCoordinator).openBookmark(bookmarkId);
         }
     }
 
@@ -103,7 +107,7 @@
     /**
      * @return The {@link BookmarkManagerCoordinator} for testing purposes.
      */
-    public BookmarkManagerCoordinator getManagerForTesting() {
+    public @Nullable BookmarkManagerCoordinator getManagerForTesting() {
         return mBookmarkManagerCoordinator;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java
index 930abdb..4f3327592 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.app.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
@@ -14,6 +16,9 @@
 import androidx.appcompat.widget.Toolbar;
 
 import org.chromium.base.Log;
+import org.chromium.build.annotations.Initializer;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.SnackbarActivity;
 import org.chromium.chrome.browser.bookmarks.BookmarkImageFetcher;
@@ -46,13 +51,11 @@
 /** The activity that enables the user to modify the title, url and parent folder of a bookmark. */
 // TODO(crbug.com/40269559): Separate the activity from its view.
 // TODO(crbug.com/40269559): Add a coordinator/mediator for business logic.
+@NullMarked
 public class BookmarkEditActivity extends SnackbarActivity {
     /** The intent extra specifying the ID of the bookmark to be edited. */
     public static final String INTENT_BOOKMARK_ID = "BookmarkEditActivity.BookmarkId";
 
-    /** The code when starting the folder move activity for a result. */
-    static final int MOVE_REQUEST_CODE = 15;
-
     private static final String TAG = "BookmarkEdit";
 
     private BookmarkModel mModel;
@@ -60,14 +63,13 @@
     private BookmarkUiPrefs mBookmarkUiPrefs;
     private BookmarkManagerOpener mBookmarkManagerOpener;
     private BookmarkId mBookmarkId;
-    private boolean mInFolderSelect;
     private PropertyModel mFolderSelectRowModel;
 
     private ImprovedBookmarkRowCoordinator mFolderSelectRowCoordinator;
     private ImprovedBookmarkRow mFolderSelectRow;
     private BookmarkTextInputLayout mTitleEditText;
     private BookmarkTextInputLayout mUrlEditText;
-    private MenuItem mDeleteButton;
+    private @Nullable MenuItem mDeleteButton;
     private FrameLayout mFolderPickerRowContainer;
 
     private final BookmarkUiPrefs.Observer mBookmarkUiPrefsObserver =
@@ -85,15 +87,12 @@
                 public void bookmarkModelChanged() {
                     if (mModel.doesBookmarkExist(mBookmarkId)) {
                         updateViewContent(true);
-                    } else if (!mInFolderSelect) {
-                        // This happens either when the user clicks delete button or partner
-                        // bookmark is removed in background.
-                        finish();
                     }
                 }
             };
 
     @Override
+    @Initializer
     protected void onProfileAvailable(Profile profile) {
         super.onProfileAvailable(profile);
         mProfile = profile;
@@ -114,7 +113,7 @@
 
         Toolbar toolbar = findViewById(R.id.toolbar);
         setSupportActionBar(toolbar);
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        assumeNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
 
         View shadow = findViewById(R.id.shadow);
         View scrollView = findViewById(R.id.scroll_view);
@@ -158,12 +157,13 @@
     /**
      * @param modelChanged Whether this view update is due to a model change in background.
      */
+    @Initializer
     private void updateViewContent(boolean modelChanged) {
-        BookmarkItem bookmarkItem = mModel.getBookmarkById(mBookmarkId);
+        BookmarkItem bookmarkItem = assumeNonNull(mModel.getBookmarkById(mBookmarkId));
         // While the user is editing the bookmark, do not override user's input.
         if (!modelChanged) {
-            mTitleEditText.getEditText().setText(bookmarkItem.getTitle());
-            mUrlEditText.getEditText().setText(bookmarkItem.getUrl().getSpec());
+            assumeNonNull(mTitleEditText.getEditText()).setText(bookmarkItem.getTitle());
+            assumeNonNull(mUrlEditText.getEditText()).setText(bookmarkItem.getUrl().getSpec());
         }
         mTitleEditText.setEnabled(bookmarkItem.isEditable());
         mUrlEditText.setEnabled(bookmarkItem.isUrlEditable());
@@ -201,7 +201,8 @@
     @Override
     protected void onStop() {
         if (mModel.doesBookmarkExist(mBookmarkId)) {
-            final GURL originalUrl = mModel.getBookmarkById(mBookmarkId).getUrl();
+            BookmarkItem bookmarkItem = assumeNonNull(mModel.getBookmarkById(mBookmarkId));
+            final GURL originalUrl = bookmarkItem.getUrl();
             final String title = mTitleEditText.getTrimmedText();
             final String url = mUrlEditText.getTrimmedText();
 
@@ -209,7 +210,7 @@
                 mModel.setBookmarkTitle(mBookmarkId, title);
             }
 
-            if (!mUrlEditText.isEmpty() && mModel.getBookmarkById(mBookmarkId).isUrlEditable()) {
+            if (!mUrlEditText.isEmpty() && bookmarkItem.isUrlEditable()) {
                 GURL fixedUrl = UrlFormatter.fixupUrl(url);
                 if (fixedUrl.isValid() && !fixedUrl.equals(originalUrl)) {
                     mModel.setBookmarkUrl(mBookmarkId, fixedUrl);
@@ -240,12 +241,12 @@
     }
 
     @VisibleForTesting
-    MenuItem getDeleteButton() {
+    @Nullable MenuItem getDeleteButton() {
         return mDeleteButton;
     }
 
     private void updateFolderPickerRow(@BookmarkRowDisplayPref int displayPref) {
-        BookmarkItem bookmarkItem = mModel.getBookmarkById(mBookmarkId);
+        BookmarkItem bookmarkItem = assumeNonNull(mModel.getBookmarkById(mBookmarkId));
         mFolderSelectRowModel =
                 mFolderSelectRowCoordinator.createBasePropertyModel(bookmarkItem.getParentId());
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java
index ce9f913..bae0629 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java
@@ -4,12 +4,17 @@
 
 package org.chromium.chrome.browser.app.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.view.Menu;
 import android.view.MenuItem;
 
 import androidx.appcompat.widget.Toolbar;
 
 import org.chromium.base.IntentUtils;
+import org.chromium.build.annotations.Initializer;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.SynchronousInitializationActivity;
 import org.chromium.chrome.browser.back_press.BackPressHelper;
@@ -34,39 +39,42 @@
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * The activity that enables the user to pick the parent folder for the given {@link BookmarkId}.
  * Used for the improved android bookmarks manager.
  */
+@NullMarked
 public class BookmarkFolderPickerActivity extends SynchronousInitializationActivity {
     /** The intent extra specifying the ID of the bookmark to be moved. */
     public static final String INTENT_BOOKMARK_IDS = "BookmarkFolderPickerActivity.BookmarkIds";
 
-    private BookmarkModel mBookmarkModel;
-    private List<BookmarkId> mBookmarkIds;
-    private BookmarkImageFetcher mBookmarkImageFetcher;
-    private BookmarkFolderPickerCoordinator mCoordinator;
+    private @Nullable BookmarkFolderPickerCoordinator mCoordinator;
 
     @Override
+    @Initializer
     protected void onProfileAvailable(Profile profile) {
         super.onProfileAvailable(profile);
-        mBookmarkModel = BookmarkModel.getForProfile(profile);
+        BookmarkModel bookmarkModel = BookmarkModel.getForProfile(profile);
 
         List<String> bookmarkIdsAsStrings =
                 IntentUtils.safeGetStringArrayListExtra(getIntent(), INTENT_BOOKMARK_IDS);
-        mBookmarkIds = BookmarkUtils.stringListToBookmarkIds(mBookmarkModel, bookmarkIdsAsStrings);
-        if (mBookmarkIds.isEmpty()) {
+        bookmarkIdsAsStrings =
+                bookmarkIdsAsStrings == null ? new ArrayList<>() : bookmarkIdsAsStrings;
+        List<BookmarkId> bookmarkIds =
+                BookmarkUtils.stringListToBookmarkIds(bookmarkModel, bookmarkIdsAsStrings);
+        if (bookmarkIds.isEmpty()) {
             finish();
             return;
         }
 
-        mBookmarkImageFetcher =
+        BookmarkImageFetcher bookmarkImageFetcher =
                 new BookmarkImageFetcher(
                         profile,
                         this,
-                        mBookmarkModel,
+                        bookmarkModel,
                         ImageFetcherFactory.createImageFetcher(
                                 ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE,
                                 profile.getProfileKey(),
@@ -77,7 +85,7 @@
                 new BookmarkAddNewFolderCoordinator(
                         this,
                         new ModalDialogManager(new AppModalPresenter(this), ModalDialogType.APP),
-                        mBookmarkModel);
+                        bookmarkModel);
         BookmarkUiPrefs bookmarkUiPrefs =
                 new BookmarkUiPrefs(ChromeSharedPreferences.getInstance());
         ShoppingService shoppingService = ShoppingServiceFactory.getForProfile(profile);
@@ -86,15 +94,15 @@
         mCoordinator =
                 new BookmarkFolderPickerCoordinator(
                         this,
-                        mBookmarkModel,
-                        mBookmarkIds,
+                        bookmarkModel,
+                        bookmarkIds,
                         this::finish,
                         addNewFolderCoordinator,
                         bookmarkUiPrefs,
                         new ImprovedBookmarkRowCoordinator(
                                 this,
-                                mBookmarkImageFetcher,
-                                mBookmarkModel,
+                                bookmarkImageFetcher,
+                                bookmarkModel,
                                 bookmarkUiPrefs,
                                 shoppingService),
                         shoppingService);
@@ -103,20 +111,20 @@
 
         Toolbar toolbar = mCoordinator.getToolbar();
         setSupportActionBar(toolbar);
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        assumeNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
         setContentView(mCoordinator.getView());
     }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         getMenuInflater().inflate(R.menu.bookmark_folder_picker_menu, menu);
-        mCoordinator.updateToolbarButtons();
+        assumeNonNull(mCoordinator).updateToolbarButtons();
         return super.onCreateOptionsMenu(menu);
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        if (mCoordinator.optionsItemSelected(item)) {
+        if (assumeNonNull(mCoordinator).optionsItemSelected(item)) {
             return true;
         }
         return super.onOptionsItemSelected(item);
@@ -124,7 +132,9 @@
 
     @Override
     protected void onDestroy() {
-        mCoordinator.destroy();
+        if (mCoordinator != null) {
+            mCoordinator.destroy();
+        }
         super.onDestroy();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/ColdStartTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/base/ColdStartTracker.java
index 0fa0435f..e79b954 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/ColdStartTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/ColdStartTracker.java
@@ -7,13 +7,6 @@
 import static org.chromium.build.NullUtil.assumeNonNull;
 
 import android.app.Activity;
-import android.os.Build;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.os.Process;
-import android.os.SystemClock;
-
-import androidx.annotation.RequiresApi;
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
@@ -102,17 +95,10 @@
     @EnsuresNonNull("mStartedAsCold")
     private void detectStartedAsCold() {
         if (mStartedAsCold != null) return;
-        if (VERSION.SDK_INT >= VERSION_CODES.P) {
-            mStartedAsCold = isColdStartupOnP();
-            return;
-        }
-
-        // Fallback: treat recently started process as cold.
-        mStartedAsCold = (SystemClock.elapsedRealtime() - Process.getStartElapsedRealtime() < 500);
+        mStartedAsCold = isColdStartup();
     }
 
-    @RequiresApi(Build.VERSION_CODES.P)
-    private boolean isColdStartupOnP() {
+    private boolean isColdStartup() {
         @ProcessCreationReason
         int creationReason = SplitCompatAppComponentFactory.getProcessCreationReason();
         if (creationReason <= ProcessCreationReason.PENDING) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
index 177b567..475f35d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
@@ -9,35 +9,26 @@
 import android.system.Os;
 import android.system.StructStat;
 
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 
-import dalvik.system.DexFile;
-
 import org.chromium.base.BuildInfo;
 import org.chromium.base.BundleUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.shared_preferences.SharedPreferencesManager;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.base.version_info.VersionInfo;
-import org.chromium.build.BuildConfig;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.DeferredStartupHandler;
-import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
-import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 
 import java.io.File;
 import java.io.IOException;
 
 /** Performs work-arounds for Android bugs which result in invalid or unreadable dex. */
-@RequiresApi(Build.VERSION_CODES.O)
 @NullMarked
 public class DexFixer {
     private static final String TAG = "DexFixer";
-    private static boolean sHasIsolatedSplits;
 
     @WorkerThread
     public static void fixDexInBackground() {
@@ -48,10 +39,6 @@
         fixDexIfNecessary(Runtime.getRuntime());
     }
 
-    static void setHasIsolatedSplits(boolean value) {
-        sHasIsolatedSplits = value;
-    }
-
     static void scheduleDexFix() {
         if (shouldSkipDexFix()) {
             return;
@@ -127,48 +114,6 @@
     }
 
     private static @DexFixerReason int needsDexCompile(ApplicationInfo appInfo) {
-        // Android O MR1 has a bug where bg-dexopt-job will break optimized dex files for isolated
-        // splits. This leads to *very* slow startup on those devices. To mitigate this, we attempt
-        // to force a dex compile if necessary.
-        if (sHasIsolatedSplits && Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) {
-            // If the app has just been updated, it will be compiled with quicken. The next time
-            // bg-dexopt-job runs it will break the optimized dex for splits. If we force compile
-            // now, then bg-dexopt-job won't mess up the splits, and we save the user a slow
-            // startup.
-            SharedPreferencesManager prefManager = ChromeSharedPreferences.getInstance();
-            long versionCode = BuildConfig.VERSION_CODE;
-            // The default value is always lesser than any non-negative versionCode. This prevents
-            // some tests from failing when application's versionCode is stuck at 0.
-            if (prefManager.readLong(
-                            ChromePreferenceKeys.ISOLATED_SPLITS_DEX_COMPILE_VERSION,
-                            versionCode - 1)
-                    != versionCode) {
-                // Compiling the dex is an asynchronous operation anyways, so update the pref here
-                // rather than attempting to wait.
-                prefManager.writeLong(
-                        ChromePreferenceKeys.ISOLATED_SPLITS_DEX_COMPILE_VERSION, versionCode);
-                return DexFixerReason.O_MR1_AFTER_UPDATE;
-            }
-
-            // Check for corrupt dex.
-            String[] splitNames = appInfo.splitNames;
-            if (splitNames != null) {
-                for (int i = 0; i < splitNames.length; i++) {
-                    // Ignore config splits like "config.en".
-                    if (splitNames[i].contains(".")) {
-                        continue;
-                    }
-                    try {
-                        if (DexFile.isDexOptNeeded(appInfo.splitSourceDirs[i])) {
-                            return DexFixerReason.O_MR1_CORRUPTED;
-                        }
-                    } catch (IOException e) {
-                        return DexFixerReason.O_MR1_IO_EXCEPTION;
-                    }
-                }
-            }
-        }
-
         String oatPath = odexPathFromApkPath(appInfo.sourceDir);
         try {
             StructStat st = Os.stat(oatPath);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixerReason.java b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixerReason.java
index 3326eb5..bc6f04f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixerReason.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixerReason.java
@@ -11,28 +11,13 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-/** Histogram enum to monitor DexFixer. */
-@IntDef({
-    DexFixerReason.STAT_FAILED,
-    DexFixerReason.FAILED_TO_RUN,
-    DexFixerReason.NOT_NEEDED,
-    DexFixerReason.O_MR1_AFTER_UPDATE,
-    DexFixerReason.O_MR1_CORRUPTED,
-    DexFixerReason.O_MR1_IO_EXCEPTION,
-    DexFixerReason.NOT_READABLE
-})
+/** Enum to monitor DexFixer. */
+@IntDef({DexFixerReason.STAT_FAILED, DexFixerReason.NOT_NEEDED, DexFixerReason.NOT_READABLE})
 @Retention(RetentionPolicy.SOURCE)
 @NullMarked
 public @interface DexFixerReason {
-    // These values are persisted to logs. Entries should not be renumbered and
-    // numeric values should never be reused.
     int STAT_FAILED = 0;
-    int FAILED_TO_RUN = 1;
-    int NOT_NEEDED = 2;
+    int NOT_NEEDED = 1;
     // Values greater than NOT_NEEDED trigger Dexopt.
-    int O_MR1_AFTER_UPDATE = 5;
-    int O_MR1_CORRUPTED = 6;
-    int O_MR1_IO_EXCEPTION = 7;
-    int NOT_READABLE = 8;
-    int COUNT = 9;
+    int NOT_READABLE = 2;
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
index a87d0d4..8c4deac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -9,7 +9,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.SystemClock;
@@ -72,9 +71,6 @@
     @Override
     protected void attachBaseContext(Context context) {
         if (isBrowserProcess()) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                DexFixer.setHasIsolatedSplits(true);
-            }
             setImplSupplier(
                     () -> {
                         return (Impl)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerImpl.java
index a95026b..1227ff38 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerImpl.java
@@ -14,7 +14,6 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.IntentUtils;
-import org.chromium.base.ObserverList;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.Supplier;
@@ -35,7 +34,6 @@
 /** Implementation of {@link BookmarkOpener} which relies on intents. */
 @NullMarked
 public class BookmarkOpenerImpl implements BookmarkOpener {
-    private final ObserverList<BookmarkOpener.Observer> mObservers = new ObserverList<>();
     private final Supplier<BookmarkModel> mBookmarkModelSupplier;
     private final Context mContext;
     private final @Nullable ComponentName mComponentName;
@@ -56,21 +54,6 @@
     }
 
     @Override
-    public void destroy() {
-        mObservers.clear();
-    }
-
-    @Override
-    public void addObserver(Observer obs) {
-        mObservers.addObserver(obs);
-    }
-
-    @Override
-    public void removeObserver(Observer obs) {
-        mObservers.removeObserver(obs);
-    }
-
-    @Override
     public boolean openBookmarkInCurrentTab(BookmarkId id, boolean incognito) {
         if (id == null) return false;
         BookmarkItem item = mBookmarkModelSupplier.get().getBookmarkById(id);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TwaFinishHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TwaFinishHandler.java
index d3892e90..f245950 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TwaFinishHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TwaFinishHandler.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.browserservices.trustedwebactivityui;
 
 import android.app.Activity;
-import android.os.Build;
 import android.os.Bundle;
 
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
@@ -52,7 +51,7 @@
 
     private boolean finishAndRemoveTask() {
         WebApkExtras webApkExtras = mIntentDataProvider.getWebApkExtras();
-        if (webApkExtras != null && Build.VERSION.SDK_INT >= 23) {
+        if (webApkExtras != null) {
             WebApkServiceClient.getInstance().finishAndRemoveTaskSdk23(mActivity, webApkExtras);
             return true;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/SplashController.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/SplashController.java
index cc51e4f..bd129037 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/SplashController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/SplashController.java
@@ -115,9 +115,6 @@
         mIsWindowInitiallyTranslucent =
                 BaseCustomTabActivity.isWindowInitiallyTranslucent(activity);
 
-        customTabOrientationController.delayOrientationRequestsIfNeeded(
-                this, mIsWindowInitiallyTranslucent);
-
         mLifecycleDispatcher.register(this);
         mTabObserverRegistrar.registerActivityTabObserver(this);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragment.java
index dea7164..428effc5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragment.java
@@ -10,7 +10,6 @@
 import android.app.ProgressDialog;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -955,12 +954,7 @@
         if (activity == null) return;
         Vibrator v = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
         final long duration = 50;
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            v.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE));
-        } else {
-            // Deprecated in API 26.
-            v.vibrate(duration);
-        }
+        v.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE));
     }
 
     private boolean isInMultiWindowMode() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
index 879eae3..21952469 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
@@ -12,7 +12,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.view.AttachedSurfaceControl;
 import android.view.Surface;
 import android.view.View;
@@ -155,19 +154,12 @@
      * The {@link CompositorSurfaceManagerImpl} constructor creates a handler (inside the
      * SurfaceView constructor on android N and before) and thus can only be called on the UI
      * thread. If the layout is inflated on a background thread this fails, thus we only initialize
-     * the {@link CompositorSurfaceManager} in the constructor if on the UI thread (or we are
-     * running on android O+), otherwise it is initialized inside the first call to
-     * {@link #setRootView}.
+     * the {@link CompositorSurfaceManager} in the constructor if on the UI thread, otherwise it is
+     * initialized inside the first call to {@link #setRootView}.
      */
     private void initializeIfOnUiThread() {
-        if (!ThreadUtils.runningOnUiThread() && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            return;
-        }
-
         mCompositorSurfaceManager = new CompositorSurfaceManagerImpl(this, this);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            mScreenStateReceiver = new ScreenStateReceiverWorkaround();
-        }
+        mScreenStateReceiver = new ScreenStateReceiverWorkaround();
 
         // Cover the black surface before it has valid content.  Set this placeholder view to
         // visible, but don't yet make SurfaceView visible, in order to delay
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index e5f66fa3..8120dca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -19,7 +19,6 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.AttributeSet;
@@ -410,9 +409,7 @@
         }
         handleSystemUiVisibilityChange();
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            setDefaultFocusHighlightEnabled(false);
-        }
+        setDefaultFocusHighlightEnabled(false);
     }
 
     private Point getViewportSize() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/NoSystemGestureFrameLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/NoSystemGestureFrameLayout.java
index 6c62b54..6870d1a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/NoSystemGestureFrameLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/NoSystemGestureFrameLayout.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
@@ -25,10 +24,8 @@
     @SuppressWarnings("DrawAllocation")
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            setSystemGestureExclusionRects(
-                    Collections.singletonList(
-                            new Rect(0, 0, Math.abs(right - left), Math.abs(top - bottom))));
-        }
+        setSystemGestureExclusionRects(
+                Collections.singletonList(
+                        new Rect(0, 0, Math.abs(right - left), Math.abs(top - bottom))));
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index e732680b..d27eec0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -11,8 +11,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.FloatProperty;
@@ -1121,8 +1119,7 @@
 
     /** Allow / disallow system gestures on touchable areas on the strip. */
     private void updateTouchableAreas() {
-        // #setSystemGestureExclusionRects requires API Q.
-        if (VERSION.SDK_INT < VERSION_CODES.Q || !mIsLayoutOptimizationsEnabled) return;
+        if (!mIsLayoutOptimizationsEnabled) return;
 
         if ((getStripVisibilityState() & StripVisibilityState.HIDDEN_BY_FADE) != 0) {
             // Reset the system gesture exclusion rects to allow system gestures on the tab strip
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java
index 9c487d0d..16818dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.contextualsearch;
 
-import android.os.Build;
 import android.view.textclassifier.TextClassifier;
 
 import androidx.annotation.VisibleForTesting;
@@ -47,16 +46,14 @@
     /**
      * Constructs an instance that can return a {@link SelectionClient} that's a mix of an optional
      * Smart Selection client and a transient Contextual Search client.
+     *
      * @param webContents The {@link WebContents} that will show popups for this client.
      */
     SelectionClientManager(WebContents webContents) {
-        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
-            assert webContents != null;
-            mOptionalSelectionClient = SelectionClient.createSmartSelectionClient(webContents);
-            SelectionPopupController controller =
-                    SelectionPopupController.fromWebContents(webContents);
-            controller.setSelectionClient(mOptionalSelectionClient);
-        }
+        assert webContents != null;
+        mOptionalSelectionClient = SelectionClient.createSmartSelectionClient(webContents);
+        SelectionPopupController controller = SelectionPopupController.fromWebContents(webContents);
+        controller.setSelectionClient(mOptionalSelectionClient);
         mIsSmartSelectionEnabledInChrome = mOptionalSelectionClient != null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 37d47e89..9d8372a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -56,7 +56,6 @@
 import org.chromium.chrome.browser.history.HistoryManagerUtils;
 import org.chromium.chrome.browser.history.HistoryTabHelper;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
-import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.night_mode.NightModeStateProvider;
 import org.chromium.chrome.browser.page_info.ChromePageInfo;
 import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
@@ -85,15 +84,6 @@
 
     private CustomTabsOpenTimeRecorder mOpenTimeRecorder;
 
-    /**
-     * The last MotionEvent object blocked due to the activity being in paused state. We're
-     * interested in MotionEvent#ACTION_DOWN which is likely the very first event received when
-     * multi-window mode is entered. We inject this one after the activity is resumed (or it regains
-     * the focus) in order to recover the corresponding user gesture which otherwise would have gone
-     * missing.
-     */
-    private MotionEvent mBlockedEvent;
-
     private static final boolean sBlockTouchesDuringEnterAnimation =
             ChromeFeatureList.sCctBlockTouchesDuringEnterAnimation.isEnabled();
     private boolean mIsEnterAnimationCompleted;
@@ -385,7 +375,7 @@
         if (sBlockTouchesDuringEnterAnimation && !mIsEnterAnimationCompleted) {
             return true;
         }
-        if (sPreventTouches && shouldPreventTouch(ev)) {
+        if (sPreventTouches && shouldPreventTouch()) {
             // Discard the events which may be trickling down from an overlay activity above.
             return true;
         }
@@ -405,28 +395,11 @@
     }
 
     @VisibleForTesting(otherwise = PRIVATE)
-    boolean shouldPreventTouch(MotionEvent ev) {
+    boolean shouldPreventTouch() {
         if (ApplicationStatus.getStateForActivity(this) == ActivityState.RESUMED) return false;
-        mBlockedEvent = ev;
         return true;
     }
 
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus) {
-        super.onWindowFocusChanged(hasFocus);
-        // No need to do the following from Q and onward where multi-resume state is supported
-        // in split screen mode.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) return;
-
-        if (hasFocus
-                && mBlockedEvent != null
-                && MultiWindowUtils.getInstance().isInMultiWindowMode(this)) {
-            mBlockedEvent.setAction(MotionEvent.ACTION_DOWN);
-            super.dispatchTouchEvent(mBlockedEvent); // Inject the blocked event
-            mBlockedEvent = null;
-        }
-    }
-
     /**
      * Show the web page with CustomTabActivity, without any navigation control. Used in showing the
      * terms of services page or help pages for Chrome.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabOrientationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabOrientationController.java
index 9b384b5..d2ffe912 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabOrientationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabOrientationController.java
@@ -4,11 +4,7 @@
 
 package org.chromium.chrome.browser.customtabs;
 
-import android.os.Build;
-
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
-import org.chromium.chrome.browser.browserservices.ui.splashscreen.SplashController;
-import org.chromium.chrome.browser.browserservices.ui.splashscreen.SplashscreenObserver;
 import org.chromium.content_public.browser.ScreenOrientationProvider;
 import org.chromium.device.mojom.ScreenOrientationLockType;
 import org.chromium.ui.base.ActivityWindowAndroid;
@@ -28,32 +24,6 @@
         mLockScreenOrientation = intentDataProvider.getDefaultOrientation();
     }
 
-    /**
-     * Delays screen orientation requests if the activity window's initial translucency and the
-     * Android OS version requires it. Should be called: - Prior to pre inflation startup occurring.
-     * - Only if the splash screen is shown for the activity.
-     */
-    public void delayOrientationRequestsIfNeeded(
-            SplashController splashController, boolean isWindowInitiallyTranslucent) {
-        // Setting the screen orientation while the activity is translucent throws an exception on
-        // O (but not on O MR1).
-        if (!isWindowInitiallyTranslucent || Build.VERSION.SDK_INT != Build.VERSION_CODES.O) return;
-
-        ScreenOrientationProvider.getInstance().delayOrientationRequests(mActivityWindowAndroid);
-
-        splashController.addObserver(
-                new SplashscreenObserver() {
-                    @Override
-                    public void onTranslucencyRemoved() {
-                        ScreenOrientationProvider.getInstance()
-                                .runDelayedOrientationRequests(mActivityWindowAndroid);
-                    }
-
-                    @Override
-                    public void onSplashscreenHidden(long startTimestamp, long endTimestamp) {}
-                });
-    }
-
     public void setCanControlOrientation(boolean inAppMode) {
         int defaultWebOrientation =
                 inAppMode ? mLockScreenOrientation : ScreenOrientationLockType.DEFAULT;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
index 55b49b94..9298f1e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
@@ -10,7 +10,6 @@
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.os.Build;
 import android.text.TextUtils;
 
 import org.chromium.build.annotations.NullMarked;
@@ -91,10 +90,8 @@
 
             // This is a workaround for crbug/1098580. ActivityManager.TaskDescription
             // does not handle adaptive icon when passing a bitmap. So set the task icon to be null
-            // to preserve the client app's icon. Only set this flag on O+ because this does not
-            // work with old_style_webapk.
-            if (mIntentDataProvider.isWebApkActivity()
-                    && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            // to preserve the client app's icon.
+            if (mIntentDataProvider.isWebApkActivity()) {
                 mUseClientIcon = true;
             }
         }
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 1ee7532..bb4ac0a 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
@@ -12,7 +12,6 @@
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Process;
 import android.os.SystemClock;
@@ -1924,7 +1923,7 @@
         // cgroups a process is part of can be queried by reading /proc/<pid>/cgroup, which is
         // world-readable.
         String cgroupFilename = "/proc/" + pid + "/cgroup";
-        String controllerName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? "cpuset" : "cpu";
+        String controllerName = "cpuset";
         try (BufferedReader reader = new BufferedReader(new FileReader(cgroupFilename))) {
             String line = null;
             while ((line = reader.readLine()) != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.java
index 04656caf..f536945 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.graphics.Color;
-import android.os.Build;
 import android.view.Window;
 
 import androidx.annotation.Nullable;
@@ -61,17 +60,13 @@
         }
         // PCCT is deemed incapable of system dark button support due to the way it implements
         // partial height (window coordinate translation). We do the darkening ourselves.
-        boolean supportsDarkButtons =
-                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
-                        && !intentDataProvider.isPartialCustomTab();
+        boolean supportsDarkButtons = !intentDataProvider.isPartialCustomTab();
         boolean needsDarkButtons =
                 navigationBarColor != null
                         && !ColorUtils.shouldUseLightForegroundOnBackground(navigationBarColor);
 
         updateBarColor(window, navigationBarColor, supportsDarkButtons, needsDarkButtons);
 
-        // navigationBarDividerColor can only be set in Android P+
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return;
         Integer dividerColor =
                 getDividerColor(
                         context, navigationBarColor, navigationBarDividerColor, needsDarkButtons);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabVersionCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabVersionCompat.java
index 899edaa3..cca03240 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabVersionCompat.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabVersionCompat.java
@@ -316,8 +316,6 @@
         }
 
         private static int getDisplayCutoutRightInset(Display display) {
-            // TODO(crbug.com/40898784): Make this work on P.
-            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return 0;
             DisplayCutout cutout = display.getCutout();
             return cutout != null ? cutout.getSafeInsetRight() : 0;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java
index 3a3b430..865a2bc8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java
@@ -13,7 +13,6 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.provider.Browser;
@@ -312,8 +311,6 @@
         @Override
         public OMAInfo doInBackground() {
             OMAInfo omaInfo = null;
-            final DownloadManager manager =
-                    (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
             boolean isContentUri =
                     (mDownloadId == DownloadConstants.INVALID_DOWNLOAD_ID)
                             && ContentUriUtils.isContentUri(mDownloadInfo.getFilePath());
@@ -321,8 +318,6 @@
                 ParcelFileDescriptor fd = null;
                 if (isContentUri) {
                     fd = ContentUriUtils.openContentUri(mDownloadInfo.getFilePath(), "r");
-                } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
-                    fd = manager.openDownloadedFile(mDownloadId);
                 } else {
                     fd =
                             ParcelFileDescriptor.open(
@@ -1052,66 +1047,32 @@
                 String path = mDownloadInfo.getFilePath();
                 if (!TextUtils.isEmpty(path)) {
                     File fromFile = new File(path);
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                        // Copy the downloaded content to the intermediate URI and publish it.
-                        String pendingUri =
-                                DownloadCollectionBridge.createIntermediateUriForPublish(
-                                        mDownloadInfo.getFileName(),
-                                        mDownloadInfo.getMimeType(),
-                                        mDownloadInfo.getOriginalUrl().getSpec(),
-                                        mDownloadInfo.getReferrer().getSpec());
-                        success =
-                                DownloadCollectionBridge.copyFileToIntermediateUri(
-                                        path, pendingUri);
-                        if (success) {
-                            String uri = DownloadCollectionBridge.publishDownload(pendingUri);
-                            fromFile.delete();
-                            // Post a nofification to open the Android download page.
-                            mNewDownloadInfo =
-                                    DownloadInfo.Builder.fromDownloadInfo(mDownloadInfo)
-                                            .setFilePath(uri)
-                                            .setContentId(
-                                                    new ContentId("", String.valueOf(mDownloadId)))
-                                            .build();
-                        } else {
-                            DownloadCollectionBridge.deleteIntermediateUri(pendingUri);
-                        }
-                    } else {
-                        // Move the downloaded content from the app directory to public directory.
-                        String fileName = fromFile.getName();
-                        DownloadManager manager =
-                                (DownloadManager)
-                                        mContext.getSystemService(Context.DOWNLOAD_SERVICE);
-                        File toFile =
-                                new File(
-                                        Environment.getExternalStoragePublicDirectory(
-                                                Environment.DIRECTORY_DOWNLOADS),
-                                        fileName);
-                        success = fromFile.renameTo(toFile);
-                        if (success) {
-                            manager.addCompletedDownload(
-                                    fileName,
-                                    mDownloadInfo.getDescription(),
-                                    false,
+                    // Copy the downloaded content to the intermediate URI and publish it.
+                    String pendingUri =
+                            DownloadCollectionBridge.createIntermediateUriForPublish(
+                                    mDownloadInfo.getFileName(),
                                     mDownloadInfo.getMimeType(),
-                                    toFile.getPath(),
-                                    mDownloadInfo.getBytesReceived(),
-                                    true);
-                        }
+                                    mDownloadInfo.getOriginalUrl().getSpec(),
+                                    mDownloadInfo.getReferrer().getSpec());
+                    success = DownloadCollectionBridge.copyFileToIntermediateUri(path, pendingUri);
+                    if (success) {
+                        String uri = DownloadCollectionBridge.publishDownload(pendingUri);
+                        fromFile.delete();
+                        // Post a nofification to open the Android download page.
+                        mNewDownloadInfo =
+                                DownloadInfo.Builder.fromDownloadInfo(mDownloadInfo)
+                                        .setFilePath(uri)
+                                        .setContentId(
+                                                new ContentId("", String.valueOf(mDownloadId)))
+                                        .build();
+                    } else {
+                        DownloadCollectionBridge.deleteIntermediateUri(pendingUri);
                     }
                     if (!success) {
                         if (fromFile.delete()) {
-                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                                Log.w(TAG, "Failed to publish the downloaded file.");
-                            } else {
-                                Log.w(TAG, "Failed to rename the file.");
-                            }
+                            Log.w(TAG, "Failed to publish the downloaded file.");
                         } else {
-                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                                Log.w(TAG, "Failed to publish and delete the file.");
-                            } else {
-                                Log.w(TAG, "Failed to rename and delete the file.");
-                            }
+                            Log.w(TAG, "Failed to publish and delete the file.");
                         }
                     }
                 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
index c8bba54..6147194 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
@@ -7,7 +7,6 @@
 import android.app.ActivityManager;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
-import android.os.Build;
 import android.os.Process;
 import android.os.SystemClock;
 import android.text.format.DateUtils;
@@ -66,9 +65,8 @@
 
     /**
      * App standby bucket status, used for UMA reporting. Enum values correspond to the return
-     * values of {@link UsageStatsManager#getAppStandbyBucket}.
-     * These values are persisted to logs. Entries should not be renumbered and
-     * numeric values should never be reused.
+     * values of {@link UsageStatsManager#getAppStandbyBucket}. These values are persisted to logs.
+     * Entries should not be renumbered and numeric values should never be reused.
      */
     @IntDef({
         StandbyBucketStatus.ACTIVE,
@@ -76,7 +74,6 @@
         StandbyBucketStatus.FREQUENT,
         StandbyBucketStatus.RARE,
         StandbyBucketStatus.RESTRICTED,
-        StandbyBucketStatus.UNSUPPORTED,
         StandbyBucketStatus.EXEMPTED,
         StandbyBucketStatus.NEVER,
         StandbyBucketStatus.OTHER,
@@ -88,7 +85,7 @@
         int FREQUENT = 2;
         int RARE = 3;
         int RESTRICTED = 4;
-        int UNSUPPORTED = 5;
+        // Deprecated: int UNSUPPORTED = 5;
         int EXEMPTED = 6;
         int NEVER = 7;
         int OTHER = 8;
@@ -172,7 +169,6 @@
 
     /** Records various levels of background restrictions imposed by android on chrome. */
     public static void recordBackgroundRestrictions() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return;
         Context context = ContextUtils.getApplicationContext();
         ActivityManager activityManager =
                 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -205,8 +201,6 @@
     }
 
     private static @StandbyBucketStatus int getStandbyBucket(Context context) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return StandbyBucketStatus.UNSUPPORTED;
-
         UsageStatsManager usageStatsManager =
                 (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
         int standbyBucket = usageStatsManager.getAppStandbyBucket();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
index fc2b9a9..e332394 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -17,8 +17,6 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.text.Spannable;
@@ -927,7 +925,6 @@
                         && ChromeFeatureList.isEnabled(
                                 ChromeFeatureList.SHOW_WARNINGS_FOR_SUSPICIOUS_NOTIFICATIONS);
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.NOTIFICATION_ONE_TAP_UNSUBSCRIBE)
-                && VERSION.SDK_INT >= VERSION_CODES.P
                 && identifyingAttributes.notificationType == NotificationType.WEB_PERSISTENT
                 && !skipUAButtons
                 && !shouldTreatNotificationAsSuspicious) {
@@ -1039,10 +1036,6 @@
             return Promise.fulfilled(true);
         }
 
-        if (!UsageStatsService.isEnabled()) {
-            return Promise.fulfilled(false);
-        }
-
         // Only native calls into this here code, so the native process must be running, which is
         // important if we end up lazily constructing `UsageStatsService` here, which uses JNI.
         assert BrowserStartupController.getInstance().isFullBrowserStarted();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java
index b0bccd2..18e7f00 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java
@@ -9,7 +9,6 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Environment;
 import android.provider.MediaStore.MediaColumns;
 import android.text.format.DateUtils;
@@ -144,8 +143,6 @@
     @VisibleForTesting
     public static @JniType("std::string") String publishArchiveToDownloadsCollection(
             OfflinePageItem page) {
-        assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
-
         final String isPending = "is_pending"; // MediaStore.IS_PENDING
 
         // Collect all fields for creating intermediate URI.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
index 68ce90d..2b2626f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
@@ -8,7 +8,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Settings;
@@ -258,30 +257,22 @@
         setManagedPreferenceDelegateForPreference(PREF_PASSWORDS);
         setManagedPreferenceDelegateForPreference(PREF_SEARCH_ENGINE);
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            // If we are on Android O+ the Notifications preference should lead to the Android
-            // Settings notifications page.
-            Intent intent = new Intent();
-            intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
-            intent.putExtra(
-                    Settings.EXTRA_APP_PACKAGE,
-                    ContextUtils.getApplicationContext().getPackageName());
-            PackageManager pm = getActivity().getPackageManager();
-            if (intent.resolveActivity(pm) != null) {
-                Preference notifications = findPreference(PREF_NOTIFICATIONS);
-                notifications.setOnPreferenceClickListener(
-                        preference -> {
-                            startActivity(intent);
-                            // We handle the click so the default action isn't triggered.
-                            return true;
-                        });
-            } else {
-                removePreferenceIfPresent(PREF_NOTIFICATIONS);
-            }
+        // The Notifications preference should lead to the Android Settings notifications page.
+        Intent intent = new Intent();
+        intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
+        intent.putExtra(
+                Settings.EXTRA_APP_PACKAGE, ContextUtils.getApplicationContext().getPackageName());
+        PackageManager pm = getActivity().getPackageManager();
+        if (intent.resolveActivity(pm) != null) {
+            Preference notifications = findPreference(PREF_NOTIFICATIONS);
+            notifications.setOnPreferenceClickListener(
+                    preference -> {
+                        startActivity(intent);
+                        // We handle the click so the default action isn't triggered.
+                        return true;
+                    });
         } else {
-            // The per-website notification settings page can be accessed from Site
-            // Settings, so we don't need to show this here.
-            getPreferenceScreen().removePreference(findPreference(PREF_NOTIFICATIONS));
+            removePreferenceIfPresent(PREF_NOTIFICATIONS);
         }
 
         TemplateUrlService templateUrlService =
@@ -458,9 +449,7 @@
     }
 
     private void updateAutofillPreferences() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
-                && ChromeFeatureList.isEnabled(
-                        AutofillFeatures.AUTOFILL_VIRTUAL_VIEW_STRUCTURE_ANDROID)) {
+        if (ChromeFeatureList.isEnabled(AutofillFeatures.AUTOFILL_VIRTUAL_VIEW_STRUCTURE_ANDROID)) {
             addPreferenceIfAbsent(PREF_AUTOFILL_SECTION);
             addPreferenceIfAbsent(PREF_AUTOFILL_OPTIONS);
             Preference preference = findPreference(PREF_AUTOFILL_OPTIONS);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
index e1d5a64..6888791 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
@@ -23,7 +23,6 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.device.DeviceConditions;
 import org.chromium.chrome.browser.notifications.NotificationConstants;
 import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
 import org.chromium.chrome.browser.sharing.SharingNotificationUtil;
@@ -84,26 +83,11 @@
         }
     }
 
-    /** Handles the device unlock event to remove notification and just show dialer. */
-    public static final class PhoneUnlockedReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // We only try to remove the notifications if we have opened the dialer.
-            if (intent != null
-                    && Intent.ACTION_USER_PRESENT.equals(intent.getAction())
-                    && shouldOpenDialer()) {
-                SharingNotificationUtil.dismissNotification(
-                        NotificationConstants.GROUP_CLICK_TO_CALL,
-                        NotificationConstants.NOTIFICATION_ID_CLICK_TO_CALL);
-            }
-        }
-    }
-
     /**
      * Displays a notification that opens the dialer when clicked.
      *
      * @param phoneNumber The phone number to show in the dialer when the user taps the
-     *                    notification.
+     *     notification.
      */
     private static void displayNotification(String phoneNumber) {
         Context context = ContextUtils.getApplicationContext();
@@ -153,35 +137,6 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
-    /** Returns true if we should open the dialer straight away. */
-    private static boolean shouldOpenDialer() {
-        // On Android Q and above, we never open the dialer directly.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            return false;
-        }
-
-        // On Android N and below, we always open the dialer. If device is locked, we also show a
-        // notification. We can listen to ACTION_USER_PRESENT and remove this notification when
-        // device is unlocked.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            return true;
-        }
-
-        // On Android O and P, we open dialer only when device is unlocked since we cannot listen to
-        // ACTION_USER_PRESENT.
-        return DeviceConditions.isCurrentlyScreenOnAndUnlocked(
-                ContextUtils.getApplicationContext());
-    }
-
-    /** Returns true if we should show notification to the user. */
-    private static boolean shouldShowNotification() {
-        // Always show the notification for Android Q and above. For pre-Q, only show notification
-        // if device is locked.
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
-                || !DeviceConditions.isCurrentlyScreenOnAndUnlocked(
-                        ContextUtils.getApplicationContext());
-    }
-
     /**
      * Handles a phone number sent from another device.
      *
@@ -190,12 +145,6 @@
     @CalledByNative
     @VisibleForTesting
     static void handleMessage(@JniType("std::string") String phoneNumber) {
-        if (shouldOpenDialer()) {
-            openDialer(phoneNumber);
-        }
-
-        if (shouldShowNotification()) {
-            displayNotification(phoneNumber);
-        }
+        displayNotification(phoneNumber);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java
index 5426080..d23a3a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java
@@ -10,7 +10,6 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Color;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.view.View;
@@ -367,13 +366,11 @@
         if (DialogWhenLargeContentLayout.shouldShowAsDialog(this)) {
             // Set status bar and navigation bar to dark if the promo is shown as a dialog.
             setStatusBarColor(Color.BLACK);
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-                // Use dark navigation bar.
-                Window window = getWindow();
-                window.setNavigationBarColor(Color.BLACK);
-                window.setNavigationBarDividerColor(Color.BLACK);
-                UiUtils.setNavigationBarIconColor(window.getDecorView().getRootView(), false);
-            }
+            // Use dark navigation bar.
+            Window window = getWindow();
+            window.setNavigationBarColor(Color.BLACK);
+            window.setNavigationBarDividerColor(Color.BLACK);
+            UiUtils.setNavigationBarIconColor(window.getDecorView().getRootView(), false);
         } else {
             // Set the status bar color to the fullsceen sign-in background color.
             setStatusBarColor(SemanticColorUtils.getDefaultBgColor(this));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
index d61d73f..6cbdad7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
@@ -11,7 +11,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
-import android.os.Build;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.text.format.Formatter;
@@ -255,9 +254,7 @@
                         @Override
                         public void onClick(DialogInterface dialog, int id) {
                             SearchActivityPreferencesManager.resetCachedValues();
-                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                                SiteChannelsManager.getInstance().deleteAllSiteChannels();
-                            }
+                            SiteChannelsManager.getInstance().deleteAllSiteChannels();
                             activityManager.clearApplicationUserData();
                         }
                     });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
index a8214dbd..ab1d5b55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
@@ -10,7 +10,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorStateListDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.view.LayoutInflater;
 import android.view.View;
 
@@ -246,13 +245,10 @@
                                 .inflate(mTileLayoutResId, parent, false);
 
         tileView.initialize(tile, mTitleLinesCount);
-        // TODO(crbug.com/403353768): Unify tile background.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            tileView.setBackground(
-                    new ColorStateListDrawable(
-                            AppCompatResources.getColorStateList(
-                                    parent.getContext(), R.color.tile_bg_color_list)));
-        }
+        tileView.setBackground(
+                new ColorStateListDrawable(
+                        AppCompatResources.getColorStateList(
+                                parent.getContext(), R.color.tile_bg_color_list)));
 
         if (!mNativeInitializationComplete || setupDelegate == null) {
             return tileView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java
index c049b08..282d0e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/GoogleServicesSettings.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.sync.settings;
 
-import android.os.Build;
 import android.os.Bundle;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -257,8 +256,7 @@
                     PriceTrackingUtilities.isTrackPricesOnTabsEnabled(getProfile()));
         }
         if (mUsageStatsReporting != null) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
-                    && mPrefService.getBoolean(Pref.USAGE_STATS_ENABLED)) {
+            if (mPrefService.getBoolean(Pref.USAGE_STATS_ENABLED)) {
                 mUsageStatsReporting.setOnPreferenceClickListener(
                         preference -> {
                             UsageStatsConsentDialog.create(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index d0d89bb..734117d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -2278,15 +2278,13 @@
             return;
         }
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            ComponentName componentName =
-                    AutofillManagerWrapper.getAutofillServiceComponentName(manager);
-            if (componentName != null) {
-                RecordHistogram.recordEnumeratedHistogram(
-                        UMA_AUTOFILL_THIRD_PARTY_MODE_DISABLED_PROVIDER,
-                        AutofillProviderUMA.getCurrentProvider(componentName.getPackageName()),
-                        AutofillProviderUMA.Provider.MAX_VALUE);
-            }
+        ComponentName componentName =
+                AutofillManagerWrapper.getAutofillServiceComponentName(manager);
+        if (componentName != null) {
+            RecordHistogram.recordEnumeratedHistogram(
+                    UMA_AUTOFILL_THIRD_PARTY_MODE_DISABLED_PROVIDER,
+                    AutofillProviderUMA.getCurrentProvider(componentName.getPackageName()),
+                    AutofillProviderUMA.Provider.MAX_VALUE);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
index e2bca94..b0599dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
@@ -11,13 +11,11 @@
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Color;
-import android.os.Build;
 import android.view.Window;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
@@ -60,7 +58,6 @@
 import java.util.Optional;
 
 /** Controls the bottom system navigation bar color for the provided {@link Window}. */
-@RequiresApi(Build.VERSION_CODES.O_MR1)
 class TabbedNavigationBarColorController
         implements BottomAttachedUiObserver.Observer, NavigationBarColorProvider {
     /** The amount of time transitioning from one color to another should take in ms. */
@@ -191,8 +188,6 @@
             @NonNull ObservableSupplier<Integer> overviewColorSupplier,
             @NonNull EdgeToEdgeSystemBarColorHelper edgeToEdgeSystemBarColorHelper,
             @Nullable BottomAttachedUiObserver bottomAttachedUiObserver) {
-        assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1;
-
         mContext = context;
         mFullScreenManager = fullscreenManager;
         mEdgeToEdgeSystemBarColorHelper = edgeToEdgeSystemBarColorHelper;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index 3bba62c..aa55e84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -1787,7 +1787,6 @@
         }
 
         if (mBookmarkOpener != null) {
-            mBookmarkOpener.destroy();
             mBookmarkOpener = null;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
index ebad192..d1a1c5a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.usage_stats;
 
 import android.app.Activity;
-import android.os.Build;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -51,19 +50,13 @@
     private DigitalWellbeingClient mClient;
     private boolean mOptInState;
 
-    /** Returns if the UsageStatsService is enabled on this device */
-    public static boolean isEnabled() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
-    }
-
     /** Return the {@link UsageStatsService} for the given {@link Profile}. */
     public static UsageStatsService getForProfile(Profile profile) {
-        assert isEnabled();
         return sProfileMap.getForProfile(profile, UsageStatsService::new);
     }
 
     /**
-     * Creates a UsageStatsService for the given Activity if the feature is enabled.
+     * Creates a UsageStatsService for the given Activity.
      *
      * @param activity The activity in which page view events are occurring.
      * @param profile The {@link Profile} associated with the activity.
@@ -75,8 +68,6 @@
             Profile profile,
             ActivityTabProvider activityTabProvider,
             Supplier<TabContentManager> tabContentManagerSupplier) {
-        if (!isEnabled()) return;
-
         getForProfile(profile)
                 .createPageViewObserver(activity, activityTabProvider, tabContentManagerSupplier);
     }
@@ -90,9 +81,7 @@
         mTokenTracker = new TokenTracker(mBridge);
         mPageViewObservers = new ArrayList<>();
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            mClient = ServiceLoaderUtil.maybeCreate(DigitalWellbeingClient.class);
-        }
+        mClient = ServiceLoaderUtil.maybeCreate(DigitalWellbeingClient.class);
         if (mClient == null) {
             mClient = new DigitalWellbeingClient();
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
index 337c349..591e73d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
@@ -7,10 +7,8 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.net.Uri;
-import android.os.Build;
 import android.provider.MediaStore;
 
-import androidx.annotation.RequiresApi;
 import androidx.core.content.ContextCompat;
 import androidx.test.filters.MediumTest;
 
@@ -136,7 +134,6 @@
 
     /** Tests that clicks on <input type="file" /> trigger intent calls to ActivityWindowAndroid. */
     @Test
-    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     @MediumTest
     @Feature({"TextInput", "Main"})
     @DisabledTest(message = "https://crbug.com/724163")
@@ -197,9 +194,7 @@
                                     Intent.EXTRA_INTENT);
             Assert.assertNotNull(contentIntent);
             Assert.assertFalse(contentIntent.hasCategory(Intent.CATEGORY_OPENABLE));
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-                Assert.assertTrue(contentIntent.hasExtra(Intent.EXTRA_ALLOW_MULTIPLE));
-            }
+            Assert.assertTrue(contentIntent.hasExtra(Intent.EXTRA_ALLOW_MULTIPLE));
             resetActivityWindowAndroidForTest();
         }
 
@@ -221,7 +216,6 @@
     /** Tests that content URI resolving to local app dir is checked correctly. */
     @Test
     @MediumTest
-    @RequiresApi(Build.VERSION_CODES.O)
     public void testIsContentUriUnderAppDir() throws Throwable {
         File dataDir = ContextCompat.getDataDir(ContextUtils.getApplicationContext());
         File childDir = new File(dataDir, "android");
@@ -231,8 +225,7 @@
         TestContentProvider.resetResourceRequestCounts(ContextUtils.getApplicationContext());
         TestContentProvider.setDataFilePath(
                 ContextUtils.getApplicationContext(), dataDir.getPath());
-        Assert.assertEquals(
-                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O,
+        Assert.assertTrue(
                 SelectFileDialog.isContentUriUnderAppDir(
                         Uri.parse(TestContentProvider.createContentUrl(temp.getName())),
                         ContextUtils.getApplicationContext()));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java
index e5b202b..7742da2c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java
@@ -7,7 +7,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -148,11 +147,7 @@
 
     @After
     public void tearDown() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-            mHandlerThread.quitSafely();
-        } else {
-            mHandlerThread.quit();
-        }
+        mHandlerThread.quitSafely();
     }
 
     // Implements Handler.Callback
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java
index fdd6657..6755ce7b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java
@@ -28,7 +28,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.os.Build;
 import android.text.Spanned;
 import android.text.style.ClickableSpan;
 import android.view.View;
@@ -153,13 +152,11 @@
         // There can be some left-over notification channels from other tests.
         // TODO(crbug.com/41452182): Find a general solution to avoid leaking channels between
         // tests.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            ThreadUtils.runOnUiThreadBlocking(
-                    () -> {
-                        SiteChannelsManager manager = SiteChannelsManager.getInstance();
-                        manager.deleteAllSiteChannels();
-                    });
-        }
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    SiteChannelsManager manager = SiteChannelsManager.getInstance();
+                    manager.deleteAllSiteChannels();
+                });
     }
 
     /** Waits for the progress dialog to disappear from the given CBD preference. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
index 2073338..2f0e67a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 
 import androidx.browser.customtabs.CustomTabsSessionToken;
 import androidx.test.core.app.ApplicationProvider;
@@ -32,7 +31,6 @@
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.HistogramWatcher;
-import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.browser.LauncherShortcutActivity;
 import org.chromium.chrome.browser.base.ColdStartTracker;
 import org.chromium.chrome.browser.browserservices.intents.SessionHolder;
@@ -270,14 +268,9 @@
         waitForHistogram(ntpColdStartWatcher);
     }
 
-    /**
-     * Tests warm start metric for main icon launches recorded correctly. Minimum SDK Level is P+
-     * due to how ColdStartTracker determines a cold start. The mechanism is time-based prior to P
-     * and is therefore less robust.
-     */
+    /** Tests warm start metric for main icon launches recorded correctly. */
     @Test
     @LargeTest
-    @MinAndroidSdkLevel(Build.VERSION_CODES.P)
     public void testWarmStartMainIntentTimeToFirstDrawRecordedCorrectly() throws Exception {
         // No records made for main intent cold starts.
         HistogramWatcher mainIntentTimeToFirstDrawWatcher =
@@ -410,12 +403,6 @@
                             BinderCallsListener listener = BinderCallsListener.getInstance();
                             return listener.installListener();
                         });
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
-            // THe API was added in Android 10, but don't skip tests in earlier
-            // releases to check we don't cause crashes there.
-            Assert.assertFalse(success);
-            return;
-        }
         Assert.assertTrue(success);
 
         HistogramWatcher ntpBinderWatcher =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index c36d318..939b337f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -42,7 +42,6 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
-import android.os.Build;
 import android.os.Bundle;
 import android.text.format.DateUtils;
 import android.view.Gravity;
@@ -597,13 +596,11 @@
         // TODO(crbug.com/41452182): Find a general solution to avoid leaking channels
         // between
         // tests.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            ThreadUtils.runOnUiThreadBlocking(
-                    () -> {
-                        SiteChannelsManager manager = SiteChannelsManager.getInstance();
-                        manager.deleteAllSiteChannels();
-                    });
-        }
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    SiteChannelsManager manager = SiteChannelsManager.getInstance();
+                    manager.deleteAllSiteChannels();
+                });
 
         setThirdPartyCookieBlocking(CookieControlsMode.INCOGNITO_ONLY);
         clearPermissions();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
index e7f1ec0d..3c47c1a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
@@ -34,7 +34,6 @@
 
 import android.app.Activity;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Looper;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -301,17 +300,8 @@
 
         // Assert for "Basics" section
         assertSettingsExists(MainSettings.PREF_SEARCH_ENGINE, SearchEngineSettings.class);
-        if (supportThirdPartyFillingSetting()) {
-            assertSettingsExists(MainSettings.PREF_AUTOFILL_OPTIONS, null);
-            assertSettingsExists(MainSettings.PREF_AUTOFILL_SECTION, null);
-        } else {
-            Assert.assertNull(
-                    "Third party filling setting should be hidden",
-                    mMainSettings.findPreference(MainSettings.PREF_AUTOFILL_OPTIONS));
-            Assert.assertNull(
-                    "Autofill section header should be hidden",
-                    mMainSettings.findPreference(MainSettings.PREF_AUTOFILL_SECTION));
-        }
+        assertSettingsExists(MainSettings.PREF_AUTOFILL_OPTIONS, null);
+        assertSettingsExists(MainSettings.PREF_AUTOFILL_SECTION, null);
         assertSettingsExists(MainSettings.PREF_PASSWORDS, PasswordSettings.class);
         assertSettingsExists("autofill_payment_methods", AutofillPaymentMethodsFragment.class);
         assertSettingsExists("autofill_addresses", AutofillProfilesFragment.class);
@@ -1069,15 +1059,10 @@
     }
 
     private boolean supportNotificationSettings() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false;
         return PackageManagerUtils.canResolveActivity(
                 new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS));
     }
 
-    private boolean supportThirdPartyFillingSetting() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
-    }
-
     private void testNewPreferenceLabel(
             @NonNull Class prefFragmentClass,
             @NonNull String prefKey,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java
index 5ef62567..28e79dd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java
@@ -18,8 +18,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.when;
 
-import android.os.Build;
-
 import androidx.test.filters.SmallTest;
 
 import org.junit.Assert;
@@ -39,7 +37,6 @@
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -107,21 +104,15 @@
     public void testExceptionToggleShowing(
             @ContentSettingsType.EnumType int contentSettingsType,
             @ContentSettingValues int contentSettingValue) {
-        // Preference for Notification on O+ is added as a ChromeImageViewPreference. See
+        // Preference should be added as a ChromeImageViewPreference. See
         // SingleWebsiteSettings#setUpNotificationsPreference
-        Assume.assumeFalse(
-                "Preference for Notification is not a toggle on Android N-.",
-                contentSettingsType == ContentSettingsType.NOTIFICATIONS
-                        && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O);
+        Assume.assumeFalse(contentSettingsType == ContentSettingsType.NOTIFICATIONS);
 
         new SingleExceptionTestCase(contentSettingsType, contentSettingValue).run();
     }
 
     @Test
     @SmallTest
-    @DisableIf.Build(
-            sdk_is_less_than = Build.VERSION_CODES.O,
-            message = "Notification does not have a toggle when disabled.")
     public void testNotificationException() {
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSingleWebsitePreferences(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
index 94626aab..2b8951a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
@@ -46,7 +46,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Bundle;
 import android.view.View;
 
@@ -2396,20 +2395,8 @@
         ChromeFeatureList.PERMISSION_SITE_SETTING_RADIO_BUTTON
     })
     public void testOnlyExpectedPreferencesNotificationsWithToggle() {
-        String[] notifications_enabled;
-        String[] notifications_disabled;
-        // The "notifications_vibrate" option has been removed in Android O but is present in
-        // earlier versions.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            notifications_enabled =
-                    new String[] {
-                        "binary_toggle", "notifications_quiet_ui", "notifications_vibrate"
-                    };
-            notifications_disabled = new String[] {"binary_toggle", "notifications_vibrate"};
-        } else {
-            notifications_enabled = new String[] {"binary_toggle", "notifications_quiet_ui"};
-            notifications_disabled = BINARY_TOGGLE;
-        }
+        String[] notifications_enabled = new String[] {"binary_toggle", "notifications_quiet_ui"};
+        String[] notifications_disabled = BINARY_TOGGLE;
 
         testExpectedPreferences(
                 SiteSettingsCategory.Type.NOTIFICATIONS,
@@ -2426,25 +2413,9 @@
     })
     @DisableFeatures(ChromeFeatureList.PERMISSION_DEDICATED_CPSS_SETTING_ANDROID)
     public void testOnlyExpectedPreferencesNotifications() {
-        String[] notifications_enabled;
-        String[] notifications_disabled;
-        // The "notifications_vibrate" option has been removed in Android O but is present in
-        // earlier versions.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            notifications_enabled =
-                    new String[] {
-                        "info_text",
-                        "binary_radio_button",
-                        "notifications_quiet_ui",
-                        "notifications_vibrate"
-                    };
-            notifications_disabled =
-                    new String[] {"info_text", "binary_radio_button", "notifications_vibrate"};
-        } else {
-            notifications_enabled =
-                    new String[] {"info_text", "binary_radio_button", "notifications_quiet_ui"};
-            notifications_disabled = BINARY_RADIO_BUTTON_AND_INFO_TEXT;
-        }
+        String[] notifications_enabled =
+                new String[] {"info_text", "binary_radio_button", "notifications_quiet_ui"};
+        String[] notifications_disabled = BINARY_RADIO_BUTTON_AND_INFO_TEXT;
 
         testExpectedPreferences(
                 SiteSettingsCategory.Type.NOTIFICATIONS,
@@ -3677,9 +3648,6 @@
     @Test
     @SmallTest
     @Feature({"Preferences"})
-    @DisableIf.Build(
-            message = "Flaky, see crbug.com/1170671",
-            sdk_is_less_than = Build.VERSION_CODES.Q)
     // Auto does not have actions to handle ACTION_CHANNEL_NOTIFICATION_SETTINGS
     @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
     public void testEmbargoedNotificationSiteSettings() throws Exception {
@@ -3734,7 +3702,6 @@
     @Feature({"Preferences"})
     @DisabledTest(message = "https://crbug.com/1094934")
     public void testEmbargoedNotificationCategorySiteSettings() throws Exception {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
         final String urlToEmbargo =
                 mPermissionRule.getURLWithHostName(
                         "example.com", "/chrome/test/data/notifications/notification_tester.html");
@@ -3847,10 +3814,6 @@
     @Test
     @MediumTest
     @Feature({"Preferences"})
-    @DisableIf.Build(
-            message = "https://crbug.com/1414569",
-            sdk_is_greater_than = Build.VERSION_CODES.N_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.P)
     public void testProtectedContentDefaultOption() throws Exception {
         initializeUpdateWaiter(/* expectGranted= */ true);
         mPermissionRule.runNoPromptTest(
@@ -3865,10 +3828,6 @@
     @Test
     @MediumTest
     @Feature({"Preferences"})
-    @DisableIf.Build(
-            message = "https://crbug.com/1414569",
-            sdk_is_greater_than = Build.VERSION_CODES.N_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.P)
     public void testProtectedContentAskAllow() throws Exception {
         setGlobalTriStateToggleForCategory(
                 SiteSettingsCategory.Type.PROTECTED_MEDIA, ContentSettingValues.ASK);
@@ -3886,10 +3845,6 @@
     @Test
     @MediumTest
     @Feature({"Preferences"})
-    @DisableIf.Build(
-            message = "https://crbug.com/1414569",
-            sdk_is_greater_than = Build.VERSION_CODES.N_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.P)
     public void testProtectedContentAskBlocked() throws Exception {
         setGlobalTriStateToggleForCategory(
                 SiteSettingsCategory.Type.PROTECTED_MEDIA, ContentSettingValues.ASK);
@@ -3907,10 +3862,6 @@
     @Test
     @MediumTest
     @Feature({"Preferences"})
-    @DisableIf.Build(
-            message = "https://crbug.com/1414569",
-            sdk_is_greater_than = Build.VERSION_CODES.N_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.P)
     public void testProtectedContentBlocked() throws Exception {
         setGlobalTriStateToggleForCategory(
                 SiteSettingsCategory.Type.PROTECTED_MEDIA, ContentSettingValues.BLOCK);
@@ -3928,10 +3879,7 @@
     @Test
     @MediumTest
     @Feature({"Preferences"})
-    @DisableIf.Build(
-            message = "https://crbug.com/1269556,https://crbug.com/1414569",
-            sdk_is_greater_than = Build.VERSION_CODES.N_MR1)
-    @DisableIf.Device(DeviceFormFactor.ONLY_TABLET) // https://crbug.com/1234530
+    @DisabledTest(message = "https://crbug.com/1269556,https://crbug.com/1414569,crbug.com/1234530")
     public void testProtectedContentAllowThenBlock() throws Exception {
         initializeUpdateWaiter(/* expectGranted= */ true);
         mPermissionRule.runNoPromptTest(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSanityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSanityTest.java
index 0c679ed..a0a75b6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSanityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSanityTest.java
@@ -5,9 +5,6 @@
 package org.chromium.chrome.browser.vr;
 
 import static org.chromium.chrome.browser.vr.WebXrArTestFramework.PAGE_LOAD_TIMEOUT_S;
-import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_SHORT_MS;
-
-import android.os.Build;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.MediumTest;
@@ -42,9 +39,6 @@
     "enable-features=WebXRIncubations,LogJsConsoleMessages"
 })
 public class WebXrArSanityTest {
-    public static final boolean ENABLE_CAMERA_ACCESS =
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
-
     @ClassParameter
     private static final List<ParameterSet> sClassParams =
             ArTestRuleUtils.generateDefaultTestRuleParameters();
@@ -76,13 +70,7 @@
         mWebXrArTestFramework.loadFileAndAwaitInitialization(
                 "webxr_test_basic_all_ar_features", PAGE_LOAD_TIMEOUT_S);
 
-        if (!ENABLE_CAMERA_ACCESS) {
-            mWebXrArTestFramework.runJavaScriptOrFail(
-                    "disableCameraAccess()", POLL_TIMEOUT_SHORT_MS);
-        }
-
-        mWebXrArTestFramework.enterSessionWithUserGestureOrFail(
-                /* needsCameraPermission= */ ENABLE_CAMERA_ACCESS);
+        mWebXrArTestFramework.enterSessionWithUserGestureOrFail(/* needsCameraPermission= */ true);
 
         // The recording is 12 seconds long, let's tell the test to run for 10 seconds and wait for
         // a bit more than that before timing out.
@@ -101,13 +89,7 @@
         mWebXrArTestFramework.loadFileAndAwaitInitialization(
                 "webxr_test_basic_all_ar_features", PAGE_LOAD_TIMEOUT_S);
 
-        if (!ENABLE_CAMERA_ACCESS) {
-            mWebXrArTestFramework.runJavaScriptOrFail(
-                    "disableCameraAccess()", POLL_TIMEOUT_SHORT_MS);
-        }
-
-        mWebXrArTestFramework.enterSessionWithUserGestureOrFail(
-                /* needsCameraPermission= */ ENABLE_CAMERA_ACCESS);
+        mWebXrArTestFramework.enterSessionWithUserGestureOrFail(/* needsCameraPermission= */ true);
 
         // The recording is 37 seconds long, let's tell the test to run for 30 seconds and wait for
         // a bit more than that before timing out.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java
index f3c014d..65b9922 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java
@@ -997,12 +997,6 @@
     @Test
     @SmallTest
     public void testInternalAuthenticatorMakeCredential_attestationIncluded() {
-        // This test can't work on Android N because it lacks the java.nio.file
-        // APIs used to load the test data.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            return;
-        }
-
         mIntentSender.setNextResultIntent(
                 Fido2ApiTestHelper.createSuccessfulMakeCredentialIntentWithAttestation());
 
@@ -1025,12 +1019,6 @@
     @SmallTest
     public void testInternalAuthenticatorMakeCredential_rkRequired_attestationKept()
             throws Exception {
-        // This test can't work on Android N because it lacks the java.nio.file
-        // APIs used to load the test data.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            return;
-        }
-
         mIntentSender.setNextResultIntent(
                 Fido2ApiTestHelper.createSuccessfulMakeCredentialIntentWithAttestation());
 
@@ -1058,12 +1046,6 @@
     @SmallTest
     public void testInternalAuthenticatorMakeCredential_rkPreferred_attestationKept()
             throws Exception {
-        // This test can't work on Android N because it lacks the java.nio.file
-        // APIs used to load the test data.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            return;
-        }
-
         mIntentSender.setNextResultIntent(
                 Fido2ApiTestHelper.createSuccessfulMakeCredentialIntentWithAttestation());
 
@@ -1090,12 +1072,6 @@
     @Test
     @SmallTest
     public void testInternalAuthenticatorMakeCredential_credprops() throws Exception {
-        // This test can't work on Android N because it lacks the java.nio.file
-        // APIs used to load the test data.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            return;
-        }
-
         mIntentSender.setNextResultIntent(
                 Fido2ApiTestHelper.createSuccessfulMakeCredentialIntentWithCredProps());
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/base/DexFixerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/base/DexFixerTest.java
index c769ba83..f5326a8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/base/DexFixerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/base/DexFixerTest.java
@@ -13,7 +13,6 @@
 import android.system.Os;
 import android.system.StructStat;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -31,9 +30,6 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.build.BuildConfig;
-import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
-import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 
 import java.io.IOException;
 
@@ -65,11 +61,6 @@
         ShadowOs.sWorldReadable = true;
     }
 
-    @After
-    public void tearDown() {
-        DexFixer.setHasIsolatedSplits(false);
-    }
-
     private void verifyDexOpt() {
         try {
             verify(mMockRuntime)
@@ -98,12 +89,7 @@
     public void testFixDexIfNecessary_notReadableWithSplits() {
         ApplicationInfo appInfo = ContextUtils.getApplicationContext().getApplicationInfo();
         appInfo.splitNames = new String[] {"ignored.en"};
-        DexFixer.setHasIsolatedSplits(true);
         ShadowOs.sWorldReadable = false;
-        ChromeSharedPreferences.getInstance()
-                .writeLong(
-                        ChromePreferenceKeys.ISOLATED_SPLITS_DEX_COMPILE_VERSION,
-                        BuildConfig.VERSION_CODE);
 
         @DexFixerReason int reason = DexFixer.fixDexIfNecessary(mMockRuntime);
         assertThat(reason).isEqualTo(DexFixerReason.NOT_READABLE);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabsFilterTouchUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabsFilterTouchUnitTest.java
index cbbe699..40876c5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabsFilterTouchUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabsFilterTouchUnitTest.java
@@ -7,8 +7,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.view.MotionEvent;
-
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.filters.SmallTest;
 
@@ -16,7 +14,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
@@ -44,8 +41,6 @@
     public ActivityScenarioRule<CustomTabActivity> mActivityScenarioRule =
             new ActivityScenarioRule<>(CustomTabActivity.class);
 
-    @Mock private MotionEvent mMotionEvent;
-
     private CustomTabActivity mActivity;
 
     @Before
@@ -57,8 +52,8 @@
     @SmallTest
     public void testShouldPreventTouch() {
         ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
-        assertFalse("Events should be accepted.", mActivity.shouldPreventTouch(mMotionEvent));
+        assertFalse("Events should be accepted.", mActivity.shouldPreventTouch());
         ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED);
-        assertTrue("Events should be discarded.", mActivity.shouldPreventTouch(mMotionEvent));
+        assertTrue("Events should be discarded.", mActivity.shouldPreventTouch());
     }
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 337c4899..30bdd36f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -17269,12 +17269,6 @@
       <message name="IDS_WEBAUTHN_PASSKEY_PHONE_TABLET_OR_SECURITY_KEY_LABEL" desc="The label on a button-like element in a list of options. Clicking this causes Chrome to show a QR code that the user can scan with their phone to use that phone for signing into a website. Here 'phone' is used as a short hand for smartphone. Users can also insert and tap their security key on the QR code screen.">
         Use a phone, tablet, or security key
       </message>
-      <message name="IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_OR_TABLET_LABEL" desc="The label on a button-like element in a list of options. Clicking this causes Chrome to show a QR code that the user can scan with their phone to use that phone for signing into a website. Here 'phone' is used as a short hand for smartphone. This string is used when a specific phone is also an option in the list, so the word 'different' is intended to communicate that this is the correct option when none of the previously list phones are correct.">
-        Use a different phone or tablet
-      </message>
-      <message name="IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_TABLET_OR_SECURITY_KEY_LABEL" desc="The label on a button-like element in a list of options. Clicking this causes Chrome to show a QR code that the user can scan with their phone to use that phone for signing into a website. Here 'phone' is used as a short hand for smartphone. This string is used when a specific phone is also an option in the list, so the word 'different' is intended to communicate that this is the correct option when none of the previously list phones are correct. Users can also insert and tap their security key on the QR code screen.">
-        Use a different phone, tablet, or security key
-      </message>
       <message name="IDS_WEBAUTHN_PHONE_CONFIRMATION_TITLE" desc="The title of a dialog shown when a user can use a passkey from a phone or tablet they have already paired with Chrome to sign in to a website. Refer to Glossary for the meaning of 'passkey'; do not translate it as 'password'.">
         Use a passkey from <ph name="DEVICE_NAME">$1<ex>Ted's Pixel 6 Pro</ex></ph> to sign in to <ph name="WEBSITE">$2<ex>accounts.google.com</ex></ph>
       </message>
@@ -17481,9 +17475,6 @@
       <message name="IDS_WEBAUTHN_SOURCE_USB_SECURITY_KEY" desc="The subtitle shown in a button that lets the user select a passkey to sign in, indicating that the passkey resides in a USB security key.">
         USB security key
       </message>
-      <message name="IDS_WEBAUTHN_SOURCE_PHONE" desc="The subtitle shown in a button that lets the user select a passkey to sign in, indicating that the passkey resides in their phone.">
-        From "<ph name="PHONE_NAME">$1<ex>Pixel 7</ex></ph>"
-      </message>
       <message name="IDS_WEBAUTHN_PASSKEYS_AND_SECURITY_KEYS" desc="The title of a dialog prompting the user to create or use a passkey on their phones by scanning a QR code or on a security key. Refer to Glossary for the meaning of 'passkey'; do not translate it as 'password'">
         Passkeys &amp; Security Keys
       </message>
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_OR_TABLET_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_OR_TABLET_LABEL.png.sha1
deleted file mode 100644
index 4dd84dc..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_OR_TABLET_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-25dc4f9b83a9c40b7cc2b757992c68170a302bbe
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_TABLET_OR_SECURITY_KEY_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_TABLET_OR_SECURITY_KEY_LABEL.png.sha1
deleted file mode 100644
index edf1678..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_TABLET_OR_SECURITY_KEY_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-51c7866eeeb65257b23929bfa809f9e9b19d4856
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAUTHN_SOURCE_PHONE.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAUTHN_SOURCE_PHONE.png.sha1
deleted file mode 100644
index edf1678..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAUTHN_SOURCE_PHONE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-51c7866eeeb65257b23929bfa809f9e9b19d4856
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 708198e..92c8251 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -4143,27 +4143,6 @@
   <message name="IDS_SETTINGS_SECURITY_KEYS_FORCE_PIN_CHANGE" desc="An error message shown when a user attempts to use a security key (an authentication hardware device) that has a default PIN (short, often numeric codes that are often used with, for example, ATM cards) set. Before using the key, the user needs to change the PIN to a new code.">
     To use your new security key, set a new PIN
   </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_PHONE_EDIT_DIALOG_TITLE" desc="The title of a dialog that is shown when a user chooses to edit details of a phone that can be used to sign-in with.">
-    Edit phone
-  </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_PHONES_YOUR_DEVICES" desc="The title of a section on a settings page that lists phoens that are signed into (and syncing with) the user's Google account.">
-    Your devices
-  </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_PHONES_SYNCED_DESC" desc="The description of a section on a settings page that lists phoens that are signed into (and syncing with) the user's Google account.">
-    You're signed in to Chrome on these devices, so you can use them as security keys.
-  </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DEVICES" desc="The title of a section on a settings page that lists phoens that can be used for signing into websites. The word 'linked' was picked to be distinct from 'paired', as in 'Bluetooth pairing'. The technology does use Bluetooth, but is distinct from Bluetooth pairing.">
-    Linked devices
-  </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DESC" desc="The description of a section on a settings page that lists phoens that can be used for signing into websites. The word 'linked' was picked to be distinct from 'paired', as in 'Bluetooth pairing'. The technology does use Bluetooth, but is distinct from Bluetooth pairing.">
-    You linked these devices by scanning a QR code.
-  </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE" desc="The title of an option in Chrome's privacy settings for managing phones that can be used to sign into websites.">
-    Manage phones
-  </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE_DESC" desc="The description of an option in Chrome's privacy settings for managing phones that can be used for signing into websites. A 'security key' is typically a USB peripherial used to secure sign-ins. In this case a phone can be used as a security key.">
-    Control which phones you use as security keys
-  </message>
   <message name="IDS_SETTINGS_EXTENSION_OR_APP_DISPLAY_NAME" desc="The title of a page containing site settings for an extension or Isolated Web App (IWA). The display name contains a human-readable extension/IWA name followed by the extension/IWA ID.">
     <ph name="EXTENSION_OR_APP_NAME">$1<ex>Google Docs Offline</ex></ph> (ID: <ph name="EXTENSION_OR_APP_ID">$2<ex>ghbmnnjooekpmoecnnnilnnbdlolhkhi</ex></ph>)
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DESC.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DESC.png.sha1
deleted file mode 100644
index 7586e20..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-88717c95c919939d125d3291f842fc8a20b2ba86
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DEVICES.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DEVICES.png.sha1
deleted file mode 100644
index 9a290bf..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DEVICES.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-4ba7d88d7a28d6b4b80c324ac91db3b8c0b50359
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE.png.sha1
deleted file mode 100644
index 5be65d00..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0528714568ba075ed0ac24586a17944c1558343c
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE_DESC.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE_DESC.png.sha1
deleted file mode 100644
index 5be65d00..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0528714568ba075ed0ac24586a17944c1558343c
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_SYNCED_DESC.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_SYNCED_DESC.png.sha1
deleted file mode 100644
index 7586e20..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_SYNCED_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-88717c95c919939d125d3291f842fc8a20b2ba86
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_YOUR_DEVICES.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_YOUR_DEVICES.png.sha1
deleted file mode 100644
index 9a290bf..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONES_YOUR_DEVICES.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-4ba7d88d7a28d6b4b80c324ac91db3b8c0b50359
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONE_EDIT_DIALOG_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONE_EDIT_DIALOG_TITLE.png.sha1
deleted file mode 100644
index 9ab2c7f7..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SECURITY_KEYS_PHONE_EDIT_DIALOG_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c9c685033d4de64016f512ece926d5a14cae0a7d
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0238bfaf..028209ef 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1266,6 +1266,7 @@
     {"intent_picker", "true"},
     {"file_system_access", "true"},
     {"zoom", "true"},
+    {"pwa_install", "true"},
 };
 const FeatureEntry::FeatureVariation kPageActionsMigrationVariations[] = {
     {"with all migrated page actions enabled", kPageActionsMigrationParams,
@@ -13006,13 +13007,19 @@
 #if BUILDFLAG(IS_ANDROID)
     {"supervised-user-interstitial-without-approvals",
      flag_descriptions::kSupervisedUserInterstitialWithoutApprovalsName,
-     flag_descriptions::
-         kSupervisedUserInterstitialWithoutApprovalsDescription,
+     flag_descriptions::kSupervisedUserInterstitialWithoutApprovalsDescription,
      kOsAndroid,
      FEATURE_VALUE_TYPE(
          supervised_user::kSupervisedUserInterstitialWithoutApprovals)},
 #endif  // BUILDFLAG(IS_ANDROID)
 
+#if !BUILDFLAG(IS_ANDROID)
+    {"enable-ntp-browser-promos",
+     flag_descriptions::kEnableNtpBrowserPromosName,
+     flag_descriptions::kEnableNtpBrowserPromosDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(user_education::features::kEnableNtpBrowserPromos)},
+#endif
+
     // Add new entries above this line.
 
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
diff --git a/chrome/browser/actor/actor_test_util.cc b/chrome/browser/actor/actor_test_util.cc
index de924ff9..868603f 100644
--- a/chrome/browser/actor/actor_test_util.cc
+++ b/chrome/browser/actor/actor_test_util.cc
@@ -58,6 +58,17 @@
   return action;
 }
 
+BrowserAction MakeClick(const gfx::Point& click_point) {
+  BrowserAction action;
+  ClickAction* click = action.add_actions()->mutable_click();
+  Coordinate* coordinate = click->mutable_target()->mutable_coordinate();
+  coordinate->set_x(click_point.x());
+  coordinate->set_y(click_point.y());
+  click->set_click_type(ClickAction::LEFT);
+  click->set_click_count(ClickAction::SINGLE);
+  return action;
+}
+
 BrowserAction MakeHistoryBack() {
   BrowserAction action;
   action.add_actions()->mutable_back();
diff --git a/chrome/browser/actor/actor_test_util.h b/chrome/browser/actor/actor_test_util.h
index 8a45ef46..916c368 100644
--- a/chrome/browser/actor/actor_test_util.h
+++ b/chrome/browser/actor/actor_test_util.h
@@ -22,6 +22,8 @@
     content::RenderFrameHost& rfh,
     int content_node_id);
 optimization_guide::proto::BrowserAction MakeClick(
+    const gfx::Point& click_point);
+optimization_guide::proto::BrowserAction MakeClick(
     content::RenderFrameHost& rfh,
     const gfx::Point& click_point);
 optimization_guide::proto::BrowserAction MakeHistoryBack();
diff --git a/chrome/browser/actor/browser_action_util.cc b/chrome/browser/actor/browser_action_util.cc
index 2d461e1..fec656e4 100644
--- a/chrome/browser/actor/browser_action_util.cc
+++ b/chrome/browser/actor/browser_action_util.cc
@@ -7,16 +7,21 @@
 #include "chrome/common/actor/actor_logging.h"
 #include "components/optimization_guide/content/browser/page_content_proto_provider.h"
 #include "components/optimization_guide/proto/features/actions_data.pb.h"
+#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
+#include "ui/gfx/geometry/point_f.h"
 
 namespace actor {
 
 using ::content::RenderFrameHost;
+using ::content::RenderWidgetHost;
 using ::content::WebContents;
 using ::optimization_guide::DocumentIdentifierUserData;
 using ::optimization_guide::proto::Action;
 using ::optimization_guide::proto::ActionTarget;
+using ::optimization_guide::proto::DocumentIdentifier;
 
 namespace {
 
@@ -47,6 +52,20 @@
   }
 }
 
+// Finds the local root of a given RenderFrameHost. The local root is the
+// highest ancestor in the frame tree that shares the same RenderWidgetHost.
+RenderFrameHost* GetLocalRoot(RenderFrameHost* rfh) {
+  RenderFrameHost* local_root = rfh;
+  while (local_root && local_root->GetParent()) {
+    if (local_root->GetRenderWidgetHost() !=
+        local_root->GetParent()->GetRenderWidgetHost()) {
+      break;
+    }
+    local_root = local_root->GetParent();
+  }
+  return local_root;
+}
+
 }  // namespace
 
 const ActionTarget* ExtractTarget(const Action& action) {
@@ -97,41 +116,89 @@
   }
 }
 
-RenderFrameHost* FindTargetFrame(WebContents& web_contents,
-                                 const Action& action) {
+RenderFrameHost* GetRenderFrameForDocumentIdentifier(
+    content::WebContents& web_contents,
+    std::string_view target_document_token) {
+  RenderFrameHost* render_frame = nullptr;
+  web_contents.ForEachRenderFrameHostWithAction([&target_document_token,
+                                                 &render_frame](
+                                                    RenderFrameHost* rfh) {
+    // Skip inactive frame and its children.
+    if (!rfh->IsActive()) {
+      return RenderFrameHost::FrameIterationAction::kSkipChildren;
+    }
+    auto* user_data = DocumentIdentifierUserData::GetForCurrentDocument(rfh);
+    if (user_data && user_data->serialized_token() == target_document_token) {
+      render_frame = rfh;
+      return RenderFrameHost::FrameIterationAction::kStop;
+    }
+    return RenderFrameHost::FrameIterationAction::kContinue;
+  });
+  return render_frame;
+}
+
+RenderFrameHost* GetRootFrameForWidget(content::WebContents& web_contents,
+                                       RenderWidgetHost* rwh) {
+  RenderFrameHost* root_frame = nullptr;
+  web_contents.ForEachRenderFrameHostWithAction([rwh, &root_frame](
+                                                    RenderFrameHost* rfh) {
+    if (!rfh->IsActive()) {
+      return RenderFrameHost::FrameIterationAction::kSkipChildren;
+    }
+    // A frame is a local root if it has no parent or if its parent belongs
+    // to a different widget. We are looking for the local root frame
+    // associated with the target widget.
+    if (rfh->GetRenderWidgetHost() == rwh &&
+        (!rfh->GetParent() || rfh->GetParent()->GetRenderWidgetHost() != rwh)) {
+      root_frame = rfh;
+      return RenderFrameHost::FrameIterationAction::kStop;
+    }
+    return RenderFrameHost::FrameIterationAction::kContinue;
+  });
+  return root_frame;
+}
+
+RenderFrameHost* FindTargetLocalRootFrame(WebContents& web_contents,
+                                          const Action& action) {
+  // If the action targets the tab as a whole, the target is the primary main
+  // frame.
   if (IsTargetingTab(action)) {
     return web_contents.GetPrimaryMainFrame();
   }
 
   const ActionTarget* target = ExtractTarget(action);
-
-  if (target) {
-    const std::string& serialized_token =
-        target->document_identifier().serialized_token();
-
-    RenderFrameHost* target_frame = nullptr;
-    web_contents.ForEachRenderFrameHostWithAction(
-        [&serialized_token, &target_frame](RenderFrameHost* rfh) {
-          auto* user_data =
-              DocumentIdentifierUserData::GetForCurrentDocument(rfh);
-          if (user_data && user_data->serialized_token() == serialized_token) {
-            // If the frame is inactive it shouldn't be targeted for tool use.
-            if (rfh->IsActive()) {
-              target_frame = rfh;
-            }
-            return RenderFrameHost::FrameIterationAction::kStop;
-          }
-          return RenderFrameHost::FrameIterationAction::kContinue;
-        });
-    return target_frame;
-  } else if (action.action_case() == Action::kScroll) {
-    // A scroll action may not have a target, which indicates scrolling the
-    // main frame.
-    return web_contents.GetPrimaryMainFrame();
-  } else {
+  if (!target) {
+    // A scroll action may not have a target, which indicates scrolling the main
+    // frame.
+    if (action.action_case() == Action::kScroll) {
+      return web_contents.GetPrimaryMainFrame();
+    }
     ACTOR_LOG() << "Page-level BrowserAction did not specify an ActionTarget.";
     return nullptr;
   }
+
+  if (target->has_content_node_id()) {
+    const std::string& serialized_token =
+        target->document_identifier().serialized_token();
+
+    RenderFrameHost* target_frame =
+        GetRenderFrameForDocumentIdentifier(web_contents, serialized_token);
+    // After finding the target frame, walk up to its local root.
+    return GetLocalRoot(target_frame);
+  }
+
+  if (target->has_coordinate()) {
+    const gfx::PointF target_point =
+        gfx::PointF(target->coordinate().x(), target->coordinate().y());
+    RenderWidgetHost* target_rwh = web_contents.FindWidgetAtPoint(target_point);
+    if (!target_rwh) {
+      return nullptr;
+    }
+    return GetRootFrameForWidget(web_contents, target_rwh);
+  }
+
+  ACTOR_LOG() << "Page-level BrowserAction ActionTarget is invalid.";
+  return nullptr;
 }
 
 }  // namespace actor
diff --git a/chrome/browser/actor/browser_action_util.h b/chrome/browser/actor/browser_action_util.h
index 16ae15b7..ada981d 100644
--- a/chrome/browser/actor/browser_action_util.h
+++ b/chrome/browser/actor/browser_action_util.h
@@ -5,14 +5,18 @@
 #ifndef CHROME_BROWSER_ACTOR_BROWSER_ACTION_UTIL_H_
 #define CHROME_BROWSER_ACTOR_BROWSER_ACTION_UTIL_H_
 
+#include <string_view>
+
 namespace content {
 class RenderFrameHost;
+class RenderWidgetHost;
 class WebContents;
 }  // namespace content
 
 namespace optimization_guide::proto {
 class Action;
 class ActionTarget;
+class DocumentIdentifier;
 }  // namespace optimization_guide::proto
 
 namespace actor {
@@ -23,11 +27,26 @@
 const optimization_guide::proto::ActionTarget* ExtractTarget(
     const optimization_guide::proto::Action& action);
 
-// Finds the specific frame in the given WebContents that's requested by the
+// Iterates through the frame tree to find the active RenderFrameHost associated
+// with a given DocumentIdentifier.
+content::RenderFrameHost* GetRenderFrameForDocumentIdentifier(
+    content::WebContents& web_contents,
+    const std::string_view target_document_token);
+
+// Iterates through the frame tree to find the local root RenderFrameHost
+// associated with a given RenderWidgetHost. A local root is a frame that is
+// the highest in its frame subtree to be associated with the widget.
+content::RenderFrameHost* GetRootFrameForWidget(
+    content::WebContents& web_contents,
+    content::RenderWidgetHost* rwh);
+
+// Finds local root frame in the given WebContents that's requested by the
 // given action. For a tab-targeting action, this returns the current primary
-// main frame. For frame-targeting actions, this returns null if the frame is no
-// longer active or has a new document since the action was generated.
-content::RenderFrameHost* FindTargetFrame(
+// main frame. For frame-targeting actions, this returns a nullptr if the
+// frame is no longer active or has a new document since the action was
+// generated. Otherwise it returns the local root RenderFrameHost that contains
+// the target node or coordinate.
+content::RenderFrameHost* FindTargetLocalRootFrame(
     content::WebContents& web_contents,
     const optimization_guide::proto::Action& action);
 
diff --git a/chrome/browser/actor/execution_engine.cc b/chrome/browser/actor/execution_engine.cc
index 599caf6..deadb22 100644
--- a/chrome/browser/actor/execution_engine.cc
+++ b/chrome/browser/actor/execution_engine.cc
@@ -27,7 +27,9 @@
 #include "chrome/common/actor/action_result.h"
 #include "chrome/common/chrome_features.h"
 #include "components/optimization_guide/content/browser/page_content_proto_provider.h"
+#include "components/optimization_guide/content/browser/page_content_proto_util.h"
 #include "components/optimization_guide/proto/features/actions_data.pb.h"
+#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -181,6 +183,51 @@
       FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
 }
 
+// Perform validation based on APC and document identifier for coordinate based
+// target to compare the candidate frame with the target frame identified in
+// last observation.
+bool ValidateTargetFrameCandidate(
+    const ActionTarget* target,
+    RenderFrameHost* candidate_frame,
+    WebContents& web_contents,
+    AnnotatedPageContent* last_observed_page_content) {
+  std::string target_document_token;
+  // The document identifier in the action itself takes highest precedence.
+  if (target->has_document_identifier()) {
+    target_document_token = target->document_identifier().serialized_token();
+  } else if (last_observed_page_content) {
+    // Otherwise, fall back to APC hit testing.
+    // TODO(crbug.com/426021822): FindNodeAtPoint does not handle corner cases
+    // like clip paths. Need more checks to ensure we don't drop actions
+    // unnecessarily.
+    std::optional<optimization_guide::TargetNodeInfo> target_node_info =
+        optimization_guide::FindNodeAtPoint(*last_observed_page_content,
+                                            target->coordinate());
+    if (target_node_info) {
+      target_document_token =
+          target_node_info->document_identifier.serialized_token();
+    } else {
+      return false;
+    }
+  } else {
+    // An error if document identifier isn't set on target and no cached APC
+    // available
+    return false;
+  }
+
+  RenderFrameHost* apc_target_frame =
+      GetRenderFrameForDocumentIdentifier(web_contents, target_document_token);
+
+  // Only return the candidate if its RenderWidgetHost matches the target
+  // and it's also a local root frame(i.e. has no parent or parent has
+  // a different RenderWidgetHost)
+  if (apc_target_frame && apc_target_frame->GetRenderWidgetHost() ==
+                              candidate_frame->GetRenderWidgetHost()) {
+    return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 ExecutionEngine::ExecutionEngine(Profile* profile)
@@ -399,12 +446,12 @@
                                "The tab is no longer present."));
     return;
   }
-
-  RenderFrameHost* target_frame = nullptr;
+  RenderFrameHost* target_frame_candidate = nullptr;
   if (ActionRequiresFrame(action)) {
-    target_frame = FindTargetFrame(*tab->GetContents(), action);
+    target_frame_candidate =
+        FindTargetLocalRootFrame(*tab->GetContents(), action);
 
-    if (!target_frame) {
+    if (!target_frame_candidate) {
       journal_->Log(LastCommittedURLOfCurrentTask(), task_->id(), "Act Failed",
                     "The target frame is no longer present in the tab.");
       CompleteActions(
@@ -412,10 +459,24 @@
                      "The target frame is no longer present in the tab."));
       return;
     }
-  }
 
+    const ActionTarget* target = ExtractTarget(action);
+
+    // Perform validation for coordinate based target only.
+    if (target && target->has_coordinate() &&
+        !ValidateTargetFrameCandidate(target, target_frame_candidate,
+                                      *tab->GetContents(),
+                                      last_observed_page_content_.get())) {
+      journal_->Log(LastCommittedURLOfCurrentTask(), task_->id(), "Act Failed",
+                    "The target frame has changed.");
+      CompleteActions(MakeResult(
+          mojom::ActionResultCode::kFrameLocationChangedSinceObservation,
+          "The target frame has changed."));
+      return;
+    }
+  }
   tool_controller_.Invoke(
-      action, *journal_, task_->id(), tab, target_frame,
+      action, *journal_, task_->id(), tab, target_frame_candidate,
       base::BindOnce(&ExecutionEngine::FinishOneAction, GetWeakPtr()));
 }
 
diff --git a/chrome/browser/actor/tools/tool_controller.cc b/chrome/browser/actor/tools/tool_controller.cc
index c1e520a..534dd51c 100644
--- a/chrome/browser/actor/tools/tool_controller.cc
+++ b/chrome/browser/actor/tools/tool_controller.cc
@@ -78,6 +78,7 @@
     case Action::kMoveMouse:
     case Action::kDragAndRelease:
     case Action::kSelect: {
+      CHECK(frame);
       // PageTools are all implemented in the renderer so share the PageTool
       // implementation to shuttle them there.
       return std::make_unique<PageTool>(journal, *frame, action);
diff --git a/chrome/browser/actor/tools/tools_browsertest.cc b/chrome/browser/actor/tools/tools_browsertest.cc
index 24444cc..ff064f2d6 100644
--- a/chrome/browser/actor/tools/tools_browsertest.cc
+++ b/chrome/browser/actor/tools/tools_browsertest.cc
@@ -2325,9 +2325,12 @@
   WeakDocumentPtr first_rfh = main_frame()->GetWeakDocumentPtr();
   ASSERT_TRUE(first_rfh.AsRenderFrameHostIfValid()->IsActive());
 
+  std::optional<int> body_id = GetDOMNodeId(*main_frame(), "body");
+  ASSERT_TRUE(body_id);
+
   // Create an action that targets the first document.
   BrowserAction action =
-      MakeClick(*first_rfh.AsRenderFrameHostIfValid(), gfx::Point(10, 10));
+      MakeClick(*first_rfh.AsRenderFrameHostIfValid(), body_id.value());
 
   // Navigate to the second document - we expect this should put the first
   // document into the BFCache rather than destroying the RenderFrameHost.
diff --git a/chrome/browser/ai/ai_rewriter.cc b/chrome/browser/ai/ai_rewriter.cc
index f85c07f4..be7401e9 100644
--- a/chrome/browser/ai/ai_rewriter.cc
+++ b/chrome/browser/ai/ai_rewriter.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ai/ai_rewriter.h"
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/ai/ai_context_bound_object.h"
 #include "chrome/browser/ai/ai_utils.h"
diff --git a/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc b/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc
index d9eb28b3..7aba10b 100644
--- a/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc
+++ b/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/android/dom_distiller/distiller_ui_handle_android.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace dom_distiller {
 
diff --git a/chrome/browser/android/metrics/android_session_durations_service.cc b/chrome/browser/android/metrics/android_session_durations_service.cc
index 4bd669c6..c63d50e 100644
--- a/chrome/browser/android/metrics/android_session_durations_service.cc
+++ b/chrome/browser/android/metrics/android_session_durations_service.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/android/metrics/android_session_durations_service.h"
 
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "chrome/browser/android/metrics/android_session_durations_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/android/service_tab_launcher.cc b/chrome/browser/android/service_tab_launcher.cc
index 4bc976fb..3edad5c 100644
--- a/chrome/browser/android/service_tab_launcher.cc
+++ b/chrome/browser/android/service_tab_launcher.cc
@@ -8,6 +8,7 @@
 
 #include "base/android/jni_string.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 441a2567..e295072b 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -17,6 +17,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/slim/layer.h"
 #include "chrome/browser/android/background_tab_manager.h"
diff --git a/chrome/browser/apps/app_service/publishers/app_publisher.cc b/chrome/browser/apps/app_service/publishers/app_publisher.cc
index a0b3b2e3..3d96bf67 100644
--- a/chrome/browser/apps/app_service/publishers/app_publisher.cc
+++ b/chrome/browser/apps/app_service/publishers/app_publisher.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/apps/app_service/publishers/app_publisher.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "components/services/app_service/public/cpp/capability_access.h"
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.cc b/chrome/browser/ash/accessibility/accessibility_manager.cc
index 201d084..06bda66 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager.cc
+++ b/chrome/browser/ash/accessibility/accessibility_manager.cc
@@ -36,6 +36,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/chrome/browser/ash/app_list/chrome_app_list_item.cc b/chrome/browser/ash/app_list/chrome_app_list_item.cc
index 09b6010..bbe5828 100644
--- a/chrome/browser/ash/app_list/chrome_app_list_item.cc
+++ b/chrome/browser/ash/app_list/chrome_app_list_item.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "ash/public/cpp/app_list/app_list_types.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/ash/app_list/app_list_client_impl.h"
 #include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h"
diff --git a/chrome/browser/ash/app_list/test/test_app_list_controller.cc b/chrome/browser/ash/app_list/test/test_app_list_controller.cc
index 6f654ff..a5074646 100644
--- a/chrome/browser/ash/app_list/test/test_app_list_controller.cc
+++ b/chrome/browser/ash/app_list/test/test_app_list_controller.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/app_list/test/test_app_list_controller.h"
 
 #include "ash/public/cpp/app_list/app_list_controller_observer.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/app_list/app_list_client_impl.h"
 #include "chrome/browser/ash/app_list/app_list_model_updater.h"
 
diff --git a/chrome/browser/ash/app_mode/load_profile.cc b/chrome/browser/ash/app_mode/load_profile.cc
index 382b54d..b7c0410 100644
--- a/chrome/browser/ash/app_mode/load_profile.cc
+++ b/chrome/browser/ash/app_mode/load_profile.cc
@@ -17,6 +17,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/sequence_checker.h"
 #include "base/syslog_logging.h"
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
index 02ea01e..da1893a 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/app_restore/arc_ghost_window_delegate.h"
 
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.h"
 #include "chrome/browser/ash/app_restore/arc_window_utils.h"
diff --git a/chrome/browser/ash/arc/fileapi/arc_content_file_system_async_file_util.cc b/chrome/browser/ash/arc/fileapi/arc_content_file_system_async_file_util.cc
index fcb41953..8be7a0bb 100644
--- a/chrome/browser/ash/arc/fileapi/arc_content_file_system_async_file_util.cc
+++ b/chrome/browser/ash/arc/fileapi/arc_content_file_system_async_file_util.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_size_util.h"
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_url_util.h"
diff --git a/chrome/browser/ash/arc/fileapi/arc_content_file_system_backend_delegate.cc b/chrome/browser/ash/arc/fileapi/arc_content_file_system_backend_delegate.cc
index 12a442ca..7fd6e57 100644
--- a/chrome/browser/ash/arc/fileapi/arc_content_file_system_backend_delegate.cc
+++ b/chrome/browser/ash/arc/fileapi/arc_content_file_system_backend_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_backend_delegate.h"
 
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_async_file_util.h"
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_file_stream_reader.h"
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_url_util.h"
diff --git a/chrome/browser/ash/arc/fileapi/arc_documents_provider_async_file_util.cc b/chrome/browser/ash/arc/fileapi/arc_documents_provider_async_file_util.cc
index 8687600f..adc588f 100644
--- a/chrome/browser/ash/arc/fileapi/arc_documents_provider_async_file_util.cc
+++ b/chrome/browser/ash/arc/fileapi/arc_documents_provider_async_file_util.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/files/safe_base_name.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_size_util.h"
 #include "chrome/browser/ash/arc/fileapi/arc_documents_provider_file_system_url_util.h"
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_move.cc b/chrome/browser/ash/arc/input_overlay/actions/action_move.cc
index db9bad7..48e501d0 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action_move.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_move.cc
@@ -15,6 +15,7 @@
 
 #include "base/check_op.h"
 #include "base/containers/contains.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ash/arc/input_overlay/actions/action.h"
 #include "chrome/browser/ash/arc/input_overlay/touch_id_manager.h"
diff --git a/chrome/browser/ash/arc/input_overlay/actions/input_element.cc b/chrome/browser/ash/arc/input_overlay/actions/input_element.cc
index 9afed57..49972d0 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/input_element.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/input_element.cc
@@ -8,7 +8,7 @@
 #include <iterator>
 
 #include "base/containers/contains.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/arc/input_overlay/util.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/dom/dom_code.h"
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_label.cc b/chrome/browser/ash/arc/input_overlay/ui/action_label.cc
index 07d288c..cc12e4ba 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/action_label.cc
+++ b/chrome/browser/ash/arc/input_overlay/ui/action_label.cc
@@ -12,6 +12,7 @@
 #include <set>
 
 #include "ash/style/style_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ash/arc/input_overlay/actions/action.h"
diff --git a/chrome/browser/ash/child_accounts/child_user_service.cc b/chrome/browser/ash/child_accounts/child_user_service.cc
index b0228f4..0414f74 100644
--- a/chrome/browser/ash/child_accounts/child_user_service.cc
+++ b/chrome/browser/ash/child_accounts/child_user_service.cc
@@ -7,6 +7,7 @@
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/time/time.h"
 #include "base/values.h"
diff --git a/chrome/browser/ash/crosapi/login_ash.cc b/chrome/browser/ash/crosapi/login_ash.cc
index 9623205..ec23138a 100644
--- a/chrome/browser/ash/crosapi/login_ash.cc
+++ b/chrome/browser/ash/crosapi/login_ash.cc
@@ -6,6 +6,7 @@
 
 #include <optional>
 
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/login/existing_user_controller.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/ash/crostini/ansible/ansible_management_service.cc b/chrome/browser/ash/crostini/ansible/ansible_management_service.cc
index 68b1613..224dedf 100644
--- a/chrome/browser/ash/crostini/ansible/ansible_management_service.cc
+++ b/chrome/browser/ash/crostini/ansible/ansible_management_service.cc
@@ -10,6 +10,7 @@
 #include "base/check_op.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/ash/crostini/crostini_pref_names.h"
diff --git a/chrome/browser/ash/drive/fileapi/drivefs_file_system_backend_delegate.cc b/chrome/browser/ash/drive/fileapi/drivefs_file_system_backend_delegate.cc
index 8d19d4b4..c864308 100644
--- a/chrome/browser/ash/drive/fileapi/drivefs_file_system_backend_delegate.cc
+++ b/chrome/browser/ash/drive/fileapi/drivefs_file_system_backend_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/drive/fileapi/drivefs_file_system_backend_delegate.h"
 
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/drive/fileapi/drivefs_async_file_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "storage/browser/file_system/async_file_util.h"
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_misc.cc b/chrome/browser/ash/extensions/file_manager/private_api_misc.cc
index 05682e9..23558c2 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_misc.cc
@@ -21,6 +21,7 @@
 #include "base/functional/bind.h"
 #include "base/i18n/time_formatting.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/ash/file_system_provider/fileapi/provider_async_file_util.cc b/chrome/browser/ash/file_system_provider/fileapi/provider_async_file_util.cc
index 7857ce1..2f1a2c4e 100644
--- a/chrome/browser/ash/file_system_provider/fileapi/provider_async_file_util.cc
+++ b/chrome/browser/ash/file_system_provider/fileapi/provider_async_file_util.cc
@@ -15,7 +15,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/file_system_provider/mount_path_util.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
 #include "chrome/browser/ash/fileapi/fallback_copy_in_foreign_file.h"
diff --git a/chrome/browser/ash/fusebox/fusebox_server.cc b/chrome/browser/ash/fusebox/fusebox_server.cc
index 22e976c3..ad419a98 100644
--- a/chrome/browser/ash/fusebox/fusebox_server.cc
+++ b/chrome/browser/ash/fusebox/fusebox_server.cc
@@ -14,6 +14,7 @@
 #include "base/files/file_util.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/escape.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/ash/login/ash_hud_login_browsertest.cc b/chrome/browser/ash/login/ash_hud_login_browsertest.cc
index 88b7808..dfb431f 100644
--- a/chrome/browser/ash/login/ash_hud_login_browsertest.cc
+++ b/chrome/browser/ash/login/ash_hud_login_browsertest.cc
@@ -15,6 +15,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ref.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
diff --git a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc
index ad12617..ce446f7 100644
--- a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc
+++ b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc
@@ -13,7 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/no_destructor.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 #include "chrome/browser/ash/login/oobe_quick_start/connectivity/account_transfer_client_data.h"
 #include "chrome/browser/ash/login/oobe_quick_start/connectivity/fido_assertion_info.h"
diff --git a/chrome/browser/ash/login/osauth/profile_prefs_auth_policy_connector.cc b/chrome/browser/ash/login/osauth/profile_prefs_auth_policy_connector.cc
index 348186e5..1b0af2a 100644
--- a/chrome/browser/ash/login/osauth/profile_prefs_auth_policy_connector.cc
+++ b/chrome/browser/ash/login/osauth/profile_prefs_auth_policy_connector.cc
@@ -7,7 +7,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "base/containers/contains.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ash/login/quickstart_controller.cc b/chrome/browser/ash/login/quickstart_controller.cc
index b081ca0..5978b3cd 100644
--- a/chrome/browser/ash/login/quickstart_controller.cc
+++ b/chrome/browser/ash/login/quickstart_controller.cc
@@ -13,6 +13,7 @@
 #include "base/check.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h"
 #include "chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker.h"
diff --git a/chrome/browser/ash/login/screens/arc_vm_data_migration_screen.cc b/chrome/browser/ash/login/screens/arc_vm_data_migration_screen.cc
index 1c8376d..216835f 100644
--- a/chrome/browser/ash/login/screens/arc_vm_data_migration_screen.cc
+++ b/chrome/browser/ash/login/screens/arc_vm_data_migration_screen.cc
@@ -10,6 +10,7 @@
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/ash/login/screens/base_screen.cc b/chrome/browser/ash/login/screens/base_screen.cc
index 586f9bbf..3ee94e5 100644
--- a/chrome/browser/ash/login/screens/base_screen.cc
+++ b/chrome/browser/ash/login/screens/base_screen.cc
@@ -8,6 +8,7 @@
 #include "base/check_op.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/values.h"
 #include "chrome/browser/ash/login/wizard_context.h"
diff --git a/chrome/browser/ash/login/test/profile_prepared_waiter.cc b/chrome/browser/ash/login/test/profile_prepared_waiter.cc
index 92c8b90..ee0157d 100644
--- a/chrome/browser/ash/login/test/profile_prepared_waiter.cc
+++ b/chrome/browser/ash/login/test/profile_prepared_waiter.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/login/test/profile_prepared_waiter.h"
 
 #include "base/check_op.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/login/existing_user_controller.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 
diff --git a/chrome/browser/ash/login/users/default_user_image/default_user_images.cc b/chrome/browser/ash/login/users/default_user_image/default_user_images.cc
index 7d0839d6..a1753e55 100644
--- a/chrome/browser/ash/login/users/default_user_image/default_user_images.cc
+++ b/chrome/browser/ash/login/users/default_user_image/default_user_images.cc
@@ -18,6 +18,7 @@
 #include "ash/public/cpp/default_user_image.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index b6c18bf..304b6c3 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -26,6 +26,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/syslog_logging.h"
@@ -51,10 +52,6 @@
 #include "chrome/browser/ash/login/oobe_screen.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
 #include "chrome/browser/ash/login/quickstart_controller.h"
-#include "chromeos/ash/experiences/arc/arc_features.h"
-#include "chromeos/ash/experiences/arc/arc_prefs.h"
-#include "chromeos/ash/experiences/arc/arc_util.h"
-#include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"
 // Make sure to include new screen to all relevant metric enums.
 // LINT.IfChange(UsageMetrics)
 #include "chrome/browser/ash/login/screens/account_selection_screen.h"
@@ -256,6 +253,10 @@
 #include "chromeos/ash/components/settings/timezone_settings.h"
 #include "chromeos/ash/components/timezone/timezone_provider.h"
 #include "chromeos/ash/components/timezone/timezone_request.h"
+#include "chromeos/ash/experiences/arc/arc_features.h"
+#include "chromeos/ash/experiences/arc/arc_prefs.h"
+#include "chromeos/ash/experiences/arc/arc_util.h"
+#include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"
 #include "chromeos/ash/services/cros_healthd/private/cpp/dlc_utils.h"
 #include "chromeos/ash/services/rollback_network_config/public/mojom/rollback_network_config.mojom.h"
 #include "components/prefs/pref_registry_simple.h"
diff --git a/chrome/browser/ash/nearby/nearby_dependencies_provider.cc b/chrome/browser/ash/nearby/nearby_dependencies_provider.cc
index a9744e79..222f1295 100644
--- a/chrome/browser/ash/nearby/nearby_dependencies_provider.cc
+++ b/chrome/browser/ash/nearby/nearby_dependencies_provider.cc
@@ -11,6 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/singleton.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ash/nearby/bluetooth_adapter_manager.h"
 #include "chrome/browser/ash/nearby/nearby_dependencies_provider_factory.h"
 #include "chrome/browser/ash/nearby/presence/credential_storage/credential_storage_initializer.h"
diff --git a/chrome/browser/ash/os_feedback/chrome_os_feedback_delegate_browsertest.cc b/chrome/browser/ash/os_feedback/chrome_os_feedback_delegate_browsertest.cc
index bb50f35..68804e5 100644
--- a/chrome/browser/ash/os_feedback/chrome_os_feedback_delegate_browsertest.cc
+++ b/chrome/browser/ash/os_feedback/chrome_os_feedback_delegate_browsertest.cc
@@ -22,7 +22,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
diff --git a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc
index 69352eb..2e10113 100644
--- a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc
+++ b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc
index de9e518..037f0df 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc
@@ -13,6 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/syslog_logging.h"
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
index 73f9cc4..64de838 100644
--- a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
+++ b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "chrome/browser/browser_process.h"
 #include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
 #include "chromeos/ash/components/network/network_handler.h"
diff --git a/chrome/browser/ash/printing/automatic_usb_printer_configurer_unittest.cc b/chrome/browser/ash/printing/automatic_usb_printer_configurer_unittest.cc
index 1a9f98e..0775ccc2 100644
--- a/chrome/browser/ash/printing/automatic_usb_printer_configurer_unittest.cc
+++ b/chrome/browser/ash/printing/automatic_usb_printer_configurer_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/constants/ash_features.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ash/printing/fake_cups_printers_manager.h"
 #include "chrome/browser/ash/printing/printers_map.h"
diff --git a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc
index 7b0042dc..4831392 100644
--- a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc
+++ b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_ambient_provider_impl.cc
@@ -35,7 +35,7 @@
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "chrome/browser/ash/system_web_apps/apps/personalization_app/ambient_video_albums.h"
 #include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_manager.h"
diff --git a/chrome/browser/background/extensions/background_mode_manager.cc b/chrome/browser/background/extensions/background_mode_manager.cc
index c179c97..ddbecb5 100644
--- a/chrome/browser/background/extensions/background_mode_manager.cc
+++ b/chrome/browser/background/extensions/background_mode_manager.cc
@@ -21,6 +21,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/one_shot_event.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/background/extensions/background_mode_manager_aura.cc b/chrome/browser/background/extensions/background_mode_manager_aura.cc
index 64ee095f3..fdc1bd3 100644
--- a/chrome/browser/background/extensions/background_mode_manager_aura.cc
+++ b/chrome/browser/background/extensions/background_mode_manager_aura.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/notimplemented.h"
 #include "chrome/browser/background/extensions/background_mode_manager.h"
 
 // No background jobs for aura for now.
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index 009c9df..244887a 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -10,6 +10,7 @@
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java
index ffff179..a6d655b4e 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java
@@ -16,6 +16,7 @@
 
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.bookmarks.BookmarkListEntry.ViewType;
 import org.chromium.chrome.browser.bookmarks.BookmarkUiPrefs.BookmarkRowDisplayPref;
 import org.chromium.components.bookmarks.BookmarkId;
@@ -31,6 +32,7 @@
 import java.util.List;
 
 /** Coordinates the views/mediators that make up the bookmark folder picker. */
+@NullMarked
 public class BookmarkFolderPickerCoordinator implements BackPressHandler {
     private final ObservableSupplierImpl<Boolean> mBackPressStateSupplier =
             new ObservableSupplierImpl<>();
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java
index c6f61bcf..e194374 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java
@@ -4,10 +4,13 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.Initializer;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.bookmarks.BookmarkListEntry.ViewType;
 import org.chromium.chrome.browser.bookmarks.BookmarkUiPrefs.BookmarkRowDisplayPref;
 import org.chromium.chrome.browser.bookmarks.ImprovedBookmarkRowProperties.ImageVisibility;
@@ -24,10 +27,12 @@
 import java.util.Objects;
 
 /** Mediator for the folder picker activity. */
+@NullMarked
 class BookmarkFolderPickerMediator {
     private final BookmarkModelObserver mBookmarkModelObserver =
             new BookmarkModelObserver() {
                 @Override
+                @SuppressWarnings("NullAway")
                 public void bookmarkModelChanged() {
                     if (mBookmarkModel.doAllBookmarksExist(mBookmarkIds)) {
                         populateFoldersForParentId(
@@ -106,10 +111,10 @@
 
         boolean allMovedBookmarksMatchParent = true;
         BookmarkId firstParentId =
-                mBookmarkModel.getBookmarkById(mBookmarkIds.get(0)).getParentId();
+                assumeNonNull(mBookmarkModel.getBookmarkById(mBookmarkIds.get(0))).getParentId();
         List<BookmarkItem> bookmarkItems = new ArrayList<>();
         for (BookmarkId id : mBookmarkIds) {
-            BookmarkItem item = mBookmarkModel.getBookmarkById(id);
+            BookmarkItem item = assumeNonNull(mBookmarkModel.getBookmarkById(id));
             bookmarkItems.add(item);
             if (item.isFolder()) {
                 mMovingAtLeastOneFolder = true;
@@ -132,8 +137,8 @@
         // siblings to the original parent.
         BookmarkId bookmarkIdToShow =
                 mAllMovedBookmarksMatchParent
-                        ? mBookmarkModel.getBookmarkById(firstParentId).getParentId()
-                        : mBookmarkModel.getRootFolderId();
+                        ? assumeNonNull(mBookmarkModel.getBookmarkById(firstParentId)).getParentId()
+                        : assumeNonNull(mBookmarkModel.getRootFolderId());
 
         mModel.set(BookmarkFolderPickerProperties.CANCEL_CLICK_LISTENER, mFinishRunnable);
         mModel.set(BookmarkFolderPickerProperties.MOVE_CLICK_LISTENER, this::onMoveClicked);
@@ -160,8 +165,9 @@
         mBookmarkUiPrefs.removeObserver(mBookmarkUiPrefsObserver);
     }
 
+    @Initializer
     void populateFoldersForParentId(BookmarkId parentId) {
-        BookmarkItem parentItem = mBookmarkModel.getBookmarkById(parentId);
+        BookmarkItem parentItem = assumeNonNull(mBookmarkModel.getBookmarkById(parentId));
         mCurrentParentItem = parentItem;
         updateToolbarTitleForCurrentParent();
         updateButtonsForCurrentParent();
@@ -189,7 +195,7 @@
     }
 
     ListItem createFolderPickerRow(BookmarkListEntry entry) {
-        BookmarkItem bookmarkItem = entry.getBookmarkItem();
+        BookmarkItem bookmarkItem = assumeNonNull(entry.getBookmarkItem());
         BookmarkId bookmarkId = bookmarkItem.getId();
 
         PropertyModel propertyModel =
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkListEntry.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkListEntry.java
index 07a9652a..b9796a6 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkListEntry.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkListEntry.java
@@ -117,15 +117,6 @@
                 /* meta= */ null);
     }
 
-    /** Creates a divider to separate sections in the bookmark list. */
-    static BookmarkListEntry createDivider() {
-        return new BookmarkListEntry(
-                ViewType.DIVIDER,
-                /* bookmarkItem= */ null,
-                /* sectionHeaderData= */ null,
-                /* meta= */ null);
-    }
-
     /**
      * Create an entry representing the reading list read/unread section header.
      *
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java
index 3da66d9f..9821da8d 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.app.Activity;
 import android.content.Context;
 import android.view.LayoutInflater;
@@ -12,8 +14,6 @@
 import android.view.ViewGroup;
 
 import androidx.annotation.LayoutRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.recyclerview.widget.RecyclerView;
@@ -25,6 +25,8 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.bookmarks.BookmarkListEntry.ViewType;
 import org.chromium.chrome.browser.bookmarks.BookmarkUiPrefs.BookmarkRowDisplayPref;
 import org.chromium.chrome.browser.commerce.ShoppingServiceFactory;
@@ -40,6 +42,7 @@
 import org.chromium.chrome.browser.ui.signin.signin_promo.BookmarkSigninPromoDelegate;
 import org.chromium.chrome.browser.ui.signin.signin_promo.SigninPromoCoordinator;
 import org.chromium.components.bookmarks.BookmarkId;
+import org.chromium.components.bookmarks.BookmarkItem;
 import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
 import org.chromium.components.browser_ui.util.GlobalDiscardableReferencePool;
 import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableRecyclerViewAdapter;
@@ -62,18 +65,19 @@
 
 /** Responsible for setting up sub-components and routing incoming/outgoing signals */
 // TODO(crbug.com/40268641): Add a new coordinator so this class doesn't own everything.
+@NullMarked
 public class BookmarkManagerCoordinator
         implements SearchDelegate, BackPressHandler, OnAttachStateChangeListener {
 
     private final SelectionDelegate<BookmarkId> mSelectionDelegate =
             new SelectionDelegate<>() {
                 @Override
-                public boolean toggleSelectionForItem(BookmarkId bookmark) {
-                    if (mBookmarkModel.getBookmarkById(bookmark) != null
-                            && !mBookmarkModel.getBookmarkById(bookmark).isEditable()) {
+                public boolean toggleSelectionForItem(@Nullable BookmarkId bookmarkId) {
+                    BookmarkItem bookmarkItem = mBookmarkModel.getBookmarkById(bookmarkId);
+                    if (bookmarkItem != null && !bookmarkItem.isEditable()) {
                         return false;
                     }
-                    return super.toggleSelectionForItem(bookmark);
+                    return super.toggleSelectionForItem(bookmarkId);
                 }
             };
 
@@ -83,7 +87,7 @@
         }
 
         @Override
-        public boolean onFailedToRecycleView(@NonNull ViewHolder holder) {
+        public boolean onFailedToRecycleView(ViewHolder holder) {
             // The view has transient state, which is probably because there's an outstanding
             // fade animation. Theoretically we could clear it and let the RecyclerView continue
             // normally, but it seems sometimes this is called after bind, and the transient
@@ -118,8 +122,8 @@
     private final BookmarkManagerMediator mMediator;
     private final ImageFetcher mImageFetcher;
     private final SnackbarManager mSnackbarManager;
-    private final SigninPromoCoordinator mSigninPromoCoordinator;
-    private final BookmarkPromoHeader mPromoHeaderManager;
+    private final @Nullable SigninPromoCoordinator mSigninPromoCoordinator;
+    private final @Nullable BookmarkPromoHeader mPromoHeaderManager;
     private final BookmarkModel mBookmarkModel;
     private final Profile mProfile;
     private final BookmarkUiPrefs mBookmarkUiPrefs;
@@ -140,14 +144,14 @@
      * @param priceDropNotificationManager Manages price drop notifications.
      */
     public BookmarkManagerCoordinator(
-            @NonNull Context context,
+            Context context,
             boolean isDialogUi,
-            @NonNull SnackbarManager snackbarManager,
-            @NonNull Profile profile,
-            @NonNull BookmarkUiPrefs bookmarkUiPrefs,
-            @NonNull BookmarkOpener bookmarkOpener,
-            @NonNull BookmarkManagerOpener bookmarkManagerOpener,
-            @NonNull PriceDropNotificationManager priceDropNotificationManager) {
+            SnackbarManager snackbarManager,
+            Profile profile,
+            BookmarkUiPrefs bookmarkUiPrefs,
+            BookmarkOpener bookmarkOpener,
+            BookmarkManagerOpener bookmarkManagerOpener,
+            PriceDropNotificationManager priceDropNotificationManager) {
         mContext = context;
         mProfile = profile;
         mImageFetcher =
@@ -180,7 +184,7 @@
         // Disable everything except move animations. Switching between folders should be as
         // seamless as possible without flickering caused by these animations. While dragging
         // should still pick up the slide animation from moves.
-        ItemAnimator itemAnimator = mRecyclerView.getItemAnimator();
+        ItemAnimator itemAnimator = assumeNonNull(mRecyclerView.getItemAnimator());
         itemAnimator.setChangeDuration(0);
         itemAnimator.setAddDuration(0);
         itemAnimator.setRemoveDuration(0);
@@ -366,12 +370,12 @@
     // OnAttachStateChangeListener implementation.
 
     @Override
-    public void onViewAttachedToWindow(@NonNull View view) {
+    public void onViewAttachedToWindow(View view) {
         mMediator.onAttachedToWindow();
     }
 
     @Override
-    public void onViewDetachedFromWindow(@NonNull View view) {
+    public void onViewDetachedFromWindow(View view) {
         mMediator.onDetachedFromWindow();
     }
 
@@ -411,15 +415,11 @@
 
     @VisibleForTesting
     View buildPersonalizedPromoView(ViewGroup parent) {
+        assumeNonNull(mPromoHeaderManager);
         return mPromoHeaderManager.createPersonalizedSigninAndSyncPromoHolder(parent);
     }
 
     @VisibleForTesting
-    View buildLegacyPromoView(ViewGroup parent) {
-        return mPromoHeaderManager.createSyncPromoHolder(parent);
-    }
-
-    @VisibleForTesting
     View buildBatchUploadCardView(ViewGroup parent) {
         // The signin_settings_card_view is used for Batch Upload Cards.
         return inflate(parent, R.layout.signin_settings_card_view);
@@ -509,22 +509,23 @@
     public BookmarkManagerTestingDelegate getTestingDelegate() {
         return new BookmarkManagerTestingDelegate() {
             @Override
-            public BookmarkId getBookmarkIdByPositionForTesting(int position) {
+            public @Nullable BookmarkId getBookmarkIdByPositionForTesting(int position) {
                 return mMediator.getIdByPositionForTesting(position);
             }
 
             @Override
-            public ImprovedBookmarkRow getBookmarkRowByPosition(int position) {
-                return (ImprovedBookmarkRow) getBookmarkViewHolderByPosition(position).itemView;
+            public @Nullable ImprovedBookmarkRow getBookmarkRowByPosition(int position) {
+                ViewHolder viewHolder = getBookmarkViewHolderByPosition(position);
+                return viewHolder == null ? null : (ImprovedBookmarkRow) viewHolder.itemView;
             }
 
             @Override
-            public ViewHolder getBookmarkViewHolderByPosition(int position) {
+            public @Nullable ViewHolder getBookmarkViewHolderByPosition(int position) {
                 return getViewHolderByPosition(getBookmarkStartIndex() + position);
             }
 
             @Override
-            public ViewHolder getViewHolderByPosition(int position) {
+            public @Nullable ViewHolder getViewHolderByPosition(int position) {
                 return mRecyclerView.findViewHolderForAdapterPosition(position);
             }
 
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateProperties.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateProperties.java
index aae22e1..aaedc59 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateProperties.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateProperties.java
@@ -4,11 +4,13 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
 
 /** Responsible for hosting properties of BookmarkManager empty state. */
+@NullMarked
 class BookmarkManagerEmptyStateProperties {
     static final WritableIntPropertyKey EMPTY_STATE_TITLE_RES = new WritableIntPropertyKey();
     static final WritableIntPropertyKey EMPTY_STATE_DESCRIPTION_RES = new WritableIntPropertyKey();
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateViewBinder.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateViewBinder.java
index 87717eb..65ebacc 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateViewBinder.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerEmptyStateViewBinder.java
@@ -12,10 +12,12 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Responsible for binding views to their properties. */
+@NullMarked
 class BookmarkManagerEmptyStateViewBinder {
     public static void bindEmptyStateView(PropertyModel model, View view, PropertyKey key) {
         if (key == EMPTY_STATE_TITLE_RES) {
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java
index ef7dfcb..3d8ede9f 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
 import static org.chromium.components.browser_ui.widget.BrowserUiListMenuUtils.buildMenuListItem;
 
 import android.app.Activity;
@@ -11,8 +12,6 @@
 import android.text.TextUtils;
 
 import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.LifecycleOwner;
@@ -25,6 +24,9 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.build.annotations.Initializer;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.bookmarks.BookmarkListEntry.ViewType;
 import org.chromium.chrome.browser.bookmarks.BookmarkMetrics.BookmarkManagerFilter;
 import org.chromium.chrome.browser.bookmarks.BookmarkUiPrefs.BookmarkRowDisplayPref;
@@ -79,6 +81,7 @@
 
 /** Responsible for BookmarkManager business logic. */
 // TODO(crbug.com/40256938): Remove BookmarkDelegate if possible.
+@NullMarked
 class BookmarkManagerMediator
         implements BookmarkDelegate, PartnerBookmarksReader.FaviconUpdateObserver {
     private static final int PROMO_MAX_INDEX = 1;
@@ -91,6 +94,7 @@
         private BookmarkDelegate mBookmarkDelegate;
         private SelectionDelegate<BookmarkId> mSelectionDelegate;
 
+        @Initializer
         void onBookmarkDelegateInitialized(BookmarkDelegate delegate) {
             mBookmarkDelegate = delegate;
             mSelectionDelegate = delegate.getSelectionDelegate();
@@ -136,7 +140,10 @@
                         // back to all bookmarks mode.
                         if (Objects.equals(id, getCurrentFolderId())) {
                             if (mBookmarkModel.getTopLevelFolderIds().contains(id)) {
-                                openFolder(mBookmarkModel.getDefaultFolderViewLocation());
+                                BookmarkId defaultFolder =
+                                        mBookmarkModel.getDefaultFolderViewLocation();
+                                assumeNonNull(defaultFolder);
+                                openFolder(defaultFolder);
                             } else {
                                 openFolder(parent.getId());
                             }
@@ -226,14 +233,15 @@
                 }
 
                 @Override
-                public void onFolderStateSet(BookmarkId folder) {
+                public void onFolderStateSet(@Nullable BookmarkId folder) {
                     clearHighlight();
 
                     mDragReorderableRecyclerViewAdapter.enableDrag();
 
+                    BookmarkId currentId = assumeNonNull(getCurrentFolderId());
                     setBookmarks(
                             mBookmarkQueryHandler.buildBookmarkListForParent(
-                                    getCurrentFolderId(), mCurrentPowerFilter));
+                                    currentId, mCurrentPowerFilter));
                     setSearchTextAndUpdateButtonVisibility("");
                     clearSearchBoxFocus();
                 }
@@ -275,7 +283,7 @@
                 public boolean isPassivelyDraggable(PropertyModel propertyModel) {
                     BookmarkListEntry bookmarkListEntry =
                             propertyModel.get(BookmarkManagerProperties.BOOKMARK_LIST_ENTRY);
-                    BookmarkItem bookmarkItem = bookmarkListEntry.getBookmarkItem();
+                    BookmarkItem bookmarkItem = assumeNonNull(bookmarkListEntry.getBookmarkItem());
                     return bookmarkItem.isReorderable();
                 }
             };
@@ -384,14 +392,14 @@
     private final BookmarkManagerOpener mBookmarkManagerOpener;
     private final PriceDropNotificationManager mPriceDropNotificationManager;
 
-    @Nullable private BatchUploadCardCoordinator mBatchUploadCardCoordinator;
+    private @Nullable BatchUploadCardCoordinator mBatchUploadCardCoordinator;
     // Whether this instance has been destroyed.
     private boolean mIsDestroyed;
-    private String mInitialUrl;
+    private @Nullable String mInitialUrl;
     private boolean mFaviconsNeedRefresh;
-    private BasicNativePage mNativePage;
+    private @Nullable BasicNativePage mNativePage;
     // Keep track of the currently highlighted bookmark - used for "show in folder" action.
-    private BookmarkId mHighlightedBookmark;
+    private @Nullable BookmarkId mHighlightedBookmark;
     // If selection is currently enabled in the bookmarks manager.
     private boolean mIsSelectionEnabled;
     // Track if we're the source of bookmark model reordering so the event can be ignored.
@@ -483,7 +491,7 @@
         onScrollListenerConsumer.accept(
                 new OnScrollListener() {
                     @Override
-                    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                         if (dy > 0) {
                             clearSearchBoxFocus();
                         }
@@ -602,12 +610,11 @@
         }
     }
 
-    @Nullable
-    BookmarkPromoHeader getPromoHeaderManager() {
+    @Nullable BookmarkPromoHeader getPromoHeaderManager() {
         return mPromoHeaderManager;
     }
 
-    BookmarkId getIdByPosition(int position) {
+    @Nullable BookmarkId getIdByPosition(int position) {
         BookmarkListEntry entry = getItemByPosition(position);
         if (entry == null || entry.getBookmarkItem() == null) return null;
         return entry.getBookmarkItem().getId();
@@ -624,10 +631,9 @@
 
     public void setOrder() {
         assert !topLevelFoldersShowing() : "Cannot reorder top-level folders!";
-        assert getCurrentFolderId().getType() != BookmarkType.READING_LIST
-                : "Cannot reorder reading list!";
-        assert getCurrentFolderId().getType() != BookmarkType.PARTNER
-                : "Cannot reorder partner bookmarks!";
+        BookmarkId currentId = assumeNonNull(getCurrentFolderId());
+        assert currentId.getType() != BookmarkType.READING_LIST : "Cannot reorder reading list!";
+        assert currentId.getType() != BookmarkType.PARTNER : "Cannot reorder partner bookmarks!";
         assert getCurrentUiMode() == BookmarkUiMode.FOLDER
                 : "Can only reorder items from folder mode!";
 
@@ -637,15 +643,14 @@
         // Get the new order for the IDs.
         List<Long> newOrder = new ArrayList<>(endIndex - startIndex + 1);
         for (int i = startIndex; i <= endIndex; i++) {
-            BookmarkItem bookmarkItem = getItemByPosition(i).getBookmarkItem();
-            // The parter bookmark folder is under "Mobile boomkmarks", but can't be reordered.
+            BookmarkItem bookmarkItem = assumeNonNull(getItemByPosition(i).getBookmarkItem());
+            // The partner bookmark folder is under "Mobile bookmarks", but can't be reordered.
             if (!bookmarkItem.isReorderable()) {
                 assert i == endIndex
                         : "Partner bookmarks should always be at the end of the list when mobile"
                                 + " bookmark children are re-ordered.";
                 continue;
             }
-            assert bookmarkItem != null;
             newOrder.add(bookmarkItem.getId().getId());
         }
         long[] newOrderArr = new long[newOrder.size()];
@@ -854,9 +859,8 @@
      */
     private void setState(BookmarkUiState state) {
         if (!state.isValid(mBookmarkModel)) {
-            state =
-                    BookmarkUiState.createFolderState(
-                            mBookmarkModel.getDefaultFolderViewLocation(), mBookmarkModel);
+            BookmarkId defaultFolder = assumeNonNull(mBookmarkModel.getDefaultFolderViewLocation());
+            state = BookmarkUiState.createFolderState(defaultFolder, mBookmarkModel);
         }
 
         @BookmarkUiMode int currentUiMode = getCurrentUiMode();
@@ -911,9 +915,10 @@
         } else if (state.mUiMode == BookmarkUiMode.SEARCHING) {
             String searchText = getCurrentSearchText();
             if (!preserveFolderBookmarksOnEmptySearch || !TextUtils.isEmpty(searchText)) {
+                String trimmedText = searchText == null ? "" : searchText.trim();
                 setBookmarks(
                         mBookmarkQueryHandler.buildBookmarkListForSearch(
-                                searchText.trim(), mCurrentPowerFilter));
+                                trimmedText, mCurrentPowerFilter));
             }
         }
 
@@ -973,7 +978,7 @@
         setSearchBoxFocusAndHideKeyboardIfNeeded(false);
     }
 
-    private PropertyModel getSearchBoxPropertyModel() {
+    private @Nullable PropertyModel getSearchBoxPropertyModel() {
         int index = getCurrentSearchBoxIndex();
         return index < 0 ? null : mModelList.get(index).model;
     }
@@ -993,7 +998,7 @@
             updateOrAdd(index, buildSearchBoxRow());
         } else {
             // Update the filter visibility if the search box is already built.
-            updateSearchBoxShoppingFilterVisibility(getSearchBoxPropertyModel());
+            updateSearchBoxShoppingFilterVisibility(assumeNonNull(getSearchBoxPropertyModel()));
         }
         index++;
 
@@ -1106,7 +1111,7 @@
             return mCanShowSigninPromo.getAsBoolean() ? ViewType.SIGNIN_PROMO : ViewType.INVALID;
         }
 
-        if (mPromoHeaderManager.shouldShowPromo()) {
+        if (mPromoHeaderManager != null && mPromoHeaderManager.shouldShowPromo()) {
             return ViewType.SIGNIN_PROMO;
         } else {
             return ViewType.INVALID;
@@ -1357,14 +1362,13 @@
         mBookmarkModel.finishLoadingBookmarkModel(this::onBookmarkModelLoaded);
     }
 
-    @VisibleForTesting
-    BatchUploadCardCoordinator getBatchUploadCardCoordinator() {
+    /* package */ @Nullable BatchUploadCardCoordinator getBatchUploadCardCoordinatorForTesting() {
         return mBatchUploadCardCoordinator;
     }
 
     @VisibleForTesting
-    ListItem buildImprovedBookmarkRow(BookmarkListEntry bookmarkListEntry) {
-        BookmarkItem bookmarkItem = bookmarkListEntry.getBookmarkItem();
+    /* package */ ListItem buildImprovedBookmarkRow(BookmarkListEntry bookmarkListEntry) {
+        BookmarkItem bookmarkItem = assumeNonNull(bookmarkListEntry.getBookmarkItem());
         BookmarkId bookmarkId = bookmarkItem.getId();
 
         PropertyModel propertyModel =
@@ -1400,11 +1404,11 @@
 
     @VisibleForTesting
     ModelList createListMenuModelList(BookmarkListEntry entry, @Location int location) {
-        BookmarkItem bookmarkItem = entry.getBookmarkItem();
-        BookmarkId bookmarkId = bookmarkItem.getId();
-
         ModelList listItems = new ModelList();
+
+        BookmarkItem bookmarkItem = entry.getBookmarkItem();
         if (bookmarkItem == null) return listItems;
+        BookmarkId bookmarkId = bookmarkItem.getId();
 
         // Reading list items can sometimes be movable (for type swapping purposes), but for
         // UI purposes they shouldn't be movable.
@@ -1466,7 +1470,7 @@
     @VisibleForTesting
     ListMenu createListMenuForBookmark(PropertyModel model) {
         BookmarkListEntry entry = model.get(BookmarkManagerProperties.BOOKMARK_LIST_ENTRY);
-        BookmarkId bookmarkId = entry.getBookmarkItem().getId();
+        BookmarkId bookmarkId = assumeNonNull(entry.getBookmarkItem()).getId();
         ModelList listItems =
                 createListMenuModelList(entry, model.get(BookmarkManagerProperties.LOCATION));
         ListMenu.Delegate delegate =
@@ -1481,15 +1485,18 @@
                         }
                     } else if (textId == R.string.bookmark_item_edit) {
                         BookmarkItem bookmarkItem = mBookmarkModel.getBookmarkById(bookmarkId);
+                        assumeNonNull(bookmarkItem);
                         mBookmarkManagerOpener.startEditActivity(
                                 mContext, mProfile, bookmarkItem.getId());
                     } else if (textId == R.string.reading_list_mark_as_read) {
                         BookmarkItem bookmarkItem = mBookmarkModel.getBookmarkById(bookmarkId);
+                        assumeNonNull(bookmarkItem);
                         mBookmarkModel.setReadStatusForReadingList(
                                 bookmarkItem.getId(), /* read= */ true);
                         RecordUserAction.record("Android.BookmarkPage.ReadingList.MarkAsRead");
                     } else if (textId == R.string.reading_list_mark_as_unread) {
                         BookmarkItem bookmarkItem = mBookmarkModel.getBookmarkById(bookmarkId);
+                        assumeNonNull(bookmarkItem);
                         mBookmarkModel.setReadStatusForReadingList(
                                 bookmarkItem.getId(), /* read= */ false);
                         RecordUserAction.record("Android.BookmarkPage.ReadingList.MarkAsUnread");
@@ -1508,6 +1515,7 @@
                         }
                     } else if (textId == R.string.bookmark_show_in_folder) {
                         BookmarkItem bookmarkItem = mBookmarkModel.getBookmarkById(bookmarkId);
+                        assumeNonNull(bookmarkItem);
                         openFolder(bookmarkItem.getParentId());
                         highlightBookmark(bookmarkId);
                         RecordUserAction.record("MobileBookmarkManagerShowInFolder");
@@ -1540,7 +1548,7 @@
 
         PowerBookmarkUtils.setPriceTrackingEnabledWithSnackbars(
                 mBookmarkModel,
-                entry.getBookmarkItem().getId(),
+                assumeNonNull(entry.getBookmarkItem()).getId(),
                 enabled,
                 mSnackbarManager,
                 mContext.getResources(),
@@ -1589,7 +1597,7 @@
         return true;
     }
 
-    private void onSearchTextChangeCallback(String searchText) {
+    private void onSearchTextChangeCallback(@Nullable String searchText) {
         searchText = searchText == null ? "" : searchText;
         setSearchTextAndUpdateButtonVisibility(searchText);
         onSearchChange(searchText);
@@ -1600,10 +1608,11 @@
     }
 
     private void setSearchTextAndUpdateButtonVisibility(String searchText) {
-        getSearchBoxPropertyModel().set(BookmarkSearchBoxRowProperties.SEARCH_TEXT, searchText);
+        PropertyModel searchModel = assumeNonNull(getSearchBoxPropertyModel());
+        searchModel.set(BookmarkSearchBoxRowProperties.SEARCH_TEXT, searchText);
         boolean isVisible = !TextUtils.isEmpty(searchText);
-        getSearchBoxPropertyModel()
-                .set(BookmarkSearchBoxRowProperties.CLEAR_SEARCH_TEXT_BUTTON_VISIBILITY, isVisible);
+        searchModel.set(
+                BookmarkSearchBoxRowProperties.CLEAR_SEARCH_TEXT_BUTTON_VISIBILITY, isVisible);
     }
 
     private void onSearchBoxFocusChange(Boolean hasFocus) {
@@ -1612,7 +1621,8 @@
     }
 
     private void setSearchBoxFocusAndHideKeyboardIfNeeded(boolean hasFocus) {
-        getSearchBoxPropertyModel().set(BookmarkSearchBoxRowProperties.HAS_FOCUS, hasFocus);
+        PropertyModel searchModel = assumeNonNull(getSearchBoxPropertyModel());
+        searchModel.set(BookmarkSearchBoxRowProperties.HAS_FOCUS, hasFocus);
         if (hasFocus) {
             if (getCurrentUiMode() == BookmarkUiMode.FOLDER) {
                 setState(BookmarkUiState.createSearchState(""));
@@ -1630,8 +1640,8 @@
         }
 
         BookmarkMetrics.reportBookmarkManagerFilterUsed(BookmarkManagerFilter.SHOPPING);
-        getSearchBoxPropertyModel()
-                .set(BookmarkSearchBoxRowProperties.SHOPPING_CHIP_SELECTED, isFiltering);
+        PropertyModel searchModel = assumeNonNull(getSearchBoxPropertyModel());
+        searchModel.set(BookmarkSearchBoxRowProperties.SHOPPING_CHIP_SELECTED, isFiltering);
         refresh();
     }
 
@@ -1721,31 +1731,31 @@
     // Testing methods.
 
     /** Whether to prevent the bookmark model from fully loading for testing. */
-    static void preventLoadingForTesting(boolean preventLoading) {
+    /* package */ static void preventLoadingForTesting(boolean preventLoading) {
         sPreventLoadingForTesting = preventLoading;
     }
 
-    void finishLoadingForTesting() {
+    /* package */ void finishLoadingForTesting() {
         finishLoadingBookmarkModel();
     }
 
-    void clearStateStackForTesting() {
+    /* package */ void clearStateStackForTesting() {
         mStateStack.clear();
     }
 
-    BookmarkUndoController getUndoControllerForTesting() {
+    /* package */ BookmarkUndoController getUndoControllerForTesting() {
         return mBookmarkUndoController;
     }
 
-    DragStateDelegate getDragStateDelegateForTesting() {
+    /* package */ DragStateDelegate getDragStateDelegateForTesting() {
         return mDragStateDelegate;
     }
 
-    BookmarkId getIdByPositionForTesting(int position) {
+    /* package */ @Nullable BookmarkId getIdByPositionForTesting(int position) {
         return getIdByPosition(getBookmarkItemStartIndex() + position);
     }
 
-    void simulateSignInForTesting() {
+    /* package */ void simulateSignInForTesting() {
         mBookmarkUiObserver.onFolderStateSet(getCurrentFolderId());
     }
 }
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerProperties.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerProperties.java
index 31489e5f..5efc17dd 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerProperties.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerProperties.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.bookmarks;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.sync.ui.batch_upload_card.BatchUploadCardCoordinator;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.ui.modelutil.PropertyKey;
@@ -13,6 +14,7 @@
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
 
 /** Responsible for hosting properties of BookmarkManager views. */
+@NullMarked
 public class BookmarkManagerProperties {
     public static final WritableObjectPropertyKey<BookmarkPromoHeader> BOOKMARK_PROMO_HEADER =
             new WritableObjectPropertyKey<>();
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerTestingDelegate.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerTestingDelegate.java
index c6a7f47..e97768d 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerTestingDelegate.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerTestingDelegate.java
@@ -18,16 +18,16 @@
      * searching for the position, for example if the index 0 then the 1st bookmark in the list will
      * be returned rather than having to offset by non-bookmark list items.
      */
-    BookmarkId getBookmarkIdByPositionForTesting(int position);
+    @Nullable BookmarkId getBookmarkIdByPositionForTesting(int position);
 
     /** Returns the ImprovedBookmarkRow by position, ignores other view types like above. */
-    ImprovedBookmarkRow getBookmarkRowByPosition(int position);
+    @Nullable ImprovedBookmarkRow getBookmarkRowByPosition(int position);
 
     /** Returns the bookmark's ViewHolder by position, ignores other view types like above. */
-    ViewHolder getBookmarkViewHolderByPosition(int position);
+    @Nullable ViewHolder getBookmarkViewHolderByPosition(int position);
 
     /** Returns any view holder by position. */
-    ViewHolder getViewHolderByPosition(int position);
+    @Nullable ViewHolder getViewHolderByPosition(int position);
 
     /** Returns the bookmark count in the current context. */
     int getBookmarkCount();
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerViewBinder.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerViewBinder.java
index b70a462..f0ed8c7 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerViewBinder.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerViewBinder.java
@@ -4,12 +4,15 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.res.Resources;
 import android.view.View;
 import android.widget.TextView;
 
 import androidx.annotation.DimenRes;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.bookmarks.BookmarkListEntry.SectionHeaderData;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.ui.signin.PersonalizedSigninPromoView;
@@ -17,6 +20,7 @@
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Responsible for binding views to their properties. */
+@NullMarked
 class BookmarkManagerViewBinder {
     static void bindPersonalizedPromoView(PropertyModel model, View view, PropertyKey key) {
         assert !ChromeFeatureList.isEnabled(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP);
@@ -44,6 +48,7 @@
                     model.get(BookmarkManagerProperties.BOOKMARK_LIST_ENTRY);
             TextView title = view.findViewById(R.id.title);
             SectionHeaderData sectionHeaderData = bookmarkListEntry.getSectionHeaderData();
+            assumeNonNull(sectionHeaderData);
             title.setText(resources.getText(sectionHeaderData.titleRes));
             final @DimenRes int topPaddingRes = sectionHeaderData.topPaddingRes;
             if (topPaddingRes != Resources.ID_NULL) {
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
index 40fd133..64200c3d 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
@@ -38,7 +38,7 @@
         ResettersForTesting.register(() -> sInstanceForTesting = null);
     }
 
-    /** Sets a pre-configured runnable which loads the parter bookmarks shim. */
+    /** Sets a pre-configured runnable which loads the partner bookmarks shim. */
     public static void setPartnerBookmarkIteratorProvider(
             PartnerBookmarkIteratorProvider provider) {
         BookmarkBridge.setPartnerBookmarkIteratorProvider(provider);
@@ -46,7 +46,7 @@
 
     /** Provider for the PartnerBookmark iterator. */
     public interface PartnerBookmarkIteratorProvider {
-        /** Fetches the iterator of PartnerBookmarks and notifieds the callback when ready. */
+        /** Fetches the iterator of PartnerBookmarks and notifies the callback when ready. */
         void getIterator(Callback<PartnerBookmark.BookmarkIterator> iterator);
     }
 
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpener.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpener.java
index 3e14a07..eca51f7 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpener.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkOpener.java
@@ -14,24 +14,6 @@
 /** Consolidates logic about opening bookmarks. */
 @NullMarked
 public interface BookmarkOpener {
-    /** Observer interface for when bookmarks are opened. */
-    interface Observer {
-        /**
-         * Called when a bookmark opened event happens. This is invoked once when multiple bookmarks
-         * are opened in new tabs.
-         */
-        void onAnyBookmarkOpenedEvent();
-    }
-
-    /** Destroys the opener. */
-    void destroy();
-
-    /** Add an observer to the class. */
-    void addObserver(Observer obs);
-
-    /** Remove an observer from the class. */
-    void removeObserver(Observer obs);
-
     /**
      * Open the given id in the current tab.
      *
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
index 5bad6a4e..e72362c 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
@@ -6,9 +6,8 @@
 
 import android.content.ComponentName;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManagerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -18,6 +17,7 @@
 import org.chromium.components.embedder_support.util.UrlConstants;
 
 /** A native page holding a {@link BookmarkManagerCoordinator} on _tablet_. */
+@NullMarked
 public class BookmarkPage extends BasicNativePage {
     private final BookmarkManagerCoordinator mBookmarkManagerCoordinator;
     private final BookmarkOpener mBookmarkOpener;
@@ -32,9 +32,9 @@
      * @param host A NativePageHost to load urls.
      */
     public BookmarkPage(
-            @NonNull SnackbarManager snackbarManager,
-            @NonNull Profile profile,
-            @NonNull NativePageHost host,
+            SnackbarManager snackbarManager,
+            Profile profile,
+            NativePageHost host,
             @Nullable ComponentName componentName) {
         super(host);
         mTitle = host.getContext().getString(R.string.bookmarks);
@@ -77,8 +77,6 @@
     @Override
     public void destroy() {
         super.destroy();
-
-        mBookmarkOpener.destroy();
         mBookmarkManagerCoordinator.onDestroyed();
     }
 
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPane.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPane.java
index 1597f82..9722ef7 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPane.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPane.java
@@ -12,12 +12,11 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.hub.DisplayButtonData;
 import org.chromium.chrome.browser.hub.FadeHubLayoutAnimationFactory;
 import org.chromium.chrome.browser.hub.FullButtonData;
@@ -34,7 +33,6 @@
 import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManagerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileProvider;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController.MenuOrKeyboardActionHandler;
 import org.chromium.components.embedder_support.util.UrlConstants;
@@ -42,6 +40,7 @@
 import java.util.function.DoubleConsumer;
 
 /** A {@link Pane} representing history. */
+@NullMarked
 public class BookmarkPane implements Pane {
 
     // Below are dependencies of the pane itself.
@@ -52,7 +51,7 @@
             new ObservableSupplierImpl<>();
     private final ObservableSupplierImpl<Boolean> mHairlineVisibilitySupplier =
             new ObservableSupplierImpl<>();
-    private final ObservableSupplierImpl<View> mHubOverlayViewSupplier =
+    private final ObservableSupplierImpl<@Nullable View> mHubOverlayViewSupplier =
             new ObservableSupplierImpl<>();
     private final ObservableSupplierImpl<Boolean> mHubSearchEnabledStateSupplier =
             new ObservableSupplierImpl<>();
@@ -64,23 +63,20 @@
     private final SnackbarManager mSnackbarManager;
     private final OneshotSupplier<ProfileProvider> mProfileProviderSupplier;
 
-    private BookmarkManagerCoordinator mBookmarkManager;
-    private BookmarkOpener mBookmarkOpener;
-    private BookmarkOpener.Observer mBookmarkOpenerObserver;
-    private PaneHubController mPaneHubController;
+    private @Nullable BookmarkManagerCoordinator mBookmarkManager;
+    private @Nullable BookmarkOpener mBookmarkOpener;
 
     /**
      * @param onToolbarAlphaChange Observer to notify when alpha changes during animations.
      * @param activity Used as a dependency to BookmarkManager.
      * @param snackbarManager Used as a dependency to BookmarkManager.
      * @param profileProviderSupplier Used as a dependency to BookmarkManager.
-     * @param bottomSheetController Used as a dependency to BookmarkManager.
      */
     public BookmarkPane(
-            @NonNull DoubleConsumer onToolbarAlphaChange,
-            @NonNull Activity activity,
-            @NonNull SnackbarManager snackbarManager,
-            @NonNull OneshotSupplier<ProfileProvider> profileProviderSupplier) {
+            DoubleConsumer onToolbarAlphaChange,
+            Activity activity,
+            SnackbarManager snackbarManager,
+            OneshotSupplier<ProfileProvider> profileProviderSupplier) {
         mOnToolbarAlphaChange = onToolbarAlphaChange;
         mReferenceButtonSupplier.set(
                 new ResourceButtonData(
@@ -99,15 +95,13 @@
         return PaneId.BOOKMARKS;
     }
 
-    @NonNull
     @Override
     public ViewGroup getRootView() {
         return mRootView;
     }
 
-    @Nullable
     @Override
-    public MenuOrKeyboardActionHandler getMenuOrKeyboardActionHandler() {
+    public @Nullable MenuOrKeyboardActionHandler getMenuOrKeyboardActionHandler() {
         return null;
     }
 
@@ -127,9 +121,7 @@
     }
 
     @Override
-    public void setPaneHubController(@Nullable PaneHubController paneHubController) {
-        mPaneHubController = paneHubController;
-    }
+    public void setPaneHubController(@Nullable PaneHubController paneHubController) {}
 
     @Override
     public void notifyLoadHint(@LoadHint int loadHint) {
@@ -141,8 +133,6 @@
                             () -> BookmarkModel.getForProfile(originalProfile),
                             mActivity,
                             componentName);
-            mBookmarkOpenerObserver = this::onBookmarkOpened;
-            mBookmarkOpener.addObserver(mBookmarkOpenerObserver);
             mBookmarkManager =
                     new BookmarkManagerCoordinator(
                             mActivity,
@@ -160,67 +150,53 @@
         }
     }
 
-    @NonNull
     @Override
     public ObservableSupplier<FullButtonData> getActionButtonDataSupplier() {
         return mEmptyActionButtonSupplier;
     }
 
-    @NonNull
     @Override
     public ObservableSupplier<DisplayButtonData> getReferenceButtonDataSupplier() {
         return mReferenceButtonSupplier;
     }
 
-    @NonNull
     @Override
     public ObservableSupplier<Boolean> getHairlineVisibilitySupplier() {
         return mHairlineVisibilitySupplier;
     }
 
     @Override
-    public ObservableSupplier<View> getHubOverlayViewSupplier() {
+    public ObservableSupplier<@Nullable View> getHubOverlayViewSupplier() {
         return mHubOverlayViewSupplier;
     }
 
-    @Nullable
     @Override
-    public HubLayoutAnimationListener getHubLayoutAnimationListener() {
+    public @Nullable HubLayoutAnimationListener getHubLayoutAnimationListener() {
         return null;
     }
 
-    @NonNull
     @Override
     public HubLayoutAnimatorProvider createShowHubLayoutAnimatorProvider(
-            @NonNull HubContainerView hubContainerView) {
+            HubContainerView hubContainerView) {
         return FadeHubLayoutAnimationFactory.createFadeInAnimatorProvider(
                 hubContainerView, HUB_LAYOUT_FADE_DURATION_MS, mOnToolbarAlphaChange);
     }
 
-    @NonNull
     @Override
     public HubLayoutAnimatorProvider createHideHubLayoutAnimatorProvider(
-            @NonNull HubContainerView hubContainerView) {
+            HubContainerView hubContainerView) {
         return FadeHubLayoutAnimationFactory.createFadeOutAnimatorProvider(
                 hubContainerView, HUB_LAYOUT_FADE_DURATION_MS, mOnToolbarAlphaChange);
     }
 
-    @NonNull
     @Override
     public ObservableSupplier<Boolean> getHubSearchEnabledStateSupplier() {
         return mHubSearchEnabledStateSupplier;
     }
 
-    private void onBookmarkOpened() {
-        mPaneHubController.selectTabAndHideHub(Tab.INVALID_TAB_ID);
-    }
-
     private void destroyManagerAndRemoveView() {
         if (mBookmarkManager != null) {
-            mBookmarkOpener.removeObserver(mBookmarkOpenerObserver);
-            mBookmarkOpener.destroy();
             mBookmarkOpener = null;
-
             mBookmarkManager.onDestroyed();
             mBookmarkManager = null;
         }
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
index b524aa0..25c46d45 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
@@ -4,14 +4,17 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import static org.chromium.build.NullUtil.assertNonNull;
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.LegacySyncPromoView;
 import org.chromium.chrome.browser.signin.SigninAndHistorySyncActivityLauncherImpl;
@@ -33,6 +36,7 @@
  * Class that manages all the logic and UI behind the signin promo header in the bookmark content
  * UI. The header is shown only on certain situations, (e.g., not signed in).
  */
+@NullMarked
 public class BookmarkPromoHeader
         implements SyncService.SyncStateChangedListener,
                 SignInStateObserver,
@@ -60,7 +64,7 @@
         mProfile = profile;
         mPromoHeaderChangeAction = promoHeaderChangeAction;
         mSyncService = SyncServiceFactory.getForProfile(profile);
-        mSigninManager = IdentityServicesProvider.get().getSigninManager(mProfile);
+        mSigninManager = assertNonNull(IdentityServicesProvider.get().getSigninManager(mProfile));
         mAccountManagerFacade = AccountManagerFacadeProvider.getInstance();
 
         AccountPickerBottomSheetStrings bottomSheetStrings =
@@ -85,7 +89,7 @@
         mSigninManager.addSignInStateObserver(this);
         if (mSyncPromoController != null) {
             mAccountManagerFacade.addObserver(this);
-            mProfileDataCache.addObserver(this);
+            assumeNonNull(mProfileDataCache).addObserver(this);
         }
 
         updatePromoState();
@@ -97,7 +101,7 @@
 
         if (mSyncPromoController != null) {
             mAccountManagerFacade.removeObserver(this);
-            mProfileDataCache.removeObserver(this);
+            assumeNonNull(mProfileDataCache).removeObserver(this);
         }
 
         mSigninManager.removeSignInStateObserver(this);
@@ -123,6 +127,8 @@
 
     /** Sets up the sync promo view. */
     void setUpSyncPromoView(PersonalizedSigninPromoView view) {
+        assumeNonNull(mSyncPromoController);
+        assumeNonNull(mProfileDataCache);
         mSyncPromoController.setUpSyncPromoView(
                 mProfileDataCache, view, this::setPersonalizedSigninPromoDeclined);
     }
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowProperties.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowProperties.java
index a00a24c..6a204d7 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowProperties.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowProperties.java
@@ -5,12 +5,14 @@
 package org.chromium.chrome.browser.bookmarks;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
 
 /** Responsible for hosting properties for {@link BookmarkSearchBoxRow}. */
+@NullMarked
 class BookmarkSearchBoxRowProperties {
     public static final ReadableObjectPropertyKey<Callback<String>> SEARCH_TEXT_CHANGE_CALLBACK =
             new ReadableObjectPropertyKey<>();
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowViewBinder.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowViewBinder.java
index 8f7ce0e28..f2bb7fe 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowViewBinder.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchBoxRowViewBinder.java
@@ -10,6 +10,7 @@
 import androidx.annotation.StringRes;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.components.browser_ui.widget.chips.ChipView;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -17,6 +18,7 @@
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
 
 /** Binds model properties to view methods for {@link BookmarkSearchBoxRow}. */
+@NullMarked
 class BookmarkSearchBoxRowViewBinder {
     public static ViewBinder<PropertyModel, View, PropertyKey> createViewBinder() {
         return new BookmarkSearchBoxRowViewBinder()::bind;
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUiObserver.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUiObserver.java
index 1e51fc7..babc8af1 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUiObserver.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUiObserver.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.bookmarks;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.bookmarks.BookmarkUiState.BookmarkUiMode;
 import org.chromium.components.bookmarks.BookmarkId;
 
@@ -21,7 +22,7 @@
     /**
      * @see BookmarkDelegate#openFolder(BookmarkId)
      */
-    default void onFolderStateSet(BookmarkId folder) {}
+    default void onFolderStateSet(@Nullable BookmarkId folder) {}
 
     /** Called when the bookmark UI mode changes. */
     default void onUiModeChanged(@BookmarkUiMode int mode) {}
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkQueryHandler.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkQueryHandler.java
index 309b6808..24e78ba0 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkQueryHandler.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkQueryHandler.java
@@ -190,7 +190,7 @@
         if (!PowerBookmarkUtils.isShoppingListItem(mShoppingService, meta)) return false;
         return mShoppingService.isSubscribedFromCache(
                 PowerBookmarkUtils.createCommerceSubscriptionForShoppingSpecifics(
-                        assumeNonNull(meta).getShoppingSpecifics()));
+                        meta.getShoppingSpecifics()));
     }
 
     private List<BookmarkListEntry> collectLeafNodes(BookmarkId parentId) {
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java
index 785075192..cd13b88 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowCoordinator.java
@@ -4,12 +4,15 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.Pair;
 
 import org.chromium.base.supplier.LazyOneshotSupplier;
 import org.chromium.base.supplier.LazyOneshotSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.bookmarks.BookmarkUiPrefs.BookmarkRowDisplayPref;
 import org.chromium.chrome.browser.bookmarks.ImprovedBookmarkRowProperties.ImageVisibility;
 import org.chromium.components.bookmarks.BookmarkId;
@@ -23,6 +26,7 @@
 import java.util.Objects;
 
 /** Business logic for the improved bookmark row. */
+@NullMarked
 public class ImprovedBookmarkRowCoordinator {
     private final Context mContext;
     private final BookmarkImageFetcher mBookmarkImageFetcher;
@@ -59,7 +63,7 @@
     /** Sets the given bookmark id. */
     public PropertyModel createBasePropertyModel(BookmarkId bookmarkId) {
         PropertyModel propertyModel = new PropertyModel(ImprovedBookmarkRowProperties.ALL_KEYS);
-        BookmarkItem bookmarkItem = mBookmarkModel.getBookmarkById(bookmarkId);
+        BookmarkItem bookmarkItem = assumeNonNull(mBookmarkModel.getBookmarkById(bookmarkId));
         PowerBookmarkMeta meta = mBookmarkModel.getPowerBookmarkMeta(bookmarkId);
         final @BookmarkRowDisplayPref int displayPref =
                 mBookmarkUiPrefs.getBookmarkRowDisplayPref();
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java
index 43a6054..d6f36e9 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowProperties.java
@@ -12,6 +12,7 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.base.supplier.LazyOneshotSupplier;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.listmenu.ListMenuDelegate;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -24,6 +25,7 @@
 import java.util.function.BooleanSupplier;
 
 /** Responsible for hosting properties of the improved bookmark row. */
+@NullMarked
 public class ImprovedBookmarkRowProperties {
     @IntDef({
         ImageVisibility.DRAWABLE,
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java
index 9e014fff..d2493a8 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowViewBinder.java
@@ -6,6 +6,7 @@
 
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.bookmarks.ImprovedBookmarkRowProperties.ImageVisibility;
 import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter;
 import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightParams;
@@ -14,6 +15,7 @@
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Binds model properties to view methods for ImprovedBookmarkRow. */
+@NullMarked
 public class ImprovedBookmarkRowViewBinder {
     public static void bind(PropertyModel model, View view, PropertyKey key) {
         ImprovedBookmarkRow row = (ImprovedBookmarkRow) view;
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java
index 896881a8..ed811d0 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java
@@ -11,6 +11,7 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.Contract;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.commerce.PriceTrackingUtils;
@@ -40,6 +41,7 @@
     private static @Nullable PowerBookmarkMeta sPowerBookmarkMetaForTesting;
 
     /** Returns whether the given meta is a shopping list item. */
+    @Contract("_, null -> false")
     public static boolean isShoppingListItem(
             ShoppingService shoppingService, @Nullable PowerBookmarkMeta meta) {
         return CommerceFeatureUtils.isShoppingListEligible(shoppingService)
diff --git a/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerTest.java b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerTest.java
index 40d3e38b..baddb74 100644
--- a/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerTest.java
+++ b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerTest.java
@@ -28,7 +28,6 @@
 import org.chromium.base.test.util.UserActionTester;
 import org.chromium.chrome.browser.app.bookmarks.BookmarkActivity;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.ui.signin.signin_promo.SigninPromoCoordinator;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.R;
@@ -62,14 +61,12 @@
     private BookmarkManagerCoordinator mBookmarkManagerCoordinator;
     private RecyclerView mItemsContainer;
 
-    private TabModelSelector mTabModelSelector;
     private UserActionTester mActionTester;
 
     @Before
     public void setUp() {
         mActivityTestRule.startOnBlankPage();
         mActionTester = new UserActionTester();
-        mTabModelSelector = mActivityTestRule.getActivity().getTabModelSelectorSupplier().get();
 
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
diff --git a/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java b/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java
index 4dbf0f1..42fd9a5 100644
--- a/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java
+++ b/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java
@@ -29,8 +29,6 @@
 import static org.chromium.ui.test.util.MockitoHelper.doCallback;
 import static org.chromium.ui.test.util.MockitoHelper.doRunnable;
 
-import static java.util.Map.entry;
-
 import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
@@ -1719,7 +1717,7 @@
                         eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
                         any(Callback.class));
         mMediator
-                .getBatchUploadCardCoordinator()
+                .getBatchUploadCardCoordinatorForTesting()
                 .immediatelyHideBatchUploadCardAndUpdateItsVisibility();
 
         mBookmarkUiPrefs.setBookmarkRowSortOrder(BookmarkRowSortOrder.ALPHABETICAL);
@@ -1792,7 +1790,7 @@
                         eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
                         any(Callback.class));
         mMediator
-                .getBatchUploadCardCoordinator()
+                .getBatchUploadCardCoordinatorForTesting()
                 .immediatelyHideBatchUploadCardAndUpdateItsVisibility();
 
         mBookmarkUiPrefs.setBookmarkRowSortOrder(BookmarkRowSortOrder.ALPHABETICAL);
@@ -1867,7 +1865,7 @@
                         eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
                         any(Callback.class));
         mMediator
-                .getBatchUploadCardCoordinator()
+                .getBatchUploadCardCoordinatorForTesting()
                 .immediatelyHideBatchUploadCardAndUpdateItsVisibility();
 
         mBookmarkUiPrefs.setBookmarkRowSortOrder(BookmarkRowSortOrder.ALPHABETICAL);
diff --git a/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/FakeBookmarkModel.java b/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/FakeBookmarkModel.java
index 0f7cb4cd..7a31dd9 100644
--- a/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/FakeBookmarkModel.java
+++ b/chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/FakeBookmarkModel.java
@@ -30,10 +30,10 @@
     public static final String OTHER_FOLDER_TITLE = "Other bookmarks";
     public static final String DESKTOP_FOLDER_TITLE = "Bookmarks bar";
     public static final String MOBILE_FOLDER_TITLE = "Mobile bookmarks";
-    public static final String PARTNER_FOLDER_TITLE = "Parter bookmarks";
+    public static final String PARTNER_FOLDER_TITLE = "Partner bookmarks";
     public static final String READING_LIST_FOLDER_TITLE = "Reading list";
 
-    // Factory constructor for the FakeBoomkarkModel
+    // Factory constructor for the FakeBookmarkModel
     public static FakeBookmarkModel createModel() {
         // Temporary Jni mock.
         BookmarkBridgeJni.setInstanceForTesting(Mockito.mock(BookmarkBridge.Natives.class));
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 2bf81f9..a0d0581a 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -24,6 +24,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/thread_pool.h"
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 269c68d..c7c59fa 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -122,6 +122,7 @@
 #include "third_party/blink/public/common/origin_trials/origin_trials_settings_provider.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/color/color_provider_manager.h"
+#include "ui/gl/gl_switches.h"
 
 // Per-platform #include blocks, in alphabetical order.
 
@@ -1081,6 +1082,10 @@
     command_line->AppendSwitch(net::kRemoveWhitespaceForDataURLs);
   }
 
+  if (local_state->GetBoolean(prefs::kEnableUnsafeSwiftShader)) {
+    command_line->AppendSwitch(switches::kEnableUnsafeSwiftShader);
+  }
+
 #if BUILDFLAG(IS_ANDROID)
   // The admin should also be able to use these policies to force Site Isolation
   // off (on Android; using enterprise policies to disable Site Isolation is not
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 4aeb3fd..1a845e2a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -32,6 +32,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
@@ -1407,6 +1408,7 @@
   registry->RegisterIntegerPref(prefs::kSCTAuditingHashdanceReportCount, 0);
   registry->RegisterBooleanPref(prefs::kDataURLWhitespacePreservationEnabled,
                                 true);
+  registry->RegisterBooleanPref(prefs::kEnableUnsafeSwiftShader, false);
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
   registry->RegisterBooleanPref(prefs::kOutOfProcessSystemDnsResolutionEnabled,
                                 true);
diff --git a/chrome/browser/chromeos/app_mode/kiosk_browser_session_unittest.cc b/chrome/browser/chromeos/app_mode/kiosk_browser_session_unittest.cc
index bf3a198..f3a5485a3b 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_browser_session_unittest.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_browser_session_unittest.cc
@@ -26,6 +26,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/json/values_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java
index e832b6b..57f374bb 100644
--- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java
+++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/PageInfoStoreInfoViewTest.java
@@ -24,7 +24,6 @@
 import androidx.test.filters.MediumTest;
 
 import org.junit.Before;
-import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,9 +48,10 @@
 import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.R;
-import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
+import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule;
+import org.chromium.chrome.test.transit.ChromeTransitTestRules;
+import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.components.commerce.core.ShoppingService;
 import org.chromium.components.commerce.core.ShoppingService.MerchantInfo;
@@ -69,15 +69,11 @@
 @Restriction({DeviceFormFactor.PHONE})
 @Batch(Batch.PER_CLASS)
 public class PageInfoStoreInfoViewTest {
-    @ClassRule
-    public static final ChromeTabbedActivityTestRule sActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     @Rule
-    public final BlankCTATabInitialStateRule mInitialStateRule =
-            new BlankCTATabInitialStateRule(sActivityTestRule, false);
+    public final AutoResetCtaTransitTestRule mActivityTestRule =
+            ChromeTransitTestRules.fastAutoResetCtaActivityRule();
 
     @Rule
     public ChromeRenderTestRule mRenderTestRule =
@@ -90,17 +86,20 @@
 
     private final MerchantInfo mFakeMerchantTrustSignals =
             new MerchantInfo(4.5f, 100, new GURL("http://fake/url"), false, 0f, false, false);
+    private WebPageStation mPage;
 
     @Before
     public void setUp() {
         ShoppingServiceFactory.setShoppingServiceForTesting(mMockShoppingService);
         doReturn(true).when(mMockShoppingService).isMerchantViewerEnabled();
+
+        mPage = mActivityTestRule.startOnBlankPage();
     }
 
     // dialogCheck ensures that a dialog is in focus when checking the view. If not
     // used it can cause flakiness issues for apis >= 30.
     private void openPageInfoFromStoreIcon(boolean fromStoreIcon, boolean dialogCheck) {
-        ChromeActivity activity = sActivityTestRule.getActivity();
+        ChromeActivity activity = mActivityTestRule.getActivity();
         Tab tab = activity.getActivityTab();
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
diff --git a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java
index f0dc769..220a632 100644
--- a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java
+++ b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java
@@ -13,7 +13,6 @@
 
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,8 +29,9 @@
 import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge;
 import org.chromium.chrome.browser.sync.SyncServiceFactory;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
+import org.chromium.chrome.test.transit.ChromeTransitTestRules;
+import org.chromium.chrome.test.transit.ReusedCtaTransitTestRule;
+import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.components.sync.DataType;
 import org.chromium.components.sync.SyncService;
@@ -42,15 +42,11 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.PER_CLASS)
 public class PriceTrackingFeaturesTest {
-    @ClassRule
-    public static ChromeTabbedActivityTestRule sActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     @Rule
-    public BlankCTATabInitialStateRule mInitialStateRule =
-            new BlankCTATabInitialStateRule(sActivityTestRule, false);
+    public ReusedCtaTransitTestRule<WebPageStation> mActivityTestRule =
+            ChromeTransitTestRules.blankPageStartReusedActivityRule();
 
     @Mock private IdentityManager mIdentityManagerMock;
 
@@ -60,6 +56,8 @@
 
     @Before
     public void setUp() throws Exception {
+        mActivityTestRule.start();
+
         IdentityServicesProvider.setInstanceForTests(mIdentityServicesProviderMock);
         when(mIdentityServicesProviderMock.getIdentityManager(any(Profile.class)))
                 .thenReturn(mIdentityManagerMock);
diff --git a/chrome/browser/content_index/content_index_provider_impl.cc b/chrome/browser/content_index/content_index_provider_impl.cc
index 0f3f9d2f..f517f09 100644
--- a/chrome/browser/content_index/content_index_provider_impl.cc
+++ b/chrome/browser/content_index/content_index_provider_impl.cc
@@ -8,6 +8,7 @@
 #include <string_view>
 
 #include "base/barrier_closure.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/chrome/browser/data_sharing/desktop/data_sharing_sdk_delegate_desktop.cc b/chrome/browser/data_sharing/desktop/data_sharing_sdk_delegate_desktop.cc
index 807f87f..6f9f880 100644
--- a/chrome/browser/data_sharing/desktop/data_sharing_sdk_delegate_desktop.cc
+++ b/chrome/browser/data_sharing/desktop/data_sharing_sdk_delegate_desktop.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/data_sharing/desktop/data_sharing_sdk_delegate_desktop.h"
 
+#include "base/notimplemented.h"
 #include "chrome/browser/data_sharing/desktop/data_sharing_conversion_utils.h"
 #include "chrome/browser/ui/webui/data_sharing/data_sharing_page_handler.h"
 #include "chrome/common/webui_url_constants.h"
diff --git a/chrome/browser/device_reauth/win/device_authenticator_win.cc b/chrome/browser/device_reauth/win/device_authenticator_win.cc
index 3ad95a22..8b4781d 100644
--- a/chrome/browser/device_reauth/win/device_authenticator_win.cc
+++ b/chrome/browser/device_reauth/win/device_authenticator_win.cc
@@ -8,7 +8,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/devtools/device/usb/android_usb_socket.cc b/chrome/browser/devtools/device/usb/android_usb_socket.cc
index 9b50bed..a7b903e93 100644
--- a/chrome/browser/devtools/device/usb/android_usb_socket.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_socket.cc
@@ -13,7 +13,7 @@
 
 #include "base/check_op.h"
 #include "base/functional/callback_helpers.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_address.h"
 #include "net/base/net_errors.h"
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 67a1711..c4d332c 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -25,6 +25,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/escape.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index c291f8d..22f0b02 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -19,6 +19,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/strings/escape.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/chrome/browser/devtools/devtools_window_android.cc b/chrome/browser/devtools/devtools_window_android.cc
index 8a065ae..3eeff6a 100644
--- a/chrome/browser/devtools/devtools_window_android.cc
+++ b/chrome/browser/devtools/devtools_window_android.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/devtools/devtools_window.h"
 
+#include "base/notimplemented.h"
 #include "content/public/browser/keyboard_event_processing_result.h"
 
 using content::WebContents;
diff --git a/chrome/browser/download/download_crx_util.cc b/chrome/browser/download/download_crx_util.cc
index 1a19814..67154ea 100644
--- a/chrome/browser/download/download_crx_util.cc
+++ b/chrome/browser/download/download_crx_util.cc
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/auto_reset.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc
index ee96d2b9..75882f7 100644
--- a/chrome/browser/download/download_offline_content_provider.cc
+++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -11,6 +11,7 @@
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/download/offline_item_model.cc b/chrome/browser/download/offline_item_model.cc
index 8001c4e6..47beaac 100644
--- a/chrome/browser/download/offline_item_model.cc
+++ b/chrome/browser/download/offline_item_model.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc
index 29f1ac1..107a8ac8 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_info.cc
@@ -50,20 +50,14 @@
 }
 
 std::optional<size_t> GetUserIndex(const GURL& url) {
-  const re2::RE2 kUserPathRegex{"/u/\\d+/"};
+  const re2::RE2 kUserPathRegex{"/u/(\\d+)/"};
 
   int account_id = 0;
-  std::string account_id_str;
-
-  if (re2::RE2::PartialMatch(url.path_piece(), kUserPathRegex,
-                             &account_id_str)) {
-    // Remove the leading "/u/" and the trailing "/".
-    if (base::StringToInt(account_id_str.substr(3, account_id_str.size() - 4),
-                          &account_id)) {
-      return account_id;
-    }
+  if (re2::RE2::PartialMatch(url.path_piece(), kUserPathRegex, &account_id)) {
+    return account_id;
   }
 
+  std::string account_id_str;
   if (net::GetValueForKeyInQuery(url, "authuser", &account_id_str) &&
       base::StringToInt(account_id_str, &account_id)) {
     return account_id;
diff --git a/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc b/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc
index 1591eae..64a92f3d 100644
--- a/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc
+++ b/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc
@@ -51,6 +51,7 @@
 #include "base/win/scoped_hstring.h"
 #include "chrome/browser/enterprise/platform_auth/cloud_ap_utils_win.h"
 #include "chrome/browser/enterprise/platform_auth/platform_auth_features.h"
+#include "components/policy/core/common/policy_logger.h"
 #include "net/cookies/cookie_util.h"
 #include "net/http/http_request_headers.h"
 #include "url/gurl.h"
@@ -198,6 +199,11 @@
   for (DWORD i = 0; i < cookie_info_count; ++i) {
     const ProofOfPossessionCookieInfo& cookie = cookie_info[i];
     auto ascii_cookie_name = base::WideToASCII(cookie.name);
+    // TODO(b/425887809): Remove after debugging.
+    VLOG_POLICY(1, EXTENSIBLE_SSO)
+        << "[CloudAPAuthEnabled] Fetched cookie with name " << ascii_cookie_name
+        << " and size " << wcslen(cookie.data);
+
     if (base::StartsWith(ascii_cookie_name, kHeaderPrefix,
                          base::CompareCase::INSENSITIVE_ASCII)) {
       // Removing cookie attributes from the value before setting it as a
@@ -256,11 +262,18 @@
     base::UmaHistogramExactLinear("Enterprise.PlatformAuth.GetAuthData.Count",
                                   cookie_info_count,
                                   10);  // Expect < 10 cookies.
+    // TODO(b/425887809): Remove after debugging.
+    VLOG_POLICY(1, EXTENSIBLE_SSO)
+        << "[CloudAPAuthEnabled] Successfully fetched " << cookie_info_count
+        << " cookies.";
   } else {
     base::UmaHistogramTimes("Enterprise.PlatformAuth.GetAuthData.FailureTime",
                             delta);
     base::UmaHistogramSparse(
         "Enterprise.PlatformAuth.GetAuthData.FailureHresult", int{hresult});
+    // TODO(b/425887809): Remove after debugging.
+    VLOG_POLICY(1, EXTENSIBLE_SSO)
+        << "[CloudAPAuthEnabled] Failed to fetch cookies.";
   }
 
   return auth_headers;
diff --git a/chrome/browser/enterprise/watermark/BUILD.gn b/chrome/browser/enterprise/watermark/BUILD.gn
index e5257d9..b45b254 100644
--- a/chrome/browser/enterprise/watermark/BUILD.gn
+++ b/chrome/browser/enterprise/watermark/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "settings.cc",
     "settings.h",
+    "watermark_features.cc",
+    "watermark_features.h",
     "watermark_style_policy_handler.cc",
     "watermark_style_policy_handler.h",
     "watermark_view.cc",
diff --git a/chrome/browser/enterprise/watermark/watermark_features.cc b/chrome/browser/enterprise/watermark/watermark_features.cc
new file mode 100644
index 0000000..3a5d49b
--- /dev/null
+++ b/chrome/browser/enterprise/watermark/watermark_features.cc
@@ -0,0 +1,13 @@
+// Copyright 2025 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/enterprise/watermark/watermark_features.h"
+
+namespace enterprise_watermark {
+
+BASE_FEATURE(kEnableWatermarkCustomization,
+             "EnableWatermarkCustomization",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace enterprise_watermark
diff --git a/chrome/browser/enterprise/watermark/watermark_features.h b/chrome/browser/enterprise/watermark/watermark_features.h
new file mode 100644
index 0000000..44301729
--- /dev/null
+++ b/chrome/browser/enterprise/watermark/watermark_features.h
@@ -0,0 +1,16 @@
+// Copyright 2025 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_ENTERPRISE_WATERMARK_WATERMARK_FEATURES_H_
+#define CHROME_BROWSER_ENTERPRISE_WATERMARK_WATERMARK_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace enterprise_watermark {
+
+BASE_DECLARE_FEATURE(kEnableWatermarkCustomization);
+
+}  // namespace enterprise_watermark
+
+#endif  // CHROME_BROWSER_ENTERPRISE_WATERMARK_WATERMARK_FEATURES_H_
diff --git a/chrome/browser/extensions/api/BUILD.gn b/chrome/browser/extensions/api/BUILD.gn
index 57201c94..de2fcefc 100644
--- a/chrome/browser/extensions/api/BUILD.gn
+++ b/chrome/browser/extensions/api/BUILD.gn
@@ -41,6 +41,7 @@
     "//chrome/browser/extensions/api/reading_list",
     "//chrome/browser/extensions/api/runtime",
     "//chrome/browser/extensions/api/scripting",
+    "//chrome/browser/extensions/api/webrtc_logging_private",
   ]
 
   if (enable_extensions) {
@@ -73,7 +74,6 @@
       "//chrome/browser/extensions/api/web_view",
       "//chrome/browser/extensions/api/webrtc_audio_private",
       "//chrome/browser/extensions/api/webrtc_desktop_capture_private",
-      "//chrome/browser/extensions/api/webrtc_logging_private",
     ]
 
     if (enable_pdf) {
diff --git a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
index 9164975..5e00cb7 100644
--- a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
+++ b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <string>
 
+#include "base/notimplemented.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
diff --git a/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc b/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc
index d118fa23..9e41823 100644
--- a/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc
+++ b/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc
@@ -8,7 +8,7 @@
 
 #include "base/check.h"
 #include "base/containers/contains.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/api/document_scan/document_scan_test_utils.h"
 
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
index 0dad0ff5..1feb567 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
index 98cd5f0..6e92545 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc
index b8835f2..023d5a9 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -10,7 +10,7 @@
 #include "base/auto_reset.h"
 #include "base/check_is_test.h"
 #include "base/functional/bind.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.cc b/chrome/browser/extensions/api/sessions/sessions_api.cc
index 25c3c2d..4e479397 100644
--- a/chrome/browser/extensions/api/sessions/sessions_api.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_api.cc
@@ -15,6 +15,7 @@
 #include "base/i18n/rtl.h"
 #include "base/lazy_instance.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
index 057129e9..2d93237 100644
--- a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
@@ -7,16 +7,18 @@
 #pragma allow_unsafe_libc_calls
 #endif
 
+#include "extensions/browser/api/socket/tcp_socket.h"
+
 #include <memory>
 
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/test/bind.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/test/test_storage_partition.h"
-#include "extensions/browser/api/socket/tcp_socket.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/address_list.h"
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/BUILD.gn b/chrome/browser/extensions/api/webrtc_logging_private/BUILD.gn
index f937f1e9..9f02ae9 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/BUILD.gn
+++ b/chrome/browser/extensions/api/webrtc_logging_private/BUILD.gn
@@ -4,8 +4,8 @@
 
 import("//extensions/buildflags/buildflags.gni")
 
-assert(enable_extensions,
-       "Cannot depend on extensions because enable_extensions=false.")
+assert(enable_extensions_core,
+       "Cannot depend on extensions because enable_extensions_core=false.")
 
 source_set("webrtc_logging_private") {
   sources = [
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
index 78631c36..c892073 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
@@ -18,26 +18,30 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
+#include "components/guest_view/buildflags/buildflags.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
-#include "extensions/browser/guest_view/web_view/web_view_guest.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/common/error_utils.h"
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
 #include "extensions/common/permissions/permissions_data.h"
 #endif
 
+#if BUILDFLAG(ENABLE_GUEST_VIEW)
+#include "extensions/browser/guest_view/web_view/web_view_guest.h"
+#endif
+
 namespace {
 
 bool CanEnableAudioDebugRecordingsFromExtension(
     const extensions::Extension* extension) {
   bool enabled_by_permissions = false;
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
   if (extension) {
     enabled_by_permissions =
         extension->permissions_data()->active_permissions().HasAPIPermission(
@@ -99,7 +103,7 @@
   //  2. From an allowlisted app that hosts a page in a webview. In this case,
   //  the app should call these API functions with the |target_webview| flag
   //  set, from a web contents that has exactly 1 webview .
-
+#if BUILDFLAG(ENABLE_GUEST_VIEW)
   // If |target_webview| is set, lookup the guest content's render process in
   // the sender's web contents. There should be exactly 1 guest.
   if (request.target_webview && *request.target_webview) {
@@ -131,6 +135,7 @@
     }
     return target_host;
   }
+#endif  // BUILDFLAG(ENABLE_GUEST_VIEW)
 
   // If |guest_process_id| is defined, directly use this id to find the
   // corresponding RenderProcessHost.
@@ -575,7 +580,7 @@
 
 ExtensionFunction::ResponseAction
 WebrtcLoggingPrivateGetLogsDirectoryFunction::Run() {
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
   // Unlike other WebrtcLoggingPrivate functions that take a RequestInfo object,
   // this function shouldn't be called by a component extension on behalf of
   // some web code. It returns a DirectoryEntry for use directly in the calling
@@ -598,9 +603,9 @@
           &WebrtcLoggingPrivateGetLogsDirectoryFunction::FireErrorCallback,
           this));
   return RespondLater();
-#else   // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#else
   return RespondNow(Error("Not supported on the current OS"));
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#endif
 }
 
 void WebrtcLoggingPrivateGetLogsDirectoryFunction::FireCallback(
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
index 773d69cf..35f0285 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
@@ -11,8 +11,11 @@
 #include "chrome/browser/media/webrtc/webrtc_logging_controller.h"
 #include "chrome/common/extensions/api/webrtc_logging_private.h"
 #include "extensions/browser/extension_function.h"
+#include "extensions/buildflags/buildflags.h"
 #include "media/media_buildflags.h"
 
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace content {
 
 class RenderProcessHost;
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index 60d41ad6..a7b122b 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -19,6 +19,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/scoped_multi_source_observation.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc
index 0b166811..69c0c5a 100644
--- a/chrome/browser/extensions/extension_action_runner.cc
+++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -15,6 +15,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/extensions/extension_action_dispatcher.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index 41d0ea2c..d9db094 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -9,6 +9,7 @@
 
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 16241f3..da6569a7 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -12,6 +12,7 @@
 #include <optional>
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/window_controller_list.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc
index 7de711c9..2936942 100644
--- a/chrome/browser/extensions/install_verifier.cc
+++ b/chrome/browser/extensions/install_verifier.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/one_shot_event.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
diff --git a/chrome/browser/extensions/system_display/display_info_provider_mac.cc b/chrome/browser/extensions/system_display/display_info_provider_mac.cc
index 6bd4baf4..54e1c4b 100644
--- a/chrome/browser/extensions/system_display/display_info_provider_mac.cc
+++ b/chrome/browser/extensions/system_display/display_info_provider_mac.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/system_display/display_info_provider_mac.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/extensions/system_display/display_info_provider.h"
 
 namespace extensions {
diff --git a/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.cc b/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.cc
index 6a81a69..8e70758 100644
--- a/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.cc
+++ b/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.cc
@@ -38,7 +38,8 @@
                       /* client= */ this),
       facilitated_payments_controller_(
           std::make_unique<FacilitatedPaymentsController>(web_contents)),
-      optimization_guide_decider_(optimization_guide_decider) {
+      optimization_guide_decider_(optimization_guide_decider),
+      device_delegate_(web_contents) {
   RegisterAllowlists();
 }
 
@@ -122,6 +123,11 @@
   return optimization_guide_decider_;
 }
 
+payments::facilitated::DeviceDelegate*
+ChromeFacilitatedPaymentsClient::GetDeviceDelegate() {
+  return &device_delegate_;
+}
+
 void ChromeFacilitatedPaymentsClient::ShowPixPaymentPrompt(
     base::span<const autofill::BankAccount> bank_account_suggestions,
     base::OnceCallback<void(int64_t)> on_payment_account_selected) {
@@ -173,10 +179,6 @@
   return autofill::StrikeDatabaseFactory::GetForProfile(profile);
 }
 
-bool ChromeFacilitatedPaymentsClient::IsPixAccountLinkingSupported() const {
-  return payments::facilitated::IsWalletEligibleForPixAccountLinking();
-}
-
 void ChromeFacilitatedPaymentsClient::ShowPixAccountLinkingPrompt(
     base::OnceCallback<void()> on_accepted,
     base::OnceCallback<void()> on_declined) {
@@ -184,11 +186,6 @@
       std::move(on_accepted), std::move(on_declined));
 }
 
-void ChromeFacilitatedPaymentsClient::OnPixAccountLinkingPromptAccepted() {
-  // TODO(crbug.com/419108993): Add metrics.
-  payments::facilitated::OpenPixAccountLinkingPageInWallet(&GetWebContents());
-}
-
 void ChromeFacilitatedPaymentsClient::RegisterAllowlists() {
   if (optimization_guide_decider_) {
     if (base::FeatureList::IsEnabled(payments::facilitated::kEwalletPayments)) {
diff --git a/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.h b/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.h
index 13a7302..a7cdf48a 100644
--- a/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.h
+++ b/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client.h
@@ -8,6 +8,7 @@
 #include "base/containers/span.h"
 #include "base/functional/callback_forward.h"
 #include "chrome/browser/facilitated_payments/ui/android/facilitated_payments_controller.h"
+#include "components/facilitated_payments/android/device_delegate_android.h"
 #include "components/facilitated_payments/content/browser/content_facilitated_payments_driver_factory.h"
 #include "components/facilitated_payments/core/browser/facilitated_payments_client.h"
 #include "components/facilitated_payments/core/browser/network_api/multiple_request_facilitated_payments_network_interface.h"
@@ -73,6 +74,7 @@
   bool IsFoldable() final;
   optimization_guide::OptimizationGuideDecider* GetOptimizationGuideDecider()
       final;
+  payments::facilitated::DeviceDelegate* GetDeviceDelegate() final;
   void ShowPixPaymentPrompt(
       base::span<const autofill::BankAccount> bank_account_suggestions,
       base::OnceCallback<void(int64_t)> on_payment_account_selected) final;
@@ -86,11 +88,9 @@
       base::RepeatingCallback<void(payments::facilitated::UiEvent)>
           ui_event_listener) final;
   autofill::StrikeDatabase* GetStrikeDatabase() final;
-  bool IsPixAccountLinkingSupported() const final;
   void ShowPixAccountLinkingPrompt(
       base::OnceCallback<void()> on_accepted,
       base::OnceCallback<void()> on_declined) final;
-  void OnPixAccountLinkingPromptAccepted() final;
 
   // Register any allowlists with the OptimizationGuide framework, so that
   // individual features can later request to check whether the current main
@@ -114,6 +114,8 @@
   raw_ptr<optimization_guide::OptimizationGuideDecider>
       optimization_guide_decider_ = nullptr;
 
+  payments::facilitated::DeviceDelegateAndroid device_delegate_;
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
 
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index 8228931..e0a1584 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -414,7 +414,8 @@
 
     if (!chrome_prefs::InitializePrefsFromMasterPrefs(
             profiles::GetDefaultProfileDir(user_data_dir),
-            std::move(initial_dictionary))) {
+            std::move(initial_dictionary),
+            g_browser_process->os_crypt_async())) {
       DLOG(ERROR) << "Failed to initialize from initial preferences.";
     }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index fe37593..49afe15 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3962,6 +3962,14 @@
     "expiry_milestone": 98
   },
   {
+    "name": "enable-ntp-browser-promos",
+    "owners": [
+      "cjgrant@chromium.org",
+      "dfried@chromium.org"
+    ],
+    "expiry_milestone": 146
+  },
+  {
     "name": "enable-oauth-ipp",
     "owners": [ "pawliczek@chromium.org", "project-bolton@google.com" ],
     "expiry_milestone": 145
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index a0ab93d..38f44ab 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1897,6 +1897,14 @@
 const char kEnableLazyLoadImageForInvisiblePageDescription[] =
     "Respect the loading = lazy attribute for images even on invisible pages.";
 
+#if !BUILDFLAG(IS_ANDROID)
+const char kEnableNtpBrowserPromosName[] =
+    "Enable new tab page browser feature suggestions";
+const char kEnableNtpBrowserPromosDescription[] =
+    "Shows suggestions to explore browser capabilities (eg. signing in) on the "
+    "new tab page.";
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 const char kSoftNavigationHeuristicsName[] = "Soft Navigation Heuristics";
 const char kSoftNavigationHeuristicsDescription[] =
     "Enables the soft navigation heuristics, including support for "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 72b487c..e7baf99 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -333,7 +333,7 @@
 
 extern const char kClearInstanceInfoWhenClosedIntentionallyName[];
 extern const char kClearInstanceInfoWhenClosedIntentionallyDescription[];
-#endif  // !BUILDFLAG(IS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 extern const char kEnableBenchmarkingName[];
 extern const char kEnableBenchmarkingDescription[];
@@ -347,6 +347,11 @@
 extern const char kEnableLazyLoadImageForInvisiblePageName[];
 extern const char kEnableLazyLoadImageForInvisiblePageDescription[];
 
+#if !BUILDFLAG(IS_ANDROID)
+extern const char kEnableNtpBrowserPromosName[];
+extern const char kEnableNtpBrowserPromosDescription[];
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 extern const char kSoftNavigationHeuristicsName[];
 extern const char kSoftNavigationHeuristicsDescription[];
 
diff --git a/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc b/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc
index 58141f4..bb34fcb 100644
--- a/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc
+++ b/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc
@@ -28,6 +28,7 @@
 #include "components/optimization_guide/proto/features/common_quality_data.pb.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
 #include "ui/base/interaction/element_identifier.h"
 
 namespace glic::test {
@@ -65,6 +66,12 @@
   }
   ~GlicActorControllerUiTest() override = default;
 
+  void SetUpOnMainThread() override {
+    // Add rule for resolving cross origin host names.
+    InteractiveGlicTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
+  }
+
   // Executes a BrowserAction and verifies it succeeds. Optionally takes an
   // error reason which, when provided, causes failure if the action is
   // successful or fails with an unexpected reason.
@@ -263,6 +270,14 @@
     });
   }
 
+  // Returns a callback that builds an encoded proto for a click action on a
+  // specific coordinate
+  ActionProtoProvider ClickActionProvider(const gfx::Point& coordinate) {
+    return base::BindLambdaForTesting([coordinate]() {
+      return EncodeActionProto(actor::MakeClick(coordinate));
+    });
+  }
+
   // Returns a callback that simply encodes the given action.
   ActionProtoProvider PassthroughProvider(const BrowserAction& action) {
     return base::BindLambdaForTesting(
@@ -442,6 +457,44 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicActorControllerUiTest,
+                       ToctouCheckFailWhenCrossOriginTargetFrameChange) {
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kNewActorTabId);
+  const GURL task_url =
+      embedded_test_server()->GetURL("/actor/two_cross_origin_iframes.html");
+  BrowserAction navigate = actor::MakeNavigate(task_url.spec());
+
+  RunTestSequence(
+      InitializeWithOpenGlicWindow(),
+      StartActorTaskInNewTab(task_url, kNewActorTabId),
+      ExecuteAction(ClickActionProvider({10, 10}), UpdatedContextOptions()),
+      GetPageContextFromFocusedTab(),
+      CheckExecutionEngineHasAnnotatedPageContentCache(),
+      ExecuteJs(kNewActorTabId,
+                "()=>{document.getElementById('topframe').remove();}"),
+      ExecuteAction(ClickActionProvider({10, 10}), UpdatedContextOptions(),
+                    glic::mojom::ActInFocusedTabErrorReason::kTargetNotFound));
+}
+
+IN_PROC_BROWSER_TEST_F(GlicActorControllerUiTest,
+                       ToctouCheckFailWhenSameSiteTargetFrameChange) {
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kNewActorTabId);
+  const GURL task_url =
+      embedded_test_server()->GetURL("/actor/two_same_site_iframes.html");
+  BrowserAction navigate = actor::MakeNavigate(task_url.spec());
+
+  RunTestSequence(
+      InitializeWithOpenGlicWindow(),
+      StartActorTaskInNewTab(task_url, kNewActorTabId),
+      ExecuteAction(ClickActionProvider({10, 10}), UpdatedContextOptions()),
+      GetPageContextFromFocusedTab(),
+      CheckExecutionEngineHasAnnotatedPageContentCache(),
+      ExecuteJs(kNewActorTabId,
+                "()=>{document.getElementById('topframe').remove();}"),
+      ExecuteAction(ClickActionProvider({10, 10}), UpdatedContextOptions(),
+                    glic::mojom::ActInFocusedTabErrorReason::kTargetNotFound));
+}
+
+IN_PROC_BROWSER_TEST_F(GlicActorControllerUiTest,
                        UsesExistingActorTabOnSubsequentNavigate) {
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kNewActorTabId);
   const GURL task_url =
diff --git a/chrome/browser/glic/widget/glic_window_controller_impl.cc b/chrome/browser/glic/widget/glic_window_controller_impl.cc
index 238daa5..0a18067 100644
--- a/chrome/browser/glic/widget/glic_window_controller_impl.cc
+++ b/chrome/browser/glic/widget/glic_window_controller_impl.cc
@@ -10,6 +10,7 @@
 #include "base/check_deref.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/glic/browser_ui/scoped_glic_button_indicator.h"
diff --git a/chrome/browser/hang_monitor/hang_crash_dump.cc b/chrome/browser/hang_monitor/hang_crash_dump.cc
index 9831bae..61d763d 100644
--- a/chrome/browser/hang_monitor/hang_crash_dump.cc
+++ b/chrome/browser/hang_monitor/hang_crash_dump.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/hang_monitor/hang_crash_dump.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 void CrashDumpHungChildProcess(base::ProcessHandle handle) {
   NOTIMPLEMENTED();
diff --git a/chrome/browser/icon_loader_android.cc b/chrome/browser/icon_loader_android.cc
index 1c91476..e8d4c12b 100644
--- a/chrome/browser/icon_loader_android.cc
+++ b/chrome/browser/icon_loader_android.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/notreached.h"
 #include "chrome/browser/icon_loader.h"
 
+#include "base/notimplemented.h"
+
 // static
 IconLoader::IconGroup IconLoader::GroupForFilepath(
     const base::FilePath& file_path) {
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc b/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc
index ccf741b4..dcd1d98 100644
--- a/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc
+++ b/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc b/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc
index 3fc97595..68d3ca88 100644
--- a/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc
+++ b/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc
@@ -7,6 +7,7 @@
 #include <inttypes.h>
 
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc b/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc
index 9f338fc..e161fa9 100644
--- a/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc
+++ b/chrome/browser/keyboard_accessory/android/address_accessory_controller_impl.cc
@@ -12,6 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/android/preferences/autofill/settings_navigation_helper.h"
diff --git a/chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.cc b/chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.cc
index 7590ec0..1e0c968c 100644
--- a/chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.cc
+++ b/chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.cc
@@ -14,6 +14,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/memory_allocator_dump.h"
diff --git a/chrome/browser/keyboard_accessory/android/payment_method_accessory_controller_impl.cc b/chrome/browser/keyboard_accessory/android/payment_method_accessory_controller_impl.cc
index d0e97af..9e3a761 100644
--- a/chrome/browser/keyboard_accessory/android/payment_method_accessory_controller_impl.cc
+++ b/chrome/browser/keyboard_accessory/android/payment_method_accessory_controller_impl.cc
@@ -14,6 +14,7 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
diff --git a/chrome/browser/lifetime/browser_shutdown.cc b/chrome/browser/lifetime/browser_shutdown.cc
index 5a016a0..240f564 100644
--- a/chrome/browser/lifetime/browser_shutdown.cc
+++ b/chrome/browser/lifetime/browser_shutdown.cc
@@ -15,6 +15,7 @@
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread.h"
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac.mm b/chrome/browser/local_discovery/service_discovery_client_mac.mm
index 33397a24..bc74381 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac.mm
@@ -23,6 +23,7 @@
 #include "base/mac/mac_util.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/thread.h"
diff --git a/chrome/browser/local_discovery/service_discovery_shared_client.cc b/chrome/browser/local_discovery/service_discovery_shared_client.cc
index 6f37c5b..a946cd5f 100644
--- a/chrome/browser/local_discovery/service_discovery_shared_client.cc
+++ b/chrome/browser/local_discovery/service_discovery_shared_client.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "net/net_buildflags.h"
 
diff --git a/chrome/browser/media/output_protection_proxy.cc b/chrome/browser/media/output_protection_proxy.cc
index a375d42..46acdbb 100644
--- a/chrome/browser/media/output_protection_proxy.cc
+++ b/chrome/browser/media/output_protection_proxy.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/chrome/browser/media/router/discovery/test_support/win/fake_network_adapter.cc b/chrome/browser/media/router/discovery/test_support/win/fake_network_adapter.cc
index 6f603cc..2cb85e70 100644
--- a/chrome/browser/media/router/discovery/test_support/win/fake_network_adapter.cc
+++ b/chrome/browser/media/router/discovery/test_support/win/fake_network_adapter.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/media/router/discovery/test_support/win/fake_network_adapter.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/media/router/discovery/test_support/win/fake_winrt_network_environment.h"
 
 namespace WinrtConnectivity = ABI::Windows::Networking::Connectivity;
diff --git a/chrome/browser/media/router/discovery/test_support/win/fake_network_information_statics.cc b/chrome/browser/media/router/discovery/test_support/win/fake_network_information_statics.cc
index b1073b0..872f281 100644
--- a/chrome/browser/media/router/discovery/test_support/win/fake_network_information_statics.cc
+++ b/chrome/browser/media/router/discovery/test_support/win/fake_network_information_statics.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/media/router/discovery/test_support/win/fake_network_information_statics.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/media/router/discovery/test_support/win/fake_vector_view.h"
 #include "chrome/browser/media/router/discovery/test_support/win/fake_winrt_network_environment.h"
 
diff --git a/chrome/browser/media/router/discovery/test_support/win/fake_vector_view.h b/chrome/browser/media/router/discovery/test_support/win/fake_vector_view.h
index 62d6f0d..54cd7566 100644
--- a/chrome/browser/media/router/discovery/test_support/win/fake_vector_view.h
+++ b/chrome/browser/media/router/discovery/test_support/win/fake_vector_view.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/media/router/discovery/test_support/win/fake_winrt_network_environment.h"
 
 namespace media_router {
diff --git a/chrome/browser/media/router/discovery/test_support/win/fake_winrt_network_environment.cc b/chrome/browser/media/router/discovery/test_support/win/fake_winrt_network_environment.cc
index 76c88f4..69a6f7b8 100644
--- a/chrome/browser/media/router/discovery/test_support/win/fake_winrt_network_environment.cc
+++ b/chrome/browser/media/router/discovery/test_support/win/fake_winrt_network_environment.cc
@@ -6,7 +6,7 @@
 
 #include <tuple>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/win/scoped_hstring.h"
 #include "chrome/browser/media/router/discovery/test_support/win/fake_connection_profile.h"
 #include "chrome/browser/media/router/discovery/test_support/win/fake_network_information_statics.h"
diff --git a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
index 03cf1a2..3db2d1d 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
+++ b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/json/string_escape.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/test/gmock_callback_support.h"
diff --git a/chrome/browser/media/router/providers/cast/cast_activity.cc b/chrome/browser/media/router/providers/cast/cast_activity.cc
index 760b90c..615417e4 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity.cc
@@ -6,6 +6,7 @@
 
 #include "base/containers/contains.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h"
 #include "chrome/browser/media/router/providers/cast/cast_session_client_impl.h"
 #include "components/media_router/common/discovery/media_sink_internal.h"
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
index 49a9cf0..6e2bf03 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
@@ -12,6 +12,7 @@
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_split.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
index a0fa73a1..c33e4780 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
@@ -10,6 +10,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
index 8b0199d..3c18a2b6 100644
--- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
@@ -12,6 +12,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/i18n/number_formatting.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media/router/media_router_feature.h"
diff --git a/chrome/browser/media/webrtc/webrtc_logging_controller.cc b/chrome/browser/media/webrtc/webrtc_logging_controller.cc
index 54414a34..0c9af22 100644
--- a/chrome/browser/media/webrtc/webrtc_logging_controller.cc
+++ b/chrome/browser/media/webrtc/webrtc_logging_controller.cc
@@ -25,10 +25,11 @@
 #include "components/webrtc_logging/browser/text_log_list.h"
 #include "content/public/browser/render_process_host.h"
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
 #include "content/public/browser/child_process_security_policy.h"
 #include "storage/browser/file_system/isolated_context.h"
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
+        // BUILDFLAG(IS_ANDROID)
 
 using webrtc_event_logging::WebRtcEventLogManager;
 
@@ -304,7 +305,7 @@
       web_app_id, callback);
 }
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
 void WebRtcLoggingController::GetLogsDirectory(
     LogsDirectoryCallback callback,
     LogsDirectoryErrorCallback error_callback) {
@@ -350,7 +351,8 @@
       FROM_HERE,
       base::BindOnce(std::move(callback), file_system.id(), registered_name));
 }
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
+        // BUILDFLAG(IS_ANDROID)
 
 void WebRtcLoggingController::OnRtpPacket(
     base::HeapArray<uint8_t> packet_header,
diff --git a/chrome/browser/media/webrtc/webrtc_logging_controller.h b/chrome/browser/media/webrtc/webrtc_logging_controller.h
index 1e97a29..1cb7755 100644
--- a/chrome/browser/media/webrtc/webrtc_logging_controller.h
+++ b/chrome/browser/media/webrtc/webrtc_logging_controller.h
@@ -133,13 +133,13 @@
                          size_t web_app_id,
                          const StartEventLoggingCallback& callback);
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
   // Ensures that the WebRTC Logs directory exists and then grants render
   // process access to the 'WebRTC Logs' directory, and invokes |callback| with
   // the ids necessary to create a DirectoryEntry object.
   void GetLogsDirectory(LogsDirectoryCallback callback,
                         LogsDirectoryErrorCallback error_callback);
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#endif
 
   // chrome::mojom::WebRtcLoggingClient methods:
   void OnAddMessages(
@@ -197,7 +197,7 @@
 
   content::BrowserContext* GetBrowserContext() const;
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
   // Grants the render process access to the 'WebRTC Logs' directory, and
   // invokes |callback| with the ids necessary to create a DirectoryEntry
   // object. If the |logs_path| couldn't be created or found, |error_callback|
@@ -205,7 +205,7 @@
   void GrantLogsDirectoryAccess(LogsDirectoryCallback callback,
                                 LogsDirectoryErrorCallback error_callback,
                                 const base::FilePath& logs_path);
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#endif
 
   static base::FilePath GetLogDirectoryAndEnsureExists(
       const base::FilePath& browser_context_directory_path);
diff --git a/chrome/browser/media/webrtc/window_icon_util_ozone.cc b/chrome/browser/media/webrtc/window_icon_util_ozone.cc
index 57156c59..c16f1dff 100644
--- a/chrome/browser/media/webrtc/window_icon_util_ozone.cc
+++ b/chrome/browser/media/webrtc/window_icon_util_ozone.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/notimplemented.h"
 #include "chrome/browser/media/webrtc/window_icon_util.h"
-
 #include "content/public/browser/desktop_media_id.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/ozone/public/ozone_platform.h"
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
index 52225c1..e57d74e 100644
--- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
@@ -13,6 +13,7 @@
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
index 5abd6ada..9d6d0ef 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -12,6 +12,7 @@
 #include "base/files/safe_base_name.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "components/services/filesystem/public/mojom/types.mojom.h"
 #include "components/storage_monitor/image_capture_device.h"
 #include "components/storage_monitor/image_capture_device_manager.h"
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
index d1b0468..327d474 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -18,6 +18,7 @@
 #include "base/files/safe_base_name.h"
 #include "base/functional/bind.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/metrics/family_link_user_metrics_provider.cc b/chrome/browser/metrics/family_link_user_metrics_provider.cc
index dde73fe..c6906a0 100644
--- a/chrome/browser/metrics/family_link_user_metrics_provider.cc
+++ b/chrome/browser/metrics/family_link_user_metrics_provider.cc
@@ -39,14 +39,10 @@
       continue;
     }
 #endif
-
-    supervised_user::SupervisedUserService* service =
-        SupervisedUserServiceFactory::GetForProfile(profile);
-
     records.push_back(supervised_user::FamilyLinkUserLogRecord::Create(
         IdentityManagerFactory::GetForProfile(profile), *profile->GetPrefs(),
         *HostContentSettingsMapFactory::GetForProfile(profile),
-        service ? service->GetURLFilter() : nullptr));
+        SupervisedUserServiceFactory::GetForProfile(profile)));
   }
   return supervised_user::EmitLogRecordHistograms(records);
 }
diff --git a/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc b/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc
index 6693b1e2..1fbf806 100644
--- a/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/metrics/family_link_user_metrics_provider.h"
 
 #include <string>
+#include <utility>
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -22,6 +23,7 @@
 #include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/supervised_user/core/browser/supervised_user_preferences.h"
+#include "components/supervised_user/core/browser/supervised_user_test_environment.h"
 #include "components/supervised_user/core/browser/supervised_user_utils.h"
 #include "components/supervised_user/core/common/pref_names.h"
 #include "components/supervised_user/core/common/supervised_user_constants.h"
@@ -63,9 +65,7 @@
                                 bool is_opted_in_to_parental_supervision) {
     Profile* profile = test_profile_manager()->CreateTestingProfile(
         test_profile, /*prefs=*/nullptr, base::UTF8ToUTF16(test_profile),
-        /*avatar_id=*/0,
-        IdentityTestEnvironmentProfileAdaptor::
-            GetIdentityTestEnvironmentFactories(),
+        /*avatar_id=*/0, GetTestingFactories(),
         /*is_supervised_profile=*/is_subject_to_parental_controls,
         /*is_new_profile=*/std::nullopt,
         /*policy_service=*/std::nullopt, /*shared_url_loader_factory=*/nullptr);
@@ -91,10 +91,31 @@
           SetSupervisedUserExtensionsMayRequestPermissionsPref(profile, true);
     }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
     return profile;
   }
 
+  // Creates the testing factories for the profile. The important part is to
+  // inject identity manager related factories and supervised user service
+  // factory - which would allow overrides in this test fixture subclasses.
+  TestingProfile::TestingFactories GetTestingFactories() {
+    TestingProfile::TestingFactories factories =
+        IdentityTestEnvironmentProfileAdaptor::
+            GetIdentityTestEnvironmentFactories();
+    factories.emplace_back(
+        SupervisedUserServiceFactory::GetInstance(),
+        base::BindOnce(
+            &FamilyLinkUserMetricsProviderTest::BuildSupervisedUserService,
+            base::Unretained(this)));
+    return factories;
+  }
+
+  // Default supervised user service, as in production.
+  virtual std::unique_ptr<KeyedService> BuildSupervisedUserService(
+      content::BrowserContext* browser_context) {
+    Profile* profile = Profile::FromBrowserContext(browser_context);
+    return SupervisedUserServiceFactory::BuildInstanceFor(profile);
+  }
+
   void SetFamilyRole(Profile* profile, kidsmanagement::FamilyRole family_role) {
     profile->GetPrefs()->SetString(prefs::kFamilyLinkUserMemberRole,
                                    FamilyRoleToString(family_role));
@@ -492,5 +513,215 @@
                                      /*expected_count=*/1);
 }
 
+#if BUILDFLAG(IS_ANDROID)
+struct ContentFiltersTestCase {
+  std::size_t profile_count;
+  std::string test_name;
+};
+
+// Test fixture for verifying that the content filters are correctly
+// reflected in the metrics. Content filters are mutually exclusive with
+// Family-Link supervision and cannot be applied to these profiles.
+class FamilyLinkUserMetricsProviderWithContentFiltersTest
+    : public FamilyLinkUserMetricsProviderTest,
+      public testing::WithParamInterface<ContentFiltersTestCase> {
+ protected:
+  void CreateProfiles(std::size_t count) {
+    CHECK_GE(email_addresses_.size(), count) << "Not enough email addresses";
+    CHECK_GE(profile_names_.size(), count) << "Not enough profile names";
+
+    for (std::size_t i = 0; i < count; ++i) {
+      Profile* unsupervised_profile = CreateUnsupervisedTestingProfile(
+          email_addresses_[i], profile_names_[i]);
+
+      // Services are lazily created, so we need to access them to force their
+      // creation. That'll trigger the ::BuildSupervisedUserService factory,
+      // which will bind fake content filters observers to this text fixture
+      // instance.
+      CHECK(SupervisedUserServiceFactory::GetInstance()->GetForProfile(
+          unsupervised_profile));
+    }
+  }
+
+  Profile* CreateUnsupervisedTestingProfile(const std::string& email,
+                                            const std::string& profile_name) {
+    // Content filters are not supported for family link supervised profiles.
+    return CreateTestingProfile(email, profile_name,
+                                /*is_subject_to_parental_controls=*/false,
+                                /*is_opted_in_to_parental_supervision=*/false);
+  }
+
+  // Fake content filters observer for search settings.
+  std::unique_ptr<FakeContentFiltersObserverBridge>
+  MakeSearchContentFiltersObserverBridge(PrefService& pref_service) {
+    return std::make_unique<FakeContentFiltersObserverBridge>(
+        kSearchContentFiltersSettingName,
+        base::BindRepeating(&EnableSearchContentFilters,
+                            std::ref(pref_service)),
+        base::BindRepeating(&DisableSearchContentFilters,
+                            std::ref(pref_service)));
+  }
+
+  // Fake content filters observer for browser content settings.
+  std::unique_ptr<FakeContentFiltersObserverBridge>
+  MakeBrowserContentFiltersObserverBridge(PrefService& pref_service) {
+    return std::make_unique<FakeContentFiltersObserverBridge>(
+        kBrowserContentFiltersSettingName,
+        base::BindRepeating(&EnableBrowserContentFilters,
+                            std::ref(pref_service)),
+        base::BindRepeating(&DisableBrowserContentFilters,
+                            std::ref(pref_service)));
+  }
+
+  // Builds the `SupervisedUserService` and captures the content observers onto
+  // this text fixture instance. Binding memory managed by foreign object (the
+  // service) to raw_ptr is fine, because raw_ptr handles will be destroyed
+  // before profile manager, that transitively owns the content observers.
+  std::unique_ptr<KeyedService> BuildSupervisedUserService(
+      content::BrowserContext* browser_context) override {
+    Profile* profile = Profile::FromBrowserContext(browser_context);
+
+    std::unique_ptr<FakeContentFiltersObserverBridge> browser_filter =
+        MakeBrowserContentFiltersObserverBridge(*profile->GetPrefs());
+    browser_content_filters_observers_.push_back(browser_filter.get());
+
+    std::unique_ptr<FakeContentFiltersObserverBridge> search_filter =
+        MakeSearchContentFiltersObserverBridge(*profile->GetPrefs());
+    search_content_filters_observers_.push_back(search_filter.get());
+
+    std::unique_ptr<SupervisedUserServicePlatformDelegate> platform_delegate =
+        std::make_unique<SupervisedUserServicePlatformDelegate>(*profile);
+
+    return std::make_unique<SupervisedUserService>(
+        IdentityManagerFactory::GetForProfile(profile),
+        profile->GetDefaultStoragePartition()
+            ->GetURLLoaderFactoryForBrowserProcess(),
+        *profile->GetPrefs(),
+        *SupervisedUserSettingsServiceFactory::GetInstance()->GetForKey(
+            profile->GetProfileKey()),
+        SyncServiceFactory::GetInstance()->GetForProfile(profile),
+        std::make_unique<SupervisedUserURLFilter>(
+            *profile->GetPrefs(), std::make_unique<FakeURLFilterDelegate>(),
+            std::make_unique<KidsChromeManagementURLCheckerClient>(
+                IdentityManagerFactory::GetForProfile(profile),
+                profile->GetDefaultStoragePartition()
+                    ->GetURLLoaderFactoryForBrowserProcess(),
+                *profile->GetPrefs(), platform_delegate->GetCountryCode(),
+                platform_delegate->GetChannel())),
+        std::make_unique<SupervisedUserServicePlatformDelegate>(*profile),
+        std::move(browser_filter), std::move(search_filter));
+  }
+
+  // Enables or disables the browser content filters for all profiles.
+  void SetBrowserContentFilters(bool enabled) {
+    for (FakeContentFiltersObserverBridge* observer :
+         browser_content_filters_observers_) {
+      observer->SetEnabled(enabled);
+    }
+  }
+
+  // Enables or disables the search content filters for all profiles.
+  void SetSearchContentFilters(bool enabled) {
+    for (FakeContentFiltersObserverBridge* observer :
+         search_content_filters_observers_) {
+      observer->SetEnabled(enabled);
+    }
+  }
+
+ private:
+  std::vector<std::string> email_addresses_{kTestEmail, kTestEmail1};
+  std::vector<std::string> profile_names_{kTestProfile, kTestProfile1};
+
+  // These are internal components of the `SupervisedUserService` and are used
+  // to simulate changes to the android content filters. Both are owned by the
+  // `SupervisedUserService`. The reason for they're held in vectors is that
+  // content filters are applied at device level, for all profiles at once.
+  std::vector<raw_ptr<FakeContentFiltersObserverBridge>>
+      browser_content_filters_observers_;
+  std::vector<raw_ptr<FakeContentFiltersObserverBridge>>
+      search_content_filters_observers_;
+};
+
+TEST_P(FamilyLinkUserMetricsProviderWithContentFiltersTest,
+       AllFiltersDisabled) {
+  CreateProfiles(GetParam().profile_count);
+
+  base::HistogramTester histogram_tester;
+  metrics_provider()->OnDidCreateMetricsLog();
+
+  histogram_tester.ExpectBucketCount(
+      kFamilyLinkUserLogSegmentHistogramName,
+      FamilyLinkUserLogRecord::Segment::kUnsupervised,
+      /*expected_count=*/1);
+  histogram_tester.ExpectTotalCount(
+      kFamilyLinkUserLogSegmentWebFilterHistogramName,
+      /*expected_count=*/0);
+}
+
+TEST_P(FamilyLinkUserMetricsProviderWithContentFiltersTest,
+       SearchFilterEnabled) {
+  CreateProfiles(GetParam().profile_count);
+  SetSearchContentFilters(true);
+
+  base::HistogramTester histogram_tester;
+  metrics_provider()->OnDidCreateMetricsLog();
+
+  histogram_tester.ExpectBucketCount(
+      kFamilyLinkUserLogSegmentHistogramName,
+      FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally,
+      /*expected_count=*/1);
+  histogram_tester.ExpectBucketCount(
+      kFamilyLinkUserLogSegmentWebFilterHistogramName, WebFilterType::kDisabled,
+      /*expected_count=*/1);
+}
+
+TEST_P(FamilyLinkUserMetricsProviderWithContentFiltersTest,
+       ContentFiltersEnabled) {
+  CreateProfiles(GetParam().profile_count);
+  SetBrowserContentFilters(true);
+
+  base::HistogramTester histogram_tester;
+  metrics_provider()->OnDidCreateMetricsLog();
+
+  histogram_tester.ExpectBucketCount(
+      kFamilyLinkUserLogSegmentHistogramName,
+      FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally,
+      /*expected_count=*/1);
+  histogram_tester.ExpectUniqueSample(
+      kFamilyLinkUserLogSegmentWebFilterHistogramName,
+      WebFilterType::kTryToBlockMatureSites,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_P(FamilyLinkUserMetricsProviderWithContentFiltersTest, AllFiltersEnabled) {
+  CreateProfiles(GetParam().profile_count);
+  SetBrowserContentFilters(true);
+  SetSearchContentFilters(true);
+
+  base::HistogramTester histogram_tester;
+  metrics_provider()->OnDidCreateMetricsLog();
+
+  histogram_tester.ExpectBucketCount(
+      kFamilyLinkUserLogSegmentHistogramName,
+      FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally,
+      /*expected_count=*/1);
+  histogram_tester.ExpectUniqueSample(
+      kFamilyLinkUserLogSegmentWebFilterHistogramName,
+      WebFilterType::kTryToBlockMatureSites,
+      /*expected_bucket_count=*/1);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    FamilyLinkUserMetricsProviderWithContentFiltersTest,
+    testing::ValuesIn<ContentFiltersTestCase>({
+        {1, "SingleProfile"},
+        {2, "MultipleProfiles"},
+    }),
+    [](const testing::TestParamInfo<ContentFiltersTestCase>& info) {
+      return info.param.test_name;
+    });
+#endif  // BUILDFLAG(IS_ANDROID)
+
 }  // namespace
 }  // namespace supervised_user
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
index 634e1a82..456e6cc 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
@@ -14,7 +14,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/nearby_sharing/certificates/common.h"
diff --git a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
index d4d51d0..582df90 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
+++ b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
@@ -10,6 +10,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/nearby_sharing/instantmessaging/constants.h"
 #include "chrome/browser/nearby_sharing/instantmessaging/proto/instantmessaging.pb.h"
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index 2fc96f1f..fded6ca 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -16,6 +16,7 @@
 #include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index e6d1155..5660825 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc
index 3124550..e96ac822 100644
--- a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc
+++ b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc
@@ -11,6 +11,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "chrome/browser/notifications/scheduler/internal/scheduler_utils.h"
 
diff --git a/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc b/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc
index 71d0ca5..3091d64e 100644
--- a/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc
+++ b/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/notifications/scheduler/internal/notification_scheduler.h"
 #include "chrome/browser/notifications/scheduler/internal/stats.h"
 #include "chrome/browser/notifications/scheduler/public/notification_params.h"
diff --git a/chrome/browser/notifications/scheduler/internal/webui_client.cc b/chrome/browser/notifications/scheduler/internal/webui_client.cc
index 270f06f..46d5af5 100644
--- a/chrome/browser/notifications/scheduler/internal/webui_client.cc
+++ b/chrome/browser/notifications/scheduler/internal/webui_client.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace notifications {
 
diff --git a/chrome/browser/notifications/scheduler/notification_background_task_scheduler_impl.cc b/chrome/browser/notifications/scheduler/notification_background_task_scheduler_impl.cc
index ee04ea67..375c057 100644
--- a/chrome/browser/notifications/scheduler/notification_background_task_scheduler_impl.cc
+++ b/chrome/browser/notifications/scheduler/notification_background_task_scheduler_impl.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/notifications/scheduler/notification_background_task_scheduler_impl.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 NotificationBackgroundTaskSchedulerImpl::
     NotificationBackgroundTaskSchedulerImpl() = default;
diff --git a/chrome/browser/notifications/scheduler/public/display_agent.cc b/chrome/browser/notifications/scheduler/public/display_agent.cc
index 01b93880..c19c19c7 100644
--- a/chrome/browser/notifications/scheduler/public/display_agent.cc
+++ b/chrome/browser/notifications/scheduler/public/display_agent.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/notifications/scheduler/public/display_agent.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace notifications {
 
diff --git a/chrome/browser/password_manager/profile_password_store_factory.cc b/chrome/browser/password_manager/profile_password_store_factory.cc
index 5ec49b0c..6547235 100644
--- a/chrome/browser/password_manager/profile_password_store_factory.cc
+++ b/chrome/browser/password_manager/profile_password_store_factory.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "chrome/browser/affiliations/affiliation_service_factory.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc b/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc
index 17ce1c30..230d5de6 100644
--- a/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc
+++ b/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/performance_manager/policies/working_set_trimmer_policy.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/platform_util_android.cc b/chrome/browser/platform_util_android.cc
index 05a80ff..c4a2daac 100644
--- a/chrome/browser/platform_util_android.cc
+++ b/chrome/browser/platform_util_android.cc
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/platform_util.h"
+
 #include <jni.h>
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
-#include "base/notreached.h"
-#include "chrome/browser/platform_util.h"
+#include "base/notimplemented.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/policy/BUILD.gn b/chrome/browser/policy/BUILD.gn
index 4fce2a9..50d3ba3 100644
--- a/chrome/browser/policy/BUILD.gn
+++ b/chrome/browser/policy/BUILD.gn
@@ -523,6 +523,7 @@
 
       # Chrome OS does not support this policy.
       "test/native_messaging_policy_browsertest.cc",
+      "test/swiftshader_enabled_browsertest.cc",
     ]
   }
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index be562e35..718a59d 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -603,6 +603,11 @@
   { key::kDisable3DAPIs,
     prefs::kDisable3DAPIs,
     base::Value::Type::BOOLEAN },
+#if !BUILDFLAG(IS_CHROMEOS)
+  { key::kEnableUnsafeSwiftShader,
+    prefs::kEnableUnsafeSwiftShader,
+    base::Value::Type::BOOLEAN },
+#endif
   { key::kDisableScreenshots,
     prefs::kDisableScreenshots,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/policy/test/swiftshader_enabled_browsertest.cc b/chrome/browser/policy/test/swiftshader_enabled_browsertest.cc
new file mode 100644
index 0000000..c1da480
--- /dev/null
+++ b/chrome/browser/policy/test/swiftshader_enabled_browsertest.cc
@@ -0,0 +1,72 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/chrome_test_utils.h"
+#include "chrome/test/base/platform_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
+#include "components/policy/policy_constants.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "ui/gl/gl_switches.h"
+
+namespace {
+//
+// Checks if WebGL is enabled in the given WebContents.
+bool IsWebGLEnabled(content::WebContents* contents) {
+  return content::EvalJs(contents,
+                         "var canvas = document.createElement('canvas');"
+                         "var context = canvas.getContext('webgl');"
+                         "context != null;")
+      .ExtractBool();
+}
+
+class SwiftShaderEnabledBrowserTest : public PlatformBrowserTest {
+ public:
+  SwiftShaderEnabledBrowserTest(const SwiftShaderEnabledBrowserTest&) = delete;
+  SwiftShaderEnabledBrowserTest& operator=(
+      const SwiftShaderEnabledBrowserTest&) = delete;
+
+ protected:
+  SwiftShaderEnabledBrowserTest() = default;
+
+  void SetUpInProcessBrowserTestFixture() override {
+    // We setup the policy here, because the policy must be 'live' before
+    // any GPU initialization since the value for this policy is passed to the
+    // GPU process via a command-line.Setting the policy in the test itself or
+    // in SetUpOnMainThread works for update-able policies, but is too late for
+    // this one.
+    provider_.SetDefaultReturns(
+        true /* is_initialization_complete_return */,
+        true /* is_first_policy_load_complete_return */);
+    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
+
+    policy::PolicyMap values;
+    values.Set(policy::key::kEnableUnsafeSwiftShader,
+               policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
+               policy::POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
+    provider_.UpdateChromePolicy(values);
+  }
+  testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
+};
+
+IN_PROC_BROWSER_TEST_F(SwiftShaderEnabledBrowserTest, EnableUnsafeSwiftShader) {
+  // Verify that WebGL is always available when EnableUnsafeSwiftShader is set,
+  // regardless of GPU hardware acceleration availability.
+  ASSERT_TRUE(
+      ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(IsWebGLEnabled(contents));
+
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  EXPECT_TRUE(command_line->HasSwitch(switches::kEnableUnsafeSwiftShader));
+}
+
+}  // namespace
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 480bc49..92ce59d 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -359,13 +359,6 @@
     public static final String INCOGNITO_REAUTH_PROMO_CARD_ENABLED =
             "Chrome.IncognitoReauth.PromoCardEnabled";
 
-    /**
-     * The last version the dex compile workaround ran on. See SplitChromeApplication for more
-     * details.
-     */
-    public static final String ISOLATED_SPLITS_DEX_COMPILE_VERSION =
-            "Chrome.IsolatedSplits.VersionCode";
-
     /** Whether Google is set as Chrome's default search engine. Default value is false. */
     public static final String IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE =
             "Chrome.GoogleBottomBar.IsDefaultSearchEngineGoogle";
@@ -1064,7 +1057,6 @@
                 IS_EEA_CHOICE_COUNTRY,
                 IS_LAST_VISITED_TAB_SRP,
                 IS_DSE_GOOGLE,
-                ISOLATED_SPLITS_DEX_COMPILE_VERSION,
                 LAST_SESSION_BROWSER_PID,
                 LAST_SESSION_APPLICATION_STATE,
                 LOCALE_MANAGER_PROMO_V3_CHECKED,
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
index 9af3aeb4..72ad2bde 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
@@ -43,6 +43,7 @@
                 "Chrome.Flags.SafeModeEnabled",
                 "Chrome.Flags.SafeString.*",
                 "Chrome.Flags.SafeValuesVersion",
+                "Chrome.IsolatedSplits.VersionCode",
                 "Chrome.OfflineMeasurements.HttpProbeResultsList",
                 "Chrome.OfflineMeasurements.IsAirplaneModeEnabledList",
                 "Chrome.OfflineMeasurements.IsRoaming",
diff --git a/chrome/browser/prefs/DEPS b/chrome/browser/prefs/DEPS
index 3136a999..ebeb7ae 100644
--- a/chrome/browser/prefs/DEPS
+++ b/chrome/browser/prefs/DEPS
@@ -6,4 +6,7 @@
   "chrome_pref_service_factory\.cc": [
     "+services/preferences/tracked",
   ],
+  "pref_hash_browsertest\.cc":[
+    "+services/preferences/tracked",
+  ],
 }
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
index ebc1c9c..0ae9d81 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -32,6 +32,7 @@
 #include "services/network/public/cpp/network_switches.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/display/display_switches.h"
+#include "ui/gl/gl_switches.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
 #include "ash/constants/ash_pref_names.h"
@@ -73,6 +74,8 @@
 const CommandLinePrefStore::BooleanSwitchToPreferenceMapEntry
     ChromeCommandLinePrefStore::boolean_switch_map_[] = {
         {switches::kDisable3DAPIs, prefs::kDisable3DAPIs, true},
+        {switches::kEnableUnsafeSwiftShader, prefs::kEnableUnsafeSwiftShader,
+         true},
         {switches::kEnableCloudPrintProxy, prefs::kCloudPrintProxyEnabled,
          true},
         {switches::kNoPings, prefs::kEnableHyperlinkAuditing, false},
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index f7ee08f..85a59f9 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -176,6 +176,9 @@
     {35, prefs::kExtensionsUIDeveloperMode, EnforcementLevel::ENFORCE_ON_LOAD,
      PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
 #endif
+    // Allows it to trigger a write to the protected pref store.
+    {36, user_prefs::kScheduleToFlushToDisk, EnforcementLevel::ENFORCE_ON_LOAD,
+     PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
 
     // See note at top, new items added here also need to be added to
     // histograms.xml's TrackedPreference enum.
@@ -381,7 +384,8 @@
     scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
     policy::BrowserPolicyConnector* connector,
     bool async,
-    scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    os_crypt_async::OSCryptAsync* os_crypt_async) {
   TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs");
 
   mojo::PendingRemote<prefs::mojom::ResetOnLoadObserver> reset_on_load_observer;
@@ -395,7 +399,7 @@
           ->CreateProfilePrefStore(
               GetTrackingConfiguration(), kTrackedPrefsReportingIDsCount,
               io_task_runner, std::move(reset_on_load_observer),
-              std::move(validation_delegate));
+              std::move(validation_delegate), os_crypt_async);
 
 #if BUILDFLAG(IS_CHROMEOS)
   io_task_runner->PostTask(
@@ -529,12 +533,14 @@
 #endif  // BUILDFLAG(IS_WIN)
 }
 
-bool InitializePrefsFromMasterPrefs(const base::FilePath& profile_path,
-                                    base::Value::Dict master_prefs) {
+bool InitializePrefsFromMasterPrefs(
+    const base::FilePath& profile_path,
+    base::Value::Dict master_prefs,
+    os_crypt_async::OSCryptAsync* os_crypt_async) {
   return CreateProfilePrefStoreManager(profile_path)
       ->InitializePrefsFromMasterPrefs(GetTrackingConfiguration(),
                                        kTrackedPrefsReportingIDsCount,
-                                       std::move(master_prefs));
+                                       std::move(master_prefs), os_crypt_async);
 }
 
 base::Time GetResetTime(Profile* profile) {
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.h b/chrome/browser/prefs/chrome_pref_service_factory.h
index 3b7416214c..0301aed 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.h
+++ b/chrome/browser/prefs/chrome_pref_service_factory.h
@@ -43,6 +43,10 @@
 class SupervisedUserSettingsService;
 }  // namespace supervised_user
 
+namespace os_crypt_async {
+class OSCryptAsync;
+}  // namespace os_crypt_async
+
 namespace chrome_prefs {
 
 // The prefix (without the trailing ".") with which the account preference
@@ -79,15 +83,18 @@
     scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
     policy::BrowserPolicyConnector* connector,
     bool async,
-    scoped_refptr<base::SequencedTaskRunner> io_task_runner);
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    os_crypt_async::OSCryptAsync* os_crypt_async);
 
 // determining the active SettingsEnforcement group. For testing only.
 void DisableDomainCheckForTesting();
 
 // Initializes the preferences for the profile at |profile_path| with the
 // preference values in |master_prefs|. Returns true on success.
-bool InitializePrefsFromMasterPrefs(const base::FilePath& profile_path,
-                                    base::Value::Dict master_prefs);
+bool InitializePrefsFromMasterPrefs(
+    const base::FilePath& profile_path,
+    base::Value::Dict master_prefs,
+    os_crypt_async::OSCryptAsync* os_crypt_async);
 
 // Retrieves the time of the last preference reset event, if any, for the
 // provided profile. If no reset has occurred, returns a null |Time|.
diff --git a/chrome/browser/prefs/chrome_pref_service_factory_unittest.cc b/chrome/browser/prefs/chrome_pref_service_factory_unittest.cc
index a809297..ef667c12 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory_unittest.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory_unittest.cc
@@ -35,7 +35,8 @@
         /*supervised_user_settings=*/nullptr, /*extension_prefs=*/nullptr,
         pref_registry_,
         /*connector=*/g_browser_process->browser_policy_connector(),
-        /*async=*/true, task_environment_.GetMainThreadTaskRunner().get());
+        /*async=*/true, task_environment_.GetMainThreadTaskRunner().get(),
+        /*os_crypt_async=*/nullptr);
   }
 
   base::FilePath AccountPreferencesFilePath() const {
diff --git a/chrome/browser/prefs/profile_pref_store_manager.cc b/chrome/browser/prefs/profile_pref_store_manager.cc
index 6663745..8459557 100644
--- a/chrome/browser/prefs/profile_pref_store_manager.cc
+++ b/chrome/browser/prefs/profile_pref_store_manager.cc
@@ -15,6 +15,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/chrome_constants.h"
+#include "components/os_crypt/async/browser/os_crypt_async.h"
 #include "components/prefs/json_pref_store.h"
 #include "components/prefs/persistent_pref_store.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -85,7 +86,8 @@
     mojo::PendingRemote<prefs::mojom::ResetOnLoadObserver>
         reset_on_load_observer,
     mojo::PendingRemote<prefs::mojom::TrackedPreferenceValidationDelegate>
-        validation_delegate) {
+        validation_delegate,
+    os_crypt_async::OSCryptAsync* os_crypt) {
   if (!kPlatformSupportsPreferenceTracking) {
     return new JsonPrefStore(profile_path_.Append(chrome::kPreferencesFilename),
                              nullptr, io_task_runner);
@@ -94,14 +96,15 @@
       CreateTrackedPrefStoreConfiguration(
           std::move(tracking_configuration), reporting_ids_count,
           std::move(reset_on_load_observer), std::move(validation_delegate)),
-      io_task_runner);
+      io_task_runner, /*os_crypt=*/os_crypt);
 }
 
 bool ProfilePrefStoreManager::InitializePrefsFromMasterPrefs(
     std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
         tracking_configuration,
     size_t reporting_ids_count,
-    base::Value::Dict master_prefs) {
+    base::Value::Dict master_prefs,
+    os_crypt_async::OSCryptAsync* os_crypt) {
   // Create the profile directory if it doesn't exist yet (very possible on
   // first run).
   if (!base::CreateDirectory(profile_path_))
@@ -112,7 +115,7 @@
         CreateTrackedPrefStoreConfiguration(std::move(tracking_configuration),
                                             reporting_ids_count, {},
                                             mojo::NullRemote()),
-        master_prefs);
+        master_prefs, /*os_crypt=*/os_crypt);
   }
 
   // This will write out to a single combined file which will be immediately
diff --git a/chrome/browser/prefs/profile_pref_store_manager.h b/chrome/browser/prefs/profile_pref_store_manager.h
index 7e89884..97eb050 100644
--- a/chrome/browser/prefs/profile_pref_store_manager.h
+++ b/chrome/browser/prefs/profile_pref_store_manager.h
@@ -31,6 +31,10 @@
 class PrefRegistrySyncable;
 }  // namespace user_prefs
 
+namespace os_crypt_async {
+class OSCryptAsync;
+}  // namespace os_crypt_async
+
 // Provides a facade through which the user preference store may be accessed and
 // managed.
 class ProfilePrefStoreManager {
@@ -86,7 +90,8 @@
       mojo::PendingRemote<prefs::mojom::ResetOnLoadObserver>
           reset_on_load_observer,
       mojo::PendingRemote<prefs::mojom::TrackedPreferenceValidationDelegate>
-          validation_delegate);
+          validation_delegate,
+      os_crypt_async::OSCryptAsync* os_crypt);
 
   // Initializes the preferences for the managed profile with the preference
   // values in |master_prefs|. Acts synchronously, including blocking IO.
@@ -95,7 +100,8 @@
       std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
           tracking_configuration,
       size_t reporting_ids_count,
-      base::Value::Dict master_prefs);
+      base::Value::Dict master_prefs,
+      os_crypt_async::OSCryptAsync* os_crypt);
 
  private:
   // Connects to the pref service over mojo and configures it.
diff --git a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
index 86563b8..ed234ab4 100644
--- a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
+++ b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
@@ -221,7 +221,7 @@
         manager_->CreateProfilePrefStore(
             prefs::CloneTrackedConfiguration(configuration_), kReportingIdCount,
             base::SingleThreadTaskRunner::GetCurrentDefault(),
-            std::move(observer), std::move(validation_delegate));
+            std::move(observer), std::move(validation_delegate), nullptr);
     InitializePrefStore(pref_store.get());
     pref_store = nullptr;
   }
@@ -273,7 +273,7 @@
     pref_store_ = manager_->CreateProfilePrefStore(
         prefs::CloneTrackedConfiguration(configuration_), kReportingIdCount,
         base::SingleThreadTaskRunner::GetCurrentDefault(), std::move(observer),
-        std::move(validation_delegate));
+        std::move(validation_delegate), nullptr);
     pref_store_->AddObserver(&registry_verifier_);
     PrefStoreReadObserver read_observer(pref_store_);
     read_observer.Read();
@@ -390,7 +390,7 @@
   master_prefs.Set(kProtectedAtomic, kHelloWorld);
   EXPECT_TRUE(manager_->InitializePrefsFromMasterPrefs(
       prefs::CloneTrackedConfiguration(configuration_), kReportingIdCount,
-      std::move(master_prefs)));
+      std::move(master_prefs), nullptr));
 
   LoadExistingPrefs();
 
diff --git a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
index ac7adb4b..44fbc20 100644
--- a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
+++ b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
@@ -39,17 +39,21 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/prefs/json_pref_store.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/prefs/segregated_pref_store.h"
 #include "components/search_engines/default_search_manager.h"
 #include "components/search_engines/template_url_data.h"
 #include "components/signin/public/base/signin_switches.h"
 #include "components/sync/base/features.h"
+#include "content/public/test/browser_task_environment.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_launcher.h"
 #include "extensions/browser/pref_names.h"
 #include "extensions/common/extension.h"
 #include "services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h"
+#include "services/preferences/tracked/features.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
 #include "ash/constants/ash_switches.h"
@@ -155,6 +159,13 @@
 }
 
 #if !BUILDFLAG(IS_CHROMEOS)
+// Helper function to get the test profile directory path.
+base::FilePath GetProfileDir() {
+  base::FilePath profile_dir;
+  CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &profile_dir));
+  return profile_dir.AppendASCII(TestingProfile::kTestUserProfileDir);
+}
+
 std::optional<base::Value::Dict> ReadPrefsDictionary(
     const base::FilePath& pref_file) {
   JSONFileValueDeserializer deserializer(pref_file);
@@ -332,6 +343,22 @@
     extensions::ExtensionBrowserTest::TearDown();
   }
 
+  void TearDownOnMainThread() override {
+    // In the PRE_ test, we must ensure all asynchronous
+    // work is flushed before the test exits, guaranteeing the pref files on
+    // disk are in a stable state for the main test to read.
+    if (content::IsPreTest()) {
+      // First, allow any pending asynchronous tasks (like our deferred
+      // validation) to complete.
+      base::RunLoop().RunUntilIdle();
+      // Then, commit any writes that were scheduled by those tasks.
+      base::RunLoop run_loop;
+      profile()->GetPrefs()->CommitPendingWrite(run_loop.QuitClosure());
+      run_loop.Run();
+    }
+    extensions::ExtensionBrowserTest::TearDownOnMainThread();
+  }
+
   // In the PRE_ test, find the number of tracked preferences that were
   // initialized and save it to a file to be read back in the main test and used
   // as the total number of tracked preferences.
@@ -353,7 +380,6 @@
           user_prefs::tracked::kTrackedPrefHistogramNullInitialized, ALLOW_ANY);
       EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM,
                 num_tracked_prefs_ > 0);
-
       // Split tracked prefs are reported as Unchanged not as NullInitialized
       // when an empty dictionary is encountered on first run (this should only
       // hit for pref #5 in the current design).
@@ -362,7 +388,6 @@
           BEGIN_ALLOW_SINGLE_BUCKET + 5);
       EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
                 num_split_tracked_prefs);
-
       if (SupportsRegistryValidation()) {
         // Same checks as above, but for the registry.
         num_tracked_prefs_ = GetTrackedPrefHistogramCount(
@@ -1044,8 +1069,9 @@
     // not protecting; if protection is enabled the change should be a Cleared.
     int changed_expected =
         protection_level_ > PROTECTION_DISABLED_ON_PLATFORM &&
-        protection_level_ < PROTECTION_ENABLED_BASIC
-        ? 1 : 0;
+                protection_level_ < PROTECTION_ENABLED_BASIC
+            ? 1
+            : 0;
     int cleared_expected =
         protection_level_ >= PROTECTION_ENABLED_BASIC
         ? 1 : 0;
@@ -1197,15 +1223,15 @@
         {
           "keyword" : "badkeyword",
           "name" : "badname",
-          "search_url" : "http://bad_default_engine/search?q=dirty_user_query",
-          "encoding" : "utf-8",
-          "id" : 1
+          "search_url" :
+          "http://bad_default_engine/search?q=dirty_user_query", "encoding" :
+          "utf-8", "id" : 1
         }, {
           "keyword" : "badkeyword2",
           "name" : "badname2",
-          "search_url" : "http://bad_default_engine2/search?q=dirty_user_query",
-          "encoding" : "utf-8",
-          "id" : 2
+          "search_url" :
+          "http://bad_default_engine2/search?q=dirty_user_query", "encoding"
+          : "utf-8", "id" : 2
         }
       ]
     })";
@@ -1300,8 +1326,8 @@
     // Setting the extensions dict to an invalid type gets noticed regardless
     // of protection level. This implementation just happened to be easier and
     // it doesn't seem important to not protect the kExtensions from being the
-    // wrong type at any protection level. PrefService will correct the type
-    // either way.
+    // wrong type at any protection level. PrefService will correct the
+    // type either way.
     EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
               GetTrackedPrefHistogramCount(
                   user_prefs::tracked::kTrackedPrefHistogramCleared,
@@ -1407,3 +1433,495 @@
 
 PREF_HASH_BROWSER_TEST(PrefHashBrowserTestAccountValueUntrustedAddition,
                        AccountValueUntrustedAddition);
+
+// Suffix used to distinguish encrypted hash keys from MAC keys in storage.
+const char kEncryptedHashSuffix[] = "_encrypted_hash";
+// Base class for tests that need to control the EncryptedPrefHashing
+// feature flag.
+class PrefHashBrowserTestEncryptedBase : public PrefHashBrowserTestBase {};
+
+// Tests that a tampered encrypted hash is caught and triggers a reset.
+class PrefHashBrowserTestEncryptedTampered
+    : public PrefHashBrowserTestEncryptedBase {
+ public:
+  PrefHashBrowserTestEncryptedTampered() {
+    // Feature must be ON for both the PRE_ and main test phases.
+    feature_list_.InitAndEnableFeature(tracked::kEncryptedPrefHashing);
+  }
+
+  void SetupPreferences() override {
+    // PRE_ test (feature ON): Set a value to ensure both MAC and encrypted
+    // hashes are written.
+    profile()->GetPrefs()->SetString(prefs::kHomePage, "http://example.com");
+  }
+
+  void AttackPreferencesOnDisk(
+      base::Value::Dict* unprotected_preferences,
+      base::Value::Dict* protected_preferences) override {
+    // Attack the encrypted hash, leaving the legacy MAC intact.
+    base::Value::Dict* selected_prefs =
+        protection_level_ >= PROTECTION_ENABLED_BASIC ? protected_preferences
+                                                      : unprotected_preferences;
+    ASSERT_TRUE(selected_prefs);
+
+    // Hashes are stored in the "protection.macs" dictionary.
+    base::Value::Dict* macs_dict =
+        selected_prefs->FindDictByDottedPath("protection.macs");
+    ASSERT_TRUE(macs_dict);
+
+    const std::string encrypted_hash_key =
+        std::string(prefs::kHomePage) + kEncryptedHashSuffix;
+
+    // Verify the key exists, then tamper with it.
+    ASSERT_TRUE(macs_dict->contains(encrypted_hash_key));
+    macs_dict->Set(encrypted_hash_key, "invalid_tampered_hash");
+  }
+
+  void VerifyReactionToPrefAttack() override {
+    // Main test (feature ON):
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      return;
+    }
+
+    // The validation prioritizes the encrypted hash. Since it's invalid, a
+    // change should be detected.
+    if (protection_level_ >= PROTECTION_ENABLED_BASIC) {
+      // The tampered encrypted hash should be detected and trigger a reset.
+      histograms_.ExpectUniqueSample(
+          user_prefs::tracked::kTrackedPrefHistogramChangedEncrypted,
+          2 /* homepage reporting_id */, 1);
+      histograms_.ExpectUniqueSample(
+          user_prefs::tracked::kTrackedPrefHistogramResetEncrypted,
+          2 /* homepage reporting_id */, 1);
+      // The pref should now be reset to its default value.
+      EXPECT_TRUE(profile()->GetPrefs()->GetString(prefs::kHomePage).empty());
+    } else {
+      // If enforcement is off, we should want a reset but not perform it.
+      histograms_.ExpectUniqueSample(
+          user_prefs::tracked::kTrackedPrefHistogramChangedEncrypted,
+          2 /* homepage reporting_id */, 1);
+      histograms_.ExpectUniqueSample(
+          user_prefs::tracked::kTrackedPrefHistogramWantedResetEncrypted,
+          2 /* homepage reporting_id */, 1);
+      // The pref value should remain as it was on disk.
+      EXPECT_EQ("http://example.com",
+                profile()->GetPrefs()->GetString(prefs::kHomePage));
+    }
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+PREF_HASH_BROWSER_TEST(PrefHashBrowserTestEncryptedTampered, EncryptedTampered);
+
+// Tests the fallback path: loads prefs with only legacy MACs and verifies
+// that new encrypted hashes are created without resetting any values.
+class PrefHashBrowserTestEncryptedFallbackAndGeneratingEH
+    : public PrefHashBrowserTestEncryptedBase {
+ public:
+  PrefHashBrowserTestEncryptedFallbackAndGeneratingEH() {
+    if (content::IsPreTest()) {
+      // PRE_ phase: Feature is explicitly OFF to write only legacy MACs.
+      feature_list_.InitWithFeatures({}, {tracked::kEncryptedPrefHashing});
+    } else {
+      // Main phase: Feature is ON to trigger the fallback and the generation of
+      // encrypted hash process.
+      feature_list_.InitWithFeatures({tracked::kEncryptedPrefHashing}, {});
+    }
+  }
+
+  // Runs in the PRE_ test, with the encryption feature OFF.
+  void SetupPreferences() override {
+    profile()->GetPrefs()->SetString(prefs::kHomePage, "http://example.com");
+  }
+
+  // Runs before the main test. Verifies the on-disk state.
+  void AttackPreferencesOnDisk(
+      base::Value::Dict* unprotected_preferences,
+      base::Value::Dict* protected_preferences) override {
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      return;
+    }
+
+    // The 'macs' dict may be in either pref file depending on platform.
+    base::Value::Dict* macs_dict = nullptr;
+    if (protected_preferences) {
+      macs_dict =
+          protected_preferences->FindDictByDottedPath("protection.macs");
+    }
+    if (!macs_dict) {
+      macs_dict =
+          unprotected_preferences->FindDictByDottedPath("protection.macs");
+    }
+    ASSERT_TRUE(macs_dict);
+
+    // VERIFY: The legacy MAC for 'homepage' must exist.
+    ASSERT_TRUE(macs_dict->contains(prefs::kHomePage));
+
+    // VERIFY: The encrypted hash for 'homepage' must NOT exist yet.
+    const std::string encrypted_hash_key =
+        std::string(prefs::kHomePage) + kEncryptedHashSuffix;
+    ASSERT_FALSE(macs_dict->contains(encrypted_hash_key));
+  }
+
+  // Runs in the main test, with the encryption feature ON.
+  void VerifyReactionToPrefAttack() override {
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      return;
+    }
+
+    // Verify initial load behavior.
+    EXPECT_EQ("http://example.com",
+              profile()->GetPrefs()->GetString(prefs::kHomePage));
+
+    histograms_.ExpectBucketCount(
+        user_prefs::tracked::kTrackedPrefHistogramUnchangedViaHmacFallback,
+        2 /* homepage reporting_id */, 1);
+    EXPECT_GE(
+        GetTrackedPrefHistogramCount(
+            user_prefs::tracked::kTrackedPrefHistogramUnchangedViaHmacFallback,
+            ALLOW_ANY),
+        1);
+    histograms_.ExpectTotalCount(
+        user_prefs::tracked::kTrackedPrefHistogramReset, 0);
+
+    base::RunLoop run_loop;
+    // A write operation is scheduled after the encryptor received.
+    profile()->GetPrefs()->CommitPendingWrite(run_loop.QuitClosure());
+    run_loop.Run();
+#if !BUILDFLAG(IS_CHROMEOS)
+    std::optional<base::Value::Dict> final_protected_prefs;
+    std::optional<base::Value::Dict> final_unprotected_prefs;
+    base::Value::Dict* final_macs_dict = nullptr;
+
+    {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      base::FilePath profile_dir = GetProfileDir();
+      const base::FilePath protected_pref_file =
+          profile_dir.Append(chrome::kSecurePreferencesFilename);
+      if (base::PathExists(protected_pref_file)) {
+        final_protected_prefs = ReadPrefsDictionary(protected_pref_file);
+      }
+    }
+
+    if (final_protected_prefs.has_value()) {
+      final_macs_dict =
+          final_protected_prefs->FindDictByDottedPath("protection.macs");
+    }
+
+    if (!final_macs_dict) {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      base::FilePath profile_dir = GetProfileDir();
+      const base::FilePath unprotected_pref_file =
+          profile_dir.Append(chrome::kPreferencesFilename);
+      final_unprotected_prefs = ReadPrefsDictionary(unprotected_pref_file);
+      ASSERT_TRUE(final_unprotected_prefs.has_value());
+      final_macs_dict =
+          final_unprotected_prefs->FindDictByDottedPath("protection.macs");
+    }
+    ASSERT_TRUE(final_macs_dict);
+
+    // VERIFY: The new encrypted hash should now exist on disk.
+    const std::string encrypted_hash_key =
+        std::string(prefs::kHomePage) + kEncryptedHashSuffix;
+    EXPECT_TRUE(final_macs_dict->contains(encrypted_hash_key));
+#endif  // #if !BUILDFLAG(IS_CHROMEOS)
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+PREF_HASH_BROWSER_TEST(PrefHashBrowserTestEncryptedFallbackAndGeneratingEH,
+                       EncryptedHashGeneration);
+
+class PrefHashBrowserTestEncryptedSplitPrefFallbackAndGeneratingEH
+    : public PrefHashBrowserTestEncryptedBase {
+ public:
+  PrefHashBrowserTestEncryptedSplitPrefFallbackAndGeneratingEH() {
+    if (content::IsPreTest()) {
+      // PRE_ phase: Feature is OFF to write only legacy MACs.
+      feature_list_.InitWithFeatures({}, {tracked::kEncryptedPrefHashing});
+    } else {
+      // Main phase: Feature is ON to trigger FallbackAndGeneratingEH.
+      feature_list_.InitWithFeatures({tracked::kEncryptedPrefHashing}, {});
+    }
+  }
+
+  void SetupPreferences() override {
+    // This creates a split preference entry for extensions.settings.
+    InstallExtensionWithUIAutoConfirm(test_data_dir_.AppendASCII("good.crx"),
+                                      1);
+  }
+
+  void AttackPreferencesOnDisk(
+      base::Value::Dict* unprotected_preferences,
+      base::Value::Dict* protected_preferences) override {
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      pre_test_state_ok_ = true;
+      return;
+    }
+
+    base::Value::Dict* macs_dict = nullptr;
+    if (protected_preferences) {
+      macs_dict =
+          protected_preferences->FindDictByDottedPath("protection.macs");
+    }
+    if (!macs_dict) {
+      macs_dict =
+          unprotected_preferences->FindDictByDottedPath("protection.macs");
+    }
+
+    // Instead of asserting, check if the required legacy hashes were actually
+    // written by the PRE_ test.
+    if (macs_dict && macs_dict->FindDict(extensions::pref_names::kExtensions)) {
+      // State is good, we can proceed.
+      pre_test_state_ok_ = true;
+
+      // Now we can safely assert that the encrypted hashes are not yet present.
+      const std::string encrypted_hash_key =
+          std::string(extensions::pref_names::kExtensions) +
+          kEncryptedHashSuffix;
+      ASSERT_FALSE(macs_dict->FindDict(encrypted_hash_key));
+    } else {
+      // The PRE_ test failed to write the legacy hashes. Log a warning and
+      // set the flag so the main test verification is skipped.
+      pre_test_state_ok_ = false;
+    }
+  }
+
+  void VerifyReactionToPrefAttack() override {
+    if (!pre_test_state_ok_) {
+      return;
+    }
+
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      return;
+    }
+
+    EXPECT_TRUE(extension_registry()->enabled_extensions().GetByID(kGoodCrxId));
+    histograms_.ExpectBucketCount(
+        user_prefs::tracked::kTrackedPrefHistogramUnchangedViaHmacFallback,
+        5 /* extensions.settings reporting_id */, 1);
+    histograms_.ExpectTotalCount(
+        user_prefs::tracked::kTrackedPrefHistogramReset, 0);
+
+    profile()->GetPrefs()->SetBoolean(prefs::kShowHomeButton, true);
+    base::RunLoop run_loop;
+    profile()->GetPrefs()->CommitPendingWrite(run_loop.QuitClosure());
+    run_loop.Run();
+#if !BUILDFLAG(IS_CHROMEOS)
+    std::optional<base::Value::Dict> final_protected_prefs;
+    std::optional<base::Value::Dict> final_unprotected_prefs;
+    base::Value::Dict* final_macs_dict = nullptr;
+    {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      final_protected_prefs = ReadPrefsDictionary(
+          GetProfileDir().Append(chrome::kSecurePreferencesFilename));
+      if (final_protected_prefs.has_value()) {
+        final_macs_dict =
+            final_protected_prefs->FindDictByDottedPath("protection.macs");
+      }
+    }
+    if (!final_macs_dict) {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      final_unprotected_prefs = ReadPrefsDictionary(
+          GetProfileDir().Append(chrome::kPreferencesFilename));
+      if (final_unprotected_prefs.has_value()) {
+        final_macs_dict =
+            final_unprotected_prefs->FindDictByDottedPath("protection.macs");
+      }
+    }
+    ASSERT_TRUE(final_macs_dict);
+
+    const std::string encrypted_hash_key =
+        std::string(extensions::pref_names::kExtensions) + kEncryptedHashSuffix;
+    EXPECT_TRUE(final_macs_dict->FindDict(encrypted_hash_key));
+#endif  // #if !BUILDFLAG(IS_CHROMEOS)
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  bool pre_test_state_ok_ = false;
+};
+
+PREF_HASH_BROWSER_TEST(
+    PrefHashBrowserTestEncryptedSplitPrefFallbackAndGeneratingEH,
+    EncryptedSplitPrefFallbackAndGeneratingEH);
+
+class PrefHashBrowserTestEncryptedSplitPrefTampered
+    : public PrefHashBrowserTestEncryptedBase {
+ public:
+  PrefHashBrowserTestEncryptedSplitPrefTampered() {
+    feature_list_.InitAndEnableFeature(tracked::kEncryptedPrefHashing);
+  }
+
+  void SetupPreferences() override {
+    InstallExtensionWithUIAutoConfirm(test_data_dir_.AppendASCII("good.crx"),
+                                      1);
+  }
+
+  void AttackPreferencesOnDisk(
+      base::Value::Dict* unprotected_preferences,
+      base::Value::Dict* protected_preferences) override {
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      return;
+    }
+
+    base::Value::Dict* macs_dict = nullptr;
+    if (protected_preferences) {
+      macs_dict =
+          protected_preferences->FindDictByDottedPath("protection.macs");
+    }
+    if (!macs_dict) {
+      macs_dict =
+          unprotected_preferences->FindDictByDottedPath("protection.macs");
+    }
+    ASSERT_TRUE(macs_dict);
+
+    const std::string encrypted_hash_key =
+        std::string(extensions::pref_names::kExtensions) + kEncryptedHashSuffix;
+    base::Value::Dict* encrypted_split_hashes =
+        macs_dict->FindDict(encrypted_hash_key);
+
+    if (encrypted_split_hashes) {
+      // Hashes exist, so we can perform the attack.
+      encrypted_split_hashes->Set(kGoodCrxId, "invalid_split_hash");
+      was_attacked_ = true;
+    } else {
+      // This indicates the race condition occurred. The test will still run but
+      // won't be able to verify the tampering-detection logic.
+      was_attacked_ = false;
+    }
+  }
+
+  void VerifyReactionToPrefAttack() override {
+    if (!was_attacked_) {
+      // If we couldn't perform the attack, we can't verify the reaction.
+      // The WARNING log from the attack phase will serve as the failure signal.
+      return;
+    }
+
+    if (protection_level_ < PROTECTION_ENABLED_EXTENSIONS) {
+      EXPECT_TRUE(
+          extension_registry()->enabled_extensions().GetByID(kGoodCrxId));
+      histograms_.ExpectBucketCount(
+          user_prefs::tracked::kTrackedPrefHistogramChangedEncrypted, 5, 1);
+      histograms_.ExpectBucketCount(
+          user_prefs::tracked::kTrackedPrefHistogramWantedResetEncrypted, 5, 1);
+    } else {
+      EXPECT_FALSE(
+          extension_registry()->enabled_extensions().GetByID(kGoodCrxId));
+      histograms_.ExpectBucketCount(
+          user_prefs::tracked::kTrackedPrefHistogramChangedEncrypted,
+          5 /* extensions.settings reporting_id */, 1);
+      histograms_.ExpectBucketCount(
+          user_prefs::tracked::kTrackedPrefHistogramResetEncrypted, 5, 1);
+    }
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  // Member variable to track if the attack was successfully performed.
+  bool was_attacked_ = false;
+};
+
+PREF_HASH_BROWSER_TEST(PrefHashBrowserTestEncryptedSplitPrefTampered,
+                       EncryptedSplitPrefTampered);
+
+class PrefHashBrowserTestEncryptedHashIsAuthoritative
+    : public PrefHashBrowserTestEncryptedBase {
+ public:
+  PrefHashBrowserTestEncryptedHashIsAuthoritative() {
+    feature_list_.InitAndEnableFeature(tracked::kEncryptedPrefHashing);
+  }
+
+  void SetupPreferences() override {
+    // In the PRE_ test, set a value. This will cause both a valid legacy MAC
+    // and a valid encrypted hash to be written to disk on shutdown.
+    profile()->GetPrefs()->SetString(prefs::kHomePage, "http://good.com");
+  }
+
+  void AttackPreferencesOnDisk(
+      base::Value::Dict* unprotected_preferences,
+      base::Value::Dict* protected_preferences) override {
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      return;
+    }
+
+    base::Value::Dict* macs_dict = nullptr;
+    if (protected_preferences) {
+      macs_dict =
+          protected_preferences->FindDictByDottedPath("protection.macs");
+    }
+    if (!macs_dict) {
+      macs_dict =
+          unprotected_preferences->FindDictByDottedPath("protection.macs");
+    }
+    ASSERT_TRUE(macs_dict);
+
+    const std::string encrypted_hash_key =
+        std::string(prefs::kHomePage) + kEncryptedHashSuffix;
+    ASSERT_TRUE(macs_dict->contains(prefs::kHomePage));
+    ASSERT_TRUE(macs_dict->contains(encrypted_hash_key));
+
+    // Tamper with the legacy MAC, but leave the encrypted hash
+    // (the authoritative source) and the preference value untouched.
+    macs_dict->Set(prefs::kHomePage, "invalid_legacy_mac");
+  }
+
+  void VerifyReactionToPrefAttack() override {
+    if (protection_level_ <= PROTECTION_DISABLED_ON_PLATFORM) {
+      return;
+    }
+
+    if (protection_level_ >= PROTECTION_ENABLED_BASIC) {
+      // Assert that the preference was reset to its default (empty) value.
+      EXPECT_TRUE(profile()->GetPrefs()->GetString(prefs::kHomePage).empty());
+
+      // Verify that the reset was triggered by the non-encrypted, legacy MAC
+      // validation path.
+      histograms_.ExpectUniqueSample(
+          user_prefs::tracked::kTrackedPrefHistogramChanged,
+          2 /* homepage reporting_id */, 1);
+      histograms_.ExpectUniqueSample(
+          user_prefs::tracked::kTrackedPrefHistogramReset,
+          2 /* homepage reporting_id */, 1);
+
+      // No other validation paths should have triggered a reset.
+      histograms_.ExpectTotalCount(
+          user_prefs::tracked::kTrackedPrefHistogramUnchangedEncrypted, 0);
+      histograms_.ExpectTotalCount(
+          user_prefs::tracked::kTrackedPrefHistogramResetEncrypted, 0);
+
+    } else {
+      // On platforms with low enforcement (Linux), the initial validation pass
+      // logs the invalid legacy MAC but does NOT reset the preference. The
+      // deferred validation pass then checks the authoritative encrypted hash,
+      // finds it valid, and the preference value is kept.
+      EXPECT_EQ("http://good.com",
+                profile()->GetPrefs()->GetString(prefs::kHomePage));
+
+      // Verify the preference was considered unchanged because the
+      // authoritative encrypted hash was valid.
+      histograms_.ExpectBucketCount(
+          user_prefs::tracked::kTrackedPrefHistogramUnchangedEncrypted,
+          2 /* homepage reporting_id */, 1);
+
+      // Verify no resets of any kind were performed.
+      histograms_.ExpectTotalCount(
+          user_prefs::tracked::kTrackedPrefHistogramReset, 0);
+      histograms_.ExpectTotalCount(
+          user_prefs::tracked::kTrackedPrefHistogramResetEncrypted, 0);
+      histograms_.ExpectTotalCount(
+          user_prefs::tracked::kTrackedPrefHistogramResetViaHmacFallback, 0);
+    }
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+PREF_HASH_BROWSER_TEST(PrefHashBrowserTestEncryptedHashIsAuthoritative,
+                       EncryptedHashIsAuthoritative);
diff --git a/chrome/browser/profiles/pref_service_builder_utils.cc b/chrome/browser/profiles/pref_service_builder_utils.cc
index ccb9c7b..e1f0c09 100644
--- a/chrome/browser/profiles/pref_service_builder_utils.cc
+++ b/chrome/browser/profiles/pref_service_builder_utils.cc
@@ -88,12 +88,13 @@
     scoped_refptr<base::SequencedTaskRunner> io_task_runner,
     SimpleFactoryKey* key,
     const base::FilePath& profile_path,
-    bool async_prefs) {
+    bool async_prefs,
+    os_crypt_async::OSCryptAsync* os_crypt_async) {
   supervised_user::SupervisedUserSettingsService* supervised_user_settings =
       SupervisedUserSettingsServiceFactory::GetForKey(key);
   supervised_user_settings->Init(profile_path, io_task_runner, !async_prefs);
   return chrome_prefs::CreateProfilePrefs(
       profile_path, std::move(pref_validation_delegate), policy_service,
       supervised_user_settings, extension_pref_store, pref_registry,
-      browser_policy_connector, async_prefs, io_task_runner);
+      browser_policy_connector, async_prefs, io_task_runner, os_crypt_async);
 }
diff --git a/chrome/browser/profiles/pref_service_builder_utils.h b/chrome/browser/profiles/pref_service_builder_utils.h
index a2cd943..7ce79405 100644
--- a/chrome/browser/profiles/pref_service_builder_utils.h
+++ b/chrome/browser/profiles/pref_service_builder_utils.h
@@ -34,6 +34,10 @@
 class PrefRegistrySyncable;
 }
 
+namespace os_crypt_async {
+class OSCryptAsync;
+}  // namespace os_crypt_async
+
 // This file includes multiple helper functions to create the Profile's
 // PrefService. Note: please update all of the callers if updating any helper
 // function. Currently, these code are called in both ProfileImpl and
@@ -57,6 +61,7 @@
     scoped_refptr<base::SequencedTaskRunner> io_task_runner,
     SimpleFactoryKey* key,
     const base::FilePath& profile_path,
-    bool async_prefs);
+    bool async_prefs,
+    os_crypt_async::OSCryptAsync* os_crypt_async);
 
 #endif  // CHROME_BROWSER_PROFILES_PREF_SERVICE_BUILDER_UTILS_H_
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 0a7e4615..9e7ac54 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -663,7 +663,7 @@
       profile_policy_connector_->policy_service(),
       g_browser_process->browser_policy_connector(),
       std::move(pref_validation_delegate), GetIOTaskRunner(), key_.get(), path_,
-      async_prefs);
+      async_prefs, g_browser_process->os_crypt_async());
   key_->SetPrefs(prefs_.get());
 }
 
diff --git a/chrome/browser/push_notification/push_notification_service_desktop_impl_unittest.cc b/chrome/browser/push_notification/push_notification_service_desktop_impl_unittest.cc
index 62b0b17..33025d7 100644
--- a/chrome/browser/push_notification/push_notification_service_desktop_impl_unittest.cc
+++ b/chrome/browser/push_notification/push_notification_service_desktop_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/notimplemented.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/push_notification/prefs/push_notification_prefs.h"
diff --git a/chrome/browser/push_notification/server_client/push_notification_server_client_desktop_impl_unittest.cc b/chrome/browser/push_notification/server_client/push_notification_server_client_desktop_impl_unittest.cc
index fb41624..b5ecef7 100644
--- a/chrome/browser/push_notification/server_client/push_notification_server_client_desktop_impl_unittest.cc
+++ b/chrome/browser/push_notification/server_client/push_notification_server_client_desktop_impl_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/gtest_util.h"
 #include "base/test/metrics/histogram_tester.h"
diff --git a/chrome/browser/renderer_context_menu/link_to_text_menu_observer.cc b/chrome/browser/renderer_context_menu/link_to_text_menu_observer.cc
index 96b7ee0..f3f06b8 100644
--- a/chrome/browser/renderer_context_menu/link_to_text_menu_observer.cc
+++ b/chrome/browser/renderer_context_menu/link_to_text_menu_observer.cc
@@ -10,6 +10,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/primary_tts.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/primary_tts.ts
index 5d54870..4e6e47e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/primary_tts.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/primary_tts.ts
@@ -5,10 +5,12 @@
 /**
  * @fileoverview Default implementation for TTS in the background context.
  */
+import {BridgeHelper} from '/common/bridge_helper.js';
 import {constants} from '/common/constants.js';
 import {LocalStorage} from '/common/local_storage.js';
 import {TestImportManager} from '/common/testing/test_import_manager.js';
 
+import {BridgeConstants} from '../common/bridge_constants.js';
 import {Msgs} from '../common/msgs.js';
 import {OffscreenCommandType} from '../common/offscreen_command_type.js';
 import {PanelCommand, PanelCommandType} from '../common/panel_command.js';
@@ -22,6 +24,9 @@
 
 type TtsVoice = chrome.tts.TtsVoice;
 
+const TARGET = BridgeConstants.PrimaryTts.TARGET;
+const Action = BridgeConstants.PrimaryTts.Action;
+
 class Utterance {
   static nextUtteranceId_ = 1;
   textString: string;
@@ -97,10 +102,9 @@
     this.currentPunctuationEcho_ =
         SettingsManager.getNumber(TtsSettings.PUNCTUATION_ECHO);
 
-    chrome.runtime.onMessage.addListener(
-        (message: any|undefined, _sender: chrome.runtime.MessageSender,
-         _sendResponse: (value: any) => void) =>
-            this.handleMessageFromOffscreen_(message));
+    BridgeHelper.registerHandler(
+        TARGET, Action.ON_VOICES_CHANGED,
+        () => this.updateVoice(SettingsManager.getString('voiceName')));
 
     this.setDefaultVoiceIfChromecast_();
 
@@ -150,15 +154,6 @@
         undefined, setDefault);
   }
 
-  private handleMessageFromOffscreen_(message: any|undefined) {
-    switch (message['command']) {
-      case OffscreenCommandType.ON_VOICES_CHANGED:
-        this.updateVoice(SettingsManager.getString('voiceName'));
-        break;
-    }
-    return false;
-  }
-
   /**
    * @param textString The string of text to be spoken.
    * @param queueMode The queue mode to use for speaking.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/background_bridge.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/background_bridge.ts
index 00bc5c03..34839a45 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/background_bridge.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/background_bridge.ts
@@ -237,6 +237,14 @@
     },
   },
 
+  LocaleOutputHelper: {
+    onVoicesChanged(): Promise<void> {
+      return BridgeHelper.sendMessage(
+          BridgeConstants.LocaleOutputHelper.TARGET,
+          BridgeConstants.LocaleOutputHelper.Action.ON_VOICES_CHANGED);
+    },
+  },
+
   LogStore: {
     /** Clear the log buffer. */
     clearLog(): Promise<void> {
@@ -353,6 +361,14 @@
     },
   },
 
+  PrimaryTts: {
+    onVoicesChanged(): Promise<void> {
+      return BridgeHelper.sendMessage(
+          BridgeConstants.PrimaryTts.TARGET,
+          BridgeConstants.PrimaryTts.Action.ON_VOICES_CHANGED);
+    },
+  },
+
   TtsBackground: {
     /** Gets the voice currently used by ChromeVox when calling tts. */
     getCurrentVoice(): Promise<string> {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts
index 8f60666..6cc5d28 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts
@@ -136,6 +136,11 @@
     },
   },
 
+  LocaleOutputHelper: {
+    TARGET: 'LocaleOutputHelper',
+    Action: {ON_VOICES_CHANGED: 'onVoicesChanged'},
+  },
+
   LogStore: {
     TARGET: 'LogStore',
     Action: {
@@ -188,6 +193,11 @@
     },
   },
 
+  PrimaryTts: {
+    TARGET: 'PrimaryTts',
+    Action: {ON_VOICES_CHANGED: 'onVoicesChanged'},
+  },
+
   TtsBackground: {
     TARGET: 'TtsBackground',
     Action: {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/locale_output_helper.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/locale_output_helper.ts
index b8f7487d..83cbf2f4 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/locale_output_helper.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/locale_output_helper.ts
@@ -9,15 +9,19 @@
  * 'en-US'. For more information on locales:
  * https://en.wikipedia.org/wiki/Locale_(computer_software)
  */
+import {BridgeHelper} from '/common/bridge_helper.js';
 import {TestImportManager} from '/common/testing/test_import_manager.js';
 
-import {OffscreenCommandType} from '../common/offscreen_command_type.js';
+import {BridgeConstants} from '../common/bridge_constants.js';
 
 import {Msgs} from './msgs.js';
 
 type AutomationNode = chrome.automation.AutomationNode;
 type TtsVoice = chrome.tts.TtsVoice;
 
+const TARGET = BridgeConstants.LocaleOutputHelper.TARGET;
+const Action = BridgeConstants.LocaleOutputHelper.Action;
+
 interface TextWithLocale {
   text: string;
   locale: string;
@@ -37,19 +41,8 @@
 
     this.setAvailableVoices_();
 
-    chrome.runtime.onMessage.addListener(
-        (message: any|undefined, _sender: chrome.runtime.MessageSender,
-         _sendResponse: (value: any) => void) =>
-            this.handleMessageFromOffscreen_(message));
-  }
-
-  private handleMessageFromOffscreen_(message: any|undefined) {
-    switch (message['command']) {
-      case OffscreenCommandType.ON_VOICES_CHANGED:
-        this.setAvailableVoices_();
-        break;
-    }
-    return false;
+    BridgeHelper.registerHandler(
+        TARGET, Action.ON_VOICES_CHANGED, () => this.setAvailableVoices_());
   }
 
   private setAvailableVoices_(): void {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/offscreen_command_type.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/offscreen_command_type.ts
index 362c4ea..4693b5e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/offscreen_command_type.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/offscreen_command_type.ts
@@ -18,6 +18,8 @@
   LIBLOUIS_START_WORKER = 'LibLouisStartWorker',
   LIBLOUIS_RPC = 'LibLouisRPC',
   ON_CLIPBOARD_DATA_CHANGED = 'onClipboardDataChanged',
+  ON_KEY_DOWN = 'onKeyDown',
+  ON_KEY_UP = 'onKeyUp',
   ON_VOICES_CHANGED = 'onvoiceschanged',
   PLAY_EARCON = 'playEarcon',
   RECORD_EARCONS_FOR_TEST = 'recordEarconsForTest',
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts
index f774cf2..7070a92 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts
@@ -225,8 +225,8 @@
   constructor() {
     if (window.speechSynthesis) {
       window.speechSynthesis.onvoiceschanged = () => {
-        chrome.runtime.sendMessage(
-            undefined, {command: OffscreenCommandType.ON_VOICES_CHANGED});
+        BackgroundBridge.LocaleOutputHelper.onVoicesChanged();
+        BackgroundBridge.PrimaryTts.onVoicesChanged();
       };
     }
 
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index f2a9ed2..ba4683fc 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -140,9 +140,6 @@
     "privacy_page/secure_dns_input.ts",
     "privacy_page/security_keys_bio_enroll_dialog.ts",
     "privacy_page/security_keys_credential_management_dialog.ts",
-    "privacy_page/security_keys_phones_dialog.ts",
-    "privacy_page/security_keys_phones_list.ts",
-    "privacy_page/security_keys_phones_subpage.ts",
     "privacy_page/security_keys_pin_field.ts",
     "privacy_page/security_keys_reset_dialog.ts",
     "privacy_page/security_keys_set_pin_dialog.ts",
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index 26c1bbe..f6eaf94c 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -33,9 +33,6 @@
 import './privacy_sandbox/privacy_sandbox_manage_topics_subpage.js';
 import './privacy_sandbox/privacy_sandbox_topics_subpage.js';
 import './privacy_page/security_keys_subpage.js';
-import './privacy_page/security_keys_phones_subpage.js';
-import './privacy_page/security_keys_phones_list.js';
-import './privacy_page/security_keys_phones_dialog.js';
 import './privacy_page/security_page_v2.js';
 import './privacy_page/security_page.js';
 import './safety_hub/safety_hub_page.js';
@@ -206,9 +203,8 @@
 export {SecureDnsResolverType, SettingsSecureDnsElement} from './privacy_page/secure_dns.js';
 export {SecureDnsInputElement} from './privacy_page/secure_dns_input.js';
 export {BioEnrollDialogPage, SettingsSecurityKeysBioEnrollDialogElement} from './privacy_page/security_keys_bio_enroll_dialog.js';
-export {Ctap2Status, SampleStatus, SecurityKeysBioEnrollProxy, SecurityKeysBioEnrollProxyImpl, SecurityKeysCredentialBrowserProxy, SecurityKeysCredentialBrowserProxyImpl, SecurityKeysPhone, SecurityKeysPhonesBrowserProxy, SecurityKeysPhonesBrowserProxyImpl, SecurityKeysPhonesList, SecurityKeysPinBrowserProxy, SecurityKeysPinBrowserProxyImpl, SecurityKeysResetBrowserProxy, SecurityKeysResetBrowserProxyImpl} from './privacy_page/security_keys_browser_proxy.js';
+export {Ctap2Status, SampleStatus, SecurityKeysBioEnrollProxy, SecurityKeysBioEnrollProxyImpl, SecurityKeysCredentialBrowserProxy, SecurityKeysCredentialBrowserProxyImpl, SecurityKeysPinBrowserProxy, SecurityKeysPinBrowserProxyImpl, SecurityKeysResetBrowserProxy, SecurityKeysResetBrowserProxyImpl} from './privacy_page/security_keys_browser_proxy.js';
 export {CredentialManagementDialogPage, SettingsSecurityKeysCredentialManagementDialogElement} from './privacy_page/security_keys_credential_management_dialog.js';
-export {SecurityKeysPhonesSubpageElement} from './privacy_page/security_keys_phones_subpage.js';
 export {ResetDialogPage, SettingsSecurityKeysResetDialogElement} from './privacy_page/security_keys_reset_dialog.js';
 export {SetPinDialogPage, SettingsSecurityKeysSetPinDialogElement} from './privacy_page/security_keys_set_pin_dialog.js';
 export {SecurityKeysSubpageElement} from './privacy_page/security_keys_subpage.js';
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 24d62dd..fe9dbe9 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -143,15 +143,6 @@
         </template>
       </template>
 
-      <template is="dom-if" if="[[enableManagePhones_]]">
-        <template is="dom-if" route-path="/securityKeys/phones">
-          <settings-subpage associated-control="[[$$('#securityLinkRow')]]"
-              page-title="$i18n{securityKeysPhonesManage}">
-            <security-keys-phones-subpage></security-keys-phones-subpage>
-          </settings-subpage>
-        </template>
-      </template>
-
       <template is="dom-if" route-path="/content">
         <settings-subpage
             associated-control="[[$$('#permissionsLinkRow')]]"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
index 040ccbf4..30b89ed 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
@@ -109,13 +109,6 @@
         },
       },
 
-      enableManagePhones_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.getBoolean('enableSecurityKeysManagePhones');
-        },
-      },
-
       blockAutoplayStatus_: {
         type: Object,
         value() {
@@ -350,7 +343,6 @@
   declare private showPrivacyGuideDialog_: boolean;
   declare private enableSafeBrowsingSubresourceFilter_: boolean;
   declare private enableBlockAutoplayContentSetting_: boolean;
-  declare private enableManagePhones_: boolean;
   declare private blockAutoplayStatus_: BlockAutoplayStatus;
   declare private enableDeleteBrowsingDataRevamp_: boolean;
   declare private enableFederatedIdentityApiContentSetting_: boolean;
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts
index f8727834..c83eb15 100644
--- a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts
@@ -294,45 +294,6 @@
   close(): void;
 }
 
-/**
- * An object that represents a known phone. The name will not contain any
- * new-line characters and is suitable for showing in UI. The publicKey is a
- * base64-encoded X9.62 P-256 point, but should be treated as an opaque string.
- * It can be passed to functions in |SecurityKeysPhonesBrowserProxy| to identify
- * a specific phone.
- */
-export interface SecurityKeysPhone {
-  name: string;
-  publicKey: string;
-}
-
-/**
- * A pair of lists of |SecurityKeysPhone|s. The first is a list of phones known
- * because they are syncing to the same account. The second are phones that have
- * been linked by scanning a QR code. Only elements from the latter can be
- * passed to |delete| or |rename| in |SecurityKeysPhonesBrowserProxy|.
- */
-export type SecurityKeysPhonesList = [SecurityKeysPhone[], SecurityKeysPhone[]];
-
-export interface SecurityKeysPhonesBrowserProxy {
-  /**
-   * Enumerates known phones.
-   */
-  enumerate(): Promise<SecurityKeysPhonesList>;
-
-  /**
-   * Deletes a linked phone by public key.
-   */
-  delete(publicKey: string): Promise<SecurityKeysPhonesList>;
-
-  /**
-   * Rename a linked phone.
-   *
-   * Rename the phone the given public key so that it is now known as |newName|.
-   */
-  rename(publicKey: string, newName: string): Promise<void>;
-}
-
 export class SecurityKeysPinBrowserProxyImpl implements
     SecurityKeysPinBrowserProxy {
   startSetPin() {
@@ -478,29 +439,3 @@
 }
 
 let bioEnrollProxyInstance: SecurityKeysBioEnrollProxy|null = null;
-
-export class SecurityKeysPhonesBrowserProxyImpl implements
-    SecurityKeysPhonesBrowserProxy {
-  enumerate() {
-    return sendWithPromise('securityKeyPhonesEnumerate');
-  }
-
-  delete(name: string) {
-    return sendWithPromise('securityKeyPhonesDelete', name);
-  }
-
-  rename(publicKey: string, newName: string) {
-    return sendWithPromise('securityKeyPhonesRename', publicKey, newName);
-  }
-
-  static getInstance(): SecurityKeysPhonesBrowserProxy {
-    return phonesProxyInstance ||
-        (phonesProxyInstance = new SecurityKeysPhonesBrowserProxyImpl());
-  }
-
-  static setInstance(obj: SecurityKeysPhonesBrowserProxy) {
-    phonesProxyInstance = obj;
-  }
-}
-
-let phonesProxyInstance: SecurityKeysPhonesBrowserProxy|null = null;
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_phones_dialog.html b/chrome/browser/resources/settings/privacy_page/security_keys_phones_dialog.html
deleted file mode 100644
index b17a13e..0000000
--- a/chrome/browser/resources/settings/privacy_page/security_keys_phones_dialog.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<style include="settings-shared"></style>
-<cr-dialog id="dialog" close-text="$i18n{close}" show-on-attach>
-  <div slot="title">$i18n{securityKeysPhoneEditDialogTitle}</div>
-  <div slot="body">
-    <cr-input id="name"
-              spellcheck="false"
-              label="$i18n{securityKeysCredentialDisplayNameLabel}"
-              value="[[name]]"
-              on-input="validate_"
-              autofocus>
-    </cr-input>
-  </div>
-  <div slot="button-container">
-    <cr-button class="cancel-button" on-click="onCancelClick_" id="cancel">
-        $i18n{cancel}</cr-button>
-    <cr-button id="actionButton" class="action-button" on-click="onSaveClick_">
-        $i18n{save}
-    </cr-button>
-  </div>
-</cr-dialog>
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_phones_dialog.ts b/chrome/browser/resources/settings/privacy_page/security_keys_phones_dialog.ts
deleted file mode 100644
index 83ce1454..0000000
--- a/chrome/browser/resources/settings/privacy_page/security_keys_phones_dialog.ts
+++ /dev/null
@@ -1,79 +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.
-
-/**
- * @fileoverview A dialog for editing the name of a phone that has been linked
-    for use as a security key.
- */
-import 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
-import 'chrome://resources/cr_elements/cr_input/cr_input.js';
-
-import type {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import type {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
-import type {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import type {SecurityKeysPhonesBrowserProxy} from './security_keys_browser_proxy.js';
-import {SecurityKeysPhonesBrowserProxyImpl} from './security_keys_browser_proxy.js';
-import {getTemplate} from './security_keys_phones_dialog.html.js';
-
-export interface SecurityKeysPhonesDialog {
-  $: {
-    name: CrInputElement,
-    dialog: CrDialogElement,
-    actionButton: CrButtonElement,
-  };
-}
-
-export class SecurityKeysPhonesDialog extends PolymerElement {
-  static get is() {
-    return 'security-keys-phones-dialog';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      name: String,
-      publicKey: String,
-    };
-  }
-
-  declare name: string;
-  declare publicKey: string;
-  private browserProxy_: SecurityKeysPhonesBrowserProxy =
-      SecurityKeysPhonesBrowserProxyImpl.getInstance();
-
-  private onCancelClick_() {
-    this.$.dialog.cancel();
-  }
-
-  private onSaveClick_() {
-    const newName = this.$.name.value;
-    if (newName === this.name) {
-      this.$.dialog.close();
-      return;
-    }
-
-    this.browserProxy_.rename(this.publicKey, newName)
-        .then(() => this.$.dialog.close());
-  }
-
-  private validate_(event: Event) {
-    const input = event.target as CrInputElement;
-    input.invalid = input.value === '';
-    this.$.actionButton.disabled = input.invalid;
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'security-keys-phones-dialog': SecurityKeysPhonesDialog;
-  }
-}
-
-customElements.define(SecurityKeysPhonesDialog.is, SecurityKeysPhonesDialog);
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_phones_list.html b/chrome/browser/resources/settings/privacy_page/security_keys_phones_list.html
deleted file mode 100644
index 360df535..0000000
--- a/chrome/browser/resources/settings/privacy_page/security_keys_phones_list.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<style include="settings-shared">
-  .list-item {
-    justify-content: space-between;
-  }
-
-  #table .cr-row:first-child {
-    border-top: none;
-  }
-</style>
-<div id="outer" class="list-frame" role="table">
-  <div role="rowgroup" id="table">
-    <template is="dom-repeat" items="[[phones]]">
-      <div class="list-item cr-row" role="row">
-        <span role="cell" class="name-column">[[item.name]]</span>
-        <template is="dom-if" if="[[!immutable]]">
-          <span role="cell">
-            <cr-icon-button class="icon-more-vert"
-                            on-click="onDotsClick_"
-                            data-phone-public-key$="[[item.publicKey]]"
-                            title="$i18n{moreActions}">
-            </cr-icon-button>
-          </span>
-        </template>
-      </div>
-    </template>
-
-    <cr-action-menu id="menu" role-description="$i18n{menu}">
-      <button class="dropdown-item" on-click="onEditClick_" id="edit">
-        $i18n{edit}
-      </button>
-      <button class="dropdown-item" on-click="onDeleteClick_" id="delete">
-        $i18n{delete}
-      </button>
-    </cr-action-menu>
-  </div>
-</div>
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_phones_list.ts b/chrome/browser/resources/settings/privacy_page/security_keys_phones_list.ts
deleted file mode 100644
index a2168e4..0000000
--- a/chrome/browser/resources/settings/privacy_page/security_keys_phones_list.ts
+++ /dev/null
@@ -1,77 +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.
-
-/**
- * @fileoverview An element that lists phones usable as security keys,
-    optionally with a drop-down menu for editing or deleting them.
- */
-import '../settings_shared.css.js';
-import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
-import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
-
-import {AnchorAlignment} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import type {SecurityKeysPhone} from './security_keys_browser_proxy.js';
-import {getTemplate} from './security_keys_phones_list.html.js';
-
-class SecurityKeysPhonesListElement extends PolymerElement {
-  static get is() {
-    return 'security-keys-phones-list';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      immutable: {type: Boolean, value: false},
-      phones: {type: Array, value: []},
-    };
-  }
-
-  declare immutable: boolean;
-  declare phones: SecurityKeysPhone[];
-  // Contains the public key of the phone that the action menu was opened for.
-  private publicKeyForActionMenu_: string|null;
-
-  private onDotsClick_(e: Event) {
-    this.publicKeyForActionMenu_ =
-        (e.target as HTMLElement).dataset['phonePublicKey']!;
-
-    this.shadowRoot!.querySelector('cr-action-menu')!.showAt(
-        e.target as HTMLElement, {
-          anchorAlignmentY: AnchorAlignment.AFTER_END,
-        });
-  }
-
-  private onEditClick_(e: Event) {
-    this.handleClick_(e, 'edit-security-key-phone');
-  }
-
-  private onDeleteClick_(e: Event) {
-    this.handleClick_(e, 'delete-security-key-phone');
-  }
-
-  private handleClick_(
-      e: Event,
-      eventName: 'edit-security-key-phone'|'delete-security-key-phone') {
-    e.stopPropagation();
-    this.closePopupMenu_();
-
-    this.dispatchEvent(new CustomEvent(eventName, {
-      bubbles: true,
-      composed: true,
-      detail: this.publicKeyForActionMenu_,
-    }));
-  }
-
-  private closePopupMenu_() {
-    this.shadowRoot!.querySelector('cr-action-menu')!.close();
-  }
-}
-
-customElements.define(
-    SecurityKeysPhonesListElement.is, SecurityKeysPhonesListElement);
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_phones_subpage.html b/chrome/browser/resources/settings/privacy_page/security_keys_phones_subpage.html
deleted file mode 100644
index 4fdafd0..0000000
--- a/chrome/browser/resources/settings/privacy_page/security_keys_phones_subpage.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<style include="cr-shared-style settings-shared"></style>
-
-<style>
-  /* An H2 is the first element on the page and the top padding is excessive
-     in that context. */
-  h2:first-of-type {
-    padding-top: 0;
-  }
-</style>
-
-<div class="cr-row first">
-  <div class="flex cr-padded-text">
-    <h2>$i18n{securityKeysPhonesYourDevices}</h2>
-    <div class="secondary">$i18n{securityKeysPhonesSyncedDesc}</div>
-  </div>
-</div>
-
-<security-keys-phones-list id="syncedPhonesList" immutable
-                           phones="[[syncedPhones_]]">
-</security-keys-phones-list>
-
-<div class="cr-row first">
-  <div class="flex cr-padded-text">
-    <h2>$i18n{securityKeysPhonesLinkedDevices}</h2>
-    <div class="secondary">$i18n{securityKeysPhonesLinkedDesc}</div>
-  </div>
-</div>
-
-<security-keys-phones-list id="linkedPhonesList" phones="[[linkedPhones_]]">
-</security-keys-phones-list>
-
-<template is="dom-if" if="[[showDialog_]]" restamp>
-  <security-keys-phones-dialog name="[[dialogName_]]"
-                               public-key="[[dialogPublicKey_]]"
-                               on-close="onDialogClose_">
-  </security-keys-phones-dialog>
-</template>
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_phones_subpage.ts b/chrome/browser/resources/settings/privacy_page/security_keys_phones_subpage.ts
deleted file mode 100644
index e1ff50f..0000000
--- a/chrome/browser/resources/settings/privacy_page/security_keys_phones_subpage.ts
+++ /dev/null
@@ -1,117 +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.
-
-/**
- * @fileoverview A settings subpage that allows the user to see and manage the
-    set of phones that are usable as security keys.
- */
-import '../settings_shared.css.js';
-
-import {assert} from 'chrome://resources/js/assert.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import type {SecurityKeysPhone, SecurityKeysPhonesBrowserProxy, SecurityKeysPhonesList} from './security_keys_browser_proxy.js';
-import {SecurityKeysPhonesBrowserProxyImpl} from './security_keys_browser_proxy.js';
-import {getTemplate} from './security_keys_phones_subpage.html.js';
-
-declare global {
-  interface HTMLElementEventMap {
-    'edit-security-key-phone': CustomEvent<string>;
-    'delete-security-key-phone': CustomEvent<string>;
-  }
-}
-
-export class SecurityKeysPhonesSubpageElement extends PolymerElement {
-  static get is() {
-    return 'security-keys-phones-subpage';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      syncedPhones_: Array,
-      linkedPhones_: Array,
-      showDialog_: Boolean,
-      dialogName_: String,
-      dialogPublicKey_: String,
-    };
-  }
-
-  declare private syncedPhones_: SecurityKeysPhone[];
-  declare private linkedPhones_: SecurityKeysPhone[];
-  declare private showDialog_: boolean;
-  declare private dialogName_: string;
-  declare private dialogPublicKey_: string;
-  private browserProxy_: SecurityKeysPhonesBrowserProxy =
-      SecurityKeysPhonesBrowserProxyImpl.getInstance();
-
-  override ready() {
-    super.ready();
-
-    this.addEventListener(
-        'edit-security-key-phone', this.editPhone_.bind(this));
-    this.addEventListener(
-        'delete-security-key-phone', this.deletePhone_.bind(this));
-
-    this.browserProxy_.enumerate().then(this.onEnumerateComplete_.bind(this));
-  }
-
-  /**
-   * Called when the browser has a new set of phone details.
-   */
-  private onEnumerateComplete_([syncedPhones, linkedPhones]:
-                                   SecurityKeysPhonesList) {
-    this.syncedPhones_ = syncedPhones;
-    this.linkedPhones_ = linkedPhones;
-  }
-
-  /**
-   * Called when the user clicks "Edit" in a drop-down menu to open the dialog.
-   */
-  private editPhone_(e: CustomEvent<string>) {
-    this.dialogPublicKey_ = e.detail;
-    this.dialogName_ = this.nameFromPublicKey_(e.detail);
-    this.showDialog_ = true;
-  }
-
-  /**
-   * Called when an edit dialog as closed (whether successful or not).
-   */
-  private onDialogClose_() {
-    this.showDialog_ = false;
-    // The dialog may have renamed a phone so refresh the lists.
-    this.browserProxy_.enumerate().then(this.onEnumerateComplete_.bind(this));
-  }
-
-  /**
-   * Called when the user clicks "Delete" in a drop-down menu to delete a linked
-   * phone.
-   */
-  private deletePhone_(e: CustomEvent<string>) {
-    this.browserProxy_.delete(e.detail).then(
-        this.onEnumerateComplete_.bind(this));
-  }
-
-  /**
-   * Returns the name of a linked phone given its public key.
-   */
-  private nameFromPublicKey_(publicKey: string): string {
-    const matchingPhones =
-        this.linkedPhones_.filter(phone => phone.publicKey === publicKey);
-    assert(matchingPhones.length !== 0);
-    return matchingPhones[0].name;
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'security-keys-phones-subpage': SecurityKeysPhonesSubpageElement;
-  }
-}
-
-customElements.define(
-    SecurityKeysPhonesSubpageElement.is, SecurityKeysPhonesSubpageElement);
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html
index a8121519..fbedf770 100644
--- a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html
@@ -1,12 +1,5 @@
 <style include="settings-shared"></style>
 
-<template is="dom-if" if="[[enableManagePhones_]]" restamp>
-  <cr-link-row
-      id="managePhonesButton"
-      label="$i18n{securityKeysPhonesManage}"
-      sub-label="$i18n{securityKeysPhonesManageDesc}"
-      on-click="onManagePhonesClick_"></cr-link-row>
-</template>
 <cr-link-row
     id="setPINButton"
     class="hr"
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.ts b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.ts
index a7e082d..8398c5f 100644
--- a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.ts
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.ts
@@ -18,8 +18,6 @@
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
-import {routes} from '../route.js';
-import {Router} from '../router.js';
 
 import {getTemplate} from './security_keys_subpage.html.js';
 
@@ -49,14 +47,6 @@
         },
       },
 
-      enableManagePhones_: {
-        type: Boolean,
-        readOnly: true,
-        value() {
-          return loadTimeData.getBoolean('enableSecurityKeysManagePhones');
-        },
-      },
-
       showSetPINDialog_: {
         type: Boolean,
         value: false,
@@ -80,16 +70,11 @@
   }
 
   declare private enableBioEnrollment_: boolean;
-  declare private enableManagePhones_: boolean;
   declare private showSetPINDialog_: boolean;
   declare private showCredentialManagementDialog_: boolean;
   declare private showResetDialog_: boolean;
   declare private showBioEnrollDialog_: boolean;
 
-  private onManagePhonesClick_() {
-    Router.getInstance().navigateTo(routes.SECURITY_KEYS_PHONES);
-  }
-
   private onSetPin_() {
     this.showSetPINDialog_ = true;
   }
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.html b/chrome/browser/resources/settings/privacy_page/security_page.html
index 26438ab..ae93043d 100644
--- a/chrome/browser/resources/settings/privacy_page/security_page.html
+++ b/chrome/browser/resources/settings/privacy_page/security_page.html
@@ -283,16 +283,6 @@
         </cr-link-row>
     </template>
 
-<if expr="is_win">
-    <template is="dom-if" if="[[enableSecurityKeysPhonesSubpage_]]">
-        <cr-link-row id="securityKeysPhonesSubpageTrigger"
-            label="$i18n{securityKeysPhonesManage}"
-            sub-label="$i18n{securityKeysPhonesManageDesc}"
-            on-click="onManagePhonesClick_">
-        </cr-link-row>
-    </template>
-</if>
-
     <cr-link-row id="manageCertificatesLinkRow" class="hr"
         role-description="$i18n{subpageArrowRoleDescription}"
         label="$i18n{manageCertificates}"
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.ts b/chrome/browser/resources/settings/privacy_page/security_page.ts
index 5d75881..1ca971d4 100644
--- a/chrome/browser/resources/settings/privacy_page/security_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/security_page.ts
@@ -164,20 +164,6 @@
         },
       },
 
-      // <if expr="is_win">
-      enableSecurityKeysPhonesSubpage_: {
-        type: Boolean,
-        readOnly: true,
-        value() {
-          // The phones subpage is linked from the security keys subpage, if
-          // it exists. Thus the phones subpage is only linked from this page
-          // if the security keys subpage is disabled.
-          return !loadTimeData.getBoolean('enableSecurityKeysSubpage') &&
-              loadTimeData.getBoolean('enableSecurityKeysManagePhones');
-        },
-      },
-      // </if>
-
       focusConfig: {
         type: Object,
         observer: 'focusConfigChanged_',
@@ -236,9 +222,6 @@
   // </if>
 
   declare private enableSecurityKeysSubpage_: boolean;
-  // <if expr="is_win">
-  declare private enableSecurityKeysPhonesSubpage_: boolean;
-  // </if>
   declare focusConfig: FocusConfig;
   declare private showDisableSafebrowsingDialog_: boolean;
   declare private enableHashPrefixRealTimeLookups_: boolean;
@@ -534,12 +517,6 @@
     Router.getInstance().navigateTo(routes.SECURITY_KEYS);
   }
 
-  // <if expr="is_win">
-  private onManagePhonesClick_() {
-    Router.getInstance().navigateTo(routes.SECURITY_KEYS_PHONES);
-  }
-  // </if>
-
   private onEnhancedProtectionLearnMoreClick_(e: Event) {
     OpenWindowProxyImpl.getInstance().openUrl(
         loadTimeData.getString('enhancedProtectionHelpCenterURL'));
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index 6c9d9a5d..35c69da 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -56,14 +56,6 @@
 
   if (loadTimeData.getBoolean('enableSecurityKeysSubpage')) {
     r.SECURITY_KEYS = r.SECURITY.createChild('/securityKeys');
-    if (loadTimeData.getBoolean('enableSecurityKeysManagePhones')) {
-      r.SECURITY_KEYS_PHONES =
-          r.SECURITY_KEYS.createChild('/securityKeys/phones');
-    }
-    // <if expr="is_win">
-  } else if (loadTimeData.getBoolean('enableSecurityKeysManagePhones')) {
-    r.SECURITY_KEYS_PHONES = r.SECURITY.createChild('/securityKeys/phones');
-    // </if>
   }
 
   r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all');
diff --git a/chrome/browser/resources/settings/router.ts b/chrome/browser/resources/settings/router.ts
index 4c49df0..b41d795db 100644
--- a/chrome/browser/resources/settings/router.ts
+++ b/chrome/browser/resources/settings/router.ts
@@ -57,7 +57,6 @@
   SEARCH_ENGINES: Route;
   SECURITY: Route;
   SECURITY_KEYS: Route;
-  SECURITY_KEYS_PHONES: Route;
   SITE_SETTINGS: Route;
   SITE_SETTINGS_ADS: Route;
   SITE_SETTINGS_ALL: Route;
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_service.cc b/chrome/browser/safe_browsing/test_safe_browsing_service.cc
index e618e97..6c2a61ed 100644
--- a/chrome/browser/safe_browsing/test_safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/test_safe_browsing_service.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
 #include "chrome/browser/safe_browsing/chrome_ui_manager_delegate.h"
diff --git a/chrome/browser/share/fake_share_history.cc b/chrome/browser/share/fake_share_history.cc
index 1ab5f311..3e0bf99 100644
--- a/chrome/browser/share/fake_share_history.cc
+++ b/chrome/browser/share/fake_share_history.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/share/fake_share_history.h"
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 
 namespace sharing {
diff --git a/chrome/browser/sharesheet/sharesheet_service_delegator.cc b/chrome/browser/sharesheet/sharesheet_service_delegator.cc
index af02f9a..c3471d3c 100644
--- a/chrome/browser/sharesheet/sharesheet_service_delegator.cc
+++ b/chrome/browser/sharesheet/sharesheet_service_delegator.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "chrome/browser/sharesheet/sharesheet_service.h"
 #include "chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view_delegate.h"
diff --git a/chrome/browser/sharing/sharing_device_registration_impl_unittest.cc b/chrome/browser/sharing/sharing_device_registration_impl_unittest.cc
index 28470bbe..ccb1c21 100644
--- a/chrome/browser/sharing/sharing_device_registration_impl_unittest.cc
+++ b/chrome/browser/sharing/sharing_device_registration_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 03ea8cc..29e5151 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -34,6 +34,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/nix/xdg_util.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/kill.h"
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
index f0a3c1c..a0a75e51 100644
--- a/chrome/browser/signin/dice_browsertest.cc
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -1355,7 +1355,8 @@
   DiceBrowserTestWithSyncOptinScreen() {
     feature_list_.InitWithFeatures(
         /*enabled_features=*/{switches::kEnableHistorySyncOptin,
-                              switches::kEnableHistorySyncOptinFromTabHelper},
+                              switches::kEnableHistorySyncOptinFromTabHelper,
+                              syncer::kReplaceSyncPromosWithSignInPromos},
         /*disabled_features=*/{});
   }
 
diff --git a/chrome/browser/startup_data.cc b/chrome/browser/startup_data.cc
index ec5aa30..fb9efdc 100644
--- a/chrome/browser/startup_data.cc
+++ b/chrome/browser/startup_data.cc
@@ -239,7 +239,7 @@
       pref_registry_, nullptr /* extension_pref_store */,
       profile_policy_connector_->policy_service(), browser_policy_connector,
       std::move(pref_validation_delegate), io_task_runner, key_.get(), path,
-      false /* async_prefs*/);
+      false /* async_prefs*/, g_browser_process->os_crypt_async());
 }
 #endif
 
diff --git a/chrome/browser/supervised_user/chrome_supervised_user_service_platform_delegate_base.cc b/chrome/browser/supervised_user/chrome_supervised_user_service_platform_delegate_base.cc
index 9f3f4b08..eb62827a 100644
--- a/chrome/browser/supervised_user/chrome_supervised_user_service_platform_delegate_base.cc
+++ b/chrome/browser/supervised_user/chrome_supervised_user_service_platform_delegate_base.cc
@@ -63,8 +63,7 @@
               IdentityManagerFactory::GetForProfile(&profile_.get()),
               *profile_->GetPrefs(),
               *HostContentSettingsMapFactory::GetForProfile(&profile_.get()),
-              supervised_user_service ? supervised_user_service->GetURLFilter()
-                                      : nullptr)
+              supervised_user_service)
               .GetSupervisionStatusForPrimaryAccount();
   if (!user_log_segment.has_value()) {
     return;
@@ -75,6 +74,18 @@
         kSupervisionEnabledByFamilyLinkPolicy:
     case supervised_user::FamilyLinkUserLogRecord::Segment::
         kSupervisionEnabledByFamilyLinkUser:
+    case supervised_user::FamilyLinkUserLogRecord::Segment::
+        kSupervisionEnabledLocally:
+      if (!supervised_user_service->IsLocalContentFilteringEnabled()) {
+        CHECK(supervised_user_service->IsSupervisedLocally());
+        // This sub-state is exceptionally allowed: user is attributed to local
+        // supervision, but that supervision is enabled due to other reasons
+        // than browser content filtering (which would disable the incognito
+        // mode). In other words, that's a type of supervised user who can use
+        // incognito mode.
+        return;
+      }
+
       // This is a supervised profile. It is not expected for incognito to be
       // available except in some edge cases. Output the edge cases separately
       // from the "unexpected" bucket.
diff --git a/chrome/browser/supervised_user/classify_url_navigation_throttle.cc b/chrome/browser/supervised_user/classify_url_navigation_throttle.cc
index 61ddb33..5f5be59 100644
--- a/chrome/browser/supervised_user/classify_url_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/classify_url_navigation_throttle.cc
@@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/browser_process.h"
@@ -30,6 +31,7 @@
 #include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
 #include "components/supervised_user/core/browser/supervised_user_utils.h"
+#include "components/supervised_user/core/common/features.h"
 #include "components/supervised_user/core/common/supervised_user_constants.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
@@ -244,29 +246,48 @@
         return;
       }
 #endif
-      Profile* profile = Profile::FromBrowserContext(
-          navigation_handle()->GetWebContents()->GetBrowserContext());
-      std::string interstitial_html =
-          SupervisedUserInterstitial::GetHTMLContents(
-              SupervisedUserServiceFactory::GetForProfile(profile),
-              profile->GetPrefs(), result.reason, already_sent_request,
-              is_main_frame, g_browser_process->GetApplicationLocale());
       CancelDeferredNavigation(content::NavigationThrottle::ThrottleCheckResult(
-          CANCEL, net::ERR_BLOCKED_BY_CLIENT, std::move(interstitial_html)));
+          CANCEL, net::ERR_BLOCKED_BY_CLIENT,
+          GetInterstitialHTML(result, already_sent_request, is_main_frame)));
+
       break;
     }
   }
 }
 
+std::string ClassifyUrlNavigationThrottle::GetInterstitialHTML(
+    SupervisedUserURLFilter::Result result,
+    bool already_sent_request,
+    bool is_main_frame) const {
+#if BUILDFLAG(IS_ANDROID)
+  if (supervised_user_service()->IsLocalContentFilteringEnabled() &&
+      base::FeatureList::IsEnabled(
+          kSupervisedUserInterstitialWithoutApprovals)) {
+    return SupervisedUserInterstitial::GetHTMLContentsWithoutApprovals(result.url,
+        g_browser_process->GetApplicationLocale());
+  }
+#endif
+  Profile* profile = Profile::FromBrowserContext(
+      navigation_handle()->GetWebContents()->GetBrowserContext());
+  return SupervisedUserInterstitial::GetHTMLContentsWithApprovals(
+      supervised_user_service(), profile->GetPrefs(), result.reason,
+      already_sent_request, is_main_frame,
+      g_browser_process->GetApplicationLocale());
+}
+
 const GURL& ClassifyUrlNavigationThrottle::currently_navigated_url() const {
   return navigation_handle()->GetURL();
 }
 
 SupervisedUserURLFilter* ClassifyUrlNavigationThrottle::url_filter() const {
+  return supervised_user_service()->GetURLFilter();
+}
+
+SupervisedUserService* ClassifyUrlNavigationThrottle::supervised_user_service()
+    const {
   return SupervisedUserServiceFactory::GetForProfile(
-             Profile::FromBrowserContext(
-                 navigation_handle()->GetWebContents()->GetBrowserContext()))
-      ->GetURLFilter();
+      Profile::FromBrowserContext(
+          navigation_handle()->GetWebContents()->GetBrowserContext()));
 }
 
 void ClassifyUrlNavigationThrottle::MaybeCreateAndAdd(
diff --git a/chrome/browser/supervised_user/classify_url_navigation_throttle.h b/chrome/browser/supervised_user/classify_url_navigation_throttle.h
index 57d788f..6c7a777d 100644
--- a/chrome/browser/supervised_user/classify_url_navigation_throttle.h
+++ b/chrome/browser/supervised_user/classify_url_navigation_throttle.h
@@ -12,6 +12,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/elapsed_timer.h"
+#include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
 #include "components/supervised_user/core/browser/supervised_user_utils.h"
 #include "content/public/browser/navigation_handle.h"
@@ -148,8 +149,17 @@
                             bool already_sent_request,
                             bool is_main_frame);
 
+  // Returns the HTML to be used for the interstitial, specific for the profile
+  // doing the navigation.
+  std::string GetInterstitialHTML(SupervisedUserURLFilter::Result result,
+                                  bool already_sent_request,
+                                  bool is_main_frame) const;
+
   // Returns the URL filter associated with the navigated under throttling.
   SupervisedUserURLFilter* url_filter() const;
+  // Returns the supervised user service associated with the navigated under
+  // throttling.
+  SupervisedUserService* supervised_user_service() const;
 
   // All pending and completed checks.
   ClassifyUrlCheckList list_;
diff --git a/chrome/browser/task_manager/providers/web_contents/extension_task.cc b/chrome/browser/task_manager/providers/web_contents/extension_task.cc
index 548aad6f..e8d7764 100644
--- a/chrome/browser/task_manager/providers/web_contents/extension_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/extension_task.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_context.h"
diff --git a/chrome/browser/task_manager/sampling/task_manager_impl.cc b/chrome/browser/task_manager/sampling/task_manager_impl.cc
index 4b816c10..0b4aa337 100644
--- a/chrome/browser/task_manager/sampling/task_manager_impl.cc
+++ b/chrome/browser/task_manager/sampling/task_manager_impl.cc
@@ -16,6 +16,7 @@
 #include "base/containers/adapters.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/task/thread_pool.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_webauthn_delegate.cc b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_webauthn_delegate.cc
index 006de98..b355b4a 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_webauthn_delegate.cc
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_webauthn_delegate.cc
@@ -9,7 +9,7 @@
 
 #include "base/containers/span.h"
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/password_manager/android/password_manager_launcher_android.h"
 #include "chrome/browser/webauthn/android/webauthn_request_delegate_android.h"
 #include "components/password_manager/core/browser/manage_passwords_referrer.h"
diff --git a/chrome/browser/ui/android/hats/hats_service_android.cc b/chrome/browser/ui/android/hats/hats_service_android.cc
index 1dd69e948..6133e30a 100644
--- a/chrome/browser/ui/android/hats/hats_service_android.cc
+++ b/chrome/browser/ui/android/hats/hats_service_android.cc
@@ -11,6 +11,7 @@
 
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/task/sequenced_task_runner.h"
 #include "chrome/browser/android/resource_mapper.h"
diff --git a/chrome/browser/ui/android/simple_message_box_android.cc b/chrome/browser/ui/android/simple_message_box_android.cc
index f40147e..496ab352 100644
--- a/chrome/browser/ui/android/simple_message_box_android.cc
+++ b/chrome/browser/ui/android/simple_message_box_android.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace chrome {
 
diff --git a/chrome/browser/ui/android/status_tray_android.cc b/chrome/browser/ui/android/status_tray_android.cc
index 5481935..71d78bb 100644
--- a/chrome/browser/ui/android/status_tray_android.cc
+++ b/chrome/browser/ui/android/status_tray_android.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/status_icons/status_tray.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 std::unique_ptr<StatusTray> StatusTray::Create() {
   NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/android/tab_model/android_live_tab_context.cc b/chrome/browser/ui/android/tab_model/android_live_tab_context.cc
index f23c14a..6611da8 100644
--- a/chrome/browser/ui/android/tab_model/android_live_tab_context.cc
+++ b/chrome/browser/ui/android/tab_model/android_live_tab_context.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <optional>
 
+#include "base/notimplemented.h"
 #include "base/uuid.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
index 3d375cc..53471096 100644
--- a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
@@ -11,6 +11,7 @@
 #include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/ui/ash/desks/desks_templates_app_launch_handler.cc b/chrome/browser/ui/ash/desks/desks_templates_app_launch_handler.cc
index 0b96d57..73690f1b 100644
--- a/chrome/browser/ui/ash/desks/desks_templates_app_launch_handler.cc
+++ b/chrome/browser/ui/ash/desks/desks_templates_app_launch_handler.cc
@@ -9,7 +9,7 @@
 #include "ash/public/cpp/desk_template.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
diff --git a/chrome/browser/ui/ash/global_media_controls/media_item_ui_device_selector_delegate_ash.cc b/chrome/browser/ui/ash/global_media_controls/media_item_ui_device_selector_delegate_ash.cc
index 49b5fd40..8584944 100644
--- a/chrome/browser/ui/ash/global_media_controls/media_item_ui_device_selector_delegate_ash.cc
+++ b/chrome/browser/ui/ash/global_media_controls/media_item_ui_device_selector_delegate_ash.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/ash/global_media_controls/media_item_ui_device_selector_delegate_ash.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 void MediaItemUIDeviceSelectorDelegateAsh::OnAudioSinkChosen(
     const std::string& id,
diff --git a/chrome/browser/ui/ash/login/simple_web_view_dialog.cc b/chrome/browser/ui/ash/login/simple_web_view_dialog.cc
index 37c282b..795586e 100644
--- a/chrome/browser/ui/ash/login/simple_web_view_dialog.cc
+++ b/chrome/browser/ui/ash/login/simple_web_view_dialog.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ash/login/helper.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc
index 471af171..25124e1 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "components/account_id/account_id.h"
 
 MultiUserWindowManagerStub::MultiUserWindowManagerStub() = default;
diff --git a/chrome/browser/ui/ash/shelf/shelf_spinner_item_controller.cc b/chrome/browser/ui/ash/shelf/shelf_spinner_item_controller.cc
index 02c88e4..726c4ff 100644
--- a/chrome/browser/ui/ash/shelf/shelf_spinner_item_controller.cc
+++ b/chrome/browser/ui/ash/shelf/shelf_spinner_item_controller.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
 #include "chrome/browser/ui/ash/shelf/shelf_context_menu.h"
 #include "chrome/browser/ui/ash/shelf/shelf_spinner_controller.h"
diff --git a/chrome/browser/ui/ash/wallpaper/test_wallpaper_controller.cc b/chrome/browser/ui/ash/wallpaper/test_wallpaper_controller.cc
index 3b1cae9..b683096 100644
--- a/chrome/browser/ui/ash/wallpaper/test_wallpaper_controller.cc
+++ b/chrome/browser/ui/ash/wallpaper/test_wallpaper_controller.cc
@@ -15,6 +15,7 @@
 #include "ash/public/cpp/wallpaper/wallpaper_types.h"
 #include "ash/webui/common/mojom/sea_pen.mojom.h"
 #include "base/containers/adapters.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/sequenced_task_runner.h"
 #include "components/account_id/account_id.h"
diff --git a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
index 8aad91c..f7139ca 100644
--- a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
+++ b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/check_deref.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/preferences/autofill/settings_navigation_helper.h"
 #include "chrome/browser/autofill/autofill_offer_manager_factory.h"
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 6cdff82..f9eabd3 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -23,6 +23,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/process/process_info.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/ui/browser_dialogs.cc b/chrome/browser/ui/browser_dialogs.cc
index 4e6f56c..b2c30a6 100644
--- a/chrome/browser/ui/browser_dialogs.cc
+++ b/chrome/browser/ui/browser_dialogs.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/callback_helpers.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 
 #if defined(TOOLKIT_VIEWS)
 #include "components/constrained_window/constrained_window_views.h"
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 9b7935e..4aa87fb 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -12,6 +12,7 @@
 #include <utility>
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
diff --git a/chrome/browser/ui/browser_window/browser_window_features.cc b/chrome/browser/ui/browser_window/browser_window_features.cc
index eb1b867..6a2fca49 100644
--- a/chrome/browser/ui/browser_window/browser_window_features.cc
+++ b/chrome/browser/ui/browser_window/browser_window_features.cc
@@ -60,6 +60,7 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/media_router/cast_browser_controller.h"
 #include "chrome/browser/ui/views/new_tab_footer/footer_controller.h"
+#include "chrome/browser/ui/views/profiles/profile_menu_coordinator.h"
 #include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_controller.h"
 #include "chrome/browser/ui/views/side_panel/bookmarks/bookmarks_side_panel_coordinator.h"
 #include "chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.h"
@@ -319,6 +320,8 @@
   extension_window_controller_ =
       std::make_unique<extensions::BrowserExtensionWindowController>(browser);
 
+  profile_menu_coordinator_ = std::make_unique<ProfileMenuCoordinator>(browser);
+
   if (browser->is_type_normal() || browser->is_type_app()) {
     toast_service_ = std::make_unique<ToastService>(browser);
   }
diff --git a/chrome/browser/ui/browser_window/public/browser_window_features.h b/chrome/browser/ui/browser_window/public/browser_window_features.h
index 75f468c81..41fe189 100644
--- a/chrome/browser/ui/browser_window/public/browser_window_features.h
+++ b/chrome/browser/ui/browser_window/public/browser_window_features.h
@@ -33,6 +33,7 @@
 class HistorySidePanelCoordinator;
 class LocationBarModel;
 class MemorySaverOptInIPHController;
+class ProfileMenuCoordinator;
 class ReadingListSidePanelCoordinator;
 class SidePanelCoordinator;
 class SidePanelUI;
@@ -292,6 +293,10 @@
     return split_tab_scrim_controller_.get();
   }
 
+  ProfileMenuCoordinator* profile_menu_coordinator() {
+    return profile_menu_coordinator_.get();
+  }
+
   // Get the FindBarController for this browser window, creating it if it does
   // not yet exist.
   FindBarController* GetFindBarController();
@@ -412,6 +417,8 @@
   std::unique_ptr<extensions::BrowserExtensionWindowController>
       extension_window_controller_;
 
+  std::unique_ptr<ProfileMenuCoordinator> profile_menu_coordinator_;
+
   // This is an experimental API that interacts with the TabStripModel.
   std::unique_ptr<TabStripServiceRegister> tab_strip_service_;
 
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
index 8f0a0f5..138dff5 100644
--- a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
@@ -7,7 +7,7 @@
 #include <map>
 
 #import "base/apple/foundation_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #import "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
index a6b64cc3..93a3c5d4 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -12,7 +12,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_confirmation_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_confirmation_bubble_controller.cc
index a206a7d5..58180bd 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_confirmation_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_confirmation_bubble_controller.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_confirmation_bubble_controller.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
diff --git a/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_for_filling_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_for_filling_bubble_controller.cc
index f8525c1..0d8b65b 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_for_filling_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/biometric_authentication_for_filling_bubble_controller.cc
@@ -6,7 +6,7 @@
 
 #include <string>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 4fef9ed..2ec8d3c 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -16,7 +16,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/timer/timer.h"
diff --git a/chrome/browser/ui/plus_addresses/views/plus_address_creation_controller_desktop.cc b/chrome/browser/ui/plus_addresses/views/plus_address_creation_controller_desktop.cc
index a0385353a..30fab1d4 100644
--- a/chrome/browser/ui/plus_addresses/views/plus_address_creation_controller_desktop.cc
+++ b/chrome/browser/ui/plus_addresses/views/plus_address_creation_controller_desktop.cc
@@ -12,6 +12,7 @@
 
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/plus_addresses/plus_address_setting_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ui/profiles/profile_error_dialog.cc b/chrome/browser/ui/profiles/profile_error_dialog.cc
index f4fdec5..3a64be4 100644
--- a/chrome/browser/ui/profiles/profile_error_dialog.cc
+++ b/chrome/browser/ui/profiles/profile_error_dialog.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/feedback/show_feedback_page.h"
diff --git a/chrome/browser/ui/screen_capture_notification_ui_stub.cc b/chrome/browser/ui/screen_capture_notification_ui_stub.cc
index cc7f102..affa722 100644
--- a/chrome/browser/ui/screen_capture_notification_ui_stub.cc
+++ b/chrome/browser/ui/screen_capture_notification_ui_stub.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/screen_capture_notification_ui.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 // Stub implementation of the ScreenCaptureNotificationUI interface.
 class ScreenCaptureNotificationUIStub : public ScreenCaptureNotificationUI {
diff --git a/chrome/browser/ui/sharing_hub/screenshot/screenshot_captured_bubble_controller.cc b/chrome/browser/ui/sharing_hub/screenshot/screenshot_captured_bubble_controller.cc
index 0aac171..7502e64 100644
--- a/chrome/browser/ui/sharing_hub/screenshot/screenshot_captured_bubble_controller.cc
+++ b/chrome/browser/ui/sharing_hub/screenshot/screenshot_captured_bubble_controller.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/sharing_hub/screenshot/screenshot_captured_bubble_controller.h"
 
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/image_editor/screenshot_flow.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
diff --git a/chrome/browser/ui/test/test_browser_dialog.cc b/chrome/browser/ui/test/test_browser_dialog.cc
index b77020da..c4cbd51 100644
--- a/chrome/browser/ui/test/test_browser_dialog.cc
+++ b/chrome/browser/ui/test/test_browser_dialog.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 030f656..a5e516b 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -299,7 +299,7 @@
 
 BASE_FEATURE(kPageSpecificDataDialogRelatedInstalledAppsSection,
              "PageSpecificDataDialogRelatedInstalledAppsSection",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kEnableManagementPromotionBanner,
              "EnableManagementPromotionBanner",
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm
index 0b5765a..da2843c 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -6,6 +6,7 @@
 
 #import "base/apple/foundation_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_manager_mac.h"
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 1ce27ae3..cc00779f 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -6021,7 +6021,7 @@
   }
 
   // Default behavior -- show the profile menu.
-  ProfileMenuCoordinator::GetOrCreateForBrowser(browser())->Show(
+  browser()->GetFeatures().profile_menu_coordinator()->Show(
       is_source_accelerator);
 }
 
diff --git a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
index 2ca71613..08b9f7a 100644
--- a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
+++ b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
@@ -9,7 +9,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/to_string.h"
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
index 60ac42c1..74bd174b 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
@@ -6,9 +6,11 @@
 #include <vector>
 
 #include "base/memory/raw_ptr.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/metrics/histogram_base.h"
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
+#include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -20,17 +22,21 @@
 #include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ash/arc/arc_util.h"
 #include "chrome/browser/ash/arc/session/arc_session_manager.h"
+#include "chrome/browser/ui/actions/chrome_action_id.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/intent_picker_tab_helper.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
 #include "chrome/browser/ui/views/intent_picker_bubble_view.h"
 #include "chrome/browser/ui/views/location_bar/intent_chip_button.h"
 #include "chrome/browser/ui/views/location_bar/intent_picker_view.h"
+#include "chrome/browser/ui/views/page_action/page_action_view.h"
+#include "chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/link_capturing_features.h"
@@ -75,6 +81,9 @@
 
 const char kTestAppActivity[] = "abcdefg";
 
+constexpr char kMigrationEnabled[] = "MigrationEnabled";
+constexpr char kMigrationDisabled[] = "MigrationDisabled";
+
 class FakeIconLoader : public apps::IconLoader {
  public:
   FakeIconLoader() = default;
@@ -124,9 +133,10 @@
 
 }  // namespace
 
-class IntentPickerBubbleViewBrowserTestChromeOS : public InProcessBrowserTest {
+class IntentPickerBubbleViewBrowserTestChromeOSBase
+    : public InProcessBrowserTest {
  public:
-  IntentPickerBubbleViewBrowserTestChromeOS() = default;
+  IntentPickerBubbleViewBrowserTestChromeOSBase() = default;
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     arc::SetArcAvailableCommandLineForTesting(command_line);
@@ -199,12 +209,6 @@
     return app_id;
   }
 
-  IntentChipButton* GetIntentPickerIcon() {
-    return BrowserView::GetBrowserViewForBrowser(browser())
-        ->toolbar_button_provider()
-        ->GetIntentChipButton();
-  }
-
   IntentPickerBubbleView* intent_picker_bubble() {
     return IntentPickerBubbleView::intent_picker_bubble();
   }
@@ -238,6 +242,18 @@
     intent_helper_instance_->clear_handled_intents();
   }
 
+  virtual bool IsMigrationEnabled() const = 0;
+
+  views::Button* GetIntentPickerIcon() {
+    auto* toolbar_button_provider =
+        BrowserView::GetBrowserViewForBrowser(browser())
+            ->toolbar_button_provider();
+    if (IsMigrationEnabled()) {
+      return toolbar_button_provider->GetPageActionView(kActionShowIntentPicker);
+    }
+    return toolbar_button_provider->GetIntentChipButton();
+  }
+
   void ClickIconToShowBubble() {
     views::NamedWidgetShownWaiter waiter(
         views::test::AnyWidgetTestPasskey{},
@@ -280,7 +296,7 @@
         /*show_remember_selection=*/true,
         IntentPickerBubbleView::BubbleType::kLinkCapturing, std::nullopt,
         base::BindOnce(
-            &IntentPickerBubbleViewBrowserTestChromeOS::OnBubbleClosed,
+            &IntentPickerBubbleViewBrowserTestChromeOSBase::OnBubbleClosed,
             base::Unretained(this)));
   }
 
@@ -351,7 +367,6 @@
   }
 
  private:
-  base::test::ScopedFeatureList feature_list_;
   raw_ptr<apps::AppServiceProxy, DanglingUntriaged> app_service_proxy_ =
       nullptr;
   std::unique_ptr<arc::FakeIntentHelperInstance> intent_helper_instance_;
@@ -360,6 +375,23 @@
   bool bubble_closed_ = false;
 };
 
+class IntentPickerBubbleViewBrowserTestChromeOS
+    : public IntentPickerBubbleViewBrowserTestChromeOSBase,
+      public ::testing::WithParamInterface<bool> {
+ public:
+  IntentPickerBubbleViewBrowserTestChromeOS() {
+    feature_list_.InitAndEnableFeatureWithParameters(
+        features::kPageActionsMigration,
+        {{features::kPageActionsMigrationIntentPicker.name,
+          IsMigrationEnabled() ? "true" : "false"}});
+  }
+
+  bool IsMigrationEnabled() const override { return GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
 // Test that the intent picker bubble will show for ARC apps.
 //
 // TODO(crbug.com/40863954): Fix timeouts under MSAN.
@@ -368,7 +400,7 @@
 #else
 #define MAYBE_ArcOnlyShowBubble ArcOnlyShowBubble
 #endif
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        MAYBE_ArcOnlyShowBubble) {
   GURL test_url(InScopeAppUrl());
   std::string app_name = "test_name";
@@ -407,7 +439,7 @@
 }
 
 // Test that intent picker bubble shows if there is only PWA as candidates.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        PWAOnlyShowBubble) {
   GURL test_url(InScopeAppUrl());
   std::string app_name = "test_name";
@@ -438,7 +470,7 @@
 
 // Test that show intent picker bubble multiple times without closing doesn't
 // crash the browser.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        ShowBubbleMultipleTimes) {
   ShowBubbleForTesting();
   auto* bubble_1 = intent_picker_bubble();
@@ -469,7 +501,7 @@
 
 // Test that loading a page with pushState() call that doesn't change URL work
 // as normal.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        PushStateLoadingTest) {
   const GURL test_url =
       embedded_test_server()->GetURL("/intent_picker/push_state_test.html");
@@ -496,7 +528,7 @@
 }
 
 // Test that reload a page after app installation will show intent picker.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        ReloadAfterInstall) {
   GURL test_url(InScopeAppUrl());
   views::Button* intent_picker_view = GetIntentPickerIcon();
@@ -532,7 +564,7 @@
 }
 
 // Test that stay in chrome works when there is only PWA candidates.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        StayInChromePWAOnly) {
   GURL test_url(InScopeAppUrl());
   std::string app_name = "test_name";
@@ -549,7 +581,7 @@
 }
 
 // Test that stay in chrome works when there is only ARC candidates.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        StayInChromeARCOnly) {
   GURL test_url(InScopeAppUrl());
   std::string app_name = "test_name";
@@ -567,7 +599,7 @@
 
 // Test that bubble pops out when there is both PWA and ARC candidates, and
 // test launch the PWA.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        ARCAndPWACandidateLaunchPWA) {
   base::HistogramTester histogram_tester;
 
@@ -642,7 +674,7 @@
 
 // Test that bubble pops out when there is both PWA and ARC candidates, and
 // test launch the ARC app.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        ARCAndPWACandidateLaunchARC) {
   GURL test_url(InScopeAppUrl());
   std::string app_name_pwa = "pwa_test_name";
@@ -691,7 +723,7 @@
 }
 
 // Test that stay in chrome works when there is both PWA and ARC candidates.
-IN_PROC_BROWSER_TEST_F(IntentPickerBubbleViewBrowserTestChromeOS,
+IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTestChromeOS,
                        StayInChromeARCAndPWA) {
   GURL test_url(InScopeAppUrl());
   std::string app_name_pwa = "pwa_test_name";
@@ -709,15 +741,44 @@
   ASSERT_NO_FATAL_FAILURE(CheckStayInChrome());
 }
 
+INSTANTIATE_TEST_SUITE_P(All,
+                         IntentPickerBubbleViewBrowserTestChromeOS,
+                         testing::Bool(),
+                         [](const testing::TestParamInfo<bool>& info) {
+                           return info.param ? kMigrationEnabled
+                                             : kMigrationDisabled;
+                         });
+
 class IntentPickerBubbleViewBrowserTestChromeOSParameterized
-    : public IntentPickerBubbleViewBrowserTestChromeOS,
+    : public IntentPickerBubbleViewBrowserTestChromeOSBase,
       public testing::WithParamInterface<
-          apps::test::LinkCapturingFeatureVersion> {
+          std::tuple<apps::test::LinkCapturingFeatureVersion, bool>> {
  public:
-  IntentPickerBubbleViewBrowserTestChromeOSParameterized()
-      : IntentPickerBubbleViewBrowserTestChromeOS() {
-    feature_list_.InitWithFeaturesAndParameters(
-        apps::test::GetFeaturesToEnableLinkCapturingUX(GetParam()), {});
+  using ParamType = std::tuple<apps::test::LinkCapturingFeatureVersion, bool>;
+
+  IntentPickerBubbleViewBrowserTestChromeOSParameterized() {
+    std::vector<base::test::FeatureRefAndParams> features_to_enable =
+        apps::test::GetFeaturesToEnableLinkCapturingUX(std::get<0>(GetParam()));
+    std::vector<base::test::FeatureRef> features_to_disable;
+    if (std::get<1>(GetParam())) {
+      features_to_enable.push_back(
+          {features::kPageActionsMigration,
+           {{features::kPageActionsMigrationIntentPicker.name, "true"}}});
+    } else {
+      features_to_disable.push_back(features::kPageActionsMigration);
+    }
+    feature_list_.InitWithFeaturesAndParameters(features_to_enable,
+                                                features_to_disable);
+  }
+
+  bool IsMigrationEnabled() const override { return std::get<1>(GetParam()); }
+
+  apps::test::LinkCapturingFeatureVersion GetLinkCapturingVersionParam() const {
+    return std::get<0>(GetParam());
+  }
+
+  bool IsMigrationEnabledTupleElement() const {
+    return std::get<1>(GetParam());
   }
 
  private:
@@ -781,6 +842,14 @@
 INSTANTIATE_TEST_SUITE_P(
     All,
     IntentPickerBubbleViewBrowserTestChromeOSParameterized,
-    testing::Values(apps::test::LinkCapturingFeatureVersion::kV1DefaultOff,
-                    apps::test::LinkCapturingFeatureVersion::kV2DefaultOff),
-    apps::test::LinkCapturingVersionToString);
+    testing::Combine(
+        testing::Values(apps::test::LinkCapturingFeatureVersion::kV1DefaultOff,
+                        apps::test::LinkCapturingFeatureVersion::kV2DefaultOff),
+        testing::Bool()),
+    [](const testing::TestParamInfo<
+        IntentPickerBubbleViewBrowserTestChromeOSParameterized::ParamType>&
+           info) {
+      return base::StrCat(
+          {std::get<1>(info.param) ? kMigrationEnabled : kMigrationDisabled,
+           "_", apps::test::ToString(std::get<0>(info.param))});
+    });
diff --git a/chrome/browser/ui/views/page_action/page_action_controller.h b/chrome/browser/ui/views/page_action/page_action_controller.h
index 96c98ed..308838a 100644
--- a/chrome/browser/ui/views/page_action/page_action_controller.h
+++ b/chrome/browser/ui/views/page_action/page_action_controller.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <ostream>
 #include <set>
 #include <string>
 #include <vector>
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index 271d815..9288f3f 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -8,6 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc
index d938ca1..d9cda1f 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc
@@ -40,6 +40,7 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/profiles/profile_colors_util.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -1717,7 +1718,7 @@
   histogram_tester.ExpectTotalCount(
       "Signin.SyncOptIn.IdentityPill.DurationBeforeClick",
       /*expected_count=*/1);
-  auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser());
+  auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
   ASSERT_NE(coordinator, nullptr);
   EXPECT_TRUE(coordinator->IsShowing());
   EXPECT_TRUE(avatar->GetText().empty());
@@ -1803,7 +1804,7 @@
   histogram_tester.ExpectTotalCount(
       "Signin.SyncOptIn.IdentityPill.DurationBeforeClick",
       /*expected_count=*/1);
-  auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser());
+  auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
   ASSERT_NE(coordinator, nullptr);
   EXPECT_TRUE(coordinator->IsShowing());
   // The button comes back to the normal state.
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
index 511e61c4..5419d6a 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
@@ -43,6 +43,7 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/profiles/profile_colors_util.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -996,8 +997,8 @@
 
  private:
   void OnButtonClick(bool is_source_accelerator) {
-    ProfileMenuCoordinator::GetOrCreateForBrowser(&browser_.get())
-        ->Show(is_source_accelerator, coordinator_->access_point());
+    browser_->GetFeatures().profile_menu_coordinator()->Show(
+        is_source_accelerator, coordinator_->access_point());
     coordinator_->PromoUsed();
   }
 
@@ -1881,7 +1882,7 @@
   }
 
   // By default, show the profile menu.
-  ProfileMenuCoordinator::GetOrCreateForBrowser(browser_)->Show(
+  browser_->GetFeatures().profile_menu_coordinator()->Show(
       is_source_accelerator);
 }
 
diff --git a/chrome/browser/ui/views/profiles/history_sync_optin_ui_browsertest.cc b/chrome/browser/ui/views/profiles/history_sync_optin_ui_browsertest.cc
index 8530cf28..d6b02bf 100644
--- a/chrome/browser/ui/views/profiles/history_sync_optin_ui_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/history_sync_optin_ui_browsertest.cc
@@ -13,6 +13,7 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/signin/public/base/signin_switches.h"
+#include "components/sync/base/features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "ui/views/widget/any_widget_observer.h"
@@ -39,7 +40,12 @@
       public testing::WithParamInterface<PixelTestParam> {
  public:
   HistorySyncOptinUIDialogPixelTest()
-      : ProfilesPixelTestBaseT<DialogBrowserTest>(GetParam()) {}
+      : ProfilesPixelTestBaseT<DialogBrowserTest>(GetParam()) {
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{switches::kEnableHistorySyncOptin,
+                              syncer::kReplaceSyncPromosWithSignInPromos},
+        /*disabled_features=*/{});
+  }
 
   ~HistorySyncOptinUIDialogPixelTest() override = default;
 
@@ -66,8 +72,7 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list{
-      switches::kEnableHistorySyncOptin};
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_P(HistorySyncOptinUIDialogPixelTest, InvokeUi_default) {
diff --git a/chrome/browser/ui/views/profiles/profile_bubble_interactive_uitest.cc b/chrome/browser/ui/views/profiles/profile_bubble_interactive_uitest.cc
index 29e19bac..5361c871 100644
--- a/chrome/browser/ui/views/profiles/profile_bubble_interactive_uitest.cc
+++ b/chrome/browser/ui/views/profiles/profile_bubble_interactive_uitest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/signin/dice_web_signin_interceptor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
 #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h"
@@ -128,7 +129,7 @@
   }
 
   ProfileMenuViewBase* profile_menu_view() {
-    auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser());
+    auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
     return coordinator ? coordinator->GetProfileMenuViewBaseForTesting()
                        : nullptr;
   }
diff --git a/chrome/browser/ui/views/profiles/profile_menu_coordinator.cc b/chrome/browser/ui/views/profiles/profile_menu_coordinator.cc
index 81f886e9..d34758a4 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_coordinator.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_coordinator.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/user_education/browser_user_education_interface.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
@@ -28,10 +29,11 @@
 void ProfileMenuCoordinator::Show(
     bool is_source_accelerator,
     std::optional<signin_metrics::AccessPoint> explicit_signin_access_point) {
-  auto* avatar_toolbar_button =
-      BrowserView::GetBrowserViewForBrowser(&GetBrowser())
-          ->toolbar_button_provider()
-          ->GetAvatarToolbarButton();
+  // TODO(crbug.com/425953501): Update this code.
+  Browser* const browser = browser_->GetBrowserForMigrationOnly();
+  auto* avatar_toolbar_button = BrowserView::GetBrowserViewForBrowser(browser)
+                                    ->toolbar_button_provider()
+                                    ->GetAvatarToolbarButton();
 
   // Do not show avatar bubble if there is no avatar menu button, the button
   // action is disabled or the bubble is already showing.
@@ -40,29 +42,28 @@
     return;
   }
 
-  auto& browser = GetBrowser();
-  signin_ui_util::RecordProfileMenuViewShown(browser.profile());
+  signin_ui_util::RecordProfileMenuViewShown(profile_);
   // Close any existing IPH bubble for the profile menu.
-  browser.window()->NotifyFeaturePromoFeatureUsed(
+  user_education_->NotifyFeaturePromoFeatureUsed(
       feature_engagement::kIPHProfileSwitchFeature,
       FeaturePromoFeatureUsedAction::kClosePromoIfPresent);
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
-  browser.window()->NotifyFeaturePromoFeatureUsed(
+  user_education_->NotifyFeaturePromoFeatureUsed(
       feature_engagement::kIPHSupervisedUserProfileSigninFeature,
       FeaturePromoFeatureUsedAction::kClosePromoIfPresent);
 #endif
 
   std::unique_ptr<ProfileMenuViewBase> bubble;
-  bool is_incognito = browser.profile()->IsIncognitoProfile();
+  const bool is_incognito = profile_->IsIncognitoProfile();
   if (is_incognito) {
     bubble =
-        std::make_unique<IncognitoMenuView>(avatar_toolbar_button, &browser);
+        std::make_unique<IncognitoMenuView>(avatar_toolbar_button, browser);
   } else {
 #if BUILDFLAG(IS_CHROMEOS)
     // Note: on Ash, only incognito windows have a profile menu.
     NOTREACHED() << "The profile menu is not implemented on Ash.";
 #else
-    bubble = std::make_unique<ProfileMenuView>(avatar_toolbar_button, &browser,
+    bubble = std::make_unique<ProfileMenuView>(avatar_toolbar_button, browser,
                                                explicit_signin_access_point);
 #endif  // BUILDFLAG(IS_CHROMEOS)
   }
@@ -93,7 +94,7 @@
              : nullptr;
 }
 
-ProfileMenuCoordinator::ProfileMenuCoordinator(Browser* browser)
-    : BrowserUserData<ProfileMenuCoordinator>(*browser) {}
-
-BROWSER_USER_DATA_KEY_IMPL(ProfileMenuCoordinator);
+ProfileMenuCoordinator::ProfileMenuCoordinator(BrowserWindowInterface* browser)
+    : browser_(browser),
+      profile_(browser->GetProfile()),
+      user_education_(browser->GetUserEducationInterface()) {}
diff --git a/chrome/browser/ui/views/profiles/profile_menu_coordinator.h b/chrome/browser/ui/views/profiles/profile_menu_coordinator.h
index 65ff598f..55ce83a9 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_coordinator.h
+++ b/chrome/browser/ui/views/profiles/profile_menu_coordinator.h
@@ -5,9 +5,14 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_MENU_COORDINATOR_H_
 #define CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_MENU_COORDINATOR_H_
 
-#include "chrome/browser/ui/browser_user_data.h"
+#include <optional>
+
+#include "base/memory/raw_ptr.h"
 #include "ui/views/view_tracker.h"
 
+class BrowserUserEducationInterface;
+class BrowserWindowInterface;
+class Profile;
 class ProfileMenuViewBase;
 
 namespace signin_metrics {
@@ -16,9 +21,12 @@
 
 // Handles the lifetime and showing/hidden state of the profile menu bubble.
 // Owned by the associated browser.
-class ProfileMenuCoordinator : public BrowserUserData<ProfileMenuCoordinator> {
+class ProfileMenuCoordinator {
  public:
-  ~ProfileMenuCoordinator() override;
+  explicit ProfileMenuCoordinator(BrowserWindowInterface* browser);
+  ProfileMenuCoordinator(const ProfileMenuCoordinator&) = delete;
+  ProfileMenuCoordinator& operator=(const ProfileMenuCoordinator&) = delete;
+  ~ProfileMenuCoordinator();
 
   // Shows the the profile bubble for this browser.
   //
@@ -35,13 +43,13 @@
   ProfileMenuViewBase* GetProfileMenuViewBaseForTesting();
 
  private:
-  friend class BrowserUserData<ProfileMenuCoordinator>;
+  // TODO(crbug.com/425953501): Replace with `ToolbarButtonProvider` once this
+  // bug is fixed.
+  const raw_ptr<BrowserWindowInterface> browser_;
 
-  explicit ProfileMenuCoordinator(Browser* browser);
-
+  const raw_ptr<Profile> profile_;
+  const raw_ptr<BrowserUserEducationInterface> user_education_;
   views::ViewTracker bubble_tracker_;
-
-  BROWSER_USER_DATA_KEY_DECL();
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_MENU_COORDINATOR_H_
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 1bae9cd9..fd4c042 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -259,7 +259,8 @@
   }
 
   ProfileMenuViewBase* profile_menu_view() {
-    auto* coordinator = ProfileMenuCoordinator::FromBrowser(target_browser_);
+    auto* coordinator =
+        target_browser_->GetFeatures().profile_menu_coordinator();
     return coordinator ? coordinator->GetProfileMenuViewBaseForTesting()
                        : nullptr;
   }
@@ -295,7 +296,7 @@
   InstallExtension(test_data_dir_.AppendASCII("theme"), 1);
   waiter.WaitForThemeChanged();
 
-  auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser());
+  auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
   EXPECT_TRUE(coordinator->IsShowing());
 
   ui::AXNodeData root_view_data;
@@ -321,7 +322,7 @@
   InstallExtension(test_data_dir_.AppendASCII("theme"), 1);
   waiter.WaitForThemeChanged();
 
-  auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser());
+  auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
   EXPECT_TRUE(coordinator->IsShowing());
   profile_menu_view()->GetWidget()->Close();
   base::RunLoop().RunUntilIdle();
@@ -340,7 +341,8 @@
                              ui::PageTransition::PAGE_TRANSITION_LINK));
   EXPECT_EQ(1, tab_strip->active_index());
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(ProfileMenuCoordinator::FromBrowser(browser())->IsShowing());
+  EXPECT_FALSE(
+      browser()->GetFeatures().profile_menu_coordinator()->IsShowing());
 }
 
 // Profile chooser view should close when active tab is changed.
@@ -356,7 +358,8 @@
   ASSERT_NO_FATAL_FAILURE(OpenProfileMenu());
   tab_strip->ActivateTabAt(0);
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(ProfileMenuCoordinator::FromBrowser(browser())->IsShowing());
+  EXPECT_FALSE(
+      browser()->GetFeatures().profile_menu_coordinator()->IsShowing());
 }
 
 // Profile chooser view should close when active tab is closed.
@@ -372,7 +375,8 @@
   ASSERT_NO_FATAL_FAILURE(OpenProfileMenu());
   tab_strip->CloseWebContentsAt(1, TabCloseTypes::CLOSE_NONE);
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(ProfileMenuCoordinator::FromBrowser(browser())->IsShowing());
+  EXPECT_FALSE(
+      browser()->GetFeatures().profile_menu_coordinator()->IsShowing());
 }
 
 // Profile chooser view should close when the last tab is closed.
@@ -1728,8 +1732,7 @@
   void OpenProfileMenuFromCoordinator(
       std::optional<signin_metrics::AccessPoint> explicit_access_point =
           std::nullopt) {
-    auto* coordinator =
-        ProfileMenuCoordinator::GetOrCreateForBrowser(browser());
+    auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
     ASSERT_TRUE(coordinator);
     coordinator->Show(/*is_source_accelerator=*/false, explicit_access_point);
     ASSERT_NO_FATAL_FAILURE(
@@ -1737,7 +1740,7 @@
   }
 
   void ClickSyncButton() {
-    auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser());
+    auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
     ASSERT_TRUE(coordinator);
     ProfileMenuViewBase* profile_menu_view =
         coordinator->GetProfileMenuViewBaseForTesting();
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_ui_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_ui_browsertest.cc
index 28e0ad48..56392c1 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_ui_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_ui_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/test/test_browser_ui.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -539,7 +540,7 @@
   }
 
   ProfileMenuViewBase* profile_menu_view() {
-    auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser());
+    auto* coordinator = browser()->GetFeatures().profile_menu_coordinator();
     return coordinator ? coordinator->GetProfileMenuViewBaseForTesting()
                        : nullptr;
   }
diff --git a/chrome/browser/ui/views/tabs/glic_button.cc b/chrome/browser/ui/views/tabs/glic_button.cc
index eaf55c9..f2fe7ec5 100644
--- a/chrome/browser/ui/views/tabs/glic_button.cc
+++ b/chrome/browser/ui/views/tabs/glic_button.cc
@@ -8,6 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
+#include "base/notimplemented.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/background/glic/glic_launcher_configuration.h"
diff --git a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
index 3a23948..a0d0a1be 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
@@ -137,21 +137,6 @@
           view_controller_.get(),
           std::make_unique<TestSheetView>(std::make_unique<TestSheetModel>()));
       EXPECT_EQ(step_transition_observer.step_transition_count(), 0);
-    } else if (name == "manage_devices") {
-      // Add a paired phone. That should be sufficient for the "Manage
-      // devices" button to be shown.
-      dialog_model_->mechanisms.emplace_back(
-          AuthenticatorRequestDialogModel::Mechanism::Phone("Phone"), u"Phone",
-          u"Phone", kSmartphoneIcon, base::DoNothing());
-      dialog_model_->SetStep(
-          AuthenticatorRequestDialogModel::Step::kMechanismSelection);
-
-      // The "manage devices" button should have been shown on this sheet.
-      EXPECT_TRUE(test::AuthenticatorRequestDialogViewTestApi::GetSheet(
-                      view_controller_.get())
-                      ->model()
-                      ->IsManageDevicesButtonVisible());
-      EXPECT_EQ(step_transition_observer.step_transition_count(), 1);
     }
 
     dialog_model_->RemoveObserver(&step_transition_observer);
@@ -168,9 +153,3 @@
 IN_PROC_BROWSER_TEST_F(AuthenticatorDialogViewTest, InvokeUi_default) {
   ShowAndVerifyUi();
 }
-
-// Test that the models decide to show the "Manage devices" button when a phone
-// is listed.
-IN_PROC_BROWSER_TEST_F(AuthenticatorDialogViewTest, InvokeUi_manage_devices) {
-  ShowAndVerifyUi();
-}
diff --git a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
index 01a72b9b..7a6e3e82 100644
--- a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
+++ b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
@@ -217,10 +217,6 @@
           std::make_unique<AuthenticatorOffTheRecordInterstitialSheetModel>(
               dialog_model));
       break;
-    case Step::kPhoneConfirmationSheet:
-      sheet_view = std::make_unique<AuthenticatorRequestSheetView>(
-          std::make_unique<AuthenticatorPhoneConfirmationSheet>(dialog_model));
-      break;
     case Step::kCableActivate:
       sheet_view = std::make_unique<AuthenticatorRequestSheetView>(
           std::make_unique<AuthenticatorPaaskSheetModel>(dialog_model));
diff --git a/chrome/browser/ui/web_applications/share_target_utils.cc b/chrome/browser/ui/web_applications/share_target_utils.cc
index a2b56412..9b7ed10 100644
--- a/chrome/browser/ui/web_applications/share_target_utils.cc
+++ b/chrome/browser/ui/web_applications/share_target_utils.cc
@@ -8,6 +8,7 @@
 #include <optional>
 
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/ui/webauthn/account_hover_list_model.cc b/chrome/browser/ui/webauthn/account_hover_list_model.cc
index 8f8471d..f02dd0d 100644
--- a/chrome/browser/ui/webauthn/account_hover_list_model.cc
+++ b/chrome/browser/ui/webauthn/account_hover_list_model.cc
@@ -38,8 +38,7 @@
        dialog_model->creds) {
     items_.emplace_back(
         NameTokenForDisplay(cred.user.name.value_or("")),
-        AuthenticatorRequestDialogModel::GetMechanismDescription(
-            cred, dialog_model->priority_phone_name),
+        AuthenticatorRequestDialogModel::GetMechanismDescription(cred),
         ui::ImageModel::FromVectorIcon(vector_icons::kPasskeyIcon,
                                        dialog_model->ui_disabled_
                                            ? ui::kColorIconDisabled
diff --git a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
index 98b0b689..16f51b1a 100644
--- a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
+++ b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
@@ -64,7 +64,6 @@
 
 namespace {
 
-constexpr char kPhoneName[] = "Elisa's Pixel 6 Pro";
 using BleStatus = device::FidoRequestHandlerBase::BleStatus;
 
 void UpdateModelBeforeStartFlow(
@@ -140,11 +139,6 @@
         AuthenticatorTransport::kHybrid,
     };
 
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-    auto phone = std::make_unique<device::cablev2::Pairing>();
-    phone->from_sync_deviceinfo = false;
-    phone->name = kPhoneName;
-    phones.emplace_back(std::move(phone));
     transport_availability.has_platform_authenticator_credential = device::
         FidoRequestHandlerBase::RecognizedCredential::kNoRecognizedCredential;
     transport_availability.request_type =
@@ -152,10 +146,6 @@
 
     // The dialog should immediately close as soon as it is displayed.
     if (name == "mechanisms" || name == "mechanisms_disabled") {
-      // A phone is configured so that the "Manage devices" button is shown.
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/std::nullopt, std::move(phones),
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
       controller_->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kMechanismSelection);
     } else if (name == "mechanisms_create" ||
@@ -195,21 +185,9 @@
     } else if (name == "touchid_incognito") {
       controller_->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kOffTheRecordInterstitial);
-    } else if (name == "cable_activate") {
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/false, std::move(phones),
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
-      controller_->ContactPhoneForTesting(kPhoneName);
-    } else if (name == "cable_v2_activate") {
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/std::nullopt, std::move(phones),
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
-      controller_->ContactPhoneForTesting(kPhoneName);
     } else if (name == "cable_v2_pair") {
       controller_->set_cable_transport_info(
-          /*extension_is_v2=*/std::nullopt,
-          /*paired_phones=*/{},
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
+          /*extension_is_v2=*/std::nullopt, "fido://qrcode");
       controller_->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kCableV2QRCode);
     } else if (name == "cable_v2_connecting") {
@@ -386,21 +364,12 @@
           base::BindOnce([](device::AuthenticatorGetAssertionResponse) {}));
     } else if (name == "server_link_title_UNLOCK_YOUR_PHONE") {
       controller_->set_cable_transport_info(
-          /*extension_is_v2=*/true, /*paired_phones=*/{},
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
+          /*extension_is_v2=*/true, "fido://qrcode");
       controller_->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kCableActivate);
     } else if (name == "create_passkey") {
       controller_->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kCreatePasskey);
-    } else if (name == "phone_confirmation") {
-      // The phone must be from Sync.
-      phones[0]->from_sync_deviceinfo = true;
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/true, std::move(phones),
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
-      controller_->SetCurrentStepForTesting(
-          AuthenticatorRequestDialogModel::Step::kPhoneConfirmationSheet);
     }
 #if BUILDFLAG(IS_MAC)
     else if (name == "ble_permission_mac") {  // NOLINT
@@ -500,14 +469,6 @@
 }
 #endif  // BUILDFLAG(IS_MAC)
 
-IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_cable_activate) {
-  ShowAndVerifyUi();
-}
-
-IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_cable_v2_activate) {
-  ShowAndVerifyUi();
-}
-
 IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_cable_v2_pair) {
   ShowAndVerifyUi();
 }
@@ -624,10 +585,6 @@
   ShowAndVerifyUi();
 }
 
-IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_phone_confirmation) {
-  ShowAndVerifyUi();
-}
-
 // Run with:
 //
 //   --gtest_filter=BrowserUiTest.Invoke --test-launcher-interactive \
@@ -693,16 +650,6 @@
         device::PublicKeyCredentialUserEntity({2}, "elisa.beckett@ink-42.com",
                                               "Elisa Beckett"),
         std::nullopt);
-    device::DiscoverableCredentialMetadata phone_cred1(
-        device::AuthenticatorType::kPhone, "example.com", {3},
-        device::PublicKeyCredentialUserEntity({1}, "elisa.g.beckett@gmail.com",
-                                              "Elisa Beckett"),
-        std::nullopt);
-    device::DiscoverableCredentialMetadata phone_cred2(
-        device::AuthenticatorType::kPhone, "example.com", {4},
-        device::PublicKeyCredentialUserEntity({2}, "elisa.beckett@ink-42.com",
-                                              "Elisa Beckett"),
-        std::nullopt);
     device::DiscoverableCredentialMetadata ick_cred1(
         device::AuthenticatorType::kICloudKeychain, "example.com", {5},
         device::PublicKeyCredentialUserEntity({1}, "elisa.beckett@gmail.com",
@@ -714,26 +661,11 @@
                                               "Elisa Beckett"),
         "Another Example Passkey Provider");
     model_->user_entity = local_cred1.user;
-
-    // Configure a phone from sync.
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-    auto phone = std::make_unique<device::cablev2::Pairing>();
-    phone->from_sync_deviceinfo = true;
-    phone->name = kPhoneName;
-    phones.emplace_back(std::move(phone));
     controller_->set_cable_transport_info(
-        /*extension_is_v2=*/std::nullopt, std::move(phones),
-        /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
+        /*extension_is_v2=*/std::nullopt, "fido://qrcode");
 
     if (name == "no_passkeys_discovered") {
       transport_availability.recognized_credentials = {};
-    } else if (name == "local_and_phone") {
-      transport_availability.recognized_credentials = {
-          std::move(local_cred1),
-          std::move(local_cred2),
-          std::move(phone_cred1),
-          std::move(phone_cred2),
-      };
     } else if (name == "local_only" || name == "local_only_disabled") {
       transport_availability.recognized_credentials = {
           std::move(local_cred1),
@@ -746,44 +678,23 @@
       };
       transport_availability.available_transports = {
           device::FidoTransportProtocol::kInternal};
-    } else if (name == "phone_only") {
-      transport_availability.recognized_credentials = {
-          std::move(phone_cred1),
-          std::move(phone_cred2),
-      };
     } else if (name == "priority_mech" || name == "priority_mech_disabled") {
       transport_availability.has_empty_allow_list = true;
       transport_availability.recognized_credentials = {
           std::move(gpm_cred),
       };
-    } else if (name == "one_phone_cred") {
-      transport_availability.recognized_credentials = {
-          std::move(phone_cred1),
-      };
     } else if (name == "get_assertion_qr_with_usb") {
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/std::nullopt,
-          /*paired_phones=*/{},
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
       transport_availability.ble_status = BleStatus::kOn;
       transport_availability.available_transports = {
           AuthenticatorTransport::kHybrid,
           AuthenticatorTransport::kUsbHumanInterfaceDevice,
       };
     } else if (name == "get_assertion_qr_without_usb") {
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/std::nullopt,
-          /*paired_phones=*/{},
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
       transport_availability.ble_status = BleStatus::kOn;
       transport_availability.available_transports = {
           AuthenticatorTransport::kHybrid,
       };
     } else if (name == "make_credential_qr_with_usb") {
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/std::nullopt,
-          /*paired_phones=*/{},
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
       transport_availability.request_type =
           device::FidoRequestType::kMakeCredential;
       transport_availability.attestation_conveyance_preference =
@@ -794,10 +705,6 @@
           AuthenticatorTransport::kUsbHumanInterfaceDevice,
       };
     } else if (name == "make_credential_qr_without_usb") {
-      controller_->set_cable_transport_info(
-          /*extension_is_v2=*/std::nullopt,
-          /*paired_phones=*/{},
-          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
       transport_availability.request_type =
           device::FidoRequestType::kMakeCredential;
       transport_availability.attestation_conveyance_preference =
@@ -883,11 +790,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
-                       InvokeUi_local_and_phone) {
-  ShowAndVerifyUi();
-}
-
-IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
                        InvokeUi_local_only) {
   ShowAndVerifyUi();
 }
@@ -903,11 +805,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
-                       InvokeUi_phone_only) {
-  ShowAndVerifyUi();
-}
-
-IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
                        InvokeUi_priority_mech) {
   ShowAndVerifyUi();
 }
@@ -918,11 +815,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
-                       InvokeUi_one_phone_cred) {
-  ShowAndVerifyUi();
-}
-
-IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
                        InvokeUi_get_assertion_qr_with_usb) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index 5f828ed1..ba91f1e 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -757,26 +757,7 @@
 }
 
 std::u16string AuthenticatorPaaskSheetModel::GetStepDescription() const {
-  switch (*dialog_model()->cable_ui_type) {
-    case AuthenticatorRequestDialogModel::CableUIType::CABLE_V1:
-    case AuthenticatorRequestDialogModel::CableUIType::CABLE_V2_SERVER_LINK:
-      // caBLEv1 and v2 server-link don't include device names.
-      return l10n_util::GetStringUTF16(IDS_WEBAUTHN_CABLE_ACTIVATE_DESCRIPTION);
-    case AuthenticatorRequestDialogModel::CableUIType::CABLE_V2_2ND_FACTOR: {
-      DCHECK(dialog_model()->selected_phone_name);
-      return l10n_util::GetStringFUTF16(
-          IDS_WEBAUTHN_CABLE_ACTIVATE_DEVICE_NAME_DESCRIPTION,
-          base::UTF8ToUTF16(dialog_model()->selected_phone_name.value_or("")));
-    }
-  }
-}
-
-bool AuthenticatorPaaskSheetModel::IsManageDevicesButtonVisible() const {
-  return true;
-}
-
-void AuthenticatorPaaskSheetModel::OnManageDevices() {
-  dialog_model()->OnManageDevicesClicked();
+  return l10n_util::GetStringUTF16(IDS_WEBAUTHN_CABLE_ACTIVATE_DESCRIPTION);
 }
 
 // AuthenticatorClientPinEntrySheetModel
@@ -1434,43 +1415,6 @@
   return u"";
 }
 
-// AuthenticatorPhoneConfirmationSheet --------------------------------
-
-AuthenticatorPhoneConfirmationSheet::AuthenticatorPhoneConfirmationSheet(
-    AuthenticatorRequestDialogModel* dialog_model)
-    : AuthenticatorSheetModelBase(dialog_model,
-                                  OtherMechanismButtonVisibility::kVisible) {
-  vector_illustrations_.emplace(kPasskeyPhoneIcon, kPasskeyPhoneDarkIcon);
-}
-
-AuthenticatorPhoneConfirmationSheet::~AuthenticatorPhoneConfirmationSheet() =
-    default;
-
-std::u16string AuthenticatorPhoneConfirmationSheet::GetStepTitle() const {
-  return l10n_util::GetStringFUTF16(
-      IDS_WEBAUTHN_PHONE_CONFIRMATION_TITLE,
-      base::UTF8ToUTF16(dialog_model()->paired_phone_names.at(0)),
-      GetRelyingPartyIdString(dialog_model()));
-}
-
-std::u16string AuthenticatorPhoneConfirmationSheet::GetStepDescription() const {
-  return u"";
-}
-
-AuthenticatorRequestSheetModel::AcceptButtonState
-AuthenticatorPhoneConfirmationSheet::GetAcceptButtonState() const {
-  return AcceptButtonState::kEnabled;
-}
-
-std::u16string AuthenticatorPhoneConfirmationSheet::GetAcceptButtonLabel()
-    const {
-  return l10n_util::GetStringUTF16(IDS_WEBAUTHN_CONTINUE);
-}
-
-void AuthenticatorPhoneConfirmationSheet::OnAccept() {
-  dialog_model()->ContactPriorityPhone();
-}
-
 // AuthenticatorMultiSourcePickerSheetModel --------------------------------
 
 AuthenticatorMultiSourcePickerSheetModel::
@@ -1506,50 +1450,14 @@
     return;
   }
 
-  const std::optional<std::string>& phone_name =
-      dialog_model->priority_phone_name;
-  if (phone_name) {
-    primary_passkeys_label_ = l10n_util::GetStringFUTF16(
-        IDS_WEBAUTHN_FROM_PHONE_LABEL, base::UTF8ToUTF16(*phone_name));
-  }
   for (size_t i = 0; i < dialog_model->mechanisms.size(); ++i) {
-    const AuthenticatorRequestDialogModel::Mechanism& mech =
-        dialog_model->mechanisms[i];
-    if (std::holds_alternative<CredentialMech>(mech.type) &&
-        std::get<CredentialMech>(mech.type).value().source ==
-            device::AuthenticatorType::kPhone) {
-      // There should not be any phone passkeys if the phone name is empty.
-      CHECK(phone_name);
-      primary_passkey_indices_.push_back(i);
-    } else {
-      secondary_passkey_indices_.push_back(i);
-    }
+    secondary_passkey_indices_.push_back(i);
   }
 }
 
 AuthenticatorMultiSourcePickerSheetModel::
     ~AuthenticatorMultiSourcePickerSheetModel() = default;
 
-bool AuthenticatorMultiSourcePickerSheetModel::IsManageDevicesButtonVisible()
-    const {
-  using Mechanism = AuthenticatorRequestDialogModel::Mechanism;
-  // If any phones or passkeys from a phone are shown then also show a button
-  // that goes to the settings page to manage them.
-  return std::ranges::any_of(
-      dialog_model()->mechanisms, [](const Mechanism& mech) {
-        return std::holds_alternative<Mechanism::Phone>(mech.type) ||
-               (std::holds_alternative<Mechanism::Credential>(mech.type) &&
-                std::get<Mechanism::Credential>(mech.type).value().source ==
-                    device::AuthenticatorType::kPhone);
-      });
-}
-
-void AuthenticatorMultiSourcePickerSheetModel::OnManageDevices() {
-  if (dialog_model()) {
-    dialog_model()->OnManageDevicesClicked();
-  }
-}
-
 std::u16string AuthenticatorMultiSourcePickerSheetModel::GetStepTitle() const {
   if (has_passwords_) {
     return u"Use a saved credential for " +
@@ -1925,23 +1833,9 @@
 
 std::u16string AuthenticatorTrustThisComputerAssertionSheetModel::
     GetOtherMechanismButtonLabel() const {
-  const std::optional<std::string>& phone_name =
-      dialog_model()->priority_phone_name;
-  if (phone_name) {
-    return l10n_util::GetStringFUTF16(IDS_WEBAUTHN_USE_PHONE_WITH_NAME,
-                                      base::UTF8ToUTF16(*phone_name));
-  }
   return l10n_util::GetStringUTF16(IDS_WEBAUTHN_USE_A_DIFFERENT_DEVICE);
 }
 
-void AuthenticatorTrustThisComputerAssertionSheetModel::OnBack() {
-  if (dialog_model()->priority_phone_name) {
-    dialog_model()->ContactPriorityPhone();
-  } else {
-    dialog_model()->StartOver();
-  }
-}
-
 void AuthenticatorTrustThisComputerAssertionSheetModel::OnAccept() {
   webauthn::user_actions::RecordAcceptClick();
   dialog_model()->OnTrustThisComputer();
diff --git a/chrome/browser/ui/webauthn/sheet_models.h b/chrome/browser/ui/webauthn/sheet_models.h
index 1d3c1f17..1a9afe6 100644
--- a/chrome/browser/ui/webauthn/sheet_models.h
+++ b/chrome/browser/ui/webauthn/sheet_models.h
@@ -307,8 +307,6 @@
   bool IsActivityIndicatorVisible() const override;
   std::u16string GetStepTitle() const override;
   std::u16string GetStepDescription() const override;
-  bool IsManageDevicesButtonVisible() const override;
-  void OnManageDevices() override;
 };
 
 class AuthenticatorClientPinEntrySheetModel
@@ -587,24 +585,6 @@
   std::u16string GetStepDescription() const override;
 };
 
-// A confirmation screen that can be shown instead of the mechanism selection
-// screen when we are confident a request can be resolved using an already
-// paired phone.
-class AuthenticatorPhoneConfirmationSheet : public AuthenticatorSheetModelBase {
- public:
-  explicit AuthenticatorPhoneConfirmationSheet(
-      AuthenticatorRequestDialogModel* dialog_model);
-  ~AuthenticatorPhoneConfirmationSheet() override;
-
- private:
-  // AuthenticatorSheetModelBase:
-  std::u16string GetStepTitle() const override;
-  std::u16string GetStepDescription() const override;
-  AcceptButtonState GetAcceptButtonState() const override;
-  void OnAccept() override;
-  std::u16string GetAcceptButtonLabel() const override;
-};
-
 // An account and mechanism picker that combines passkeys from multiple sources.
 // Passkeys are grouped in two lists:
 // * "Primary" passkeys. These are local passkeys if available, or GPM passkeys
@@ -637,8 +617,6 @@
 
  private:
   // AuthenticatorSheetModelBase:
-  bool IsManageDevicesButtonVisible() const override;
-  void OnManageDevices() override;
   std::u16string GetStepTitle() const override;
   std::u16string GetStepDescription() const override;
 
@@ -778,7 +756,6 @@
   std::u16string GetAcceptButtonLabel() const override;
   bool IsOtherMechanismButtonVisible() const override;
   std::u16string GetOtherMechanismButtonLabel() const override;
-  void OnBack() override;
   void OnAccept() override;
 };
 
diff --git a/chrome/browser/ui/webauthn/sheet_models_unittest.cc b/chrome/browser/ui/webauthn/sheet_models_unittest.cc
index 0b68179c..b8815cd 100644
--- a/chrome/browser/ui/webauthn/sheet_models_unittest.cc
+++ b/chrome/browser/ui/webauthn/sheet_models_unittest.cc
@@ -64,9 +64,11 @@
     TestAuthenticatorSheetModel sheet_model(dialog_model.get(),
                                             MechanismVisibility::kVisible);
     dialog_model->mechanisms.clear();
-    dialog_model->mechanisms.emplace_back(Mechanism::Phone("phone"), u"phone",
-                                          u"ph", kPasskeyAoaIcon,
-                                          base::DoNothing());
+    dialog_model->mechanisms.emplace_back(
+        Mechanism::Credential(
+            {device::AuthenticatorType::kEnclave, {0}, std::nullopt}),
+        u"credential", u"cred", kPasskeyAoaIcon, base::DoNothing());
+
     dialog_model->mechanisms.emplace_back(
         Mechanism::Transport(AuthenticatorTransport::kUsbHumanInterfaceDevice),
         u"security key", u"usb", kPasskeyAoaIcon, base::DoNothing());
@@ -78,9 +80,10 @@
     TestAuthenticatorSheetModel sheet_model(dialog_model.get(),
                                             MechanismVisibility::kHidden);
     dialog_model->mechanisms.clear();
-    dialog_model->mechanisms.emplace_back(Mechanism::Phone("phone"), u"phone",
-                                          u"ph", kPasskeyAoaIcon,
-                                          base::DoNothing());
+    dialog_model->mechanisms.emplace_back(
+        Mechanism::Credential(
+            {device::AuthenticatorType::kEnclave, {0}, std::nullopt}),
+        u"credential", u"cred", kPasskeyAoaIcon, base::DoNothing());
     EXPECT_FALSE(sheet_model.IsOtherMechanismButtonVisible());
   }
 }
@@ -100,20 +103,17 @@
 
 constexpr char16_t kPasskeyName1[] = u"yuki";
 constexpr char16_t kPasskeyName2[] = u"kodai";
-constexpr char16_t kPhoneName[] = u"pixel 7";
 
 TEST_F(AuthenticatorMultiSourcePickerSheetModelTest, GPMPasskeysOnly) {
   auto dialog_model = base::MakeRefCounted<AuthenticatorRequestDialogModel>(
       /*render_frame_host=*/nullptr);
-  dialog_model->paired_phone_names = {base::UTF16ToUTF8(kPhoneName)};
-  dialog_model->priority_phone_name = dialog_model->paired_phone_names.at(0);
   dialog_model->mechanisms.emplace_back(
       Mechanism::Credential(
-          {device::AuthenticatorType::kPhone, {0}, std::nullopt}),
+          {device::AuthenticatorType::kEnclave, {0}, std::nullopt}),
       kPasskeyName1, kPasskeyName1, kPasskeyPhoneIcon, base::DoNothing());
   dialog_model->mechanisms.emplace_back(
       Mechanism::Credential(
-          {device::AuthenticatorType::kPhone, {1}, std::nullopt}),
+          {device::AuthenticatorType::kEnclave, {1}, std::nullopt}),
       kPasskeyName2, kPasskeyName2, kPasskeyPhoneIcon, base::DoNothing());
   dialog_model->mechanisms.emplace_back(
       Mechanism::Transport(AuthenticatorTransport::kUsbHumanInterfaceDevice),
@@ -122,20 +122,17 @@
   AuthenticatorMultiSourcePickerSheetModel model(dialog_model.get());
   EXPECT_THAT(model.primary_passkey_indices(), testing::ElementsAre(0, 1));
   EXPECT_THAT(model.secondary_passkey_indices(), testing::ElementsAre(2));
-  EXPECT_EQ(
-      model.primary_passkeys_label(),
-      l10n_util::GetStringFUTF16(IDS_WEBAUTHN_FROM_PHONE_LABEL, kPhoneName));
+  EXPECT_EQ(model.primary_passkeys_label(),
+            l10n_util::GetStringUTF16(IDS_WEBAUTHN_THIS_DEVICE_LABEL));
 }
 
 TEST_F(AuthenticatorMultiSourcePickerSheetModelTest,
        GPMPasskeysAndLocalPasskeys) {
   auto dialog_model = base::MakeRefCounted<AuthenticatorRequestDialogModel>(
       /*render_frame_host=*/nullptr);
-  dialog_model->paired_phone_names = {base::UTF16ToUTF8(kPhoneName)};
-  dialog_model->priority_phone_name = dialog_model->paired_phone_names.at(0);
   dialog_model->mechanisms.emplace_back(
       Mechanism::Credential(
-          {device::AuthenticatorType::kPhone, {0}, std::nullopt}),
+          {device::AuthenticatorType::kEnclave, {0}, std::nullopt}),
       kPasskeyName1, kPasskeyName1, kPasskeyPhoneIcon, base::DoNothing());
   dialog_model->mechanisms.emplace_back(
       Mechanism::Credential(
@@ -146,28 +143,8 @@
       u"security key", u"usb", kPasskeyAoaIcon, base::DoNothing());
 
   AuthenticatorMultiSourcePickerSheetModel model(dialog_model.get());
-  EXPECT_THAT(model.primary_passkey_indices(), testing::ElementsAre(1));
-  EXPECT_THAT(model.secondary_passkey_indices(), testing::ElementsAre(0, 2));
-  EXPECT_EQ(model.primary_passkeys_label(),
-            l10n_util::GetStringUTF16(IDS_WEBAUTHN_THIS_DEVICE_LABEL));
-}
-
-TEST_F(AuthenticatorMultiSourcePickerSheetModelTest, GPMMechanismAndPhones) {
-  auto dialog_model = base::MakeRefCounted<AuthenticatorRequestDialogModel>(
-      /*render_frame_host=*/nullptr);
-  dialog_model->paired_phone_names = {base::UTF16ToUTF8(kPhoneName)};
-  dialog_model->priority_phone_name = dialog_model->paired_phone_names.at(0);
-  dialog_model->mechanisms.emplace_back(
-      Mechanism::Credential(
-          {device::AuthenticatorType::kPhone, {0}, std::nullopt}),
-      kPasskeyName1, kPasskeyName1, kPasskeyPhoneIcon, base::DoNothing());
-  dialog_model->mechanisms.emplace_back(Mechanism::Enclave(), u"enclave",
-                                        u"enclave", kPasskeyAoaIcon,
-                                        base::DoNothing());
-
-  AuthenticatorMultiSourcePickerSheetModel model(dialog_model.get());
-  EXPECT_THAT(model.primary_passkey_indices(), testing::ElementsAre(1));
-  EXPECT_THAT(model.secondary_passkey_indices(), testing::ElementsAre(0));
+  EXPECT_THAT(model.primary_passkey_indices(), testing::ElementsAre(0, 1));
+  EXPECT_THAT(model.secondary_passkey_indices(), testing::ElementsAre(2));
   EXPECT_EQ(model.primary_passkeys_label(),
             l10n_util::GetStringUTF16(IDS_WEBAUTHN_THIS_DEVICE_LABEL));
 }
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler_chromeos.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler_chromeos.cc
index 874eacb..752dbc30 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler_chromeos.cc
@@ -12,6 +12,7 @@
 #include "base/containers/flat_set.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/ash/app_list/arc/arc_app_utils.h"
diff --git a/chrome/browser/ui/webui/ash/settings/pages/main/main_section.cc b/chrome/browser/ui/webui/ash/settings/pages/main/main_section.cc
index 5c3fffe9..7d4eab8 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/main/main_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/main/main_section.cc
@@ -14,6 +14,7 @@
 #include "base/feature_list.h"
 #include "base/i18n/message_formatter.h"
 #include "base/i18n/number_formatting.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
 #include "chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h"
diff --git a/chrome/browser/ui/webui/ash/user_image/user_image_source.cc b/chrome/browser/ui/webui/ash/user_image/user_image_source.cc
index aae9ba9..4230082 100644
--- a/chrome/browser/ui/webui/ash/user_image/user_image_source.cc
+++ b/chrome/browser/ui/webui/ash/user_image/user_image_source.cc
@@ -6,6 +6,7 @@
 
 #include "ash/constants/ash_features.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/notimplemented.h"
 #include "base/strings/escape.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/chrome/browser/ui/webui/connectors_internals/connectors_internals_page_handler.cc b/chrome/browser/ui/webui/connectors_internals/connectors_internals_page_handler.cc
index ce60ec7..bb3a72b3 100644
--- a/chrome/browser/ui/webui/connectors_internals/connectors_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/connectors_internals/connectors_internals_page_handler.cc
@@ -8,6 +8,7 @@
 #include "base/containers/span.h"
 #include "base/i18n/time_formatting.h"
 #include "base/json/json_writer.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/enterprise/client_certificates/certificate_provisioning_service_factory.h"
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
index b5de701..f6f897d 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/ash/login/wizard_controller.h"
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index cffaa6240..0392f50b 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -722,7 +722,7 @@
   supervised_user::Custodian second_custodian(
       second_custodian_name, second_custodian_email, profile_image_url2);
 
-  return supervised_user::BuildErrorPageHtml(
+  return supervised_user::BuildErrorPageHtmlWithApprovals(
       allow_access_requests, first_custodian, second_custodian, reason,
       g_browser_process->GetApplicationLocale(),
       /*already_sent_remote_request=*/false,
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index 70c97b8b..1a40332 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -17,6 +17,7 @@
 #include "base/json/json_reader.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
diff --git a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
index c35685b..5a986a04 100644
--- a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
@@ -13,6 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 #include "chrome/browser/browsing_data/browsing_data_important_sites_util.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index a0311f6..5cbda19 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -105,7 +105,6 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "crypto/crypto_buildflags.h"
-#include "device/fido/features.h"
 #include "media/base/media_switches.h"
 #include "net/base/url_util.h"
 #include "net/net_buildflags.h"
@@ -143,6 +142,7 @@
 #endif
 
 #if BUILDFLAG(IS_WIN)
+#include "device/fido/features.h"
 #include "device/fido/win/webauthn_api.h"
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -3743,19 +3743,6 @@
       {"securityKeysSetPinButton", IDS_SETTINGS_SECURITY_KEYS_SET_PIN_BUTTON},
       {"securityKeysSamePINAsCurrent",
        IDS_SETTINGS_SECURITY_KEYS_SAME_PIN_AS_CURRENT},
-      {"securityKeysPhoneEditDialogTitle",
-       IDS_SETTINGS_SECURITY_KEYS_PHONE_EDIT_DIALOG_TITLE},
-      {"securityKeysPhonesYourDevices",
-       IDS_SETTINGS_SECURITY_KEYS_PHONES_YOUR_DEVICES},
-      {"securityKeysPhonesSyncedDesc",
-       IDS_SETTINGS_SECURITY_KEYS_PHONES_SYNCED_DESC},
-      {"securityKeysPhonesLinkedDevices",
-       IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DEVICES},
-      {"securityKeysPhonesLinkedDesc",
-       IDS_SETTINGS_SECURITY_KEYS_PHONES_LINKED_DESC},
-      {"securityKeysPhonesManage", IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE},
-      {"securityKeysPhonesManageDesc",
-       IDS_SETTINGS_SECURITY_KEYS_PHONES_MANAGE_DESC},
   };
   html_source->AddLocalizedStrings(kSecurityKeysStrings);
   bool win_native_api_available = false;
@@ -3768,9 +3755,6 @@
                           !win_native_api_available);
   html_source->AddBoolean("enableSecurityKeysBioEnrollment",
                           !win_native_api_available);
-  html_source->AddBoolean(
-      "enableSecurityKeysManagePhones",
-      base::FeatureList::IsEnabled(device::kWebAuthnHybridLinking));
 }
 
 void AddShortcutInputStrings(content::WebUIDataSource* html_source) {
diff --git a/chrome/browser/ui/webui/settings/settings_security_key_handler.cc b/chrome/browser/ui/webui/settings/settings_security_key_handler.cc
index cdd7feea..6d016d5 100644
--- a/chrome/browser/ui/webui/settings/settings_security_key_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_security_key_handler.cc
@@ -22,14 +22,12 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
-#include "chrome/browser/webauthn/cablev2_devices.h"
 #include "chrome/browser/webauthn/local_credential_management.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
-#include "device/fido/cable/cable_discovery_data.h"
 #include "device/fido/credential_management.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/pin.h"
@@ -69,17 +67,6 @@
   return value;
 }
 
-bool DecodePublicKey(const std::string& value,
-                     std::array<uint8_t, device::kP256X962Length>* out) {
-  std::string bytes;
-  if (!base::Base64Decode(value, &bytes) || bytes.size() != out->size()) {
-    return false;
-  }
-
-  std::ranges::copy(bytes, out->begin());
-  return true;
-}
-
 }  // namespace
 
 namespace settings {
@@ -982,125 +969,6 @@
   bio_->CancelEnrollment();
 }
 
-SecurityKeysPhonesHandler::SecurityKeysPhonesHandler() = default;
-SecurityKeysPhonesHandler::~SecurityKeysPhonesHandler() = default;
-
-void SecurityKeysPhonesHandler::OnJavascriptAllowed() {}
-void SecurityKeysPhonesHandler::OnJavascriptDisallowed() {}
-
-void SecurityKeysPhonesHandler::RegisterMessages() {
-  web_ui()->RegisterMessageCallback(
-      "securityKeyPhonesEnumerate",
-      base::BindRepeating(&SecurityKeysPhonesHandler::HandleEnumerate,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "securityKeyPhonesDelete",
-      base::BindRepeating(&SecurityKeysPhonesHandler::HandleDelete,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "securityKeyPhonesRename",
-      base::BindRepeating(&SecurityKeysPhonesHandler::HandleRename,
-                          base::Unretained(this)));
-}
-
-void SecurityKeysPhonesHandler::HandleEnumerate(const base::Value::List& args) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_EQ(1u, args.size());
-
-  AllowJavascript();
-  DoEnumerate(args[0]);
-}
-
-void SecurityKeysPhonesHandler::HandleDelete(const base::Value::List& args) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_EQ(2u, args.size());
-
-  AllowJavascript();
-  const std::string& public_key_base64 = args[1].GetString();
-  std::array<uint8_t, device::kP256X962Length> public_key;
-  const bool ok = DecodePublicKey(public_key_base64, &public_key);
-  DCHECK(ok);
-
-  PrefService* const prefs =
-      Profile::FromBrowserContext(
-          web_ui()->GetWebContents()->GetBrowserContext())
-          ->GetPrefs();
-  cablev2::DeletePairingByPublicKey(prefs, public_key);
-
-  DoEnumerate(args[0]);
-}
-
-void SecurityKeysPhonesHandler::HandleRename(const base::Value::List& args) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_EQ(3u, args.size());
-
-  AllowJavascript();
-  const std::string& public_key_base64 = args[1].GetString();
-  const std::string& new_name = args[2].GetString();
-  content::BrowserContext* const browser_ctx =
-      web_ui()->GetWebContents()->GetBrowserContext();
-
-  std::array<uint8_t, device::kP256X962Length> public_key;
-  const bool ok = DecodePublicKey(public_key_base64, &public_key);
-  DCHECK(ok);
-
-  // `existing_names` is built without calling `cablev2::MergeDevices` because
-  // that function will discard linked entries with duplicate public keys, which
-  // can hide some names that we would still like to avoid colliding with.
-  std::unique_ptr<cablev2::KnownDevices> known_devices =
-      cablev2::KnownDevices::FromProfile(
-          Profile::FromBrowserContext(browser_ctx));
-
-  // Remove the device that is getting renamed from the set of linked devices.
-  std::erase_if(
-      known_devices->linked_devices,
-      [&public_key](const std::unique_ptr<device::cablev2::Pairing>& device) {
-        return device->peer_public_key_x962 == public_key;
-      });
-
-  PrefService* const prefs =
-      Profile::FromBrowserContext(browser_ctx)->GetPrefs();
-  cablev2::RenamePairing(prefs, public_key, new_name, known_devices->Names());
-
-  ResolveJavascriptCallback(args[0], base::Value());
-}
-
-void SecurityKeysPhonesHandler::DoEnumerate(const base::Value& callback_id) {
-  const std::vector<std::unique_ptr<device::cablev2::Pairing>> pairings =
-      cablev2::MergeDevices(
-          cablev2::KnownDevices::FromProfile(Profile::FromBrowserContext(
-              web_ui()->GetWebContents()->GetBrowserContext())),
-          &icu::Locale::getDefault());
-
-  base::Value::List synced;
-  base::Value::List linked;
-  std::optional<std::string> last_synced_device_name;
-  for (const auto& pairing : pairings) {
-    base::Value::Dict dict;
-    dict.Set("name", pairing->name);
-    dict.Set("publicKey", base::Base64Encode(pairing->peer_public_key_x962));
-
-    if (pairing->from_sync_deviceinfo) {
-      // Synced devices can have duplicate names. (E.g. if two or more
-      // channels are syncing from the same phone.) These are deduplicated
-      // here.
-      if (!last_synced_device_name ||
-          *last_synced_device_name != pairing->name) {
-        synced.Append(std::move(dict));
-      }
-      last_synced_device_name = pairing->name;
-    } else {
-      linked.Append(std::move(dict));
-    }
-  }
-
-  base::Value::List result;
-  result.Append(std::move(synced));
-  result.Append(std::move(linked));
-
-  ResolveJavascriptCallback(callback_id, result);
-}
-
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 
 PasskeysHandler::PasskeysHandler() = default;
diff --git a/chrome/browser/ui/webui/settings/settings_security_key_handler.h b/chrome/browser/ui/webui/settings/settings_security_key_handler.h
index 401d669..79d2419c 100644
--- a/chrome/browser/ui/webui/settings/settings_security_key_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_security_key_handler.h
@@ -251,24 +251,6 @@
   base::WeakPtrFactory<SecurityKeysBioEnrollmentHandler> weak_factory_{this};
 };
 
-class SecurityKeysPhonesHandler : public SettingsPageUIHandler {
- public:
-  SecurityKeysPhonesHandler();
-  ~SecurityKeysPhonesHandler() override;
-
- protected:
-  void RegisterMessages() override;
-  void OnJavascriptAllowed() override;
-  void OnJavascriptDisallowed() override;
-
- private:
-  void HandleEnumerate(const base::Value::List& args);
-  void HandleDelete(const base::Value::List& args);
-  void HandleRename(const base::Value::List& args);
-
-  void DoEnumerate(const base::Value& callback_id);
-};
-
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 class PasskeysHandler : public SettingsPageUIHandler {
  public:
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 7926268a..198bd8eb 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -259,7 +259,6 @@
   AddSettingsPageUIHandler(std::make_unique<SecurityKeysCredentialHandler>());
   AddSettingsPageUIHandler(
       std::make_unique<SecurityKeysBioEnrollmentHandler>());
-  AddSettingsPageUIHandler(std::make_unique<SecurityKeysPhonesHandler>());
   AddSettingsPageUIHandler(std::make_unique<PasswordManagerHandler>());
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
   AddSettingsPageUIHandler(std::make_unique<PasskeysHandler>());
diff --git a/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc b/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc
index 4db19a7..bfc474dc 100644
--- a/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc
+++ b/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc
@@ -17,6 +17,7 @@
 #include "chrome/test/interaction/webcontents_interaction_test_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/base/signin_switches.h"
+#include "components/sync/base/features.h"
 #include "components/sync/test/test_sync_service.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/browser_test.h"
@@ -30,7 +31,12 @@
     : public SigninBrowserTestBaseT<
           WebUiInteractiveTestMixin<InteractiveBrowserTest>> {
  public:
-  SyncSettingsInteractiveTest() = default;
+  SyncSettingsInteractiveTest() {
+    feature_list_.InitWithFeatures(
+        /*enabled_features=*/{switches::kEnableHistorySyncOptin,
+                              syncer::kReplaceSyncPromosWithSignInPromos},
+        /*disabled_features=*/{});
+  }
 
   // Checks if a page title matches the given regexp in ecma script dialect.
   StateChange PageWithMatchingTitle(std::string_view title_regexp) {
@@ -62,8 +68,7 @@
   }
 
  private:
-  base::test::ScopedFeatureList feature_list_{
-      switches::kEnableHistorySyncOptin};
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // TODO(crbug.com/407795729): Fix and re-enable.
diff --git a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks.mojom b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks.mojom
index 7c02f7c..d2dbe083 100644
--- a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks.mojom
+++ b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks.mojom
@@ -166,7 +166,7 @@
   // regular non permanent node.
   MoveBookmark(int64 node_id, string folder_id);
 
-  // Removes the boomkarks with id in `node_ids`. All bookmarks are expected to
+  // Removes the bookmarks with id in `node_ids`. All bookmarks are expected to
   // map to a regular non permanent node. If some of the nodes are folders, it
   // will remove all children as well.
   // Result callback is called when all nodes are removed, it contains no data.
diff --git a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
index dbe57cf..281df12 100644
--- a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
+++ b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.cc b/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.cc
index 7173d11..6c0aef0 100644
--- a/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.cc
+++ b/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.h"
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 
 namespace web_app {
diff --git a/chrome/browser/web_applications/os_integration/web_app_stubs.cc b/chrome/browser/web_applications/os_integration/web_app_stubs.cc
index 6840e1d..6097459 100644
--- a/chrome/browser/web_applications/os_integration/web_app_stubs.cc
+++ b/chrome/browser/web_applications/os_integration/web_app_stubs.cc
@@ -11,13 +11,12 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/task/task_runner.h"
 #include "chrome/browser/web_applications/os_integration/web_app_file_handler_registration.h"
 #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 
-#include "base/notreached.h"
-
 namespace web_app {
 
 bool ShouldRegisterFileHandlersWithOs() {
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc
index 1acbb1e6..21ef43a6 100644
--- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc
+++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/test/bind.h"
 #include "chrome/browser/ui/web_applications/web_app_run_on_os_login_notification.h"
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_controller.cc b/chrome/browser/webauthn/authenticator_request_dialog_controller.cc
index e5b8ba7..699bbd9 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_controller.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_controller.cc
@@ -212,7 +212,8 @@
 }
 
 // Stores the last used pairing in the user's profile if available.
-void MaybeStoreLastUsedPairing(
+// TODO(crbug.com/372493822): remove and clean up pref.
+[[maybe_unused]] void MaybeStoreLastUsedPairing(
     content::RenderFrameHost* rfh,
     const std::array<uint8_t, device::kP256X962Length>& pairing_public_key) {
   Profile* profile = Profile::FromBrowserContext(rfh->GetBrowserContext())
@@ -224,7 +225,8 @@
 
 // Retrieves the last used pairing public key from the user's profile, if
 // available.
-std::optional<std::vector<uint8_t>> RetrieveLastUsedPairing(
+// TODO(crbug.com/372493822): remove and clean up pref.
+[[maybe_unused]] std::optional<std::vector<uint8_t>> RetrieveLastUsedPairing(
     content::RenderFrameHost* rfh) {
   Profile* profile = Profile::FromBrowserContext(rfh->GetBrowserContext())
                          ->GetOriginalProfile();
@@ -254,16 +256,10 @@
   return vector_icons::kPasskeyIcon;
 }
 
-int GetHybridButtonLabel(bool has_security_key, bool specific_phones_listed) {
-  if (has_security_key) {
-    return specific_phones_listed
-               ? IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_TABLET_OR_SECURITY_KEY_LABEL
-               : IDS_WEBAUTHN_PASSKEY_PHONE_TABLET_OR_SECURITY_KEY_LABEL;
-  } else {
-    return specific_phones_listed
-               ? IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_OR_TABLET_LABEL
-               : IDS_WEBAUTHN_PASSKEY_PHONE_OR_TABLET_LABEL;
-  }
+int GetHybridButtonLabel(bool has_security_key) {
+  return has_security_key
+             ? IDS_WEBAUTHN_PASSKEY_PHONE_TABLET_OR_SECURITY_KEY_LABEL
+             : IDS_WEBAUTHN_PASSKEY_PHONE_OR_TABLET_LABEL;
 }
 
 // SourcePriority determines which credential will be used when doing a modal
@@ -291,7 +287,6 @@
 std::optional<std::pair<int, AuthenticatorTransport>> GetWindowsAPIButtonLabel(
     const device::FidoRequestHandlerBase::TransportAvailabilityInfo&
         transport_availability,
-    bool specific_phones_listed,
     UIPresentation ui_presentation) {
   if (ui_presentation == UIPresentation::kModalImmediate) {
     return std::nullopt;
@@ -339,9 +334,8 @@
     }
   }
   if (win_handles_hybrid) {
-    return std::make_pair(
-        GetHybridButtonLabel(win_handles_security_key, specific_phones_listed),
-        AuthenticatorTransport::kHybrid);
+    return std::make_pair(GetHybridButtonLabel(win_handles_security_key),
+                          AuthenticatorTransport::kHybrid);
   }
   if (win_handles_security_key) {
     return std::make_pair(IDS_WEBAUTHN_TRANSPORT_EXTERNAL_SECURITY_KEY,
@@ -430,9 +424,6 @@
             // Always use the standard iCloud Keychain icon here.
             return kIcloudKeychainIcon;
           },
-          [](const Mechanism::Phone&) -> const gfx::VectorIcon& {
-            return kSmartphoneIcon;
-          },
           [](const Mechanism::AddPhone&) -> const gfx::VectorIcon& {
             return kQrcodeGeneratorIcon;
           },
@@ -460,7 +451,6 @@
 
 void AuthenticatorRequestDialogController::ResetEphemeralState() {
   ephemeral_state_ = {};
-  model_->selected_phone_name.reset();
   model_->creds.clear();
   model_->priority_mechanism_index.reset();
 }
@@ -664,22 +654,6 @@
   OnAccountPreselected(model_->creds.at(index).cred_id);
 }
 
-void AuthenticatorRequestDialogController::ContactPriorityPhone() {
-  if (model_->step() == Step::kTrustThisComputerAssertion) {
-    auto* pref_service =
-        Profile::FromBrowserContext(GetRenderFrameHost()->GetBrowserContext())
-            ->GetOriginalProfile()
-            ->GetPrefs();
-    int current_gpm_decline_count = pref_service->GetInteger(
-        webauthn::pref_names::kEnclaveDeclinedGPMBootstrappingCount);
-    pref_service->SetInteger(
-        webauthn::pref_names::kEnclaveDeclinedGPMBootstrappingCount,
-        std::min(current_gpm_decline_count + 1,
-                 device::enclave::kMaxGPMBootstrapPrompts));
-  }
-  ContactPhone(paired_phones_[*priority_phone_index_]->name);
-}
-
 void AuthenticatorRequestDialogController::OnBioEnrollmentDone() {
   std::move(bio_enrollment_callback_).Run();
 }
@@ -921,11 +895,6 @@
                 mechanism.callback.Run();
                 return;
               }
-              if (std::get<Mechanism::Credential>(type)->source ==
-                  AuthenticatorType::kPhone) {
-                SetCurrentStep(Step::kPhoneConfirmationSheet);
-                return;
-              }
             }
           }
         }
@@ -1073,11 +1042,6 @@
   DispatchRequestAsync(&*platform_authenticator_it);
 }
 
-void AuthenticatorRequestDialogController::OnPhoneContactFailed(
-    const std::string& name) {
-  ContactNextPhoneByName(name);
-}
-
 void AuthenticatorRequestDialogController::OnCableEvent(
     device::cablev2::Event event) {
   switch (event) {
@@ -1381,8 +1345,7 @@
   bool phone_is_option =
       !WebAuthnApiSupportsHybrid() &&
       std::ranges::any_of(model_->mechanisms, [](const Mechanism& m) -> bool {
-        return std::holds_alternative<Mechanism::Phone>(m.type) ||
-               std::holds_alternative<Mechanism::AddPhone>(m.type);
+        return std::holds_alternative<Mechanism::AddPhone>(m.type);
       });
   bool have_other_option = enclave_is_option || phone_is_option;
   bool windows_was_priority =
@@ -1520,20 +1483,13 @@
 
   MaybeStartChallengeFetch();
 
-  if (source != AuthenticatorType::kPhone &&
-      source != AuthenticatorType::kEnclave) {
+  // `source` should not be `kPhone` here.
+  if (source != AuthenticatorType::kEnclave) {
     HideDialogAndDispatchToPlatformAuthenticator(source);
     return source;
   }
 
-  // `source` should not be `kPhone` here except in some tests, which don't
-  // configure the enclave.
-  if (source != AuthenticatorType::kPhone) {
-    model_->OnGPMPasskeySelected(credential_id);
-    return source;
-  }
-
-  ContactPriorityPhone();
+  model_->OnGPMPasskeySelected(credential_id);
   return source;
 }
 
@@ -1543,25 +1499,6 @@
       std::move(test_authenticator));
 }
 
-void AuthenticatorRequestDialogController::ContactPhoneForTesting(
-    const std::string& name) {
-  // Ensure BLE is powered so that `ContactPhone()` shows the "Check your phone"
-  // screen right away.
-  transport_availability_.ble_status = BleStatus::kOn;
-  model_->ble_adapter_is_powered = true;
-  ContactPhone(name);
-}
-
-void AuthenticatorRequestDialogController::SetPriorityPhoneIndex(
-    std::optional<size_t> index) {
-  if (index) {
-    model_->priority_phone_name = paired_phones_.at(*index)->name;
-  } else {
-    model_->priority_phone_name.reset();
-  }
-  priority_phone_index_ = index;
-}
-
 void AuthenticatorRequestDialogController::StartTransportFlowForTesting(
     AuthenticatorTransport transport) {
   StartGuidedFlowForTransport(transport);
@@ -1619,12 +1556,7 @@
 
 void AuthenticatorRequestDialogController::set_cable_transport_info(
     std::optional<bool> extension_is_v2,
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> paired_phones,
-    base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-        contact_phone_callback,
     const std::optional<std::string>& cable_qr_string) {
-  DCHECK(paired_phones.empty() || contact_phone_callback);
-
   if (extension_is_v2.has_value()) {
     cable_extension_provided_ = true;
     if (*extension_is_v2) {
@@ -1639,20 +1571,7 @@
         AuthenticatorRequestDialogModel::CableUIType::CABLE_V2_2ND_FACTOR;
   }
 
-  paired_phones_ = std::move(paired_phones);
-  contact_phone_callback_ = std::move(contact_phone_callback);
   model_->cable_qr_string = cable_qr_string;
-
-  model_->paired_phone_names.clear();
-  std::ranges::transform(paired_phones_,
-                         std::back_inserter(model_->paired_phone_names),
-                         &device::cablev2::Pairing::name);
-  model_->paired_phone_names.erase(
-      std::unique(model_->paired_phone_names.begin(),
-                  model_->paired_phone_names.end()),
-      model_->paired_phone_names.end());
-
-  paired_phones_contacted_.assign(paired_phones_.size(), false);
 }
 
 void AuthenticatorRequestDialogController::set_allow_icloud_keychain(
@@ -1978,43 +1897,6 @@
   CancelAuthenticatorRequest();
 }
 
-void AuthenticatorRequestDialogController::ContactPhone(
-    const std::string& name) {
-  if (transport_availability_.ble_status == BleStatus::kPermissionDenied) {
-    // |step| is not saved because macOS asks the user to restart Chrome
-    // after permission has been granted. So the user will end up retrying
-    // the whole WebAuthn request in the new process.
-    SetCurrentStep(Step::kBlePermissionMac);
-    return;
-  }
-
-  if (transport_availability_.request_type ==
-          FidoRequestType::kMakeCredential &&
-      transport_availability_.is_off_the_record_context) {
-    after_off_the_record_interstitial_ =
-        base::BindOnce(&AuthenticatorRequestDialogController::
-                           ContactPhoneAfterOffTheRecordInterstitial,
-                       weak_factory_.GetWeakPtr(), name);
-    SetCurrentStep(Step::kOffTheRecordInterstitial);
-    return;
-  }
-
-  ContactPhoneAfterOffTheRecordInterstitial(name);
-}
-
-void AuthenticatorRequestDialogController::
-    ContactPhoneAfterOffTheRecordInterstitial(std::string name) {
-  EnsureBleAdapterIsPoweredAndContinue(base::BindOnce(
-      &AuthenticatorRequestDialogController::ContactPhoneAfterBleIsPowered,
-      weak_factory_.GetWeakPtr(), std::move(name)));
-}
-
-void AuthenticatorRequestDialogController::ContactPhoneAfterBleIsPowered(
-    std::string name) {
-  ContactNextPhoneByName(name);
-  SetCurrentStep(Step::kCableActivate);
-}
-
 void AuthenticatorRequestDialogController::StartAutofillRequest() {
   model_->creds = transport_availability_.recognized_credentials;
 
@@ -2022,18 +1904,8 @@
   auto* web_contents =
       content::WebContents::FromRenderFrameHost(render_frame_host);
   std::vector<password_manager::PasskeyCredential> credentials;
-  std::optional<size_t> priority_phone_index =
-      GetIndexOfMostRecentlyUsedPhoneFromSync();
   std::optional<std::u16string> priority_phone_name;
-  if (priority_phone_index) {
-    priority_phone_name =
-        base::UTF8ToUTF16(paired_phones_[*priority_phone_index]->name);
-  }
   for (const auto& credential : model_->creds) {
-    if (credential.source == AuthenticatorType::kPhone &&
-        !priority_phone_index) {
-      continue;
-    }
     if (credential.source == AuthenticatorType::kEnclave &&
         enclave_enabled_status_ != EnclaveEnabledStatus::kEnabled) {
       continue;
@@ -2112,62 +1984,6 @@
       base::BindOnce(request_callback_, authenticator->authenticator_id));
 }
 
-void AuthenticatorRequestDialogController::ContactNextPhoneByName(
-    const std::string& name) {
-  bool found_name = false;
-  model_->selected_phone_name.reset();
-  for (size_t i = 0; i != paired_phones_.size(); i++) {
-    const std::unique_ptr<device::cablev2::Pairing>& phone = paired_phones_[i];
-    if (phone->name == name) {
-      found_name = true;
-      model_->selected_phone_name = name;
-      if (!paired_phones_contacted_[i]) {
-        MaybeStoreLastUsedPairing(GetRenderFrameHost(),
-                                  phone->peer_public_key_x962);
-        paired_phones_contacted_[i] = true;
-        contact_phone_callback_.Run(
-            std::make_unique<device::cablev2::Pairing>(*phone));
-        break;
-      }
-    } else if (found_name) {
-      // |paired_phones_| is sorted by name so as soon as we see a mismatch
-      // after a match, we're done.
-      break;
-    }
-  }
-
-  DCHECK(found_name);
-}
-
-std::optional<size_t>
-AuthenticatorRequestDialogController::GetIndexOfMostRecentlyUsedPhoneFromSync()
-    const {
-  // Try finding the most recently used phone from sync.
-  std::optional<std::vector<uint8_t>> last_used_pairing =
-      RetrieveLastUsedPairing(GetRenderFrameHost());
-  if (last_used_pairing) {
-    for (size_t i = 0; i < paired_phones_.size(); ++i) {
-      if (paired_phones_[i]->from_sync_deviceinfo &&
-          std::ranges::equal(paired_phones_[i]->peer_public_key_x962,
-                             *last_used_pairing)) {
-        return i;
-      }
-    }
-  }
-  // Could not find a most recently used phone. Instead, return the phone that
-  // last published to sync.
-  std::optional<int> ret;
-  for (size_t i = 0; i < paired_phones_.size(); ++i) {
-    if (paired_phones_[i]->from_sync_deviceinfo) {
-      if (!ret || paired_phones_[*ret]->last_updated <
-                      paired_phones_[i]->last_updated) {
-        ret = i;
-      }
-    }
-  }
-  return ret;
-}
-
 void AuthenticatorRequestDialogController::SortRecognizedCredentials() {
   struct {
     bool operator()(const device::DiscoverableCredentialMetadata& a,
@@ -2202,17 +2018,10 @@
 void AuthenticatorRequestDialogController::PopulateMechanisms() {
   const bool is_get_assertion =
       transport_availability_.request_type == FidoRequestType::kGetAssertion;
-  SetPriorityPhoneIndex(GetIndexOfMostRecentlyUsedPhoneFromSync());
-  bool list_phone_passkeys = is_get_assertion && priority_phone_index_;
-  bool specific_phones_listed = false;
   bool specific_local_passkeys_listed = false;
-  bool enclave_passkeys_shown = false;
   if (is_get_assertion && IsModalRequest(ui_presentation())) {
     // List passkeys instead of mechanisms for platform & GPM authenticators.
     for (const auto& cred : transport_availability_.recognized_credentials) {
-      if (cred.source == AuthenticatorType::kPhone && !list_phone_passkeys) {
-        continue;
-      }
       if (cred.source == AuthenticatorType::kICloudKeychain &&
           !allow_icloud_keychain_) {
         continue;
@@ -2223,13 +2032,8 @@
           // proceeding.  Instead, we'll show a button to trigger reauth.
           continue;
         }
-        enclave_passkeys_shown = true;
       }
-      if (cred.source == AuthenticatorType::kPhone) {
-        specific_phones_listed = true;
-      } else {
-        specific_local_passkeys_listed = true;
-      }
+      specific_local_passkeys_listed = true;
       std::u16string name = base::UTF8ToUTF16(cred.user.name.value_or(""));
       Mechanism::Type mechanism_type = Mechanism::Credential(
           {cred.source, cred.user.id, cred.last_used_time});
@@ -2243,7 +2047,7 @@
           base::UTF8ToUTF16(cred.user.display_name.value_or("")));
       mechanism.description =
           AuthenticatorRequestDialogModel::GetMechanismDescription(
-              cred, model_->priority_phone_name, ui_presentation());
+              cred, ui_presentation());
     }
     if (!passwords_.empty()) {
       PopulatePasswords();
@@ -2366,60 +2170,14 @@
   }
 
   std::optional<std::pair<int, AuthenticatorTransport>> windows_button_label;
-  windows_button_label = GetWindowsAPIButtonLabel(
-      transport_availability_, specific_phones_listed, ui_presentation());
+  windows_button_label =
+      GetWindowsAPIButtonLabel(transport_availability_, ui_presentation());
   if (windows_button_label &&
       windows_button_label->second == AuthenticatorTransport::kInternal) {
     // Add the Windows button before phones if it can trigger Windows Hello.
     AddWindowsButton(windows_button_label->first, windows_button_label->second);
   }
 
-  // Only list phones as transports if we did not already list GPM passkeys
-  // above and this is an allow-list request. That way, users can tap their
-  // synced phone name to use a non-discoverable credential from their synced
-  // phone.
-  bool all_matching_phone_creds_listed =
-      list_phone_passkeys &&
-      (specific_phones_listed || transport_availability_.has_empty_allow_list);
-  if (base::Contains(transport_availability_.available_transports, kCable) &&
-      !all_matching_phone_creds_listed && !enclave_passkeys_shown &&
-      !windows_handles_hybrid) {
-    // List phones as transports.
-    for (const auto& phone_name : model_->paired_phone_names) {
-      const std::u16string name16 = base::UTF8ToUTF16(phone_name);
-      static constexpr size_t kMaxLongNameChars = 50;
-      static constexpr size_t kMaxShortNameChars = 30;
-      std::u16string long_name, short_name;
-      gfx::ElideString(name16, kMaxLongNameChars, &long_name);
-      gfx::ElideString(name16, kMaxShortNameChars, &short_name);
-
-      Mechanism::Type mechanism_type = Mechanism::Phone(phone_name);
-      model_->mechanisms.emplace_back(
-          mechanism_type, std::move(long_name), std::move(short_name),
-          GetMechanismIcon(mechanism_type, ui_presentation()),
-          base::BindRepeating(
-              &AuthenticatorRequestDialogController::ContactPhone,
-              base::Unretained(this), phone_name));
-      specific_phones_listed = true;
-    }
-    bool skip_to_phone_confirmation =
-        is_get_assertion &&
-        transport_availability_.has_platform_authenticator_credential ==
-            device::FidoRequestHandlerBase::RecognizedCredential::
-                kNoRecognizedCredential &&
-        transport_availability_.has_icloud_keychain_credential ==
-            device::FidoRequestHandlerBase::RecognizedCredential::
-                kNoRecognizedCredential &&
-        paired_phones_.size() == 1 && IsModalRequest(ui_presentation()) &&
-        transport_availability_.is_only_hybrid_or_internal;
-    if (skip_to_phone_confirmation) {
-      FIDO_LOG(EVENT)
-          << "Skipping to phone confirmation on discoverable credential match.";
-      SetPriorityPhoneIndex(0);
-      pending_step_ = Step::kPhoneConfirmationSheet;
-    }
-  }
-
   // If the new UI is enabled, only show USB as an option if the QR code is
   // not available, if tapping it would trigger a prompt to enable BLE, or if
   // hints suggest that hybrid and USB should be separate options.
@@ -2436,8 +2194,8 @@
         base::Contains(transport_availability_.available_transports,
                        AuthenticatorTransport::kUsbHumanInterfaceDevice) &&
         !include_usb_option;
-    std::u16string label = l10n_util::GetStringUTF16(
-        GetHybridButtonLabel(merge_usb_and_hybrid, specific_phones_listed));
+    std::u16string label =
+        l10n_util::GetStringUTF16(GetHybridButtonLabel(merge_usb_and_hybrid));
     Mechanism::Type mechanism_type = Mechanism::AddPhone();
     model_->mechanisms.emplace_back(
         mechanism_type, label, label,
@@ -2675,17 +2433,12 @@
   const bool is_passkey_request = model_->resident_key_requirement !=
                                   device::ResidentKeyRequirement::kDiscouraged;
   if (is_passkey_request) {
-    if (model_->paired_phone_names.empty()) {
-      priority_list.emplace_back(Mechanism::AddPhone());
-    }
+    priority_list.emplace_back(Mechanism::AddPhone());
   } else {
     priority_list.emplace_back(Mechanism::WindowsAPI());
   }
 
   for (const auto& priority_mechanism : priority_list) {
-    // A phone should never be triggered immediately.
-    CHECK(!std::holds_alternative<Mechanism::Phone>(priority_mechanism));
-
     for (size_t i = 0; i < model_->mechanisms.size(); i++) {
       if (priority_mechanism == model_->mechanisms[i].type) {
         return i;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_controller.h b/chrome/browser/webauthn/authenticator_request_dialog_controller.h
index 8ae213f..12b2cb9e 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_controller.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_controller.h
@@ -80,7 +80,6 @@
   void EnclaveEnabledStatusChanged(EnclaveEnabledStatus status) override;
   void OnAccountSelected(size_t index) override;
   void OnAccountPreselectedIndex(size_t index) override;
-  void ContactPriorityPhone() override;
   void OnBioEnrollmentDone() override;
   void OnUserConfirmedPriorityMechanism() override;
 
@@ -132,9 +131,6 @@
   void HideDialogAndDispatchToPlatformAuthenticator(
       std::optional<device::AuthenticatorType> type = std::nullopt);
 
-  // Called when an attempt to contact a phone failed.
-  void OnPhoneContactFailed(const std::string& name);
-
   // Called when some caBLE event (e.g. receiving a BLE message, connecting to
   // the tunnel server, etc) happens.
   void OnCableEvent(device::cablev2::Event event);
@@ -283,15 +279,6 @@
 
   void SetSelectedAuthenticatorForTesting(AuthenticatorReference authenticator);
 
-  // ContactPhoneForTesting triggers a contact for a phone with the given name.
-  // Only for unittests. UI should use |mechanisms()| to enumerate the
-  // user-visible mechanisms and use the callbacks therein.
-  void ContactPhoneForTesting(const std::string& name);
-
-  // Sets `priority_phone_index_` and updates the name of the priority phone in
-  // `model_` accordingly.
-  void SetPriorityPhoneIndex(std::optional<size_t> index);
-
   // StartTransportFlowForTesting moves the UI to focus on the given transport.
   // UI should use |mechanisms()| to enumerate the user-visible mechanisms and
   // use the callbacks therein.
@@ -337,9 +324,6 @@
 
   void set_cable_transport_info(
       std::optional<bool> extension_is_v2,
-      std::vector<std::unique_ptr<device::cablev2::Pairing>> paired_phones,
-      base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-          contact_phone_callback,
       const std::optional<std::string>& cable_qr_string);
 
   bool win_native_api_enabled() const {
@@ -433,22 +417,11 @@
   // Triggers gaia account reauth to restore sync to working order.
   void ReauthForSyncRestore();
 
-  // Contacts a paired phone. The phone is specified by name.
-  void ContactPhone(const std::string& name);
-  void ContactPhoneAfterOffTheRecordInterstitial(std::string name);
-  void ContactPhoneAfterBleIsPowered(std::string name);
-
   void StartAutofillRequest();
   void StartPasskeyUpgradeRequest();
 
   void DispatchRequestAsync(AuthenticatorReference* authenticator);
 
-  void ContactNextPhoneByName(const std::string& name);
-
-  // Returns the index (into `paired_phones_`) of a phone that has been paired
-  // through Chrome Sync, or std::nullopt if there isn't one.
-  std::optional<size_t> GetIndexOfMostRecentlyUsedPhoneFromSync() const;
-
   // SortRecognizedCredentials sorts
   // `transport_availability_.recognized_credentials` into username order.
   void SortRecognizedCredentials();
@@ -540,22 +513,6 @@
   // extension.
   bool cable_extension_provided_ = false;
 
-  // paired_phones_ contains details of caBLEv2-paired phones from both Sync and
-  // QR-based pairing. The entries are sorted by name.
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> paired_phones_;
-
-  // The index, into `paired_phones_`, for the top-priority phone.
-  std::optional<size_t> priority_phone_index_;
-
-  // paired_phones_contacted_ is the same length as |paired_phones_| and
-  // contains true whenever the corresponding phone as already been contacted.
-  std::vector<bool> paired_phones_contacted_;
-
-  // contact_phone_callback can be run with a pairing in order to contact the
-  // indicated phone.
-  base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-      contact_phone_callback_;
-
   // cable_device_ready_ is true if a CTAP-level request has been sent to a
   // caBLE device. At this point we assume that any transport errors are
   // cancellations on the device, not networking errors.
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index 747a8112..42ce72b 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -93,12 +93,7 @@
 // static
 std::u16string AuthenticatorRequestDialogModel::GetMechanismDescription(
     const device::DiscoverableCredentialMetadata& cred,
-    const std::optional<std::string>& phone_name,
     UIPresentation ui_presentation) {
-  if (cred.source == device::AuthenticatorType::kPhone) {
-    return l10n_util::GetStringFUTF16(IDS_WEBAUTHN_SOURCE_PHONE,
-                                      base::UTF8ToUTF16(*phone_name));
-  }
   bool immediate_mode = UIPresentation::kModalImmediate == ui_presentation;
   if (cred.provider_name) {
     return immediate_mode ? l10n_util::GetStringFUTF16(
@@ -281,7 +276,6 @@
       {Step::kBlePowerOnManual, "kBlePowerOnManual"},
       {Step::kBlePermissionMac, "kBlePermissionMac"},
       {Step::kOffTheRecordInterstitial, "kOffTheRecordInterstitial"},
-      {Step::kPhoneConfirmationSheet, "kPhoneConfirmationSheet"},
       {Step::kCableActivate, "kCableActivate"},
       {Step::kCableV2QRCode, "kCableV2QRCode"},
       {Step::kCableV2Connecting, "kCableV2Connecting"},
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index 7d0127e..3a194803 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -84,11 +84,6 @@
   /* Cancels the flow as a result of the user clicking `Cancel` on the */     \
   /* UI. Valid action at all steps. */                                        \
   AUTHENTICATOR_REQUEST_EVENT_0(CancelAuthenticatorRequest)                   \
-  /* Contacts the "priority" paired phone. This is the phone from sync if */  \
-  /* there are a priori discovered GPM passkeys, or the first phone on the */ \
-  /* list otherwise. Only valid to call if |model_->priority_phone_name| */   \
-  /* contains a value. */                                                     \
-  AUTHENTICATOR_REQUEST_EVENT_0(ContactPriorityPhone)                         \
   /* Continues with the BLE/caBLE flow now that the Bluetooth adapter is */   \
   /* powered. Valid action when at step: kBlePowerOnManual, */                \
   /* kBlePowerOnAutomatic. */                                                 \
@@ -119,8 +114,6 @@
   AUTHENTICATOR_REQUEST_EVENT_0(OnGPMConfirmOffTheRecordCreate)               \
   /* Called when the user clicks "Forgot PIN" during UV. */                   \
   AUTHENTICATOR_REQUEST_EVENT_0(OnForgotGPMPinPressed)                        \
-  /* Called when the user clicks Manage Devices to manage their phones. */    \
-  AUTHENTICATOR_REQUEST_EVENT_0(OnManageDevicesClicked)                       \
   /* OnOffTheRecordInterstitialAccepted is called when the user accepts */    \
   /* the interstitial that warns that platform/caBLE authenticators may */    \
   /* record information even in incognito mode. */                            \
@@ -239,7 +232,6 @@
     // will be recorded.
     kOffTheRecordInterstitial,
     // Phone as a security key.
-    kPhoneConfirmationSheet,
     kCableActivate,
     kCableV2QRCode,
     kCableV2Connecting,
@@ -314,16 +306,16 @@
   };
 
   // A Mechanism is a user-visible method of authenticating. It might be a
-  // transport (such as USB), a platform authenticator, a phone, or even a
-  // delegation to a platform API. Selecting a mechanism starts the flow for the
-  // user to authenticate with it (e.g. by showing a QR code or dispatching to a
+  // transport (such as USB), a platform authenticator, or even a delegation to
+  // a platform API. Selecting a mechanism starts the flow for the user to
+  // authenticate with it (e.g. by showing a QR code or dispatching to a
   // platform authenticator).
   //
   // On get assertion requests, mechanisms can also represent credentials for
   // authenticators that support silent discovery. In this case, the |type| is
-  // |Credential| and it is annotated with the source of the credential (phone,
-  // icloud, etc). Selecting such a mechanism dispatches a request narrowed down
-  // to the specific credential to an authenticator that can fulfill it.
+  // |Credential| and it is annotated with the source of the credential (icloud,
+  // etc). Selecting such a mechanism dispatches a request narrowed down to the
+  // specific credential to an authenticator that can fulfill it.
   struct Mechanism {
     // These types describe the type of Mechanism.
     struct CredentialInfo {
@@ -355,7 +347,6 @@
     using WindowsAPI = base::StrongAlias<class WindowsAPITag, std::monostate>;
     using ICloudKeychain =
         base::StrongAlias<class iCloudKeychainTag, std::monostate>;
-    using Phone = base::StrongAlias<class PhoneTag, std::string>;
     using AddPhone = base::StrongAlias<class AddPhoneTag, std::monostate>;
     using Enclave = base::StrongAlias<class EnclaveTag, std::monostate>;
     using SignInAgain = base::StrongAlias<class SignInAgainTag, std::monostate>;
@@ -363,7 +354,6 @@
                               Password,
                               Transport,
                               WindowsAPI,
-                              Phone,
                               AddPhone,
                               ICloudKeychain,
                               Enclave,
@@ -398,11 +388,9 @@
     CABLE_V2_2ND_FACTOR,
   };
 
-  // Returns a user-friendly description for a |type|. If |type| is kPhone, a
-  // |phone_name| must be passed.
+  // Returns a user-friendly description for a |type|.
   static std::u16string GetMechanismDescription(
       const device::DiscoverableCredentialMetadata& cred,
-      const std::optional<std::string>& phone_name,
       UIPresentation ui_presentation = UIPresentation::kModal);
 
   explicit AuthenticatorRequestDialogModel(
@@ -503,19 +491,11 @@
   std::optional<int> pin_attempts;
   std::optional<int> uv_attempts;
   device::pin::PINEntryError pin_error = device::pin::PINEntryError::kNoError;
-  // A sorted, unique list of the names of paired phones.
-  std::vector<std::string> paired_phone_names;
-  // The name of the priority phone, if any.
-  std::optional<std::string> priority_phone_name;
 
   // cable_ui_type contains the type of UI to display for a caBLE transaction.
   std::optional<CableUIType> cable_ui_type;
 
   std::optional<std::string> cable_qr_string;
-  // The name of the paired phone that was passed to `ContactPhone()`. It is
-  // shown on the UI sheet that prompts the user to check their phone for
-  // a notification.
-  std::optional<std::string> selected_phone_name;
 
   // Number of remaining GPM pin entry attempts before getting locked out or
   // `std::nullopt` if there was no failed attempts during that request.
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
index 6066463..dfd9900 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
@@ -180,8 +180,6 @@
   kHasPlatformCredential,
   kOneRecognizedCred,
   kTwoRecognizedCreds,
-  kOnePhoneRecognizedCred,
-  kTwoPhoneRecognizedCred,
   kOneTouchIDRecognizedCred,
   kEmptyAllowList,
   kOnlyInternal,
@@ -220,10 +218,6 @@
       return "kOneRecognizedCred";
     case TransportAvailabilityParam::kTwoRecognizedCreds:
       return "kTwoRecognizedCreds";
-    case TransportAvailabilityParam::kOnePhoneRecognizedCred:
-      return "kOnePhoneRecognizedCred";
-    case TransportAvailabilityParam::kTwoPhoneRecognizedCred:
-      return "kTwoPhoneRecognizedCred";
     case TransportAvailabilityParam::kOneTouchIDRecognizedCred:
       return "kOneTouchIDRecognizedCred";
     case TransportAvailabilityParam::kEmptyAllowList:
@@ -282,20 +276,6 @@
   return base::JoinString(base::ToVector(s, F), ", ");
 }
 
-std::unique_ptr<device::cablev2::Pairing> GetPairingFromSync() {
-  auto pairing = std::make_unique<device::cablev2::Pairing>();
-  pairing->name = "Phone from sync";
-  pairing->from_sync_deviceinfo = true;
-  return pairing;
-}
-
-std::unique_ptr<device::cablev2::Pairing> GetPairingFromQR() {
-  auto pairing = std::make_unique<device::cablev2::Pairing>();
-  pairing->name = "Phone from QR";
-  pairing->from_sync_deviceinfo = false;
-  return pairing;
-}
-
 const device::PublicKeyCredentialUserEntity kUser1({1, 2, 3, 4},
                                                    "A",
                                                    std::nullopt);
@@ -339,18 +319,6 @@
     {1},
     kUser2,
     /*provider_name=*/std::nullopt);
-const device::DiscoverableCredentialMetadata kPhoneCred1(
-    device::AuthenticatorType::kPhone,
-    "rp.com",
-    {2},
-    kPhoneUser1,
-    /*provider_name=*/std::nullopt);
-const device::DiscoverableCredentialMetadata kPhoneCred2(
-    device::AuthenticatorType::kPhone,
-    "rp.com",
-    {3},
-    kPhoneUser2,
-    /*provider_name=*/std::nullopt);
 const device::DiscoverableCredentialMetadata kWinCred1(
     device::AuthenticatorType::kWinNative,
     "rp.com",
@@ -474,30 +442,6 @@
       model_observer_{this};
 };
 
-class EnclaveDisabledController
-    : public AuthenticatorRequestDialogModel::Observer {
- public:
-  explicit EnclaveDisabledController(AuthenticatorRequestDialogModel* model)
-      : model_(model) {
-    model_observer_.Observe(model_);
-  }
-
-  void OnGPMPasskeySelected(std::vector<uint8_t> credential_id) override {
-    model_->ContactPriorityPhone();
-  }
-
-  void OnModelDestroyed(AuthenticatorRequestDialogModel*) override {
-    model_observer_.Reset();
-    model_ = nullptr;
-  }
-
- private:
-  raw_ptr<AuthenticatorRequestDialogModel> model_;
-  base::ScopedObservation<AuthenticatorRequestDialogModel,
-                          AuthenticatorRequestDialogModel::Observer>
-      model_observer_{this};
-};
-
 TEST_F(AuthenticatorRequestDialogControllerTest, Mechanisms) {
   const auto mc = RequestType::kMakeCredential;
   const auto ga = RequestType::kGetAssertion;
@@ -506,8 +450,6 @@
   const auto cable = AuthenticatorTransport::kHybrid;
   const auto cred1 = CredentialInfoFrom(kCred1);
   const auto cred2 = CredentialInfoFrom(kCred2);
-  const auto phonecred1 = CredentialInfoFrom(kPhoneCred1);
-  const auto phonecred2 = CredentialInfoFrom(kPhoneCred2);
   const auto ickc_cred1 = CredentialInfoFrom(kCred1FromICloudKeychain);
   const auto wincred1 = CredentialInfoFrom(kWinCred1);
   const auto wincred2 = CredentialInfoFrom(kWinCred2);
@@ -525,10 +467,6 @@
   [[maybe_unused]] const auto one_touchid_cred =
       TransportAvailabilityParam::kOneTouchIDRecognizedCred;
   const auto two_cred = TransportAvailabilityParam::kTwoRecognizedCreds;
-  const auto one_phone_cred =
-      TransportAvailabilityParam::kOnePhoneRecognizedCred;
-  const auto two_phone_cred =
-      TransportAvailabilityParam::kTwoPhoneRecognizedCred;
   const auto empty_al = TransportAvailabilityParam::kEmptyAllowList;
   [[maybe_unused]] const auto enclave_cred =
       TransportAvailabilityParam::kEnclaveCred;
@@ -560,7 +498,6 @@
       TransportAvailabilityParam::kEnclaveNeedsSignIn;
   using c = AuthenticatorRequestDialogModel::Mechanism::Credential;
   using t = AuthenticatorRequestDialogModel::Mechanism::Transport;
-  using p = AuthenticatorRequestDialogModel::Mechanism::Phone;
   const auto winapi = AuthenticatorRequestDialogModel::Mechanism::WindowsAPI();
   const auto add = AuthenticatorRequestDialogModel::Mechanism::AddPhone();
   const auto sign_in_again =
@@ -592,20 +529,15 @@
 #endif
   [[maybe_unused]] const auto use_pk = Step::kPreSelectAccount;
   const auto qr = Step::kCableV2QRCode;
-  const auto pconf = Step::kPhoneConfirmationSheet;
   const auto hero = Step::kSelectPriorityMechanism;
   [[maybe_unused]] const auto enclave_touchid = Step::kGPMTouchID;
   [[maybe_unused]] const auto enclave_pin = Step::kGPMEnterPin;
-  using psync = base::StrongAlias<class PhoneFromSyncTag, std::string>;
-  using pqr = base::StrongAlias<class PhoneFromQrTag, std::string>;
-  using PhoneVariant = std::variant<psync, pqr>;
 
   struct Test {
     int line_num;
     RequestType request_type;
     base::flat_set<AuthenticatorTransport> transports;
     base::flat_set<TransportAvailabilityParam> params;
-    std::vector<PhoneVariant> phones;
     std::vector<AuthenticatorRequestDialogModel::Mechanism::Type>
         expected_mechanisms;
     Step expected_first_step;
@@ -615,16 +547,15 @@
   // clang-format off
   Test kTests[]{
       // If there's only a single mechanism, it should activate.
-      {L, mc, {usb}, {}, {}, {t(usb)}, usb_ui},
-      {L, ga, {usb}, {}, {}, {t(usb)}, usb_ui},
-      {L, ga, {usb, cable}, {}, {}, {add}, qr},
-      {L, ga, {usb, cable}, {}, {}, {add}, qr},
+      {L, mc, {usb}, {}, {t(usb)}, usb_ui},
+      {L, ga, {usb}, {}, {t(usb)}, usb_ui},
+      {L, ga, {usb, cable}, {}, {add}, qr},
+      {L, ga, {usb, cable}, {}, {add}, qr},
       // If the platform authenticator has a credential it should activate.
       {L,
        ga,
        {},
        {has_plat, one_cred},
-       {},
        {c(cred1)},
        plat_ui,
      },
@@ -633,7 +564,6 @@
        ga,
        {usb, internal},
        {has_plat, one_cred},
-       {},
        {c(cred1), t(usb)},
 #if BUILDFLAG(IS_MAC)
        plat_ui
@@ -644,23 +574,23 @@
 #if BUILDFLAG(IS_MAC)
        // Without Touch ID, the profile authenticator will show a confirmation
        // prompt.
-      {L, ga, {usb, internal}, {has_plat, one_cred, no_touchid}, {},
+      {L, ga, {usb, internal}, {has_plat, one_cred, no_touchid},
        {c(cred1), t(usb)}, use_pk},
       // When a single profile credential is available with uv!=required and no
       // Touch ID, the UI must show the confirmation because, otherwise,
       // there'll be no UI at all.
-      {L, ga, {internal}, {has_plat, one_touchid_cred, no_touchid}, {},
+      {L, ga, {internal}, {has_plat, one_touchid_cred, no_touchid},
        {c(touchid_cred1)}, hero},
       // When TouchID is present, we can jump directly to the platform UI, which
       // will be a Touch ID prompt.
-      {L, ga, {internal}, {has_plat, one_touchid_cred, uv_pref}, {},
+      {L, ga, {internal}, {has_plat, one_touchid_cred, uv_pref},
        {c(touchid_cred1)}, plat_ui},
       // Or if uv=required, plat_ui is also ok because it'll be a password
       // prompt.
-      {L, ga, {internal}, {has_plat, one_touchid_cred, uv_req, no_touchid}, {},
+      {L, ga, {internal}, {has_plat, one_touchid_cred, uv_req, no_touchid},
        {c(touchid_cred1)}, plat_ui},
       // The profile authenticator does UV even for uv=discouraged.
-      {L, ga, {internal}, {has_plat, one_touchid_cred}, {}, {c(touchid_cred1)},
+      {L, ga, {internal}, {has_plat, one_touchid_cred}, {c(touchid_cred1)},
        plat_ui},
 #endif
       // Even with an empty allow list.
@@ -668,7 +598,6 @@
        ga,
        {usb, internal},
        {has_plat, one_cred, empty_al},
-       {},
        {c(cred1), t(usb)},
        hero},
       // Two credentials shows mechanism selection.
@@ -676,7 +605,6 @@
        ga,
        {usb, internal},
        {has_plat, two_cred, empty_al},
-       {},
        {c(cred1), c(cred2), t(usb)},
        mss},
 
@@ -686,7 +614,6 @@
        mc,
        {internal},
        {},
-       {},
        {t(internal)},
        create_pk_or_plat_ui,
       },
@@ -696,52 +623,50 @@
        mc,
        {usb, internal},
        {},
-       {},
        {t(internal), t(usb)},
        create_pk_or_mss,
       },
 
       // If the Windows API is available without caBLE, it should activate.
-      {L, mc, {}, {has_winapi}, {}, {winapi}, plat_ui},
-      {L, ga, {}, {has_winapi}, {}, {winapi}, plat_ui},
+      {L, mc, {}, {has_winapi}, {winapi}, plat_ui},
+      {L, ga, {}, {has_winapi}, {winapi}, plat_ui},
       // ...even if there are discovered Windows credentials.
-      {L, ga, {}, {has_winapi, one_cred}, {}, {c(wincred1), winapi}, plat_ui},
+      {L, ga, {}, {has_winapi, one_cred}, {c(wincred1), winapi}, plat_ui},
 
       // A caBLEv1 extension should cause us to go directly to caBLE.
-      {L, ga, {usb, cable}, {v1}, {}, {t(cable), t(usb)}, cable_ui},
+      {L, ga, {usb, cable}, {v1}, {t(cable), t(usb)}, cable_ui},
 
       // If this is a Conditional UI request, don't offer the platform
       // authenticator.
-      {L, ga, {usb, internal}, {c_ui}, {}, {t(usb)}, usb_ui},
+      {L, ga, {usb, internal}, {c_ui}, {t(usb)}, usb_ui},
       {L,
        ga,
        {usb, internal, cable},
        {c_ui},
-       {pqr("a")},
-       {p("a"), add},
-       mss},
+       {add},
+       qr},
 
       // On Windows, mc with rk=required jumps to the platform UI when caBLE
       // isn't an option. The case where caBLE is possible is tested below.
-      {L, mc, {}, {has_winapi, rk}, {}, {winapi}, plat_ui},
+      {L, mc, {}, {has_winapi, rk}, {winapi}, plat_ui},
       // For rk=discouraged, always jump to Windows UI.
-      {L, mc, {cable}, {has_winapi}, {}, {winapi, add}, plat_ui},
-      {L, mc, {}, {has_winapi}, {}, {winapi}, plat_ui},
+      {L, mc, {cable}, {has_winapi}, {winapi, add}, plat_ui},
+      {L, mc, {}, {has_winapi}, {winapi}, plat_ui},
 
       // On Windows, ga with an empty allow list goes to the platform UI unless
       // caBLE is an option and resident-key is required, which is tested below.
-      {L, ga, {}, {has_winapi, empty_al}, {}, {winapi}, plat_ui},
+      {L, ga, {}, {has_winapi, empty_al}, {winapi}, plat_ui},
       // With a non-empty allow list containing non phone credentials, always
       // jump to Windows UI.
       // TODO(NEWUI): we should maintain this behaviour on Windows.
-      {L, ga, {cable}, {has_winapi}, {}, {add, winapi}, mss},
-      {L, ga, {}, {has_winapi}, {}, {winapi}, plat_ui},
+      {L, ga, {cable}, {has_winapi}, {add, winapi}, mss},
+      {L, ga, {}, {has_winapi}, {winapi}, plat_ui},
 
        // With attachment=undefined, the UI should still default to a platform
        // authenticator.
-       {L, mc, {usb, internal, cable}, {att_any}, {}, {add, t(internal)},
+       {L, mc, {usb, internal, cable}, {att_any}, {add, t(internal)},
         create_pk_or_mss},
-       {L, mc, {usb, internal}, {att_any, rk}, {}, {t(internal), t(usb)},
+       {L, mc, {usb, internal}, {att_any, rk}, {t(internal), t(usb)},
         create_pk_or_mss},
 
       // QR code first: Make credential should jump to the QR code with
@@ -750,23 +675,13 @@
        mc,
        {usb, internal, cable},
        {rk, att_xplat},
-       {},
        {add, t(internal)},
        qr},
-      // Unless there is a phone paired already.
-      {L,
-       mc,
-       {usb, internal, cable},
-       {rk, att_xplat},
-       {pqr("a")},
-       {p("a"), add, t(internal)},
-       mss},
       // Or if attachment=any
       {L,
        mc,
        {usb, internal, cable},
        {rk, att_any},
-       {},
        {add, t(internal)},
        create_pk_or_qr},
       // If RK=false, go to the default for the platform instead.
@@ -775,14 +690,13 @@
           mc,
           {usb, internal, cable},
           {},
-          {},
           {add, t(internal)},
           create_pk_or_mss,
       },
       // Windows should also jump to the QR code first.
-      {L, mc, {cable}, {att_xplat, rk, has_winapi}, {}, {add, winapi}, qr},
+      {L, mc, {cable}, {att_xplat, rk, has_winapi}, {add, winapi}, qr},
       // ... but not for attachment=undefined.
-      {L, mc, {cable}, {rk, has_winapi}, {}, {winapi, add}, plat_ui},
+      {L, mc, {cable}, {rk, has_winapi}, {winapi, add}, plat_ui},
 
       // QR code first: Get assertion should jump to the QR code with empty
       // allow-list.
@@ -790,7 +704,6 @@
        ga,
        {usb, internal, cable},
        {empty_al},
-       {},
        {add},
        qr},
       // And if the allow list only contains phones.
@@ -798,23 +711,13 @@
        ga,
        {internal, cable},
        {only_hybrid_or_internal},
-       {},
        {add},
        qr},
-      // Unless there is a QR-paired phone already.
-      {L,
-       ga,
-       {usb, internal, cable},
-       {empty_al},
-       {pqr("a")},
-       {p("a"), add},
-       mss},
       // Or a recognized platform credential.
       {L,
        ga,
        {usb, internal, cable},
        {empty_al, has_plat, one_cred},
-       {},
        {c(cred1), add},
        hero},
       // Ignore the platform credential for conditional ui requests
@@ -822,20 +725,18 @@
        ga,
        {usb, internal, cable},
        {c_ui, empty_al, has_plat, one_cred},
-       {},
        {add},
        qr},
       // If there is an allow-list containing USB, go to QR code as well.
-      {L, ga, {usb, internal, cable}, {}, {}, {add}, qr},
+      {L, ga, {usb, internal, cable}, {}, {add}, qr},
       // Windows should also jump to the QR code first.
       // TODO: the expectation here (mss) doesn't match the comment.
-      {L, ga, {cable}, {empty_al, has_winapi}, {}, {add, winapi}, mss},
+      {L, ga, {cable}, {empty_al, has_winapi}, {add, winapi}, mss},
       // Unless there is a recognized platform credential.
       {L,
        ga,
        {cable},
        {empty_al, has_winapi, has_plat, one_cred},
-       {},
        {c(wincred1), add, winapi},
        hero},
       // For <=Win 10, we can't tell if there is a credential or not. Show the
@@ -844,66 +745,8 @@
        ga,
        {cable},
        {empty_al, has_winapi, maybe_plat},
-       {},
        {winapi, add},
        mss},
-      // Phone confirmation sheet: Get assertion should jump to it if there is
-      // a single phone paired.
-      {L,
-       ga,
-       {cable, internal},
-       {only_hybrid_or_internal},
-       {pqr("a")},
-       {p("a"), add},
-       pconf},
-      // Even on Windows.
-      {L,
-       ga,
-       {cable},
-       {only_hybrid_or_internal, has_winapi},
-       {pqr("a")},
-       {p("a"), add},
-       pconf},
-      // Unless there is a recognized platform credential.
-      {L,
-       ga,
-       {cable, internal},
-       {only_hybrid_or_internal, has_plat},
-       {pqr("a")},
-       {p("a"), add, t(internal)},
-       plat_ui},
-      // Or a USB credential.
-      {L,
-       ga,
-       {usb, cable, internal},
-       {},
-       {pqr("a")},
-       {p("a"), add},
-       mss},
-      // iCloud Keychain counts as a recognised platform credential too.
-      {L,
-       ga,
-       {cable, internal},
-       {only_hybrid_or_internal, has_ickc, ickc_creds},
-       {pqr("a")},
-       {c(ickc_cred1), p("a"), add},
-       plat_ui},
-      // Or this is a conditional UI request.
-      {L,
-       ga,
-       {cable, internal},
-       {only_hybrid_or_internal, c_ui},
-       {pqr("a")},
-       {p("a"), add},
-       mss},
-      // Go to the mechanism selection screen if there are more phones paired.
-      {L,
-       ga,
-       {cable, internal},
-       {only_hybrid_or_internal},
-       {pqr("a"), pqr("b")},
-       {p("a"), p("b"), add},
-       mss},
     #if BUILDFLAG(IS_MAC)
       // If there's a single enclave passkey, we should jump directly to
       // the enclave Touch ID sheet.
@@ -911,7 +754,6 @@
        ga,
        {cable, internal},
        {only_hybrid_or_internal, empty_al, enclave_cred, uv_pref},
-       {},
        {c(enclave_cred1), add},
        enclave_touchid},
       // But not if Touch ID isn't available.
@@ -919,7 +761,6 @@
        ga,
        {cable, internal},
        {only_hybrid_or_internal, empty_al, enclave_cred, no_touchid, uv_pref},
-       {},
        {c(enclave_cred1), add},
        hero},
       // And not if uv=discouraged
@@ -927,7 +768,6 @@
        ga,
        {cable, internal},
        {only_hybrid_or_internal, empty_al, enclave_cred},
-       {},
        {c(enclave_cred1), add},
        hero},
     #endif
@@ -938,7 +778,6 @@
        ga,
        {cable, internal},
        {only_hybrid_or_internal, enclave_cred, uv_pref},
-       {},
        {c(enclave_cred1), add},
        kIsMac ? enclave_touchid : hero},
      #endif
@@ -947,7 +786,6 @@
        ga,
        {cable, internal},
        {only_hybrid_or_internal, enclave_cred},
-       {},
        {c(enclave_cred1), add},
        hero},
       // When the enclave needs to sign-in again, that should appear as a
@@ -956,7 +794,6 @@
        ga,
        {cable, usb},
        {enclave_cred, enclave_needs_sign_in},
-       {},
        {sign_in_again, add},
        mss},
       // Hinting "client-device" should not jump to the sign-in-again option.
@@ -964,7 +801,6 @@
        mc,
        {cable, usb},
        {enclave_needs_sign_in, hint_plat},
-       {},
        {sign_in_again, add},
        mss},
       // Hinting "client-device" should not just to any other options, like
@@ -973,55 +809,34 @@
        mc,
        {cable, usb, internal},
        {enclave_needs_sign_in, hint_plat},
-       {},
        {sign_in_again, add, t(internal)},
        mss},
 
-      // Tests for the new UI that lists synced passkeys mixed with local
-      // credentials.
+      // Tests for the mechanism selection screen mixing credential types.
       // Mac & Linux:
-      // Mix of phone and internal credentials.
-      {L,
-       ga,
-       {usb, cable, internal},
-       {one_phone_cred, two_cred, has_plat, empty_al},
-       {psync("a")},
-       {c(cred1), c(cred2), c(phonecred1), add},
-       mss},
       // Internal credentials + qr code.
       {L,
        ga,
        {usb, cable, internal},
        {two_cred, has_plat, empty_al},
-       {psync("a")},
        {c(cred1), c(cred2), add},
        mss},
       // qr code with ble disabled shows usb option.
-      {L, ga, {usb, cable}, {ble_off}, {}, {add, t(usb)}, mss},
+      {L, ga, {usb, cable}, {ble_off}, {add, t(usb)}, mss},
       // qr code with ble access denied shows usb option.
-      {L, ga, {usb, cable}, {ble_denied}, {}, {add, t(usb)}, mss},
+      {L, ga, {usb, cable}, {ble_denied}, {add, t(usb)}, mss},
       // Internal credentials, no qr code.
       {L,
        ga,
        {usb, internal},
        {two_cred, has_plat, empty_al},
-       {psync("a")},
        {c(cred1), c(cred2), t(usb)},
        mss},
-      // Phone credentials only.
-      {L,
-       ga,
-       {usb, cable, internal},
-       {two_phone_cred, empty_al},
-       {psync("a")},
-       {c(phonecred1), c(phonecred2), add},
-       mss},
       // Single internal credential with empty allow list.
       {L,
        ga,
        {usb, cable, internal},
        {one_cred, has_plat, empty_al},
-       {psync("a")},
        {c(cred1), add},
        hero,
      },
@@ -1030,38 +845,13 @@
        ga,
        {usb, cable, internal},
        {one_cred, has_plat},
-       {psync("a")},
-       {c(cred1), p("a"), add},
+       {c(cred1), add},
 #if BUILDFLAG(IS_MAC)
        plat_ui,
 #else
        use_pk,
 #endif
       },
-      // Single phone credential with empty allow list.
-      {L,
-       ga,
-       {usb, cable, internal},
-       {one_phone_cred, empty_al},
-       {psync("a")},
-       {c(phonecred1), add},
-       hero},
-      // Single phone credential with non-empty allow list.
-      {L,
-       ga,
-       {usb, cable, internal},
-       {one_phone_cred},
-       {psync("a")},
-       {c(phonecred1), add},
-       pconf},
-      // Phone from sync that has no credentials for empty allow-list request.
-      {L,
-       ga,
-       {usb, cable, internal},
-       {},
-       {psync("a")},
-       {p("a"), add},
-       mss},
       // Regression test for crbug.com/1484660.
       // A platform authenticator that reports the availability of credentials
       // but does not enumerate them should be listed.
@@ -1069,21 +859,19 @@
        ga,
        {usb, cable, internal},
        {has_plat},
-       {psync("a")},
-       {p("a"), add, t(internal)},
+       {add, t(internal)},
        plat_ui},
 
 #if BUILDFLAG(IS_MAC)
       // Even with iCloud Keychain present, we shouldn't jump to it without
       // additional flags set.
-      {L, mc, {internal}, {rk, has_ickc}, {}, {ickc, t(internal)}, create_pk},
+      {L, mc, {internal}, {rk, has_ickc}, {ickc, t(internal)}, create_pk},
       // iCloud Keychain should be the default if the request delegate
       // configured that.
       {L,
        mc,
        {internal},
        {rk, has_ickc, create_ickc},
-       {},
        {ickc, t(internal)},
        plat_ui},
       // ... and also for attachment=any
@@ -1091,7 +879,6 @@
        mc,
        {internal},
        {rk, att_any, has_ickc, create_ickc},
-       {},
        {ickc, t(internal)},
        plat_ui},
 #endif
@@ -1099,10 +886,10 @@
        // Tests for RP hints.
        //
        // create(): Security key hint should show security key UI.
-       {L, mc, {usb, internal, cable}, {rk, hint_sk}, {},
+       {L, mc, {usb, internal, cable}, {rk, hint_sk},
         {add, t(internal), t(usb)}, usb_ui},
        // But not if USB isn't a valid transport.
-       {L, mc, {internal, cable}, {rk, hint_sk}, {}, {add, t(internal)},
+       {L, mc, {internal, cable}, {rk, hint_sk}, {add, t(internal)},
 #if BUILDFLAG(IS_MAC)
          create_pk,
 #else
@@ -1110,16 +897,13 @@
 #endif
        },
        // If webauthn.dll is present, jump to it.
-       {L, mc, {cable}, {has_winapi, rk, hint_sk}, {}, {winapi, add}, plat_ui},
+       {L, mc, {cable}, {has_winapi, rk, hint_sk}, {winapi, add}, plat_ui},
 
        // create(): Hybrid hint should show QR.
-       {L, mc, {usb, internal, cable}, {rk, hint_hybrid}, {},
+       {L, mc, {usb, internal, cable}, {rk, hint_hybrid},
         {add, t(internal), t(usb)}, qr},
-       // ... even if there are paired phones.
-       {L, mc, {usb, internal, cable}, {rk, hint_hybrid}, {psync("a")}, {p("a"),
-        add, t(internal), t(usb)}, qr},
        // But not if Hybrid isn't a valid transport.
-       {L, mc, {usb, internal}, {rk, hint_hybrid}, {}, {t(internal), t(usb)},
+       {L, mc, {usb, internal}, {rk, hint_hybrid}, {t(internal), t(usb)},
 #if BUILDFLAG(IS_MAC)
          create_pk,
 #else
@@ -1128,16 +912,16 @@
        },
        // If older webauthn.dll is present, don't jump to it since it doesn't do
        // hybrid.
-       {L, mc, {cable}, {has_winapi, rk, hint_hybrid}, {}, {winapi, add}, qr},
+       {L, mc, {cable}, {has_winapi, rk, hint_hybrid}, {winapi, add}, qr},
 #if BUILDFLAG(IS_WIN)
        // ... but do if it supports hybrid.
-       {L, mc, {cable}, {has_winapi, win_hybrid, rk, hint_hybrid}, {}, {winapi},
+       {L, mc, {cable}, {has_winapi, win_hybrid, rk, hint_hybrid}, {winapi},
         plat_ui},
 #endif
 
        // create(): Client device hint should jump to the platform
        // authenticator.
-       {L, mc, {usb, internal, cable}, {rk, hint_plat}, {}, {add, t(internal)},
+       {L, mc, {usb, internal, cable}, {rk, hint_plat}, {add, t(internal)},
 #if BUILDFLAG(IS_MAC)
          create_pk,
 #else
@@ -1145,104 +929,80 @@
 #endif
        },
        // But not if there isn't a platform authenticator.
-       {L, mc, {usb, cable}, {rk, hint_plat}, {}, {add}, qr},
+       {L, mc, {usb, cable}, {rk, hint_plat}, {add}, qr},
        // If webauthn.dll is present, jump to it.
-       {L, mc, {cable}, {has_winapi, rk, hint_plat}, {}, {winapi, add},
+       {L, mc, {cable}, {has_winapi, rk, hint_plat}, {winapi, add},
         plat_ui},
        // Or if there's iCloud Keychain.
-       {L, mc, {cable}, {has_ickc, create_ickc, rk, hint_plat}, {}, {ickc, add},
+       {L, mc, {cable}, {has_ickc, create_ickc, rk, hint_plat}, {ickc, add},
         plat_ui},
 
        // get(): Security key hint should show security key UI.
-       {L, ga, {usb, internal, cable}, {rk, hint_sk}, {}, {add, t(usb)},
+       {L, ga, {usb, internal, cable}, {rk, hint_sk}, {add, t(usb)},
         usb_ui},
        // But not if USB isn't a valid transport.
-       {L, ga, {internal, cable}, {rk, hint_sk}, {}, {add}, qr},
+       {L, ga, {internal, cable}, {rk, hint_sk}, {add}, qr},
        // If credentials are found on a platform authenticator, they are still
        // shown.
-       {L, ga, {usb, internal, cable}, {one_cred, rk, hint_sk}, {},
+       {L, ga, {usb, internal, cable}, {one_cred, rk, hint_sk},
         {c(cred1), add, t(usb)}, mss},
        // If webauthn.dll is present, jump to it.
-       {L, ga, {cable}, {has_winapi, rk, hint_sk}, {}, {add, winapi}, plat_ui},
+       {L, ga, {cable}, {has_winapi, rk, hint_sk}, {add, winapi}, plat_ui},
 
        // get(): Hybrid hint should show QR.
-       {L, ga, {usb, internal, cable}, {rk, hint_hybrid}, {}, {add, t(usb)}, qr},
-       // ... even if there are paired phones.
-       {L, ga, {usb, internal, cable}, {rk, hint_hybrid}, {psync("a")},
-        {p("a"), add, t(usb)}, qr},
+       {L, ga, {usb, internal, cable}, {rk, hint_hybrid}, {add, t(usb)}, qr},
        // But not if hybrid isn't available.
-       {L, ga, {usb, internal}, {rk, hint_hybrid}, {}, {t(usb)}, usb_ui},
+       {L, ga, {usb, internal}, {rk, hint_hybrid}, {t(usb)}, usb_ui},
        // If older webauthn.dll is present, don't jump to it since it doesn't do
        // hybrid.
-       {L, ga, {cable}, {has_winapi, rk, hint_hybrid}, {}, {add, winapi}, qr},
+       {L, ga, {cable}, {has_winapi, rk, hint_hybrid}, {add, winapi}, qr},
 #if BUILDFLAG(IS_WIN)
        // ... but do if it supports hybrid.
-       {L, ga, {cable}, {has_winapi, win_hybrid, rk, hint_hybrid}, {}, {winapi},
+       {L, ga, {cable}, {has_winapi, win_hybrid, rk, hint_hybrid}, {winapi},
         plat_ui},
 #endif
        // If credentials are found on a platform authenticator, they are still
        // shown.
-       {L, ga, {usb, internal, cable}, {one_cred, rk, hint_hybrid}, {},
+       {L, ga, {usb, internal, cable}, {one_cred, rk, hint_hybrid},
         {c(cred1), add, t(usb)}, mss},
 
        // get(): Client device hint should trigger webauthn.dll, if it exists.
-       {L, ga, {cable}, {rk, has_winapi, hint_plat}, {}, {add, winapi},
+       {L, ga, {cable}, {rk, has_winapi, hint_plat}, {add, winapi},
         plat_ui},
        // But not if there's a credential match.
        {L, ga, {usb, cable, internal}, {one_cred, has_winapi, rk, hint_plat},
-        {}, {c(wincred1), add, winapi}, mss},
+        {c(wincred1), add, winapi}, mss},
        // And otherwise it doesn't do anything because we generally assume that
        // we can enumerate platform authenticators and do a good job.
-       {L, ga, {usb, cable, internal}, {rk, hint_plat}, {}, {add}, qr},
+       {L, ga, {usb, cable, internal}, {rk, hint_plat}, {add}, qr},
 
 #if BUILDFLAG(IS_WIN)
       // Windows tests.
-      // Mix of phone and internal credentials, but no USB/NFC.
+      // Mix of internal credentials, but no USB/NFC.
       // This should jump to Windows, as there is a match with the local
       // authenticator.
       {L,
        ga,
        {cable},
-       {one_phone_cred, two_cred, has_winapi, only_hybrid_or_internal,
+       {two_cred, has_winapi, only_hybrid_or_internal,
         has_plat},
-       {psync("a")},
-       {c(wincred1), c(wincred2), c(phonecred1), add},
+       {c(wincred1), c(wincred2), add},
        plat_ui},
-      // Mix of phone, internal credentials, and USB/NFC (empty allow list).
+      // Mix of internal credentials, and USB/NFC (empty allow list).
       // This should offer dispatching to the Windows API for USB/NFC.
       {L,
        ga,
        {cable},
-       {one_phone_cred, two_cred, has_winapi, empty_al, has_plat},
-       {psync("a")},
-       {c(wincred1), c(wincred2), c(phonecred1), add, winapi},
-       mss},
-      // Phone credentials and unknown Windows Hello credential status. This
-      // should offer dispatching to the Windows API for Windows Hello.
-      {L,
-       ga,
-       {cable},
-       {two_phone_cred, has_winapi, maybe_plat, empty_al},
-       {psync("a")},
-       {c(phonecred1), c(phonecred2), winapi, add},
+       {two_cred, has_winapi, empty_al, has_plat},
+       {c(wincred1), c(wincred2), add, winapi},
        mss},
 
-      // Tests where Windows handles hybrid:
-      // Mix of phone and internal credentials (empty allow list).
-      {L,
-       ga,
-       {cable},
-       {one_phone_cred, two_cred, has_winapi, win_hybrid, empty_al, has_plat},
-       {psync("a")},
-       {c(wincred1), c(wincred2), c(phonecred1), winapi},
-       mss},
-      // Internal credentials only.
+      // Tests where Windows handles hybrid with internal credentials only.
       // This should dispatch directly to the Windows API.
       {L,
        ga,
        {},
        {two_cred, has_winapi, win_hybrid, only_internal, has_plat},
-       {},
        {c(wincred1), c(wincred2)},
        plat_ui},
 #endif  // BUILDFLAG(IS_WIN)
@@ -1352,15 +1112,6 @@
       transports_info.recognized_credentials = {std::move(touchid_cred1)};
     }
 
-    if (base::Contains(test.params,
-                       TransportAvailabilityParam::kOnePhoneRecognizedCred)) {
-      transports_info.recognized_credentials.emplace_back(kPhoneCred1);
-    }
-    if (base::Contains(test.params,
-                       TransportAvailabilityParam::kTwoPhoneRecognizedCred)) {
-      transports_info.recognized_credentials.emplace_back(kPhoneCred1);
-      transports_info.recognized_credentials.emplace_back(kPhoneCred2);
-    }
     transports_info.has_icloud_keychain = base::Contains(
         test.params, TransportAvailabilityParam::kHasICloudKeychain);
     transports_info.has_empty_allow_list = base::Contains(
@@ -1474,26 +1225,11 @@
     controller.SetAccountPreselectedCallback(base::BindRepeating(
         [](device::DiscoverableCredentialMetadata cred) {}));
 
-    if (has_v2_cable_extension.has_value() || !test.phones.empty() ||
+    if (has_v2_cable_extension.has_value() ||
         base::Contains(test.transports,
                        device::FidoTransportProtocol::kHybrid)) {
       std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-      for (const auto& phone : test.phones) {
-        auto pairing = std::make_unique<device::cablev2::Pairing>();
-        if (std::holds_alternative<pqr>(phone)) {
-          pairing->name = std::get<pqr>(phone).value();
-          pairing->from_sync_deviceinfo = false;
-        } else {
-          pairing->name = std::get<psync>(phone).value();
-          pairing->from_sync_deviceinfo = true;
-        }
-        pairing->peer_public_key_x962 = {0};
-        pairing->peer_public_key_x962[0] =
-            base::checked_cast<uint8_t>(phones.size());
-        phones.emplace_back(std::move(pairing));
-      }
       controller.set_cable_transport_info(has_v2_cable_extension,
-                                          std::move(phones), base::DoNothing(),
                                           std::nullopt);
     }
 
@@ -1566,8 +1302,7 @@
       controller.saved_authenticators().AddAuthenticator(
           AuthenticatorReference("ID", AuthenticatorTransport::kInternal,
                                  device::AuthenticatorType::kWinNative));
-      controller.set_cable_transport_info(std::nullopt, {}, base::DoNothing(),
-                                          "fido:/1234");
+      controller.set_cable_transport_info(std::nullopt, "fido:/1234");
 
       UpdateModelBeforeStartFlow(model.get(), tai);
       controller.StartFlow(std::move(tai), {});
@@ -1630,8 +1365,7 @@
   controller.saved_authenticators().AddAuthenticator(
       AuthenticatorReference("ID", AuthenticatorTransport::kInternal,
                              device::AuthenticatorType::kWinNative));
-  controller.set_cable_transport_info(std::nullopt, {}, base::DoNothing(),
-                                      "fido:/1234");
+  controller.set_cable_transport_info(std::nullopt, "fido:/1234");
   UpdateModelBeforeStartFlow(model.get(), tai);
   controller.StartFlow(std::move(tai), {});
 
@@ -1718,8 +1452,8 @@
   const auto normal = Profile::NORMAL;
   const auto otr___ = Profile::INCOGNITO;
   const auto mss = Step::kMechanismSelection;
-  const auto activate = Step::kCableActivate;
-  const auto interstitial = Step::kOffTheRecordInterstitial;
+  const auto qr = Step::kCableV2QRCode;
+  [[maybe_unused]] const auto interstitial = Step::kOffTheRecordInterstitial;
   const auto power = Step::kBlePowerOnAutomatic;
 
   const struct {
@@ -1729,14 +1463,16 @@
     std::vector<Step> steps;
   } kTests[] = {
       //               | Expected UI steps in order.
-      {mc, on_, normal, {mss, activate}},
-      {mc, on_, otr___, {mss, interstitial, activate}},
-      {mc, off, normal, {mss, power, activate}},
-      {mc, off, otr___, {mss, interstitial, power, activate}},
-      {ga, on_, normal, {mss, activate}},
-      {ga, on_, otr___, {mss, activate}},
-      {ga, off, normal, {mss, power, activate}},
-      {ga, off, otr___, {mss, power, activate}},
+      {mc, on_, normal, {qr}},
+      // TODO(crbug.com/424448497): this should show the interstitial.
+      {mc, on_, otr___, {qr}},
+      {mc, off, normal, {mss, power, qr}},
+      // TODO(crbug.com/424448497): this should show the interstitial.
+      {mc, off, otr___, {mss, power, qr}},
+      {ga, on_, normal, {qr}},
+      {ga, on_, otr___, {qr}},
+      {ga, off, normal, {mss, power, qr}},
+      {ga, off, otr___, {mss, power, qr}},
   };
 
   unsigned test_num = 0;
@@ -1753,7 +1489,9 @@
       transports_info.attestation_conveyance_preference =
           device::AttestationConveyancePreference::kNone;
     }
-    transports_info.available_transports = {AuthenticatorTransport::kHybrid};
+    transports_info.available_transports = {
+        AuthenticatorTransport::kHybrid,
+        device::FidoTransportProtocol::kUsbHumanInterfaceDevice};
     transports_info.is_off_the_record_context =
         test.profile == Profile::INCOGNITO;
 
@@ -1761,14 +1499,10 @@
         base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
     AuthenticatorRequestDialogController controller(model.get(), main_rfh());
 
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> pairings;
-    pairings.emplace_back(GetPairingFromQR());
     controller.set_cable_transport_info(
-        /*extension_is_v2=*/std::nullopt, std::move(pairings),
-        base::DoNothing(), std::nullopt);
+        /*extension_is_v2=*/std::nullopt, std::nullopt);
     UpdateModelBeforeStartFlow(model.get(), transports_info);
     controller.StartFlow(std::move(transports_info), {});
-    ASSERT_EQ(model->mechanisms.size(), 2u);
 
     for (const auto step : test.steps) {
       ASSERT_EQ(step, model->step())
@@ -1776,18 +1510,6 @@
           << " != " << static_cast<int>(model->step());
 
       switch (step) {
-        case Step::kMechanismSelection:
-          // Click the first (and only) phone.
-          for (const auto& mechanism : model->mechanisms) {
-            if (std::holds_alternative<
-                    AuthenticatorRequestDialogModel::Mechanism::Phone>(
-                    mechanism.type)) {
-              mechanism.callback.Run();
-              break;
-            }
-          }
-          break;
-
         case Step::kBlePowerOnAutomatic:
           controller.BluetoothAdapterStatusChanged(BleStatus::kOn);
           break;
@@ -1796,7 +1518,14 @@
           model->OnOffTheRecordInterstitialAccepted();
           break;
 
-        case Step::kCableActivate:
+        case Step::kCableV2QRCode:
+          break;
+
+        case Step::kMechanismSelection:
+          std::ranges::find_if(model->mechanisms, [](const auto& m) -> bool {
+            return std::holds_alternative<
+                AuthenticatorRequestDialogModel::Mechanism::AddPhone>(m.type);
+          })->callback.Run();
           break;
 
         default:
@@ -1806,36 +1535,6 @@
   }
 }
 
-TEST_F(AuthenticatorRequestDialogControllerTest, CrBug333592767) {
-  auto model =
-      base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-  AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-
-  auto phone1 = std::make_unique<device::cablev2::Pairing>();
-  phone1->name = "test";
-  phone1->from_sync_deviceinfo = true;
-  phone1->last_updated = base::Time::FromTimeT(1);
-  auto phone2 = std::make_unique<device::cablev2::Pairing>(*phone1);
-  phone2->last_updated = base::Time::FromTimeT(2);
-
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-  phones.emplace_back(std::move(phone1));
-  phones.emplace_back(std::move(phone2));
-
-  controller.set_cable_transport_info(/*extension_is_v2=*/false,
-                                      std::move(phones), base::DoNothing(),
-                                      std::nullopt);
-  TransportAvailabilityInfo transports_info;
-  transports_info.request_type = RequestType::kMakeCredential;
-  transports_info.attestation_conveyance_preference =
-      device::AttestationConveyancePreference::kNone;
-  transports_info.make_credential_attachment =
-      device::AuthenticatorAttachment::kAny;
-  transports_info.available_transports = kAllTransportsWithoutCable;
-  UpdateModelBeforeStartFlow(model.get(), transports_info);
-  controller.StartFlow(std::move(transports_info), {});
-}
-
 TEST_F(AuthenticatorRequestDialogControllerTest, AwaitingAcknowledgement) {
   const struct {
     void (AuthenticatorRequestDialogController::*event)();
@@ -1909,8 +1608,7 @@
         base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
     AuthenticatorRequestDialogController controller(model.get(), main_rfh());
     controller.SetBluetoothAdapterPowerOnCallback(power_receiver.GetCallback());
-    controller.set_cable_transport_info(true, {}, base::DoNothing(),
-                                        std::nullopt);
+    controller.set_cable_transport_info(true, std::nullopt);
     UpdateModelBeforeStartFlow(model.get(), transports_info);
     controller.StartFlow(std::move(transports_info), {});
     EXPECT_EQ(test_case.expected_final_step, model->step());
@@ -1942,8 +1640,7 @@
     AuthenticatorRequestDialogController controller(model.get(), main_rfh());
     model->observers.AddObserver(&mock_observer);
     controller.SetBluetoothAdapterPowerOnCallback(power_receiver.GetCallback());
-    controller.set_cable_transport_info(true, {}, base::DoNothing(),
-                                        std::nullopt);
+    controller.set_cable_transport_info(true, std::nullopt);
     UpdateModelBeforeStartFlow(model.get(), transports_info);
     controller.StartFlow(std::move(transports_info), {});
 
@@ -1985,8 +1682,7 @@
         base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
     AuthenticatorRequestDialogController controller(model.get(), main_rfh());
     controller.SetBluetoothAdapterPowerOnCallback(power_receiver.GetCallback());
-    controller.set_cable_transport_info(true, {}, base::DoNothing(),
-                                        std::nullopt);
+    controller.set_cable_transport_info(true, std::nullopt);
     UpdateModelBeforeStartFlow(model.get(), transports_info);
     controller.StartFlow(std::move(transports_info), {});
 
@@ -2026,8 +1722,7 @@
     AuthenticatorRequestDialogController controller(model.get(), main_rfh());
     controller.SetRequestBlePermissionCallback(
         request_ble_permission_callback_receiver.Callback());
-    controller.set_cable_transport_info(true, {}, base::DoNothing(),
-                                        std::nullopt);
+    controller.set_cable_transport_info(true, std::nullopt);
     UpdateModelBeforeStartFlow(model.get(), transports_info);
     controller.StartFlow(std::move(transports_info), {});
 
@@ -2172,157 +1867,6 @@
   model->observers.RemoveObserver(&mock_observer);
 }
 
-// Tests that selecting a phone passkey on Conditional UI contacts the priority
-// phone from sync.
-TEST_F(AuthenticatorRequestDialogControllerTest, ConditionalUIPhonePasskey) {
-  constexpr char kLinkedPhoneName[] = "Phone from QR";
-  constexpr char kOldSyncedPhoneName[] = "Old synced phone";
-  constexpr char kNewSyncedPhoneName[] = "New synced phone";
-
-  std::optional<std::string> phone_name;
-  // Creates a new dialog model for the given list of |phones|.
-  auto MakeModel = [&](bool include_old_phone)
-      -> std::tuple<scoped_refptr<AuthenticatorRequestDialogModel>,
-                    std::unique_ptr<AuthenticatorRequestDialogController>,
-                    std::unique_ptr<EnclaveDisabledController>> {
-    auto model =
-        base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-    auto controller = std::make_unique<AuthenticatorRequestDialogController>(
-        model.get(), main_rfh());
-    auto gpm_controller =
-        std::make_unique<EnclaveDisabledController>(model.get());
-
-    controller->SetAccountPreselectedCallback(base::DoNothing());
-
-    // Store the contacted phone.
-    base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-        callback = base::BindLambdaForTesting(
-            [&](std::unique_ptr<device::cablev2::Pairing> value) {
-              ASSERT_FALSE(phone_name);
-              phone_name = value->name;
-            });
-    phone_name.reset();
-
-    // Set up a linked phone and two phones from sync: an "old" one that last
-    // contacted sync yesterday, and a "new" one that last contacted sync today.
-    base::Time today = base::Time::Now();
-    base::Time yesterday = today - base::Days(1);
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-    std::unique_ptr<device::cablev2::Pairing> qr_phone = GetPairingFromQR();
-    qr_phone->name = kLinkedPhoneName;
-    phones.emplace_back(std::move(qr_phone));
-    if (include_old_phone) {
-      std::unique_ptr<device::cablev2::Pairing> old_synced_phone =
-          GetPairingFromSync();
-      old_synced_phone->last_updated = yesterday;
-      old_synced_phone->name = kOldSyncedPhoneName;
-      phones.emplace_back(std::move(old_synced_phone));
-    }
-    std::unique_ptr<device::cablev2::Pairing> recently_synced_phone =
-        GetPairingFromSync();
-    recently_synced_phone->last_updated = today;
-    recently_synced_phone->name = kNewSyncedPhoneName;
-    phones.emplace_back(std::move(recently_synced_phone));
-    controller->set_cable_transport_info(/*extension_is_v2=*/std::nullopt,
-                                         std::move(phones), std::move(callback),
-                                         std::nullopt);
-
-    // Set up a single credential from a phone.
-    device::DiscoverableCredentialMetadata credential = kCred1;
-    credential.source = device::AuthenticatorType::kPhone;
-    TransportAvailabilityInfo tai;
-    tai.recognized_credentials = {credential};
-    tai.ble_status = BleStatus::kOn;
-    tai.request_type = device::FidoRequestType::kGetAssertion;
-    tai.available_transports = {AuthenticatorTransport::kHybrid};
-    controller->SetUIPresentation(UIPresentation::kAutofill);
-    controller->StartFlow(std::move(tai), {});
-    CHECK_EQ(model->step(), Step::kPasskeyAutofill);
-    return std::make_tuple(std::move(model), std::move(controller),
-                           std::move(gpm_controller));
-  };
-
-  // Preselect the credential. This should select the phone that last contacted
-  // sync.
-  scoped_refptr<AuthenticatorRequestDialogModel> model;
-  std::unique_ptr<AuthenticatorRequestDialogController> controller;
-  std::unique_ptr<EnclaveDisabledController> gpm_controller;
-  std::tie(model, controller, gpm_controller) =
-      MakeModel(/*include_old_phone=*/true);
-  controller->OnAccountPreselected(kCred1.cred_id);
-  EXPECT_EQ(model->step(), Step::kCableActivate);
-  EXPECT_EQ(phone_name, kNewSyncedPhoneName);
-
-  // Manually contact the "old" phone from sync. This should give it priority as
-  // the most recently used.
-  std::tie(model, controller, gpm_controller) =
-      MakeModel(/*include_old_phone=*/true);
-  controller->ContactPhoneForTesting(kOldSyncedPhoneName);
-  ASSERT_EQ(phone_name, kOldSyncedPhoneName);
-
-  // Preselect the credential. This should contact the priority phone, which is
-  // the "old" phone now.
-  std::tie(model, controller, gpm_controller) =
-      MakeModel(/*include_old_phone=*/true);
-  controller->OnAccountPreselected(kCred1.cred_id);
-  EXPECT_EQ(model->step(), Step::kCableActivate);
-  EXPECT_EQ(phone_name, kOldSyncedPhoneName);
-
-  // Remove the "old" phone so that preselecting the credential again picks the
-  // "new" one.
-  std::tie(model, controller, gpm_controller) =
-      MakeModel(/*include_old_phone=*/false);
-  controller->OnAccountPreselected(kCred1.cred_id);
-  EXPECT_EQ(model->step(), Step::kCableActivate);
-  EXPECT_EQ(phone_name, kNewSyncedPhoneName);
-}
-
-// Tests that if the stored preference for the most recently used phone is not
-// valid base64, the value is ignored.
-TEST_F(AuthenticatorRequestDialogControllerTest, InvalidPriorityPhonePref) {
-  auto model =
-      base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-  auto controller = std::make_unique<AuthenticatorRequestDialogController>(
-      model.get(), main_rfh());
-  auto gpm_controller =
-      std::make_unique<EnclaveDisabledController>(model.get());
-  controller->SetAccountPreselectedCallback(base::DoNothing());
-
-  // Store the contacted phone.
-  std::unique_ptr<device::cablev2::Pairing> contacted_phone;
-  base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-      callback = base::BindLambdaForTesting(
-          [&](std::unique_ptr<device::cablev2::Pairing> value) {
-            ASSERT_FALSE(contacted_phone);
-            contacted_phone = std::move(value);
-          });
-
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-  phones.emplace_back(GetPairingFromSync());
-  controller->set_cable_transport_info(/*extension_is_v2=*/std::nullopt,
-                                       std::move(phones), std::move(callback),
-                                       std::nullopt);
-
-  // Set up a single credential from a phone.
-  device::DiscoverableCredentialMetadata credential = kCred1;
-  credential.source = device::AuthenticatorType::kPhone;
-  TransportAvailabilityInfo tai;
-  tai.recognized_credentials = {credential};
-  tai.ble_status = BleStatus::kOn;
-  tai.request_type = device::FidoRequestType::kGetAssertion;
-  tai.available_transports = {AuthenticatorTransport::kHybrid};
-  controller->SetUIPresentation(UIPresentation::kAutofill);
-  controller->StartFlow(std::move(tai), {});
-  ASSERT_EQ(model->step(), Step::kPasskeyAutofill);
-
-  // Set an invalid base64 string as the last used pairing preference.
-  profile()->GetPrefs()->SetString(
-      webauthn::pref_names::kLastUsedPairingFromSyncPublicKey, "oops!");
-  controller->OnAccountPreselected(credential.cred_id);
-  EXPECT_EQ(model->step(), Step::kCableActivate);
-  EXPECT_TRUE(contacted_phone);
-}
-
 #if BUILDFLAG(IS_WIN)
 // Tests that cancelling the Windows Platform authenticator during a Conditional
 // UI request restarts it.
@@ -2482,79 +2026,6 @@
 }
 #endif  // BUILDFLAG(IS_WIN)
 
-// Tests that if the user does not have a phone from sync, Chrome offers a phone
-// confirmation screen for an allow-list request when there is a single
-// previously paired phone, no local matches, and only hybrid or internal
-// credentials in the allow-list.
-TEST_F(AuthenticatorRequestDialogControllerTest, ContactPriorityPhone_NoSync) {
-#if BUILDFLAG(IS_WIN)
-  // TODO(crbug.com/41490900): Get test to pass in the webauthn supports
-  // hybrid case.
-  device::FakeWinWebAuthnApi fake_win_webauthn_api;
-  device::WinWebAuthnApi::ScopedOverride win_webauthn_api_override(
-      &fake_win_webauthn_api);
-  fake_win_webauthn_api.set_version(4);
-#endif  // BUILDFLAG(IS_WIN)
-
-  auto model =
-      base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-  AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-  phones.emplace_back(GetPairingFromQR());
-  controller.set_cable_transport_info(/*extension_is_v2=*/std::nullopt,
-                                      std::move(phones), base::DoNothing(),
-                                      std::nullopt);
-  TransportAvailabilityInfo transports_info;
-  transports_info.ble_status = BleStatus::kOn;
-  transports_info.request_type = device::FidoRequestType::kGetAssertion;
-  transports_info.available_transports = {AuthenticatorTransport::kHybrid};
-  transports_info.is_only_hybrid_or_internal = true;
-  transports_info.has_platform_authenticator_credential = device::
-      FidoRequestHandlerBase::RecognizedCredential::kNoRecognizedCredential;
-  transports_info.has_icloud_keychain_credential = device::
-      FidoRequestHandlerBase::RecognizedCredential::kNoRecognizedCredential;
-  UpdateModelBeforeStartFlow(model.get(), transports_info);
-  controller.StartFlow(std::move(transports_info), {});
-  EXPECT_EQ(model->step(), Step::kPhoneConfirmationSheet);
-  EXPECT_EQ(model->priority_phone_name, "Phone from QR");
-  model->ContactPriorityPhone();
-  EXPECT_EQ(model->step(), Step::kCableActivate);
-  EXPECT_EQ(model->selected_phone_name, "Phone from QR");
-}
-
-// Tests that if the user has a phone from sync, Chrome offers a phone
-// confirmation screen for an allow-list request when there is a phone passkey
-// match and no local matches.
-TEST_F(AuthenticatorRequestDialogControllerTest,
-       ContactPriorityPhone_WithSync) {
-  auto model =
-      base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-  AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-  phones.emplace_back(GetPairingFromQR());
-  phones.emplace_back(GetPairingFromSync());
-  controller.set_cable_transport_info(/*extension_is_v2=*/std::nullopt,
-                                      std::move(phones), base::DoNothing(),
-                                      std::nullopt);
-  TransportAvailabilityInfo transports_info;
-  transports_info.recognized_credentials = {kPhoneCred1, kPhoneCred2};
-  transports_info.ble_status = BleStatus::kOn;
-  transports_info.request_type = device::FidoRequestType::kGetAssertion;
-  transports_info.available_transports = {AuthenticatorTransport::kHybrid};
-  transports_info.is_only_hybrid_or_internal = true;
-  transports_info.has_platform_authenticator_credential = device::
-      FidoRequestHandlerBase::RecognizedCredential::kNoRecognizedCredential;
-  transports_info.has_icloud_keychain_credential = device::
-      FidoRequestHandlerBase::RecognizedCredential::kNoRecognizedCredential;
-  UpdateModelBeforeStartFlow(model.get(), transports_info);
-  controller.StartFlow(std::move(transports_info), {});
-  EXPECT_EQ(model->step(), Step::kPhoneConfirmationSheet);
-  EXPECT_EQ(model->priority_phone_name, "Phone from sync");
-  model->ContactPriorityPhone();
-  EXPECT_EQ(model->step(), Step::kCableActivate);
-  EXPECT_EQ(model->selected_phone_name, "Phone from sync");
-}
-
 #if BUILDFLAG(IS_MAC)
 TEST_F(AuthenticatorRequestDialogControllerTest, BluetoothPermissionPrompt) {
   // When BLE permission is denied on macOS, we should jump to the sheet that
@@ -2562,19 +2033,13 @@
   // QR code.
   for (const BleStatus ble_status :
        {BleStatus::kOn, BleStatus::kPermissionDenied}) {
-    for (const bool click_specific_phone : {false, true}) {
       SCOPED_TRACE(::testing::Message()
                    << "ble_status=" << static_cast<int>(ble_status));
-      SCOPED_TRACE(::testing::Message()
-                   << "click_specific_phone=" << click_specific_phone);
 
       auto model =
           base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
       AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-      std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-      phones.emplace_back(GetPairingFromQR());
       controller.set_cable_transport_info(/*extension_is_v2=*/std::nullopt,
-                                          std::move(phones), base::DoNothing(),
                                           std::nullopt);
       TransportAvailabilityInfo transports_info;
       transports_info.ble_status = ble_status;
@@ -2585,27 +2050,16 @@
       UpdateModelBeforeStartFlow(model.get(), transports_info);
       controller.StartFlow(std::move(transports_info), {});
 
-      std::ranges::find_if(
-          model->mechanisms,
-          [click_specific_phone](const auto& m) -> bool {
-            if (click_specific_phone) {
-              return std::holds_alternative<
-                  AuthenticatorRequestDialogModel::Mechanism::Phone>(m.type);
-            } else {
-              return std::holds_alternative<
-                  AuthenticatorRequestDialogModel::Mechanism::AddPhone>(m.type);
-            }
-          })
-          ->callback.Run();
+      std::ranges::find_if(model->mechanisms, [](const auto& m) -> bool {
+        return std::holds_alternative<
+            AuthenticatorRequestDialogModel::Mechanism::AddPhone>(m.type);
+      })->callback.Run();
 
       if (ble_status == BleStatus::kPermissionDenied) {
         EXPECT_EQ(model->step(), Step::kBlePermissionMac);
-      } else if (click_specific_phone) {
-        EXPECT_EQ(model->step(), Step::kCableActivate);
       } else {
         EXPECT_EQ(model->step(), Step::kCableV2QRCode);
       }
-    }
   }
 }
 #endif
@@ -2614,8 +2068,8 @@
   auto model =
       base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
   AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-  controller.set_cable_transport_info(/*extension_is_v2=*/std::nullopt, {},
-                                      base::DoNothing(), std::nullopt);
+  controller.set_cable_transport_info(/*extension_is_v2=*/std::nullopt,
+                                      std::nullopt);
   TransportAvailabilityInfo transports_info;
   transports_info.ble_status = BleStatus::kOn;
   transports_info.request_type = device::FidoRequestType::kGetAssertion;
@@ -2640,8 +2094,8 @@
   auto model =
       base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
   AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-  controller.set_cable_transport_info(/*extension_is_v2=*/std::nullopt, {},
-                                      base::DoNothing(), std::nullopt);
+  controller.set_cable_transport_info(/*extension_is_v2=*/std::nullopt,
+                                      std::nullopt);
   TransportAvailabilityInfo transports_info;
   transports_info.ble_status = BleStatus::kOn;
   transports_info.request_type = device::FidoRequestType::kGetAssertion;
@@ -2694,7 +2148,6 @@
     std::vector<device::DiscoverableCredentialMetadata> recognized_credentials;
     std::optional<Mechanism::Type> type_of_priority_mechanism;
   } kTests[] = {
-      {{kCred1, kCred2, kPhoneCred1}, std::nullopt},
       {{kCred1, kCred2}, std::nullopt},
       {{kCred1, kCred1FromICloudKeychain},
        Mechanism::Credential(CredentialInfoFrom(kCred1FromICloudKeychain))},
@@ -2738,12 +2191,8 @@
   device::WinWebAuthnApi::ScopedOverride win_webauthn_api_override(
       &fake_win_webauthn_api);
 #endif
-  constexpr int kDifferentPhoneOrSk =
-      IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_TABLET_OR_SECURITY_KEY_LABEL;
   constexpr int kPhoneOrSk =
       IDS_WEBAUTHN_PASSKEY_PHONE_TABLET_OR_SECURITY_KEY_LABEL;
-  constexpr int kDifferentPhone =
-      IDS_WEBAUTHN_PASSKEY_DIFFERENT_PHONE_OR_TABLET_LABEL;
   constexpr int kPhone = IDS_WEBAUTHN_PASSKEY_PHONE_OR_TABLET_LABEL;
   const auto usb = AuthenticatorTransport::kUsbHumanInterfaceDevice;
   const auto hybrid = AuthenticatorTransport::kHybrid;
@@ -2751,27 +2200,17 @@
     kNoUSB = false,
     kUSB = true,
   };
-  enum ListedPhones : bool {
-    kNoListedPhones = false,
-    kListedPhones = true,
-  };
   struct TestCase {
-    ListedPhones listed_phones;
     CanDoUSB chrome_can_do_usb;
     BleStatus ble_status;
     std::optional<AuthenticatorTransport> transport_hint;
     int expected;
   } kTestCases[] = {
-      {kNoListedPhones, kUSB, BleStatus::kOn, std::nullopt, kPhoneOrSk},
-      {kNoListedPhones, kUSB, BleStatus::kOn, usb, kPhone},
-      {kNoListedPhones, kUSB, BleStatus::kOn, hybrid, kPhone},
-      {kNoListedPhones, kUSB, BleStatus::kOff, std::nullopt, kPhone},
-      {kNoListedPhones, kNoUSB, BleStatus::kOn, std::nullopt, kPhone},
-      {kListedPhones, kUSB, BleStatus::kOn, std::nullopt, kDifferentPhoneOrSk},
-      {kListedPhones, kUSB, BleStatus::kOn, usb, kDifferentPhone},
-      {kListedPhones, kUSB, BleStatus::kOn, hybrid, kDifferentPhone},
-      {kListedPhones, kUSB, BleStatus::kOff, std::nullopt, kDifferentPhone},
-      {kListedPhones, kNoUSB, BleStatus::kOn, std::nullopt, kDifferentPhone},
+      {kUSB, BleStatus::kOn, std::nullopt, kPhoneOrSk},
+      {kUSB, BleStatus::kOn, usb, kPhone},
+      {kUSB, BleStatus::kOn, hybrid, kPhone},
+      {kUSB, BleStatus::kOff, std::nullopt, kPhone},
+      {kNoUSB, BleStatus::kOn, std::nullopt, kPhone},
   };
   for (const auto& test_case : kTestCases) {
     SCOPED_TRACE(test_case.transport_hint
@@ -2779,7 +2218,6 @@
                      : -1);
     SCOPED_TRACE(static_cast<int>(test_case.ble_status));
     SCOPED_TRACE(static_cast<int>(test_case.chrome_can_do_usb));
-    SCOPED_TRACE(static_cast<int>(test_case.listed_phones));
     auto model =
         base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
     AuthenticatorRequestDialogController controller(model.get(), main_rfh());
@@ -2787,13 +2225,8 @@
     transports_info.request_type = device::FidoRequestType::kMakeCredential;
     transports_info.attestation_conveyance_preference =
         device::AttestationConveyancePreference::kNone;
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> pairings;
-    if (test_case.listed_phones) {
-      pairings.emplace_back(GetPairingFromQR());
-    }
     controller.set_cable_transport_info(
-        /*extension_is_v2=*/std::nullopt, std::move(pairings),
-        base::DoNothing(), std::nullopt);
+        /*extension_is_v2=*/std::nullopt, std::nullopt);
     if (test_case.chrome_can_do_usb) {
       transports_info.available_transports = {
           device::FidoTransportProtocol::kHybrid,
@@ -2950,76 +2383,6 @@
 
 #endif
 
-TEST_F(AuthenticatorRequestDialogControllerTest,
-       ListGPMPasskeysInConditionalUI) {
-  NavigateAndCommit(GURL("rp.com"));
-
-  // Tests that passkeys are listed in conditional UI, but only if there is a
-  // phone from sync available.
-  ChromeWebAuthnCredentialsDelegate* delegate =
-      ChromeWebAuthnCredentialsDelegateFactory::GetFactory(web_contents())
-          ->GetDelegateForFrame(web_contents()->GetPrimaryMainFrame());
-  ASSERT_TRUE(delegate);
-
-  TransportAvailabilityInfo transports_info;
-  transports_info.request_type = device::FidoRequestType::kGetAssertion;
-  transports_info.recognized_credentials = {kPhoneCred1};
-  {
-    auto model =
-        base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-    AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-    controller.SetUIPresentation(UIPresentation::kAutofill);
-    UpdateModelBeforeStartFlow(model.get(), transports_info);
-    controller.StartFlow(transports_info, {});
-
-    // There is no phone available, so no passkeys should be sent to autofill.
-    EXPECT_TRUE(delegate->GetPasskeys().value()->empty());
-  }
-  {
-    auto model =
-        base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-    AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-    phones.emplace_back(GetPairingFromQR());
-    controller.set_cable_transport_info(
-        /*extension_is_v2=*/std::nullopt, std::move(phones), base::DoNothing(),
-        std::nullopt);
-    controller.SetUIPresentation(UIPresentation::kAutofill);
-    UpdateModelBeforeStartFlow(model.get(), transports_info);
-    controller.StartFlow(transports_info, {});
-
-    // There is no phone from sync, so no passkeys should be sent to autofill.
-    EXPECT_TRUE(delegate->GetPasskeys().value()->empty());
-  }
-  {
-    auto model =
-        base::MakeRefCounted<AuthenticatorRequestDialogModel>(main_rfh());
-    AuthenticatorRequestDialogController controller(model.get(), main_rfh());
-    std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-    phones.emplace_back(GetPairingFromSync());
-    controller.set_cable_transport_info(
-        /*extension_is_v2=*/std::nullopt, std::move(phones), base::DoNothing(),
-        std::nullopt);
-    controller.SetUIPresentation(UIPresentation::kAutofill);
-    UpdateModelBeforeStartFlow(model.get(), transports_info);
-    controller.StartFlow(transports_info, {});
-
-    auto* passkeys = delegate->GetPasskeys().value();
-    ASSERT_EQ(passkeys->size(), 1u);
-    const password_manager::PasskeyCredential& passkey = passkeys->at(0);
-    EXPECT_EQ(passkey.credential_id(), kPhoneCred1.cred_id);
-    EXPECT_EQ(passkey.display_name(), "");
-    EXPECT_EQ(passkey.username(), kPhoneCred1.user.name);
-    EXPECT_EQ(passkey.GetAuthenticatorLabel(),
-              l10n_util::GetStringFUTF16(
-                  IDS_PASSWORD_MANAGER_PASSKEY_FROM_PHONE, u"Phone from sync"));
-    EXPECT_EQ(passkey.user_id(), kPhoneCred1.user.id);
-    EXPECT_EQ(passkey.rp_id(), kPhoneCred1.rp_id);
-    EXPECT_EQ(passkey.source(),
-              password_manager::PasskeyCredential::Source::kAndroidPhone);
-  }
-}
-
 // Tests that iCloud Keychain passkeys are listed in conditional UI with the
 // correct label.
 // Regression test for crbug.com/409806800.
@@ -3059,16 +2422,11 @@
   TransportAvailabilityInfo transports_info;
   transports_info.request_type = device::FidoRequestType::kGetAssertion;
   transports_info.available_transports = {AuthenticatorTransport::kInternal};
-  transports_info.recognized_credentials = {kCred1, kCred2, kPhoneCred1};
+  transports_info.recognized_credentials = {kCred1, kCred2};
   transports_info.ble_status = BleStatus::kOn;
 
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-  phones.emplace_back(GetPairingFromSync());
-  RepeatingValueCallbackReceiver<std::unique_ptr<device::cablev2::Pairing>>
-      contact_phone_callback;
   controller.set_cable_transport_info(
-      /*extension_is_v2=*/std::nullopt, std::move(phones),
-      contact_phone_callback.Callback(), std::nullopt);
+      /*extension_is_v2=*/std::nullopt, std::nullopt);
   RepeatingValueCallbackReceiver<device::DiscoverableCredentialMetadata>
       account_preselected_callback;
   controller.SetAccountPreselectedCallback(
@@ -3118,26 +2476,6 @@
   EXPECT_EQ(result.cred_id, kCred2.cred_id);
   EXPECT_EQ(result.source, device::AuthenticatorType::kOther);
   EXPECT_EQ(request_callback.WaitForResult(), kLocalAuthenticatorId);
-
-  // Reset the model as if the user had cancelled out of the operation.
-  controller.StartOver();
-  controller.saved_authenticators().AddAuthenticator(AuthenticatorReference(
-      kLocalAuthenticatorId, AuthenticatorTransport::kInternal,
-      device::AuthenticatorType::kOther));
-
-  // The third entry should correspond to `kPhoneCred1`.
-  const AuthenticatorRequestDialogModel::Mechanism& mech3 =
-      model->mechanisms[2];
-  EXPECT_EQ(mech3.name, base::UTF8ToUTF16(*kPhoneUser1.name));
-  EXPECT_EQ(mech3.short_name, base::UTF8ToUTF16(*kPhoneUser1.name));
-  EXPECT_EQ(mech3.description,
-            l10n_util::GetStringFUTF16(IDS_WEBAUTHN_SOURCE_PHONE,
-                                       u"Phone from sync"));
-  EXPECT_EQ(mech3.icon, kSmartphoneIcon);
-  mech3.callback.Run();
-  result = account_preselected_callback.WaitForResult();
-  EXPECT_EQ(result.cred_id, kPhoneCred1.cred_id);
-  EXPECT_EQ(result.source, device::AuthenticatorType::kPhone);
 }
 
 #if BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index c07e72d..024d271 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -184,26 +184,7 @@
     }
   }
 
-  void OnNewCablePairing(std::unique_ptr<device::cablev2::Pairing> pairing) {
-    if (!profile_) {
-      FIDO_LOG(DEBUG) << "Linking event was discarded because it was received "
-                         "after the profile was destroyed.";
-      return;
-    }
-
-    // Drop linking in Incognito sessions. While an argument could be made that
-    // it's OK to persist them, this seems like the safe option.
-    if (profile_->IsOffTheRecord()) {
-      FIDO_LOG(DEBUG) << "Linking event was discarded because the profile is "
-                         "Off The Record.";
-      return;
-    }
-
-    cablev2::AddPairing(profile_, std::move(pairing));
-  }
-
   // ProfileObserver:
-
   void OnProfileWillBeDestroyed(Profile* profile) override {
     DCHECK_EQ(profile, profile_);
     profile_->RemoveObserver(this);
@@ -254,12 +235,6 @@
 
 }  // namespace
 
-std::vector<std::unique_ptr<device::cablev2::Pairing>>
-ChromeAuthenticatorRequestDelegate::TestObserver::
-    GetCablePairingsFromSyncedDevices() {
-  return {};
-}
-
 // static
 void ChromeAuthenticatorRequestDelegate::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
@@ -296,6 +271,7 @@
           IsICloudDriveEnabled(),
           /*request_is_for_google_com=*/false, /*preference=*/std::nullopt));
 #endif
+  // TODO(crbug.com/372493822): remove and clean up prefs.
   cablev2::RegisterProfilePrefs(registry);
 }
 
@@ -594,35 +570,6 @@
       base::Contains(pairings, device::CableDiscoveryData::Version::V2,
                      &device::CableDiscoveryData::version);
 
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> paired_phones;
-  base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-      contact_phone_callback;
-  if (base::FeatureList::IsEnabled(device::kWebAuthnHybridLinking) &&
-      (!cable_extension_provided ||
-       base::FeatureList::IsEnabled(device::kWebAuthCableExtensionAnywhere))) {
-    std::unique_ptr<cablev2::KnownDevices> known_devices =
-        cablev2::KnownDevices::FromProfile(profile());
-    if (g_observer) {
-      known_devices->synced_devices =
-          g_observer->GetCablePairingsFromSyncedDevices();
-    }
-    can_use_synced_phone_passkeys_ = !known_devices->synced_devices.empty();
-    paired_phones = cablev2::MergeDevices(std::move(known_devices),
-                                          &icu::Locale::getDefault());
-
-    // The debug log displays in reverse order, so the headline is emitted after
-    // the names.
-    for (const auto& pairing : paired_phones) {
-      FIDO_LOG(DEBUG) << "• " << pairing->name << " " << pairing->last_updated
-                      << " priority:" << pairing->channel_priority;
-    }
-    FIDO_LOG(DEBUG) << "Found " << paired_phones.size() << " caBLEv2 devices";
-
-    if (!paired_phones.empty()) {
-      contact_phone_callback = discovery_factory->get_cable_contact_callback();
-    }
-  }
-
   const bool non_extension_cablev2_enabled =
       (!cable_extension_permitted ||
        (!cable_extension_provided &&
@@ -645,13 +592,6 @@
 
     auto linking_handler =
         std::make_unique<CableLinkingEventHandler>(profile());
-    discovery_factory->set_cable_pairing_callback(
-        base::BindRepeating(&CableLinkingEventHandler::OnNewCablePairing,
-                            std::move(linking_handler)));
-    discovery_factory->set_cable_invalidated_pairing_callback(
-        base::BindRepeating(
-            &ChromeAuthenticatorRequestDelegate::OnInvalidatedCablePairing,
-            weak_ptr_factory_.GetWeakPtr()));
     discovery_factory->set_cable_event_callback(
         base::BindRepeating(&ChromeAuthenticatorRequestDelegate::OnCableEvent,
                             weak_ptr_factory_.GetWeakPtr()));
@@ -671,9 +611,7 @@
     if (cable_extension_provided) {
       extension_is_v2 = cablev2_extension_provided;
     }
-    dialog_controller_->set_cable_transport_info(
-        extension_is_v2, std::move(paired_phones),
-        std::move(contact_phone_callback), qr_string);
+    dialog_controller_->set_cable_transport_info(extension_is_v2, qr_string);
     discovery_factory->set_cable_data(request_type, std::move(pairings),
                                       qr_generator_key);
   }
@@ -889,20 +827,6 @@
   std::move(cancel_callback_).Run();
 }
 
-void ChromeAuthenticatorRequestDelegate::OnManageDevicesClicked() {
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(GetRenderFrameHost());
-  Browser* browser = chrome::FindBrowserWithTab(web_contents);
-  if (browser) {
-    NavigateParams params(browser,
-                          GURL("chrome://settings/securityKeys/phones"),
-                          ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL);
-    params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
-    Navigate(&params);
-  }
-}
-
-
 void ChromeAuthenticatorRequestDelegate::SetPasswordControllerForTesting(
     std::unique_ptr<PasswordCredentialController> controller) {
   password_controller_ = std::move(controller);
@@ -1064,18 +988,6 @@
   return origin.IsSameOriginWith(test_site);
 }
 
-void ChromeAuthenticatorRequestDelegate::OnInvalidatedCablePairing(
-    std::unique_ptr<device::cablev2::Pairing> failed_pairing) {
-  // A pairing was reported to be invalid. Delete it unless it came from Sync,
-  // in which case there's nothing to be done.
-  cablev2::DeletePairingByPublicKey(profile()->GetPrefs(),
-                                    failed_pairing->peer_public_key_x962);
-
-  // Contact the next phone with the same name, if any, given that no
-  // notification has been sent.
-  dialog_controller_->OnPhoneContactFailed(failed_pairing->name);
-}
-
 void ChromeAuthenticatorRequestDelegate::OnCableEvent(
     device::cablev2::Event event) {
   if (event == device::cablev2::Event::kReady) {
@@ -1120,24 +1032,13 @@
     DoGetPhoneContactableGpmPasskeysForRpId(
         TransportAvailabilityInfo tai,
         base::OnceCallback<void(TransportAvailabilityInfo)> callback) {
-  device::AuthenticatorType type;
-  std::vector<sync_pb::WebauthnCredentialSpecifics> credentials;
-
-  if (enclave_controller_ && enclave_controller_->is_active()) {
-    credentials = enclave_controller_->creds();
-    type = device::AuthenticatorType::kEnclave;
-  } else {
-    webauthn::PasskeyModel* passkey_model =
-        PasskeyModelFactory::GetInstance()->GetForProfile(profile());
-    CHECK(passkey_model);
-    credentials = passkey_model->GetPasskeysForRelyingPartyId(
-        dialog_model_->relying_party_id);
-    type = device::AuthenticatorType::kPhone;
+  if (!enclave_controller_ || !enclave_controller_->is_active() ||
+      enclave_controller_->creds().empty()) {
+    std::move(callback).Run(std::move(tai));
+    return;
   }
-
   if (dialog_controller_->ui_presentation() ==
-          UIPresentation::kModalImmediate &&
-      !credentials.empty() && enclave_controller_) {
+      UIPresentation::kModalImmediate) {
     bool enclave_ready = enclave_controller_->account_ready_state() ==
                          GPMEnclaveController::AccountReadyState::kReady;
     base::UmaHistogramBoolean(
@@ -1147,14 +1048,14 @@
       return;
     }
   }
-
-  for (const sync_pb::WebauthnCredentialSpecifics& passkey : credentials) {
+  for (const sync_pb::WebauthnCredentialSpecifics& passkey :
+       enclave_controller_->creds()) {
     const base::Time last_used_time = base::Time::FromDeltaSinceWindowsEpoch(
         base::Microseconds(passkey.last_used_time_windows_epoch_micros()));
     const base::Time creation_time =
         base::Time::FromMillisecondsSinceUnixEpoch(passkey.creation_time());
     tai.recognized_credentials.emplace_back(
-        type, passkey.rp_id(),
+        device::AuthenticatorType::kEnclave, passkey.rp_id(),
         std::vector<uint8_t>(passkey.credential_id().begin(),
                              passkey.credential_id().end()),
         device::PublicKeyCredentialUserEntity(
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
index e732ea9a..7e0b755 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -73,9 +73,6 @@
 
     virtual void OnDestroy(ChromeAuthenticatorRequestDelegate* delegate) {}
 
-    virtual std::vector<std::unique_ptr<device::cablev2::Pairing>>
-    GetCablePairingsFromSyncedDevices();
-
     virtual void OnTransportAvailabilityEnumerated(
         ChromeAuthenticatorRequestDelegate* delegate,
         device::FidoRequestHandlerBase::TransportAvailabilityInfo* tai) {}
@@ -203,8 +200,6 @@
   void OnStartOver() override;
   void OnModelDestroyed(AuthenticatorRequestDialogModel* model) override;
   void OnCancelRequest() override;
-  void OnManageDevicesClicked() override;
-
 
   void SetPasswordControllerForTesting(
       std::unique_ptr<PasswordCredentialController> controller);
@@ -257,8 +252,6 @@
   // information that will be broadcast by the device.
   bool ShouldPermitCableExtension(const url::Origin& origin);
 
-  void OnInvalidatedCablePairing(
-      std::unique_ptr<device::cablev2::Pairing> failed_pairing);
   void OnCableEvent(device::cablev2::Event event);
 
   // Adds GPM passkeys matching |rp_id| to |tai|.
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
index 5e0e4df..a32b3d1 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
@@ -73,8 +73,6 @@
 
 namespace {
 
-static constexpr char kUserName1[] = "hmiku";
-static constexpr char kUserDisplayName1[] = "Hatsune Miku";
 static constexpr char kRpId[] = "example.com";
 static constexpr char kOrigin[] = "https://example.com";
 
@@ -95,10 +93,6 @@
               Created,
               (ChromeAuthenticatorRequestDelegate * delegate),
               (override));
-  MOCK_METHOD(std::vector<std::unique_ptr<device::cablev2::Pairing>>,
-              GetCablePairingsFromSyncedDevices,
-              (),
-              (override));
   MOCK_METHOD(void,
               OnTransportAvailabilityEnumerated,
               (ChromeAuthenticatorRequestDelegate * delegate,
@@ -421,207 +415,6 @@
   }
 }
 
-// TODO(crbug.com/372493822): remove these tests when hybrid linking is cleaned
-// up.
-class HybridLinkingChromeAuthenticatorRequestDelegateTest
-    : public ChromeAuthenticatorRequestDelegateTest {
- protected:
-  base::test::ScopedFeatureList scoped_feature_list_{
-      device::kWebAuthnHybridLinking};
-};
-
-// Tests that synced GPM passkeys are injected in the transport availability
-// info if there's a phone paired.
-TEST_F(HybridLinkingChromeAuthenticatorRequestDelegateTest, GpmPasskeys) {
-  std::string relying_party = "example.com";
-  GURL url("https://example.com");
-  content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
-  ChromeWebAuthnCredentialsDelegateFactory::CreateForWebContents(
-      web_contents());
-  ChromeAuthenticatorRequestDelegate delegate(main_rfh());
-  delegate.SetRelyingPartyId(relying_party);
-
-  // Set up a paired phone from sync.
-  auto phone = std::make_unique<device::cablev2::Pairing>();
-  phone->name = "Miku's Pixel 7 XL";
-  phone->contact_id = {1, 2, 3, 4};
-  phone->id = {5, 6, 7, 8};
-  phone->from_sync_deviceinfo = true;
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-  phones.emplace_back(std::move(phone));
-  EXPECT_CALL(observer_, GetCablePairingsFromSyncedDevices)
-      .WillOnce(testing::Return(testing::ByMove(std::move(phones))));
-  MockCableDiscoveryFactory discovery_factory;
-  delegate.ConfigureDiscoveries(
-      url::Origin::Create(url), relying_party,
-      content::AuthenticatorRequestClientDelegate::RequestSource::
-          kWebAuthentication,
-      device::FidoRequestType::kGetAssertion,
-      /*resident_key_requirement=*/std::nullopt,
-      device::UserVerificationRequirement::kRequired,
-      /*user_name=*/std::nullopt,
-      /*pairings_from_extension=*/std::vector<device::CableDiscoveryData>(),
-      /*is_enclave_authenticator_available=*/false, &discovery_factory);
-
-  // Add a synced passkey for example.com and another for othersite.com.
-  webauthn::PasskeyModel* passkey_model =
-      PasskeyModelFactory::GetForProfile(profile());
-  ASSERT_TRUE(passkey_model);
-  sync_pb::WebauthnCredentialSpecifics passkey;
-  passkey.set_sync_id(std::string(16, 'a'));
-  passkey.set_credential_id(std::string(16, 'b'));
-  passkey.set_rp_id(kRpId);
-  passkey.set_user_id(std::string({5, 6, 7, 8}));
-  passkey.set_user_name(kUserName1);
-  passkey.set_user_display_name(kUserDisplayName1);
-
-  sync_pb::WebauthnCredentialSpecifics passkey_other_rp_id = passkey;
-  passkey_other_rp_id.set_rp_id("othersite.com");
-
-  passkey_model->AddNewPasskeyForTesting(std::move(passkey));
-  passkey_model->AddNewPasskeyForTesting(std::move(passkey_other_rp_id));
-
-  TransportAvailabilityInfo tai;
-  tai.request_type = device::FidoRequestType::kGetAssertion;
-  EXPECT_CALL(observer_, OnTransportAvailabilityEnumerated)
-      .WillOnce([&tai](const auto* _, const auto* new_tai) {
-        tai = std::move(*new_tai);
-      });
-  delegate.OnTransportAvailabilityEnumerated(tai);
-
-  // The GPM passkey for example.com should have been added to the recognized
-  // credentials list.
-  ASSERT_EQ(tai.recognized_credentials.size(), 1u);
-  const device::DiscoverableCredentialMetadata credential =
-      tai.recognized_credentials.at(0);
-  EXPECT_EQ(credential.cred_id, std::vector<uint8_t>(16, 'b'));
-  EXPECT_EQ(credential.rp_id, kRpId);
-  EXPECT_EQ(credential.source, device::AuthenticatorType::kPhone);
-  EXPECT_EQ(credential.user.display_name, kUserDisplayName1);
-  EXPECT_EQ(credential.user.name, kUserName1);
-  EXPECT_EQ(credential.user.id, std::vector<uint8_t>({5, 6, 7, 8}));
-}
-
-// Tests that synced GPM passkeys are not discovered if there are no sync paired
-// phones.
-TEST_F(HybridLinkingChromeAuthenticatorRequestDelegateTest,
-       GpmPasskeys_NoSyncPairedPhones) {
-  GURL url("https://example.com");
-  content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
-  ChromeWebAuthnCredentialsDelegateFactory::CreateForWebContents(
-      web_contents());
-  ChromeAuthenticatorRequestDelegate delegate(main_rfh());
-  delegate.SetRelyingPartyId(kRpId);
-
-  // Return an empty list of synced devices.
-  EXPECT_CALL(observer_, GetCablePairingsFromSyncedDevices);
-  MockCableDiscoveryFactory discovery_factory;
-  delegate.ConfigureDiscoveries(
-      url::Origin::Create(url), kRpId,
-      content::AuthenticatorRequestClientDelegate::RequestSource::
-          kWebAuthentication,
-      device::FidoRequestType::kGetAssertion,
-      /*resident_key_requirement=*/std::nullopt,
-      device::UserVerificationRequirement::kRequired,
-      /*user_name=*/std::nullopt,
-      /*pairings_from_extension=*/std::vector<device::CableDiscoveryData>(),
-      /*is_enclave_authenticator_available=*/false, &discovery_factory);
-
-  // Add a synced passkey for example.com.
-  webauthn::PasskeyModel* passkey_model =
-      PasskeyModelFactory::GetForProfile(profile());
-  ASSERT_TRUE(passkey_model);
-  sync_pb::WebauthnCredentialSpecifics passkey;
-  passkey.set_sync_id(std::string(16, 'a'));
-  passkey.set_credential_id(std::string(16, 'b'));
-  passkey.set_rp_id(kRpId);
-  passkey.set_user_id(std::string({5, 6, 7, 8}));
-  passkey_model->AddNewPasskeyForTesting(std::move(passkey));
-
-  TransportAvailabilityInfo tai;
-  tai.request_type = device::FidoRequestType::kGetAssertion;
-  EXPECT_CALL(observer_, OnTransportAvailabilityEnumerated)
-      .WillOnce([&tai](const auto* _, const auto* new_tai) {
-        tai = std::move(*new_tai);
-      });
-  delegate.OnTransportAvailabilityEnumerated(tai);
-
-  // The GPM passkey should not be present in the recognized credentials list.
-  EXPECT_TRUE(tai.recognized_credentials.empty());
-}
-
-// Tests that shadowed GPM passkeys are not discovered.
-TEST_F(HybridLinkingChromeAuthenticatorRequestDelegateTest,
-       GpmPasskeys_ShadowedPasskeys) {
-  GURL url("https://example.com");
-  content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
-  ChromeWebAuthnCredentialsDelegateFactory::CreateForWebContents(
-      web_contents());
-  ChromeAuthenticatorRequestDelegate delegate(main_rfh());
-  delegate.SetRelyingPartyId(kRpId);
-
-  // Set up a paired phone from sync.
-  auto phone = std::make_unique<device::cablev2::Pairing>();
-  phone->name = "Miku's Pixel 7 XL";
-  phone->contact_id = {1, 2, 3, 4};
-  phone->id = {5, 6, 7, 8};
-  phone->from_sync_deviceinfo = true;
-  std::vector<std::unique_ptr<device::cablev2::Pairing>> phones;
-  phones.emplace_back(std::move(phone));
-  EXPECT_CALL(observer_, GetCablePairingsFromSyncedDevices)
-      .WillOnce(testing::Return(testing::ByMove(std::move(phones))));
-  MockCableDiscoveryFactory discovery_factory;
-  delegate.ConfigureDiscoveries(
-      url::Origin::Create(url), kRpId,
-      content::AuthenticatorRequestClientDelegate::RequestSource::
-          kWebAuthentication,
-      device::FidoRequestType::kGetAssertion,
-      /*resident_key_requirement=*/std::nullopt,
-      device::UserVerificationRequirement::kRequired,
-      /*user_name=*/std::nullopt,
-      /*pairings_from_extension=*/std::vector<device::CableDiscoveryData>(),
-      /*is_enclave_authenticator_available=*/false, &discovery_factory);
-
-  // Add a synced passkey for example.com and another that shadows it.
-  webauthn::PasskeyModel* passkey_model =
-      PasskeyModelFactory::GetForProfile(profile());
-  ASSERT_TRUE(passkey_model);
-  sync_pb::WebauthnCredentialSpecifics passkey;
-  passkey.set_sync_id(std::string(16, 'a'));
-  passkey.set_credential_id(std::string(16, 'b'));
-  passkey.set_rp_id(kRpId);
-  passkey.set_user_id(std::string({5, 6, 7, 8}));
-  passkey.set_user_name(kUserName1);
-  passkey.set_user_display_name(kUserDisplayName1);
-
-  sync_pb::WebauthnCredentialSpecifics shadowed_passkey = passkey;
-  shadowed_passkey.set_credential_id(std::string(16, 'c'));
-  passkey.add_newly_shadowed_credential_ids(shadowed_passkey.credential_id());
-
-  passkey_model->AddNewPasskeyForTesting(std::move(passkey));
-  passkey_model->AddNewPasskeyForTesting(std::move(shadowed_passkey));
-
-  TransportAvailabilityInfo tai;
-  tai.request_type = device::FidoRequestType::kGetAssertion;
-  EXPECT_CALL(observer_, OnTransportAvailabilityEnumerated)
-      .WillOnce([&tai](const auto* _, const auto* new_tai) {
-        tai = std::move(*new_tai);
-      });
-  delegate.OnTransportAvailabilityEnumerated(tai);
-
-  // The GPM passkey that is not shadowed should have been added to the
-  // recognized credentials list.
-  ASSERT_EQ(tai.recognized_credentials.size(), 1u);
-  const device::DiscoverableCredentialMetadata credential =
-      tai.recognized_credentials.at(0);
-  EXPECT_EQ(credential.cred_id, std::vector<uint8_t>(16, 'b'));
-  EXPECT_EQ(credential.rp_id, kRpId);
-  EXPECT_EQ(credential.source, device::AuthenticatorType::kPhone);
-  EXPECT_EQ(credential.user.display_name, kUserDisplayName1);
-  EXPECT_EQ(credential.user.name, kUserName1);
-  EXPECT_EQ(credential.user.id, std::vector<uint8_t>({5, 6, 7, 8}));
-}
-
 TEST_F(ChromeAuthenticatorRequestDelegateTest, FilterGoogleComPasskeys) {
   auto HasCreds = device::FidoRequestHandlerBase::RecognizedCredential::
       kHasRecognizedCredential;
diff --git a/chrome/browser/webauthn/chrome_web_authentication_delegate_unittest.cc b/chrome/browser/webauthn/chrome_web_authentication_delegate_unittest.cc
index 93ac559..a721bdbc 100644
--- a/chrome/browser/webauthn/chrome_web_authentication_delegate_unittest.cc
+++ b/chrome/browser/webauthn/chrome_web_authentication_delegate_unittest.cc
@@ -33,7 +33,6 @@
 #include "content/public/browser/authenticator_request_client_delegate.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/test/web_contents_tester.h"
-#include "device/fido/cable/cable_discovery_data.h"
 #include "device/fido/features.h"
 #include "device/fido/fido_request_handler_base.h"
 #include "extensions/browser/extension_registry.h"
@@ -74,10 +73,6 @@
               Created,
               (ChromeAuthenticatorRequestDelegate * delegate),
               (override));
-  MOCK_METHOD(std::vector<std::unique_ptr<device::cablev2::Pairing>>,
-              GetCablePairingsFromSyncedDevices,
-              (),
-              (override));
   MOCK_METHOD(void,
               OnTransportAvailabilityEnumerated,
               (ChromeAuthenticatorRequestDelegate * delegate,
diff --git a/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc b/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc
index c2d6d5f2..a4b80ff 100644
--- a/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc
+++ b/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/password_manager/profile_password_store_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/ssl/cert_verifier_browser_test.h"
-#include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl_test_api.h"
@@ -83,7 +82,6 @@
 static constexpr uint8_t kCredentialID1[] = {1, 2,  3,  4,  5,  6,  7,  8,
                                              9, 10, 11, 12, 13, 14, 15, 16};
 static constexpr uint8_t kCredentialID2[] = {2, 3, 4, 5};
-static constexpr char16_t kPhoneName[] = u"Flandre's Pixel 7";
 
 static constexpr char kConditionalUIRequest[] = R"((() => {
 window.requestAbortController = new AbortController();
@@ -113,50 +111,6 @@
            e => window.domAutomationController.send('error ' + e));
 })())";
 
-sync_pb::WebauthnCredentialSpecifics CreatePasskey() {
-  sync_pb::WebauthnCredentialSpecifics passkey;
-  passkey.set_sync_id(base::RandBytesAsString(16));
-  passkey.set_credential_id(kCredentialID1, 16);
-  passkey.set_rp_id(kRpId);
-  passkey.set_user_id({1, 2, 3, 4});
-  passkey.set_user_name("flandre");
-  passkey.set_user_display_name("Flandre Scarlet");
-  return passkey;
-}
-
-syncer::DeviceInfo CreateDeviceInfo() {
-  syncer::DeviceInfo::PhoneAsASecurityKeyInfo paask_info;
-  paask_info.contact_id = std::vector<uint8_t>({1, 2, 3});
-  std::ranges::fill(paask_info.peer_public_key_x962, 0);
-  paask_info.peer_public_key_x962[0] = 1;
-  std::ranges::fill(paask_info.secret, 0);
-  paask_info.secret[0] = 2;
-  paask_info.id = device::cablev2::sync::IDNow();
-  paask_info.tunnel_server_domain = 0;
-  return syncer::DeviceInfo(
-      /*guid=*/"guid",
-      /*client_name=*/base::UTF16ToUTF8(kPhoneName),
-      /*chrome_version=*/"chrome_version",
-      /*sync_user_agent=*/"sync_user_agent",
-      sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
-      syncer::DeviceInfo::OsType::kLinux,
-      syncer::DeviceInfo::FormFactor::kDesktop,
-      /*signin_scoped_device_id=*/"signin_scoped_device_id",
-      /*manufacturer_name=*/"manufacturer_name",
-      /*model_name=*/"",
-      /*full_hardware_class=*/"full_hardware_class",
-      /*last_updated_timestamp=*/base::Time::Now(),
-      /*pulse_interval=*/base::TimeDelta(),
-      /*send_tab_to_self_receiving_enabled=*/
-      false,
-      /*send_tab_to_self_receiving_type=*/
-      sync_pb::
-          SyncEnums_SendTabReceivingType_SEND_TAB_RECEIVING_TYPE_CHROME_OR_UNSPECIFIED,
-      /*sharing_info=*/std::nullopt, std::move(paask_info),
-      /*fcm_registration_token=*/"fcm_token", syncer::DataTypeSet(),
-      /*floating_workspace_last_signin_timestamp=*/base::Time::Now());
-}
-
 // Autofill integration tests. This file contains end-to-end tests for
 // integration between WebAuthn and Autofill. These tests are sensitive to focus
 // changes, so they are interactive UI tests.
@@ -210,16 +164,6 @@
       run_loop_->QuitWhenIdle();
     }
 
-    std::vector<std::unique_ptr<device::cablev2::Pairing>>
-    GetCablePairingsFromSyncedDevices() override {
-      std::vector<std::unique_ptr<device::cablev2::Pairing>> ret;
-      ret.emplace_back(TestPhone(base::UTF16ToUTF8(kPhoneName).c_str(),
-                                 /*public_key=*/0,
-                                 /*last_updated=*/base::Time::FromTimeT(1),
-                                 /*channel_priority=*/1));
-      return ret;
-    }
-
    private:
     const raw_ptr<WebAuthnAutofillIntegrationTest> test_instance_;
     std::unique_ptr<base::RunLoop> run_loop_;
@@ -238,8 +182,6 @@
   }
 
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures({device::kWebAuthnHybridLinking},
-                                          /*disabled_features=*/{});
     ASSERT_TRUE(https_server_.InitializeAndListen());
 
     create_services_subscription_ =
@@ -336,11 +278,6 @@
             [](content::BrowserContext*) -> std::unique_ptr<KeyedService> {
               return std::make_unique<webauthn::TestPasskeyModel>();
             }));
-    DeviceInfoSyncServiceFactory::GetInstance()->SetTestingFactory(
-        context, base::BindRepeating([](content::BrowserContext* context)
-                                         -> std::unique_ptr<KeyedService> {
-          return std::make_unique<syncer::FakeDeviceInfoSyncService>();
-        }));
     // Disable the sync service by injecting a test fake. The sync service fails
     // to start when overriding the DeviceInfoSyncService with a test fake.
     SyncServiceFactory::GetInstance()->SetTestingFactory(
@@ -562,84 +499,6 @@
   RunSelectAccountTest(kConditionalUIRequestFiltered);
 }
 
-// TODO(crbug.com/372493822): remove when hybrid linking flag is removed.
-IN_PROC_BROWSER_TEST_F(WebAuthnDevtoolsAutofillIntegrationTest, GPMPasskeys) {
-  // Have the virtual device masquerade as a phone.
-  virtual_device_factory_->SetTransport(device::FidoTransportProtocol::kHybrid);
-
-  // Inject a fake phone from sync.
-  syncer::DeviceInfo device_info = CreateDeviceInfo();
-  auto* tracker = static_cast<syncer::FakeDeviceInfoTracker*>(
-      DeviceInfoSyncServiceFactory::GetForProfile(browser()->profile())
-          ->GetDeviceInfoTracker());
-  tracker->Add(&device_info);
-
-  // Inject a GPM passkey.
-  PasskeyModelFactory::GetForProfile(browser()->profile())
-      ->AddNewPasskeyForTesting(CreatePasskey());
-
-  // Make sure input events cannot close the autofill popup.
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  autofill::ChromeAutofillClient* autofill_client =
-      autofill::ChromeAutofillClient::FromWebContentsForTesting(web_contents);
-  autofill_client->SetKeepPopupOpenForTesting(true);
-
-  // Execute the Conditional UI request.
-  content::DOMMessageQueue message_queue(web_contents);
-  content::ExecuteScriptAsync(web_contents, kConditionalUIRequest);
-
-  delegate_observer_->WaitForUI();
-
-  // Interact with the username field until the popup shows up. This has the
-  // effect of waiting for the browser to send the renderer the password
-  // information, and waiting for the UI to render.
-  base::WeakPtr<autofill::AutofillSuggestionController> suggestion_controller;
-  while (!suggestion_controller) {
-    content::SimulateMouseClickOrTapElementWithId(web_contents, "username");
-    suggestion_controller =
-        autofill_client->suggestion_controller_for_testing();
-  }
-
-  // Find the webauthn credential on the suggestions list.
-  auto suggestions = suggestion_controller->GetSuggestions();
-  size_t suggestion_index = 0;
-  size_t webauthn_entry_count = 0;
-  autofill::Suggestion webauthn_entry;
-  for (size_t i = 0; i < suggestions.size(); ++i) {
-    if (suggestions[i].type == autofill::SuggestionType::kWebauthnCredential) {
-      webauthn_entry = suggestions[i];
-      suggestion_index = i;
-      webauthn_entry_count++;
-    }
-  }
-  ASSERT_EQ(webauthn_entry_count, 1u);
-  ASSERT_LT(suggestion_index, suggestions.size()) << "WebAuthn entry not found";
-  EXPECT_EQ(webauthn_entry.main_text.value, u"flandre");
-  EXPECT_EQ(webauthn_entry.labels.at(0).at(0).value,
-            l10n_util::GetStringUTF16(
-                IDS_PASSWORD_MANAGER_PASSKEY_FROM_GOOGLE_PASSWORD_MANAGER));
-  EXPECT_EQ(webauthn_entry.icon, autofill::Suggestion::Icon::kGlobe);
-
-  // Click the credential.
-  test_api(static_cast<autofill::AutofillPopupControllerImpl&>(
-               *suggestion_controller))
-      .DisableThreshold(true);
-  suggestion_controller->AcceptSuggestion(suggestion_index);
-  std::string result;
-  ASSERT_TRUE(message_queue.WaitForMessage(&result));
-  EXPECT_EQ(result, "\"webauthn: OK\"");
-
-  // Tapping a GPM passkey will not automatically hide the popup
-  // because the enclave might still be loading. Manually hide the
-  // popup so that the autofill client can be destroyed, avoiding
-  // a DCHECK on test tear down.
-  autofill_client->HideAutofillSuggestions(
-      autofill::SuggestionHidingReason::kTabGone);
-  // The tracker outlives the test. Clean up the device_info to avoid flakiness.
-  tracker->Remove(&device_info);
-}
-
 #if BUILDFLAG(IS_WIN)
 // Autofill integration test using the Windows fake API.
 class WebAuthnWindowsAutofillIntegrationTest
diff --git a/chrome/browser/webauthn/chrome_webauthn_browsertest.cc b/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
index 9b946b2..187c09c7 100644
--- a/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
+++ b/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
@@ -223,33 +223,6 @@
            e => 'error ' + e);
 })())";
 
-static constexpr char kMakeCredential[] = R"((() => {
-  return navigator.credentials.create({ publicKey: {
-    rp: { name: "" },
-    user: { id: new Uint8Array([0]), name: "foo", displayName: "" },
-    pubKeyCredParams: [{type: "public-key", alg: -7}],
-    challenge: new Uint8Array([0]),
-    timeout: 10000,
-    userVerification: 'discouraged',
-  }}).then(c => 'webauthn: OK',
-           e => 'error ' + e);
-})())";
-
-static constexpr char kMakeDiscoverableCredential[] = R"((() => {
-  return navigator.credentials.create({ publicKey: {
-    rp: { name: "" },
-    user: { id: new Uint8Array([0]), name: "foo", displayName: "" },
-    pubKeyCredParams: [{type: "public-key", alg: -7}],
-    challenge: new Uint8Array([0]),
-    timeout: 10000,
-    userVerification: 'discouraged',
-    authenticatorSelection: {
-      requireResidentKey: true,
-    },
-  }}).then(c => 'webauthn: OK',
-           e => 'error ' + e);
-})())";
-
 IN_PROC_BROWSER_TEST_F(WebAuthnBrowserTest, ChromeExtensions) {
   // Test that WebAuthn works inside of Chrome extensions. WebAuthn is based on
   // Relying Party IDs, which are domain names. But Chrome extensions don't have
@@ -360,6 +333,21 @@
     : public WebAuthnBrowserTest,
       device::WinWebAuthnApiAuthenticator::TestObserver {
  public:
+  static constexpr char kMakeDiscoverableCredential[] = R"((() => {
+    return navigator.credentials.create({ publicKey: {
+      rp: { name: "" },
+      user: { id: new Uint8Array([0]), name: "foo", displayName: "" },
+      pubKeyCredParams: [{type: "public-key", alg: -7}],
+      challenge: new Uint8Array([0]),
+      timeout: 10000,
+      userVerification: 'discouraged',
+      authenticatorSelection: {
+        requireResidentKey: true,
+      },
+    }}).then(c => 'webauthn: OK',
+            e => 'error ' + e);
+  })())";
+
   void SetUpOnMainThread() override {
     WebAuthnBrowserTest::SetUpOnMainThread();
     signal_unknown_credential_run_loop_ = std::make_unique<base::RunLoop>();
@@ -916,11 +904,6 @@
       delegate_ = delegate;
     }
 
-    std::vector<std::unique_ptr<device::cablev2::Pairing>>
-    GetCablePairingsFromSyncedDevices() override {
-      return {};
-    }
-
     void OnTransportAvailabilityEnumerated(
         ChromeAuthenticatorRequestDelegate* delegate,
         device::FidoRequestHandlerBase::TransportAvailabilityInfo* tai)
@@ -1115,11 +1098,6 @@
    public:
     void Created(ChromeAuthenticatorRequestDelegate* delegate) override {}
 
-    std::vector<std::unique_ptr<device::cablev2::Pairing>>
-    GetCablePairingsFromSyncedDevices() override {
-      return {};
-    }
-
     void OnTransportAvailabilityEnumerated(
         ChromeAuthenticatorRequestDelegate* delegate,
         device::FidoRequestHandlerBase::TransportAvailabilityInfo* tai)
@@ -1146,351 +1124,6 @@
   EXPECT_EQ(observer_.extensions_[0], "01020304");
 }
 
-// WebAuthnCableSecondFactor primarily exercises
-// ChromeAuthenticatorRequestDelegate and AuthenticatorRequestDialogController.
-// It mocks out the discovery process and thus allows the caBLE UI to be tested.
-// It uses a trace-based approach: events are recorded (as strings) in an event
-// trace which is then compared against the expected trace at the end.
-// TODO(crbug.com/372493822): remove when hybrid linking is cleaned up.
-class WebAuthnCableSecondFactor : public WebAuthnBrowserTest {
- public:
-  WebAuthnCableSecondFactor() {
-    // This makes it a little easier to compare against.
-    trace_ << std::endl;
-  }
-
-  std::ostringstream& trace() { return trace_; }
-
-  raw_ptr<AuthenticatorRequestDialogController, DanglingUntriaged>&
-  controller() {
-    return controller_;
-  }
-
- protected:
-  // DiscoveryFactory vends a single discovery that doesn't discover anything
-  // until requested to. The authenticator that is then discovered is a virtual
-  // authenticator that serves simply to end the overall WebAuthn request.
-  // Otherwise, DiscoveryFactory is responsible for tracing the caBLEv2 Pairing
-  // objects and driving the simulation when the UI requests that a phone be
-  // triggered.
-  class DiscoveryFactory : public device::FidoDiscoveryFactory {
-   public:
-    explicit DiscoveryFactory(WebAuthnCableSecondFactor* test)
-        : parent_(test) {}
-
-    std::vector<std::unique_ptr<device::FidoDiscoveryBase>> Create(
-        device::FidoTransportProtocol transport) override {
-      if (transport != device::FidoTransportProtocol::kHybrid) {
-        return {};
-      }
-
-      auto discovery = std::make_unique<PendingDiscovery>(
-          device::FidoTransportProtocol::kHybrid);
-      add_authenticator_callback_ = discovery->GetAddAuthenticatorCallback();
-      return SingleDiscovery(std::move(discovery));
-    }
-
-    void set_cable_data(
-        device::FidoRequestType request_type,
-        std::vector<device::CableDiscoveryData> cable_data,
-        const std::optional<std::array<uint8_t, device::cablev2::kQRKeySize>>&
-            qr_generator_key) override {
-      parent_->trace() << "SET_CABLE_DATA" << std::endl;
-    }
-
-    void set_cable_invalidated_pairing_callback(
-        base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-            callback) override {
-      invalid_pairing_callback_ = std::move(callback);
-    }
-
-    base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-    get_cable_contact_callback() override {
-      return base::BindLambdaForTesting(
-          [this](std::unique_ptr<device::cablev2::Pairing> pairing) {
-            parent_->trace()
-                << "CONTACT: phone_name=" << pairing->name << " public_key="
-                << static_cast<int>(pairing->peer_public_key_x962[0])
-                << " step=" << contact_step_number_ << std::endl;
-            switch (contact_step_number_) {
-              case 0:
-                // Simiulate the first tunnel failing with a Gone status. This
-                // should trigger a fallback to the second-priority phone with
-                // the same name.
-                base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                    FROM_HERE, base::BindOnce(invalid_pairing_callback_,
-                                              std::move(pairing)));
-                break;
-
-              case 1:
-                // Simulate the user clicking back and trying the phone again.
-                // This should fallback to the lower-priority phone with the
-                // same name.
-                base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                    FROM_HERE, base::BindLambdaForTesting([this]() {
-                      parent_->controller()->ContactPhoneForTesting("name2");
-                    }));
-                break;
-
-              case 2:
-                // Try some other phones.
-                base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                    FROM_HERE, base::BindLambdaForTesting([this]() {
-                      parent_->controller()->ContactPhoneForTesting("zzz");
-                    }));
-                break;
-
-              case 3:
-                // Try some other phones.
-                base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                    FROM_HERE, base::BindLambdaForTesting([this]() {
-                      parent_->controller()->ContactPhoneForTesting("aaa");
-                    }));
-                break;
-
-              case 4:
-                // All done. Discover a virtual authenticator in order to
-                // resolve the request.
-                add_authenticator_callback_.Run();
-                break;
-
-              default:
-                NOTREACHED();
-            }
-
-            contact_step_number_++;
-          });
-    }
-
-#if BUILDFLAG(IS_WIN)
-    std::unique_ptr<device::FidoDiscoveryBase>
-    MaybeCreateWinWebAuthnApiDiscovery() override {
-      return nullptr;
-    }
-#endif  // BUILDFLAG(IS_WIN)
-
-   private:
-    // PendingDiscovery yields a single virtual authenticator when requested to
-    // do so by calling the result of |GetAddAuthenticatorCallback|.
-    class PendingDiscovery final : public device::FidoDeviceDiscovery {
-     public:
-      explicit PendingDiscovery(device::FidoTransportProtocol transport)
-          : FidoDeviceDiscovery(transport) {}
-
-      base::RepeatingClosure GetAddAuthenticatorCallback() {
-        return base::BindRepeating(&PendingDiscovery::AddAuthenticator,
-                                   weak_ptr_factory_.GetWeakPtr());
-      }
-
-     protected:
-      void StartInternal() override {
-        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-            FROM_HERE, base::BindOnce(&PendingDiscovery::NotifyDiscoveryStarted,
-                                      weak_ptr_factory_.GetWeakPtr(),
-                                      /*success=*/true));
-      }
-
-     private:
-      void AddAuthenticator() {
-        scoped_refptr<device::VirtualFidoDevice::State> state(
-            new device::VirtualFidoDevice::State);
-        state->InjectRegistration(kCredentialID, "www.example.com");
-        state->fingerprints_enrolled = true;
-
-        device::VirtualCtap2Device::Config config;
-        config.resident_key_support = true;
-        config.internal_uv_support = true;
-
-        AddDevice(std::make_unique<device::VirtualCtap2Device>(state, config));
-      }
-
-      base::WeakPtrFactory<PendingDiscovery> weak_ptr_factory_{this};
-    };
-
-    const raw_ptr<WebAuthnCableSecondFactor> parent_;
-    base::RepeatingCallback<void(std::unique_ptr<device::cablev2::Pairing>)>
-        invalid_pairing_callback_;
-    base::RepeatingClosure add_authenticator_callback_;
-    int contact_step_number_ = 0;
-  };
-
-  class DelegateObserver
-      : public ChromeAuthenticatorRequestDelegate::TestObserver {
-   public:
-    explicit DelegateObserver(WebAuthnCableSecondFactor* test)
-        : parent_(test) {}
-
-    void Created(ChromeAuthenticatorRequestDelegate* delegate) override {
-      // Only a single delegate should be observed.
-      CHECK(!parent_->controller());
-    }
-
-    std::vector<std::unique_ptr<device::cablev2::Pairing>>
-    GetCablePairingsFromSyncedDevices() override {
-      std::vector<std::unique_ptr<device::cablev2::Pairing>> ret;
-
-      ret.emplace_back(TestPhone("name1", /*public_key=*/0,
-                                 /*last_updated=*/base::Time::FromTimeT(1),
-                                 /*channel_priority=*/1));
-
-      // The same public key as phone1, but a newer timestamp. It
-      // should shadow the first.
-      ret.emplace_back(TestPhone("name2", /*public_key=*/0,
-                                 /*last_updated=*/base::Time::FromTimeT(2),
-                                 /*channel_priority=*/1));
-
-      // Same name as the second, but a higher channel priority. It should take
-      // priority over it.
-      ret.emplace_back(TestPhone("name2", /*public_key=*/1,
-                                 /*last_updated=*/base::Time::FromTimeT(2),
-                                 /*channel_priority=*/2));
-
-      // Same name as second and third, but a newer timestamp than the third. It
-      // should be tried first.
-      ret.emplace_back(TestPhone("name2", /*public_key=*/2,
-                                 /*last_updated=*/base::Time::FromTimeT(3),
-                                 /*channel_priority=*/2));
-
-      // A different device with a name that should sort first.
-      ret.emplace_back(TestPhone("aaa", /*public_key=*/3,
-                                 /*last_updated=*/base::Time::FromTimeT(3),
-                                 /*channel_priority=*/2));
-
-      // A different device with a name that should sort last.
-      ret.emplace_back(TestPhone("zzz", /*public_key=*/4,
-                                 /*last_updated=*/base::Time::FromTimeT(3),
-                                 /*channel_priority=*/2));
-
-      return ret;
-    }
-
-    void OnTransportAvailabilityEnumerated(
-        ChromeAuthenticatorRequestDelegate* delegate,
-        device::FidoRequestHandlerBase::TransportAvailabilityInfo* tai)
-        override {
-      tai->available_transports.insert(device::FidoTransportProtocol::kHybrid);
-      tai->ble_status = device::FidoRequestHandlerBase::BleStatus::kOn;
-    }
-
-    void UIShown(ChromeAuthenticatorRequestDelegate* delegate) override {
-      parent_->controller() = delegate->dialog_controller();
-
-      for (const auto& name :
-           parent_->controller()->model()->paired_phone_names) {
-        parent_->trace() << "UINAME: " << name << std::endl;
-      }
-
-      // Simulate a click on the transport selection sheet.
-      parent_->controller()->ContactPhoneForTesting("name2");
-    }
-
-    void CableV2ExtensionSeen(
-        base::span<const uint8_t> server_link_data) override {}
-
-    void ConfiguringCable(device::FidoRequestType request_type) override {
-      switch (request_type) {
-        case device::FidoRequestType::kMakeCredential:
-          parent_->trace() << "TYPE: mc" << std::endl;
-          break;
-        case device::FidoRequestType::kGetAssertion:
-          parent_->trace() << "TYPE: ga" << std::endl;
-          break;
-      }
-    }
-
-   private:
-    const raw_ptr<WebAuthnCableSecondFactor> parent_;
-  };
-
- protected:
-  std::ostringstream trace_;
-  raw_ptr<AuthenticatorRequestDialogController, DanglingUntriaged> controller_ =
-      nullptr;
-#if BUILDFLAG(IS_WIN)
-  device::FakeWinWebAuthnApi fake_win_webauthn_api_;
-  device::WinWebAuthnApi::ScopedOverride override_win_webauthn_api_{
-      &fake_win_webauthn_api_};
-#endif
-  base::test::ScopedFeatureList scoped_feature_list_{
-      device::kWebAuthnHybridLinking};
-};
-
-// TODO(crbug.com/40186172): this test is flaky on Mac.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_Test DISABLED_Test
-#else
-#define MAYBE_Test Test
-#endif
-IN_PROC_BROWSER_TEST_F(WebAuthnCableSecondFactor, MAYBE_Test) {
-  DelegateObserver observer(this);
-  ChromeAuthenticatorRequestDelegate::SetGlobalObserverForTesting(&observer);
-  content::ScopedAuthenticatorEnvironmentForTesting auth_env(
-      std::make_unique<DiscoveryFactory>(this));
-
-  EXPECT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), https_server_.GetURL("www.example.com", "/title1.html")));
-
-  EXPECT_EQ(
-      "webauthn: OK",
-      content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
-                      kGetAssertionCredID1234));
-
-  constexpr char kExpectedTrace[] = R"(
-TYPE: ga
-SET_CABLE_DATA
-UINAME: aaa
-UINAME: name2
-UINAME: zzz
-CONTACT: phone_name=name2 public_key=2 step=0
-CONTACT: phone_name=name2 public_key=1 step=1
-CONTACT: phone_name=name2 public_key=0 step=2
-CONTACT: phone_name=zzz public_key=4 step=3
-CONTACT: phone_name=aaa public_key=3 step=4
-)";
-  EXPECT_EQ(kExpectedTrace, trace_.str());
-}
-
-// These two tests are separate, rather than a for loop, because the testing
-// infrastructure needs to be reset for each test and having a separate test
-// is the easiest way to do that.
-
-IN_PROC_BROWSER_TEST_F(WebAuthnCableSecondFactor, RequestTypesMakeCredential) {
-  // Check that the correct request types are plumbed through.
-  DelegateObserver observer(this);
-  ChromeAuthenticatorRequestDelegate::SetGlobalObserverForTesting(&observer);
-  content::ScopedAuthenticatorEnvironmentForTesting auth_env(
-      std::make_unique<DiscoveryFactory>(this));
-
-  EXPECT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), https_server_.GetURL("www.example.com", "/title1.html")));
-
-  EXPECT_EQ(
-      "webauthn: OK",
-      content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
-                      kMakeCredential));
-  EXPECT_TRUE(trace_.str().find("TYPE: mc\n") != std::string::npos)
-      << trace_.str();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAuthnCableSecondFactor,
-                       RequestTypesMakeDiscoverableCredential) {
-  // Check that the correct request types are plumbed through.
-  DelegateObserver observer(this);
-  ChromeAuthenticatorRequestDelegate::SetGlobalObserverForTesting(&observer);
-  content::ScopedAuthenticatorEnvironmentForTesting auth_env(
-      std::make_unique<DiscoveryFactory>(this));
-
-  EXPECT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), https_server_.GetURL("www.example.com", "/title1.html")));
-
-  EXPECT_EQ(
-      "webauthn: OK",
-      content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
-                      kMakeDiscoverableCredential));
-  EXPECT_TRUE(trace_.str().find("TYPE: mc\n") != std::string::npos)
-      << trace_.str();
-}
-
 class ChallengeUrlBrowserTest : public WebAuthnBrowserTest {
  public:
   static constexpr char kValidChallenge[] = "1234567890123456";
diff --git a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
index 8bdb7be7..9984325 100644
--- a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
+++ b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
@@ -602,17 +602,6 @@
       destruction_run_loop_->QuitWhenIdle();
     }
 
-    std::vector<std::unique_ptr<device::cablev2::Pairing>>
-    GetCablePairingsFromSyncedDevices() override {
-      std::vector<std::unique_ptr<device::cablev2::Pairing>> ret;
-      if (use_synced_device_cable_pairing_) {
-        ret.emplace_back(TestPhone("phone", /*public_key=*/0,
-                                   /*last_updated=*/base::Time::FromTimeT(1),
-                                   /*channel_priority=*/1));
-      }
-      return ret;
-    }
-
     void OnTransportAvailabilityEnumerated(
         ChromeAuthenticatorRequestDelegate* delegate,
         device::FidoRequestHandlerBase::TransportAvailabilityInfo* tai)
diff --git a/chrome/browser/webauthn/enclave_manager_unittest.cc b/chrome/browser/webauthn/enclave_manager_unittest.cc
index 13b569fa..7cac665 100644
--- a/chrome/browser/webauthn/enclave_manager_unittest.cc
+++ b/chrome/browser/webauthn/enclave_manager_unittest.cc
@@ -26,6 +26,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/json/json_reader.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/process/process.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/webauthn/gpm_enclave_controller.cc b/chrome/browser/webauthn/gpm_enclave_controller.cc
index 3d65a15..d3716d7 100644
--- a/chrome/browser/webauthn/gpm_enclave_controller.cc
+++ b/chrome/browser/webauthn/gpm_enclave_controller.cc
@@ -1119,23 +1119,15 @@
       break;
 
     case AccountState::kNone:
-      if (model_->priority_phone_name.has_value()) {
-        model_->ContactPriorityPhone();
-      } else {
-        // This can happen if a passkey is selected after the enclave times out.
-        model_->SetStep(Step::kGPMError);
-      }
+      // This can happen if a passkey is selected after the enclave times out.
+      model_->SetStep(Step::kGPMError);
       break;
 
     case AccountState::kEmpty:
-      if (model_->priority_phone_name.has_value()) {
-        model_->ContactPriorityPhone();
-      } else {
-        // The security domain is empty but there were
-        // sync entities. Most like the security domain was reset without
-        // clearing the entities, thus they are unusable.
-        model_->SetStep(Step::kGPMError);
-      }
+      // The security domain is empty but there were
+      // sync entities. Most like the security domain was reset without
+      // clearing the entities, thus they are unusable.
+      model_->SetStep(Step::kGPMError);
       break;
   }
 }
diff --git a/chrome/browser/webauthn/test_util.cc b/chrome/browser/webauthn/test_util.cc
index 16b8a70..61b765d 100644
--- a/chrome/browser/webauthn/test_util.cc
+++ b/chrome/browser/webauthn/test_util.cc
@@ -19,7 +19,6 @@
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/strings/string_number_conversions.h"
-#include "device/fido/cable/cable_discovery_data.h"
 #include "device/fido/enclave/types.h"
 #include "device/fido/fido_constants.h"
 #include "net/base/port_util.h"
@@ -122,19 +121,3 @@
 
   return device::enclave::ScopedEnclaveOverride(std::move(identity));
 }
-
-std::unique_ptr<device::cablev2::Pairing> TestPhone(const char* name,
-                                                    uint8_t public_key,
-                                                    base::Time last_updated,
-                                                    int channel_priority) {
-  auto phone = std::make_unique<device::cablev2::Pairing>();
-  phone->name = name;
-  phone->contact_id = {10, 11, 12};
-  phone->id = {4, 5, 6};
-  std::fill(phone->peer_public_key_x962.begin(),
-            phone->peer_public_key_x962.end(), public_key);
-  phone->last_updated = last_updated;
-  phone->channel_priority = channel_priority;
-  phone->from_sync_deviceinfo = true;
-  return phone;
-}
diff --git a/chrome/browser/webauthn/test_util.h b/chrome/browser/webauthn/test_util.h
index 79a788fa..a1505ebd 100644
--- a/chrome/browser/webauthn/test_util.h
+++ b/chrome/browser/webauthn/test_util.h
@@ -14,10 +14,6 @@
 #include "device/fido/enclave/constants.h"
 #include "google_apis/gaia/gaia_id.h"
 
-namespace device::cablev2 {
-struct Pairing;
-}
-
 static constexpr int32_t kSecretVersion = 417;
 static constexpr uint8_t kSecurityDomainSecret[32] = {};
 static constexpr char kSyncEmail[] = "user1@gmail.com";
@@ -65,9 +61,4 @@
 device::enclave::ScopedEnclaveOverride TestWebAuthnEnclaveIdentity(
     uint16_t port);
 
-std::unique_ptr<device::cablev2::Pairing> TestPhone(const char* name,
-                                                    uint8_t public_key,
-                                                    base::Time last_updated,
-                                                    int channel_priority);
-
 #endif  // CHROME_BROWSER_WEBAUTHN_TEST_UTIL_H_
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 4ea4f262..c2e2bfc5 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1750338859-c71ebe5c4b73a38f8bba9c065fd66e50064a9b1d-c43ec3306e41f5cfb6616c884f0723a2e9ef5bbe.profdata
+chrome-android64-main-1750357489-177384a0ab01db513be8fc3baa999ad2f53aacf4-f06918e3c7a545f7b681d02a7590c3973be54cc9.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 7b2a2e3..a439f7d 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1750341467-961577bd5f02211c39d13b1aee2af3494da05cc7-5e6f4c26944e32f31e503fa9cfddab8410e1d307.profdata
+chrome-mac-arm-main-1750363175-8b4ba7735d137dc6ea78ef20fa63c4f54e6b04d5-913bcb67a2810d40c6e41dbdfd265980c84344af.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index e097e59..aadc8c9d 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1750236942-c2635c3ea7aab0356896bdb7e63bcbcd68a39204-2aaf871f2569112490815fece0a7ea3c0001ed84.profdata
+chrome-win32-main-1750323273-a3ecc05df4b51f2bae00cbd691a02256f9a4fc30-da89cfc19ad7b608b6f9741a598b97dbb3dfc2f5.profdata
diff --git a/chrome/common/actor.mojom b/chrome/common/actor.mojom
index b85868dc..cceaa513 100644
--- a/chrome/common/actor.mojom
+++ b/chrome/common/actor.mojom
@@ -186,6 +186,10 @@
   // The target window no longer exists.
   kWindowWentAway = 25,
 
+  // The current frame target under supplied coordinate does not match the
+  // frame under that coordinate during time of observation.
+  kFrameLocationChangedSinceObservation = 26,
+
   ///////////////////////////////////////////////////////////////////////
   // Codes 100-199: Errors for navigation. (Not part of the ToolAction union
   // as it's a browser-side tool.)
diff --git a/chrome/common/chrome_paths_android.cc b/chrome/common/chrome_paths_android.cc
index 720de04b..ce9479f 100644
--- a/chrome/common/chrome_paths_android.cc
+++ b/chrome/common/chrome_paths_android.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/common/chrome_paths_internal.h"
-
 #include "base/files/file_path.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
+#include "chrome/common/chrome_paths_internal.h"
 
 namespace chrome {
 
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index d68cc91b..9152928c 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -29,6 +29,10 @@
   "reading_list.idl",
   "scripting.idl",
   "tabs.json",
+
+  # Despite the name, these APIs do not rely on any WebRTC-specific bits and
+  # as such do not belong in a conditional.
+  "webrtc_logging_private.idl",
   "webstore_private.json",
   "windows.json",
 ]
@@ -85,7 +89,6 @@
     # as such do not belong in a conditional.
     "webrtc_audio_private.idl",
     "webrtc_desktop_capture_private.idl",
-    "webrtc_logging_private.idl",
   ]
 
   if (is_chromeos) {
diff --git a/chrome/common/media/cdm_host_file_path.cc b/chrome/common/media/cdm_host_file_path.cc
index 4d1d605..1269336 100644
--- a/chrome/common/media/cdm_host_file_path.cc
+++ b/chrome/common/media/cdm_host_file_path.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/path_service.h"
 #include "build/branding_buildflags.h"
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index e02e35a..a82f752 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -1534,6 +1534,9 @@
 // Preference to disable 3D APIs (WebGL, Pepper 3D).
 inline constexpr char kDisable3DAPIs[] = "disable_3d_apis";
 
+// Preference to enable SwiftShader for WebGL fallback.
+inline constexpr char kEnableUnsafeSwiftShader[] = "enable_unsafe_swiftshader";
+
 // Whether to enable hyperlink auditing ("<a ping>").
 inline constexpr char kEnableHyperlinkAuditing[] = "enable_a_ping";
 
diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc
index 4de58e5..b1d042e 100644
--- a/chrome/installer/util/product_unittest.cc
+++ b/chrome/installer/util/product_unittest.cc
@@ -5,7 +5,7 @@
 #include <memory>
 
 #include "base/files/file_path.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_reg_util_win.h"
diff --git a/chrome/renderer/actor/select_tool.cc b/chrome/renderer/actor/select_tool.cc
index da3d351..407a200b 100644
--- a/chrome/renderer/actor/select_tool.cc
+++ b/chrome/renderer/actor/select_tool.cc
@@ -8,6 +8,7 @@
 #include <optional>
 
 #include "base/check.h"
+#include "base/notimplemented.h"
 #include "chrome/common/actor/action_result.h"
 #include "chrome/common/actor/actor_logging.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/renderer/actor/tool_utils.cc b/chrome/renderer/actor/tool_utils.cc
index 3bcade9..4342a2e 100644
--- a/chrome/renderer/actor/tool_utils.cc
+++ b/chrome/renderer/actor/tool_utils.cc
@@ -56,9 +56,10 @@
   }
 
   blink::WebNode node = blink::WebNode::FromDomNodeId(node_id);
-  // Make sure the node we're getting belongs to the document inside this
+  // Make sure the node we're getting belongs to a frame under the local root
   // frame.
-  if (node.IsNull() || node.GetDocument() != web_frame->GetDocument()) {
+  if (node.IsNull() || !node.GetDocument() || !node.GetDocument().GetFrame() ||
+      node.GetDocument().GetFrame()->LocalRoot() != web_frame->LocalRoot()) {
     return blink::WebNode();
   }
   return node;
@@ -74,7 +75,8 @@
 
 bool IsPointWithinViewport(const gfx::PointF& point,
                            const content::RenderFrame& frame) {
-  gfx::Rect viewport(frame.GetWebFrame()->FrameWidget()->VisibleViewportSize());
+  gfx::Rect viewport(
+      frame.GetWebFrame()->LocalRoot()->FrameWidget()->VisibleViewportSize());
   return viewport.Contains(gfx::ToFlooredPoint(point));
 }
 
diff --git a/chrome/renderer/actor/tool_utils_browsertest.cc b/chrome/renderer/actor/tool_utils_browsertest.cc
index 74a9b52..92c9c0c4 100644
--- a/chrome/renderer/actor/tool_utils_browsertest.cc
+++ b/chrome/renderer/actor/tool_utils_browsertest.cc
@@ -95,6 +95,15 @@
   blink::WebNode div3_in_main = GetNodeByHtmlId("div3");
   ASSERT_TRUE(div3_in_main.IsNull());
 
+  // Get node within the main frame
+  blink::WebNode div1_node = GetIframeNodeByHtmlId("iframe1", "div3");
+  ASSERT_FALSE(div1_node.IsNull());
+  ASSERT_TRUE(div1_node.IsElementNode());
+  ASSERT_EQ("div3",
+            div1_node.To<blink::WebElement>().GetAttribute("id").Utf8());
+  int32_t div1_node_id = div1_node.GetDomNodeId();
+  ASSERT_NE(0, div1_node_id);
+
   // Get node within the iframe
   blink::WebNode div3_node = GetIframeNodeByHtmlId("iframe1", "div3");
   ASSERT_FALSE(div3_node.IsNull());
@@ -121,19 +130,19 @@
   EXPECT_EQ(div3_node_id, node_found_in_child.GetDomNodeId());
   EXPECT_EQ(div3_node, node_found_in_child);  // Verify it's the exact same node
 
-  // Try to find iframe node (div3) using the main frame context -> fails
-  blink::WebNode node_not_found_in_main =
+  // Find iframe node (div3) using the main frame context.
+  blink::WebNode node_found_in_main =
       GetNodeFromId(*GetMainRenderFrame(), div3_node_id);
-  EXPECT_TRUE(node_not_found_in_main.IsNull());
+  EXPECT_EQ(div3_node_id, node_found_in_main.GetDomNodeId());
+  EXPECT_EQ(node_found_in_main, div3_node);
 
-  // Try to find main frame node (div1) using the child frame context -> fails
+  // Find main frame node (div1) using the child frame context
   blink::WebNode div1 = GetNodeByHtmlId("div1");  // Searches main frame only
   ASSERT_FALSE(div1.IsNull());
-  int32_t div1_node_id = div1.GetDomNodeId();
-  ASSERT_NE(0, div1_node_id);
-  blink::WebNode node_not_found_in_child =
+  blink::WebNode node_found_in_child2 =
       GetNodeFromId(*child_frame, div1_node_id);
-  EXPECT_TRUE(node_not_found_in_child.IsNull());
+  EXPECT_EQ(div1_node_id, node_found_in_child2.GetDomNodeId());
+  EXPECT_EQ(node_found_in_child2, div1_node);
 }
 
 }  // namespace actor
diff --git a/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc b/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
index 91b6174d..0b54079 100644
--- a/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
+++ b/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
@@ -80,6 +80,14 @@
   }
 }
 
+#if BUILDFLAG(IS_ANDROID)
+void SupervisedUserErrorPageController::LearnMore() {
+  if (delegate_) {
+    delegate_->LearnMore();
+  }
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
 void SupervisedUserErrorPageController::OnRequestUrlAccessRemote(bool success) {
   std::string result = base::ToString(success);
   std::string is_outermost_main_frame =
diff --git a/chrome/renderer/supervised_user/supervised_user_error_page_controller.h b/chrome/renderer/supervised_user/supervised_user_error_page_controller.h
index 05963019..dcfaee9 100644
--- a/chrome/renderer/supervised_user/supervised_user_error_page_controller.h
+++ b/chrome/renderer/supervised_user/supervised_user_error_page_controller.h
@@ -8,6 +8,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
 #include "gin/wrappable.h"
 
 namespace content {
@@ -47,6 +48,10 @@
   void RequestUrlAccessRemote();
   void RequestUrlAccessLocal();
 
+#if BUILDFLAG(IS_ANDROID)
+  void LearnMore();
+#endif  // BUILDFLAG(IS_ANDROID)
+
   void OnRequestUrlAccessRemote(bool success);
 
   // gin::WrappableBase
diff --git a/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate.h b/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate.h
index 121d7d4..4844d29 100644
--- a/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate.h
+++ b/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate.h
@@ -6,6 +6,7 @@
 #define CHROME_RENDERER_SUPERVISED_USER_SUPERVISED_USER_ERROR_PAGE_CONTROLLER_DELEGATE_H_
 
 #include "base/functional/callback_forward.h"
+#include "build/build_config.h"
 
 // Called when the interstitial calls the installed JS methods.
 class SupervisedUserErrorPageControllerDelegate {
@@ -24,6 +25,11 @@
   // Called to initiate local URL approval flow.
   virtual void RequestUrlAccessLocal(UrlAccessRequestInitiated callback) = 0;
 
+#if BUILDFLAG(IS_ANDROID)
+  // Called to open the learn more page for the user.
+  virtual void LearnMore() = 0;
+#endif  // BUILDFLAG(IS_ANDROID)
+
  protected:
   virtual ~SupervisedUserErrorPageControllerDelegate() = default;
 };
diff --git a/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.cc b/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.cc
index a63ced0..42f231a 100644
--- a/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.cc
+++ b/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.cc
@@ -39,6 +39,13 @@
     supervised_user_interface_->RequestUrlAccessLocal(std::move(callback));
 }
 
+#if BUILDFLAG(IS_ANDROID)
+void SupervisedUserErrorPageControllerDelegateImpl::LearnMore() {
+  // TODO(crbug.com/426107993): Refer to help center article.
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
+
 void SupervisedUserErrorPageControllerDelegateImpl::OnDestruct() {
   delete this;
 }
diff --git a/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h b/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h
index 7535ab3..7ba6ff1 100644
--- a/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h
+++ b/chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h
@@ -40,6 +40,9 @@
   void GoBack() override;
   void RequestUrlAccessRemote(UrlAccessRequestInitiated callback) override;
   void RequestUrlAccessLocal(UrlAccessRequestInitiated callback) override;
+#if BUILDFLAG(IS_ANDROID)
+  void LearnMore() override;
+#endif  // BUILDFLAG(IS_ANDROID)
 
   // content::RenderFrameObserver:
   void OnDestruct() override;
diff --git a/chrome/services/sharing/nearby/platform.cc b/chrome/services/sharing/nearby/platform.cc
index 28af046..c37aa24 100644
--- a/chrome/services/sharing/nearby/platform.cc
+++ b/chrome/services/sharing/nearby/platform.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/nearby/src/internal/platform/implementation/platform.h"
 
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/thread_pool.h"
 #include "chrome/services/sharing/nearby/nearby_connections.h"
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc
index 1a7df33..62ec723 100644
--- a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc
+++ b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc
@@ -5,7 +5,7 @@
 #include "chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h"
 
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/task_traits.h"
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc b/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc
index 7353f38..e5f8693 100644
--- a/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc
+++ b/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc
@@ -13,6 +13,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "chrome/services/sharing/nearby/platform/bluetooth_utils.h"
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_medium.cc b/chrome/services/sharing/nearby/platform/ble_v2_medium.cc
index d50735c..b978af3 100644
--- a/chrome/services/sharing/nearby/platform/ble_v2_medium.cc
+++ b/chrome/services/sharing/nearby/platform/ble_v2_medium.cc
@@ -10,6 +10,7 @@
 
 #include "base/containers/flat_set.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/services/sharing/nearby/platform/bluetooth_adapter.cc b/chrome/services/sharing/nearby/platform/bluetooth_adapter.cc
index 1d26785..a8cb744e 100644
--- a/chrome/services/sharing/nearby/platform/bluetooth_adapter.cc
+++ b/chrome/services/sharing/nearby/platform/bluetooth_adapter.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "components/cross_device/nearby/nearby_features.h"
 
 namespace nearby::chrome {
diff --git a/chrome/services/sharing/nearby/platform/bluetooth_classic_medium.cc b/chrome/services/sharing/nearby/platform/bluetooth_classic_medium.cc
index 7b9be89..f622095 100644
--- a/chrome/services/sharing/nearby/platform/bluetooth_classic_medium.cc
+++ b/chrome/services/sharing/nearby/platform/bluetooth_classic_medium.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "chrome/services/sharing/nearby/platform/bluetooth_server_socket.h"
 #include "chrome/services/sharing/nearby/platform/bluetooth_socket.h"
 #include "components/cross_device/nearby/nearby_features.h"
diff --git a/chrome/services/sharing/nearby/platform/webrtc.cc b/chrome/services/sharing/nearby/platform/webrtc.cc
index 91c33414..51610a7 100644
--- a/chrome/services/sharing/nearby/platform/webrtc.cc
+++ b/chrome/services/sharing/nearby/platform/webrtc.cc
@@ -6,6 +6,7 @@
 
 #include "ash/constants/ash_features.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc b/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc
index 6273d8d..e38c445 100644
--- a/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc
+++ b/chrome/services/sharing/nearby/platform/wifi_direct_medium.cc
@@ -8,6 +8,7 @@
 
 #include "base/files/scoped_file.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "chrome/services/sharing/nearby/platform/wifi_direct_server_socket.h"
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc b/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc
index f5376997..eb48c7fb 100644
--- a/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc
+++ b/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc
@@ -9,7 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/task_traits.h"
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc
index 0ca68ea..12b4b8b 100644
--- a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc
+++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc
@@ -12,6 +12,7 @@
 #include "base/functional/callback.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 #include "chromeos/ash/components/quick_start/quick_start_message.h"
 #include "chromeos/ash/components/quick_start/quick_start_message_type.h"
diff --git a/chrome/services/sharing/nearby/test_support/fake_device.cc b/chrome/services/sharing/nearby/test_support/fake_device.cc
index daba33e..f3094685 100644
--- a/chrome/services/sharing/nearby/test_support/fake_device.cc
+++ b/chrome/services/sharing/nearby/test_support/fake_device.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/services/sharing/nearby/test_support/fake_device.h"
 
+#include "base/notimplemented.h"
+
 namespace bluetooth {
 
 FakeDevice::FakeDevice() = default;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index feb04605..64c56569 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2736,6 +2736,7 @@
       "//services/network/public/proto:sct_audit_report_proto",
       "//services/preferences/public/cpp",
       "//services/preferences/public/cpp/tracked",
+      "//services/preferences/tracked:features",
       "//services/screen_ai/public/cpp:utilities",
       "//services/screen_ai/public/mojom",
       "//services/service_manager/public/cpp",
@@ -8182,7 +8183,6 @@
       "../browser/visited_url_ranking/desktop_tab_model_url_visit_data_fetcher_unittest.cc",
       "../browser/webauthn/authenticator_request_dialog_model_unittest.cc",
       "../browser/webauthn/authenticator_request_scheduler_unittest.cc",
-      "../browser/webauthn/cablev2_devices_unittest.cc",
       "../browser/webauthn/challenge_url_fetcher_unittest.cc",
       "../browser/webauthn/chrome_authenticator_request_delegate_unittest.cc",
       "../browser/webauthn/chrome_web_authentication_delegate_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java
index a4cd3c4..ae18c5f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java
@@ -5,9 +5,7 @@
 package org.chromium.chrome.test.util;
 
 import android.app.Activity;
-import android.os.Build;
 import android.view.View;
-import android.view.WindowManager;
 
 import androidx.core.view.WindowInsetsCompat;
 
@@ -217,19 +215,14 @@
         if (BuildInfo.getInstance().isAutomotive) {
             return true;
         }
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-            View view = tab.getContentView();
-            int visibility = view.getSystemUiVisibility();
+        View view = tab.getContentView();
+        int visibility = view.getSystemUiVisibility();
 
-            // SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN should only be used during the transition between
-            // fullscreen states, so it should always be cleared when fullscreen transitions are
-            // completed.
-            return !isFlagSet(visibility, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
-                    && (isFlagSet(visibility, View.SYSTEM_UI_FLAG_FULLSCREEN) == state);
-        } else {
-            WindowManager.LayoutParams attributes = activity.getWindow().getAttributes();
-            return isFlagSet(attributes.flags, WindowManager.LayoutParams.FLAG_FULLSCREEN) == state;
-        }
+        // SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN should only be used during the transition between
+        // fullscreen states, so it should always be cleared when fullscreen transitions are
+        // completed.
+        return !isFlagSet(visibility, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
+                && (isFlagSet(visibility, View.SYSTEM_UI_FLAG_FULLSCREEN) == state);
     }
 
     private static boolean isHideNavigationFlagSet(
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index 02d09c7..9f895493 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 1511155c..bccb056 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -20,6 +20,7 @@
 #include "base/json/json_writer.h"
 #include "base/logging.h"  // For CHECK macros.
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/test/data/actor/two_cross_origin_iframes.html b/chrome/test/data/actor/two_cross_origin_iframes.html
new file mode 100644
index 0000000..cec57c2
--- /dev/null
+++ b/chrome/test/data/actor/two_cross_origin_iframes.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width,minimum-scale=1">
+    <title>Two cross origin iframe Test Case</title>
+    <style>
+      iframe {
+        position: absolute;
+        width: 50vw;
+        height: 50vh;
+        top: 0;
+        left: 0;
+      }
+      #topframe {
+        z-index: 5;
+        background-color: darkred;
+      }
+      #bottomframe {
+        z-index: 1;
+        background-color:lightblue;
+      }
+    </style>
+  </head>
+  <iframe id="topframe" src="https://foo.com/page_with_clickable_element.html?1"></iframe>
+  <iframe id="bottomframe" src="https://foo.com/page_with_clickable_element.html?2"></iframe>
+</html>
diff --git a/chrome/test/data/actor/two_same_site_iframes.html b/chrome/test/data/actor/two_same_site_iframes.html
new file mode 100644
index 0000000..cedbf28
--- /dev/null
+++ b/chrome/test/data/actor/two_same_site_iframes.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width,minimum-scale=1">
+    <title>Two same-site iframe Test Case</title>
+    <style>
+      iframe {
+        position: absolute;
+        width: 50vw;
+        height: 50vh;
+        top: 0;
+        left: 0;
+      }
+      #topframe {
+        z-index: 5;
+        background-color: darkred;
+      }
+      #bottomframe {
+        z-index: 1;
+        background-color:lightblue;
+      }
+    </style>
+  </head>
+  <iframe id="topframe" src="page_with_clickable_element.html?1"></iframe>
+  <iframe id="bottomframe" src="page_with_clickable_element.html?2"></iframe>
+</html>
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index 42fbd895..b48d0df 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -109,10 +109,8 @@
     "secure_dns_test.ts",
     "security_keys_bio_enrollment_test.ts",
     "security_keys_credential_management_test.ts",
-    "security_keys_phones_subpage_test.ts",
     "security_keys_reset_dialog_test.ts",
     "security_keys_set_pin_dialog_test.ts",
-    "security_keys_subpage_test.ts",
     "security_keys_test_util.ts",
     "security_page_test.ts",
     "security_page_v2_test.ts",
diff --git a/chrome/test/data/webui/settings/security_keys_phones_subpage_test.ts b/chrome/test/data/webui/settings/security_keys_phones_subpage_test.ts
deleted file mode 100644
index f8f12f3..0000000
--- a/chrome/test/data/webui/settings/security_keys_phones_subpage_test.ts
+++ /dev/null
@@ -1,220 +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.
-
-/**
- * @fileoverview Tests for the Phone as a Security Key settings page.
- */
-
-import type {CrInputElement, SecurityKeysPhone, SecurityKeysPhonesBrowserProxy, SecurityKeysPhonesList, SecurityKeysPhonesSubpageElement} from 'chrome://settings/lazy_load.js';
-import {SecurityKeysPhonesBrowserProxyImpl} from 'chrome://settings/lazy_load.js';
-import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
-import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
-
-class TestSecurityKeysPhonesBrowserProxy extends TestBrowserProxy implements
-    SecurityKeysPhonesBrowserProxy {
-  constructor() {
-    super([
-      'enumerate',
-      'delete',
-      'rename',
-    ]);
-  }
-
-  // nextPhonesList_ is the next result to return from a call to `enumerate` or
-  // `delete`.
-  private nextPhonesList_: SecurityKeysPhonesList|null = null;
-
-  setNextPhonesList(syncedPhones: string[], linkedPhones: string[]) {
-    this.nextPhonesList_ =
-        [syncedPhones.map(this.toPhone_), linkedPhones.map(this.toPhone_)];
-    this.resetResolver('enumerate');
-    this.resetResolver('delete');
-  }
-
-  /* override */ enumerate(): Promise<SecurityKeysPhonesList> {
-    this.methodCalled('enumerate');
-    return this.consumeNextPhonesList_();
-  }
-
-  /* override */ delete(publicKey: string): Promise<SecurityKeysPhonesList> {
-    this.methodCalled('delete', publicKey);
-    return this.consumeNextPhonesList_();
-  }
-
-  /* override */ rename(publicKey: string, newName: string): Promise<void> {
-    this.methodCalled('rename', publicKey, newName);
-    return Promise.resolve();
-  }
-
-  private consumeNextPhonesList_(): Promise<SecurityKeysPhonesList> {
-    const result = this.nextPhonesList_;
-    this.nextPhonesList_ = null;
-    assertTrue(
-        result !== null,
-        'browserProxy methods called without result have being set for it');
-    return Promise.resolve(result);
-  }
-
-  /**
-   * Create a dummy phone given a name.
-   */
-  private toPhone_(name: string): SecurityKeysPhone {
-    return {name, publicKey: name};
-  }
-}
-
-type ShownPhones = Array<{name: string, hasDots: boolean}>;
-
-/**
- * Get the phones currently listed by the given SecurityKeysPhonesListElement.
- */
-function getPhonesFromList(list: HTMLElement): ShownPhones {
-  const items = list.shadowRoot!.querySelectorAll('.list-item');
-  const ret: ShownPhones = [];
-
-  for (const item of items) {
-    const nameSpan = item.querySelector<HTMLElement>('.name-column');
-    const dots = item.querySelector<HTMLElement>('.icon-more-vert');
-
-    if (nameSpan != null) {
-      ret.push({name: nameSpan.innerText, hasDots: dots !== null});
-    }
-  }
-
-  return ret;
-}
-
-/**
- * Get the list phones currently shown on the page.
- */
-function getPhones(page: HTMLElement): [ShownPhones, ShownPhones] {
-  return [
-    getPhonesFromList(
-        page.shadowRoot!.querySelector<HTMLElement>('#syncedPhonesList')!),
-    getPhonesFromList(
-        page.shadowRoot!.querySelector<HTMLElement>('#linkedPhonesList')!),
-  ];
-}
-
-/**
- * Click the `num`th drop-down icon in the list of linked phones.
- */
-function clickLinkedPhoneDots(page: HTMLElement, num: number) {
-  const list =
-      page.shadowRoot!.querySelector<HTMLElement>('#linkedPhonesList')!;
-  const items = list.shadowRoot!.querySelectorAll('.list-item');
-  const dots = items[num]!.querySelector<HTMLElement>('.icon-more-vert')!;
-  dots.click();
-}
-
-/**
- * Click the button named `name` in the `num`th drop-down.
- */
-function clickButton(page: HTMLElement, name: string) {
-  const list =
-      page.shadowRoot!.querySelector<HTMLElement>('#linkedPhonesList')!;
-  const menu = list.shadowRoot!.querySelector<HTMLElement>('#menu')!;
-  const button = menu.querySelector<HTMLElement>('#' + name);
-
-  assertTrue(button !== null, name + ' button missing');
-  if (button === null) {
-    return;
-  }
-
-  button.click();
-}
-
-suite('SecurityKeysPhonesSubpage', function() {
-  let browserProxy: TestSecurityKeysPhonesBrowserProxy;
-  let page: SecurityKeysPhonesSubpageElement;
-
-  // These are the initial lists of synced and linked phones that will be
-  // displayed when the test starts.
-  const initialSynced = ['Synced 1', 'Synced 2'];
-  const initialLinked = ['Linked 1', 'Linked 2'];
-
-  setup(async function() {
-    browserProxy = new TestSecurityKeysPhonesBrowserProxy();
-    SecurityKeysPhonesBrowserProxyImpl.setInstance(browserProxy);
-    document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    page = document.createElement('security-keys-phones-subpage');
-
-    browserProxy.setNextPhonesList(initialSynced, initialLinked);
-    document.body.appendChild(page);
-    await flushTasks();
-    assertEquals(browserProxy.getCallCount('enumerate'), 1);
-  });
-
-  test('Initialization', function() {
-    const shown = getPhones(page);
-
-    // The default entries should be shown.
-    assertDeepEquals(shown[0].map(x => x.name), initialSynced);
-    assertDeepEquals(shown[1].map(x => x.name), initialLinked);
-    // The synced phones should not have the dropdown dots, the linked phones
-    // should.
-    assertTrue(
-        shown[0].every(x => !x.hasDots), 'Synced phones don\'t have dots');
-    assertTrue(shown[1].every(x => x.hasDots), 'Linked phones have dots');
-  });
-
-  test('Delete', async function() {
-    clickLinkedPhoneDots(page, 0);
-
-    // 'delete' should be called for the first linked phone.
-    browserProxy.whenCalled('delete').then((name: string) => {
-      assertEquals(name, initialLinked[0]);
-    });
-    browserProxy.setNextPhonesList(initialSynced, ['Linked 2']);
-    clickButton(page, 'delete');
-    await flushTasks();
-    assertEquals(browserProxy.getCallCount('delete'), 1);
-
-    const shown = getPhones(page);
-    assertDeepEquals(shown[0].map(x => x.name), initialSynced);
-    // The first phone should have disappeared.
-    assertDeepEquals(shown[1].map(x => x.name), ['Linked 2']);
-  });
-
-  test('Edit', async function() {
-    clickLinkedPhoneDots(page, 0);
-    clickButton(page, 'edit');
-
-    await flushTasks();
-
-    const dialogs =
-        page.shadowRoot!.querySelectorAll('security-keys-phones-dialog');
-    assertEquals(dialogs.length, 1, 'num dialogs');
-    const dialog = dialogs[0]!;
-
-    const name = dialog.shadowRoot!.querySelector<CrInputElement>('#name')!;
-    assertEquals(name.value, 'Linked 1');
-    const newName = 'New name';
-    name.value = newName;
-
-    const saveButton =
-        dialog.shadowRoot!.querySelector<HTMLElement>('#actionButton')!;
-    browserProxy.whenCalled('rename').then(
-        ([publicKey, requestedName]: [string, string]) => {
-          assertEquals(publicKey, initialLinked[0]);
-          assertEquals(requestedName, newName);
-        });
-    browserProxy.setNextPhonesList(initialSynced, [newName, 'Linked 2']);
-    saveButton.click();
-
-    await flushTasks();
-    assertEquals(browserProxy.getCallCount('rename'), 1, 'rename not called');
-
-    await browserProxy.whenCalled('enumerate');
-    await flushTasks();
-    assertEquals(
-        browserProxy.getCallCount('enumerate'), 1, 'enumerate not called');
-    const shown = getPhones(page);
-
-    assertDeepEquals(shown[0].map(x => x.name), initialSynced);
-    // The first phone should have been renamed.
-    assertDeepEquals(shown[1].map(x => x.name), [newName, 'Linked 2']);
-  });
-});
diff --git a/chrome/test/data/webui/settings/security_keys_subpage_test.ts b/chrome/test/data/webui/settings/security_keys_subpage_test.ts
deleted file mode 100644
index 86e9a88a..0000000
--- a/chrome/test/data/webui/settings/security_keys_subpage_test.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Tests for the Security Keys settings subpage.
- */
-
-import 'chrome://settings/lazy_load.js';
-
-import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import type {SecurityKeysSubpageElement} from 'chrome://settings/lazy_load.js';
-import {resetRouterForTesting, Router, routes} from 'chrome://settings/settings.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
-
-suite('SecurityKeysSubpage', function() {
-  let page: SecurityKeysSubpageElement;
-
-  async function createPage() {
-    document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    page = document.createElement('security-keys-subpage');
-    document.body.appendChild(page);
-    await flushTasks();
-  }
-
-  // TODO(crbug.com/372493822): remove these tests when hybrid linking flag is
-  // removed.
-  test(
-      'Shows the manage phones button if hybrid linking is enabled',
-      async function() {
-        loadTimeData.overrideValues({enableSecurityKeysManagePhones: true});
-        await createPage();
-        resetRouterForTesting();
-        const button =
-            page.shadowRoot!.querySelector<HTMLElement>('#managePhonesButton');
-        assertTrue(!!button);
-        button.click();
-        flush();
-        assertEquals(
-            routes.SECURITY_KEYS_PHONES,
-            Router.getInstance().getCurrentRoute());
-      });
-
-  test(
-      'Does not show the manage phones button if hybrid linking is disabled',
-      async function() {
-        loadTimeData.overrideValues({enableSecurityKeysManagePhones: false});
-        await createPage();
-        resetRouterForTesting();
-        const button =
-            page.shadowRoot!.querySelector<HTMLElement>('#managePhonesButton');
-        assertFalse(!!button);
-      });
-});
diff --git a/chrome/test/data/webui/settings/security_page_test.ts b/chrome/test/data/webui/settings/security_page_test.ts
index 17b2c6b..e93a77d 100644
--- a/chrome/test/data/webui/settings/security_page_test.ts
+++ b/chrome/test/data/webui/settings/security_page_test.ts
@@ -361,40 +361,6 @@
     assertFalse(isChildVisible(page, '#securityKeysSubpageTrigger'));
   });
 
-  // On modern versions of Windows the security keys subpage will be disabled
-  // because Windows manages that itself, but a link to the subpage for
-  // managing phones as security keys will be included when hybrid linking is
-  // enabled.
-  // TODO(crbug.com/372493822): remove these tests when hybrid linking flag is
-  // removed.
-  // <if expr="is_win">
-  test(
-      'ManageSecurityKeysPhonesSubpage_HybridLinkingEnabled', async function() {
-        loadTimeData.overrideValues({enableSecurityKeysManagePhones: true});
-        await createPage();
-        resetRouterForTesting();
-
-        const triggerId = '#securityKeysPhonesSubpageTrigger';
-        assertTrue(isChildVisible(page, triggerId));
-        page.shadowRoot!.querySelector<HTMLElement>(triggerId)!.click();
-        flush();
-        assertEquals(
-            routes.SECURITY_KEYS_PHONES,
-            Router.getInstance().getCurrentRoute());
-      });
-
-  test(
-      'ManageSecurityKeysPhonesSubpage_HybridLinkingDisabled',
-      async function() {
-        loadTimeData.overrideValues({enableSecurityKeysManagePhones: false});
-        await createPage();
-        resetRouterForTesting();
-
-        const triggerId = '#securityKeysPhonesSubpageTrigger';
-        assertFalse(isChildVisible(page, triggerId));
-      });
-  // </if>
-
   // Tests the old HTTPS-Only Mode toggle UI.
   // TODO(crbug.com/349860796): Remove this test once HttpsFirstBalancedMode is
   // enabled by default.
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc
index 8e88c43..687ad7f3 100644
--- a/chrome/test/data/webui/settings/settings_browsertest.cc
+++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -564,23 +564,6 @@
   RunTest("settings/secure_dns_test.js", "runMochaSuite('SettingsSecureDns')");
 }
 
-// TODO(crbug.com/372493822): remove when hybrid linking is disabled by default.
-class HybridDisabledSettingsTest : public SettingsTest {
- public:
-  HybridDisabledSettingsTest() {
-    scoped_feature_list_.InitWithFeatures(
-        /*enabled_features=*/{},
-        /*disabled_features=*/{device::kWebAuthnHybridLinking});
-  }
-
- protected:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_F(HybridDisabledSettingsTest, SecurityKeysSubpage) {
-  RunTest("settings/security_keys_subpage_test.js", "mocha.run()");
-}
-
 IN_PROC_BROWSER_TEST_F(SettingsTest, SecurityKeysBioEnrollment) {
   RunTest("settings/security_keys_bio_enrollment_test.js", "mocha.run()");
 }
@@ -590,10 +573,6 @@
           "mocha.run()");
 }
 
-IN_PROC_BROWSER_TEST_F(SettingsTest, SecurityKeysPhonesSubpage) {
-  RunTest("settings/security_keys_phones_subpage_test.js", "mocha.run()");
-}
-
 IN_PROC_BROWSER_TEST_F(SettingsTest, SecurityKeysResetDialog) {
   RunTest("settings/security_keys_reset_dialog_test.js", "mocha.run()");
 }
diff --git a/chrome/test/payments/payment_request_test_controller_android.cc b/chrome/test/payments/payment_request_test_controller_android.cc
index 522fc6a..ec606ce 100644
--- a/chrome/test/payments/payment_request_test_controller_android.cc
+++ b/chrome/test/payments/payment_request_test_controller_android.cc
@@ -5,7 +5,7 @@
 #include "chrome/test/payments/payment_request_test_controller.h"
 
 #include "base/functional/bind.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chrome/browser/android/background_task_scheduler/chrome_background_task_factory.h"
 #include "chrome/test/payments/android/payment_request_test_bridge.h"
 
diff --git a/chrome/utility/image_writer/image_writer_stub.cc b/chrome/utility/image_writer/image_writer_stub.cc
index 5873766..4fcec41 100644
--- a/chrome/utility/image_writer/image_writer_stub.cc
+++ b/chrome/utility/image_writer/image_writer_stub.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/utility/image_writer/image_writer.h"
 
+#include "base/notimplemented.h"
+
 // This file contains the default version of the platform-specific methods of
 // the ImageWriter.  Add new platforms by creating a new version of these
 // methods and updating the compliation rules appropriately.
diff --git a/chrome/utility/safe_browsing/mac/udif.cc b/chrome/utility/safe_browsing/mac/udif.cc
index dbf4aa1..4b7363ce 100644
--- a/chrome/utility/safe_browsing/mac/udif.cc
+++ b/chrome/utility/safe_browsing/mac/udif.cc
@@ -23,6 +23,7 @@
 #include "base/containers/span.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/ostream_operators.h"
 #include "base/numerics/safe_math.h"
diff --git a/chromecast/cast_core/runtime/browser/cast_runtime_metrics_recorder.cc b/chromecast/cast_core/runtime/browser/cast_runtime_metrics_recorder.cc
index 8076800..2b0f1559 100644
--- a/chromecast/cast_core/runtime/browser/cast_runtime_metrics_recorder.cc
+++ b/chromecast/cast_core/runtime/browser/cast_runtime_metrics_recorder.cc
@@ -13,7 +13,7 @@
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/metrics/user_metrics.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "base/values.h"
diff --git a/chromecast/external_mojo/public/cpp/external_mojo_broker.cc b/chromecast/external_mojo/public/cpp/external_mojo_broker.cc
index 23e7aa30..b8bd5e61 100644
--- a/chromecast/external_mojo/public/cpp/external_mojo_broker.cc
+++ b/chromecast/external_mojo/public/cpp/external_mojo_broker.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/containers/contains.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
diff --git a/chromecast/graphics/cast_screen.cc b/chromecast/graphics/cast_screen.cc
index ff34a67..8c19e76 100644
--- a/chromecast/graphics/cast_screen.cc
+++ b/chromecast/graphics/cast_screen.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "ui/aura/env.h"
 #include "ui/display/display.h"
 
diff --git a/chromecast/media/audio/audio_output_service/receiver/cma_backend_shim.cc b/chromecast/media/audio/audio_output_service/receiver/cma_backend_shim.cc
index c123ab2..e3e9ea9 100644
--- a/chromecast/media/audio/audio_output_service/receiver/cma_backend_shim.cc
+++ b/chromecast/media/audio/audio_output_service/receiver/cma_backend_shim.cc
@@ -11,6 +11,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chromecast/media/api/cma_backend_factory.h"
diff --git a/chromecast/media/audio/cast_audio_manager_alsa.cc b/chromecast/media/audio/cast_audio_manager_alsa.cc
index 53f42281..33a56be 100644
--- a/chromecast/media/audio/cast_audio_manager_alsa.cc
+++ b/chromecast/media/audio/cast_audio_manager_alsa.cc
@@ -14,6 +14,7 @@
 
 #include "base/logging.h"
 #include "base/memory/free_deleter.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chromecast/media/api/cma_backend_factory.h"
 #include "chromecast/media/audio/audio_buildflags.h"
diff --git a/chromecast/media/audio/cast_audio_renderer.cc b/chromecast/media/audio/cast_audio_renderer.cc
index c877966b..6556e131 100644
--- a/chromecast/media/audio/cast_audio_renderer.cc
+++ b/chromecast/media/audio/cast_audio_renderer.cc
@@ -14,7 +14,7 @@
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/numerics/ranges.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
diff --git a/chromecast/media/audio/net/audio_socket_service_tcp.cc b/chromecast/media/audio/net/audio_socket_service_tcp.cc
index 8a43b2c..fc24946 100644
--- a/chromecast/media/audio/net/audio_socket_service_tcp.cc
+++ b/chromecast/media/audio/net/audio_socket_service_tcp.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/audio/net/audio_socket_service.h"
-
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
+#include "chromecast/media/audio/net/audio_socket_service.h"
 #include "net/base/address_list.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
diff --git a/chromecast/media/cma/backend/desktop/desktop_system_volume_control.cc b/chromecast/media/cma/backend/desktop/desktop_system_volume_control.cc
index 8aef34f..28f1ac6 100644
--- a/chromecast/media/cma/backend/desktop/desktop_system_volume_control.cc
+++ b/chromecast/media/cma/backend/desktop/desktop_system_volume_control.cc
@@ -4,7 +4,7 @@
 
 #include <memory>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chromecast/media/cma/backend/system_volume_control.h"
 
 namespace chromecast {
diff --git a/chromecast/media/cma/backend/proxy/cast_runtime_audio_channel_endpoint_simple.cc b/chromecast/media/cma/backend/proxy/cast_runtime_audio_channel_endpoint_simple.cc
index 059b542d..5b923db 100644
--- a/chromecast/media/cma/backend/proxy/cast_runtime_audio_channel_endpoint_simple.cc
+++ b/chromecast/media/cma/backend/proxy/cast_runtime_audio_channel_endpoint_simple.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/notimplemented.h"
 #include "chromecast/media/cma/backend/proxy/cast_runtime_audio_channel_endpoint_manager.h"
 
-#include "base/notreached.h"
-
 namespace chromecast {
 namespace media {
 
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index 37d8168..d3224315 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -12,6 +12,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/default_tick_clock.h"
 #include "chromecast/base/metrics/cast_metrics_helper.h"
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index 1e139475..47cceb7b 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -9,6 +9,7 @@
 
 #include "base/command_line.h"
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
diff --git a/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc b/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc
index 31d2493..c4c223fa 100644
--- a/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc
+++ b/chromecast/starboard/media/cdm/starboard_decryptor_cast.cc
@@ -13,7 +13,7 @@
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/hash/hash.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
diff --git a/chromeos/ash/components/auth_panel/impl/auth_panel.cc b/chromeos/ash/components/auth_panel/impl/auth_panel.cc
index 25eeddf..b53ce691 100644
--- a/chromeos/ash/components/auth_panel/impl/auth_panel.cc
+++ b/chromeos/ash/components/auth_panel/impl/auth_panel.cc
@@ -14,7 +14,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_id.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chromeos/ash/components/auth_panel/impl/auth_factor_store.h"
 #include "chromeos/ash/components/auth_panel/impl/auth_panel_event_dispatcher.h"
 #include "chromeos/ash/components/auth_panel/impl/factor_auth_view.h"
diff --git a/chromeos/ash/components/auth_panel/impl/auth_panel_event_dispatcher.cc b/chromeos/ash/components/auth_panel/impl/auth_panel_event_dispatcher.cc
index a846868..55250b6 100644
--- a/chromeos/ash/components/auth_panel/impl/auth_panel_event_dispatcher.cc
+++ b/chromeos/ash/components/auth_panel/impl/auth_panel_event_dispatcher.cc
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chromeos/ash/components/auth_panel/impl/auth_factor_store.h"
 
 namespace ash {
diff --git a/chromeos/ash/components/dbus/attestation/fake_attestation_client.cc b/chromeos/ash/components/dbus/attestation/fake_attestation_client.cc
index e3c6bd6..f3b3837 100644
--- a/chromeos/ash/components/dbus/attestation/fake_attestation_client.cc
+++ b/chromeos/ash/components/dbus/attestation/fake_attestation_client.cc
@@ -8,6 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/chromeos/ash/components/dbus/audio/fake_floss_media_client.cc b/chromeos/ash/components/dbus/audio/fake_floss_media_client.cc
index 6ade36b..27583dcf 100644
--- a/chromeos/ash/components/dbus/audio/fake_floss_media_client.cc
+++ b/chromeos/ash/components/dbus/audio/fake_floss_media_client.cc
@@ -8,7 +8,7 @@
 
 #include "base/check_op.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace ash {
 
diff --git a/chromeos/ash/components/dbus/device_management/fake_install_attributes_client.cc b/chromeos/ash/components/dbus/device_management/fake_install_attributes_client.cc
index 3e2f7a4..04e2fd63 100644
--- a/chromeos/ash/components/dbus/device_management/fake_install_attributes_client.cc
+++ b/chromeos/ash/components/dbus/device_management/fake_install_attributes_client.cc
@@ -13,7 +13,7 @@
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/thread_restrictions.h"
diff --git a/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc b/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc
index 781e459..5265deb 100644
--- a/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc
+++ b/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/protobuf_matchers.h"
 #include "base/test/task_environment.h"
diff --git a/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc b/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc
index 8be07de..066b149 100644
--- a/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc
+++ b/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc
@@ -8,6 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 
 namespace ash {
diff --git a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
index 19e1149..d917919 100644
--- a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
+++ b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
@@ -16,7 +16,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/task/thread_pool.h"
 #include "base/test/bind.h"
diff --git a/chromeos/ash/components/dbus/update_engine/update_engine_client.h b/chromeos/ash/components/dbus/update_engine/update_engine_client.h
index 327682f..8e827a8b 100644
--- a/chromeos/ash/components/dbus/update_engine/update_engine_client.h
+++ b/chromeos/ash/components/dbus/update_engine/update_engine_client.h
@@ -13,6 +13,7 @@
 
 #include "base/component_export.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "chromeos/ash/components/dbus/update_engine/update_engine.pb.h"
 #include "chromeos/dbus/common/dbus_client.h"
diff --git a/chromeos/ash/components/dbus/userdataauth/cryptohome_misc_client_unittest.cc b/chromeos/ash/components/dbus/userdataauth/cryptohome_misc_client_unittest.cc
index 7e73838a..49dec59 100644
--- a/chromeos/ash/components/dbus/userdataauth/cryptohome_misc_client_unittest.cc
+++ b/chromeos/ash/components/dbus/userdataauth/cryptohome_misc_client_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/dbus/cryptohome/UserDataAuth.pb.h"
diff --git a/chromeos/ash/components/dbus/userdataauth/mock_userdataauth_client.cc b/chromeos/ash/components/dbus/userdataauth/mock_userdataauth_client.cc
index 23a4b479..6c923df 100644
--- a/chromeos/ash/components/dbus/userdataauth/mock_userdataauth_client.cc
+++ b/chromeos/ash/components/dbus/userdataauth/mock_userdataauth_client.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace ash {
 
diff --git a/chromeos/ash/components/drivefs/fake_drivefs.cc b/chromeos/ash/components/drivefs/fake_drivefs.cc
index ced6fa5..81d8b76 100644
--- a/chromeos/ash/components/drivefs/fake_drivefs.cc
+++ b/chromeos/ash/components/drivefs/fake_drivefs.cc
@@ -17,6 +17,7 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
diff --git a/chromeos/ash/components/login/auth/auth_session_authenticator.cc b/chromeos/ash/components/login/auth/auth_session_authenticator.cc
index 40989f95..cb220be 100644
--- a/chromeos/ash/components/login/auth/auth_session_authenticator.cc
+++ b/chromeos/ash/components/login/auth/auth_session_authenticator.cc
@@ -13,6 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/time/default_clock.h"
 #include "chromeos/ash/components/cryptohome/auth_factor.h"
diff --git a/chromeos/ash/components/nearby/presence/fake_nearby_presence_service.cc b/chromeos/ash/components/nearby/presence/fake_nearby_presence_service.cc
index f35ce69..19e3b07 100644
--- a/chromeos/ash/components/nearby/presence/fake_nearby_presence_service.cc
+++ b/chromeos/ash/components/nearby/presence/fake_nearby_presence_service.cc
@@ -4,6 +4,8 @@
 
 #include "chromeos/ash/components/nearby/presence/fake_nearby_presence_service.h"
 
+#include "base/notimplemented.h"
+
 namespace ash::nearby::presence {
 
 FakeNearbyPresenceService::FakeNearbyPresenceService() = default;
diff --git a/chromeos/ash/components/telemetry_extension/diagnostics/diagnostics_service_converters.cc b/chromeos/ash/components/telemetry_extension/diagnostics/diagnostics_service_converters.cc
index 0cf9f29c..8b9825d 100644
--- a/chromeos/ash/components/telemetry_extension/diagnostics/diagnostics_service_converters.cc
+++ b/chromeos/ash/components/telemetry_extension/diagnostics/diagnostics_service_converters.cc
@@ -6,6 +6,7 @@
 
 #include <optional>
 
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "chromeos/ash/components/telemetry_extension/diagnostics/mojo_utils.h"
 #include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom.h"
diff --git a/chromeos/ash/components/tether/network_host_scan_cache.cc b/chromeos/ash/components/tether/network_host_scan_cache.cc
index f032efb..ce4b59b 100644
--- a/chromeos/ash/components/tether/network_host_scan_cache.cc
+++ b/chromeos/ash/components/tether/network_host_scan_cache.cc
@@ -5,6 +5,7 @@
 #include "chromeos/ash/components/tether/network_host_scan_cache.h"
 
 #include "base/containers/contains.h"
+#include "base/notimplemented.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
diff --git a/chromeos/ash/experiences/arc/ime/arc_ime_service.cc b/chromeos/ash/experiences/arc/ime/arc_ime_service.cc
index 419c7cd..07145dd2 100644
--- a/chromeos/ash/experiences/arc/ime/arc_ime_service.cc
+++ b/chromeos/ash/experiences/arc/ime/arc_ime_service.cc
@@ -13,6 +13,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/ash/experiences/arc/arc_browser_context_keyed_service_factory_base.h"
diff --git a/chromeos/ash/experiences/arc/mojom/video_accelerator_mojom_traits.cc b/chromeos/ash/experiences/arc/mojom/video_accelerator_mojom_traits.cc
index 400a7224..296d20b 100644
--- a/chromeos/ash/experiences/arc/mojom/video_accelerator_mojom_traits.cc
+++ b/chromeos/ash/experiences/arc/mojom/video_accelerator_mojom_traits.cc
@@ -4,6 +4,8 @@
 
 #include "chromeos/ash/experiences/arc/mojom/video_accelerator_mojom_traits.h"
 
+#include "base/notimplemented.h"
+
 namespace mojo {
 
 // Make sure values in arc::mojom::VideoCodecProfile match to the values in
diff --git a/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.cc b/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.cc
index 1bf0874..dd174ea 100644
--- a/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.cc
+++ b/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.cc
@@ -6,6 +6,7 @@
 
 #include <optional>
 
+#include "base/notimplemented.h"
 #include "chromeos/ash/experiences/arc/mojom/video_accelerator_mojom_traits.h"
 
 namespace mojo {
diff --git a/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.h b/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.h
index 7d4718c..426f6e0 100644
--- a/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.h
+++ b/chromeos/ash/experiences/arc/mojom/video_encode_accelerator_mojom_traits.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_ASH_EXPERIENCES_ARC_MOJOM_VIDEO_ENCODE_ACCELERATOR_MOJOM_TRAITS_H_
 #define CHROMEOS_ASH_EXPERIENCES_ARC_MOJOM_VIDEO_ENCODE_ACCELERATOR_MOJOM_TRAITS_H_
 
+#include "base/notimplemented.h"
 #include "chromeos/ash/experiences/arc/mojom/video_encode_accelerator.mojom-shared.h"
 #include "media/base/bitrate.h"
 #include "media/video/video_encode_accelerator.h"
diff --git a/chromeos/ash/experiences/arc/test/fake_process_instance.cc b/chromeos/ash/experiences/arc/test/fake_process_instance.cc
index bb217d0..88f1eb4 100644
--- a/chromeos/ash/experiences/arc/test/fake_process_instance.cc
+++ b/chromeos/ash/experiences/arc/test/fake_process_instance.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/check_op.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 
 namespace arc {
diff --git a/chromeos/ash/experiences/arc/video_accelerator/oop_arc_video_accelerator_factory.cc b/chromeos/ash/experiences/arc/video_accelerator/oop_arc_video_accelerator_factory.cc
index a5bfbbd5..ac144e0 100644
--- a/chromeos/ash/experiences/arc/video_accelerator/oop_arc_video_accelerator_factory.cc
+++ b/chromeos/ash/experiences/arc/video_accelerator/oop_arc_video_accelerator_factory.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "chromeos/ash/experiences/arc/mojom/protected_buffer_manager.mojom.h"
 #include "chromeos/ash/experiences/arc/video_accelerator/gpu_arc_video_decode_accelerator.h"
diff --git a/chromeos/ash/services/ime/decoder/decoder_engine.cc b/chromeos/ash/services/ime/decoder/decoder_engine.cc
index faf588e..81bdcbf 100644
--- a/chromeos/ash/services/ime/decoder/decoder_engine.cc
+++ b/chromeos/ash/services/ime/decoder/decoder_engine.cc
@@ -12,7 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/functional/callback_helpers.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chromeos/ash/services/ime/constants.h"
 
 namespace ash {
diff --git a/chromeos/ash/services/ime/ime_service.cc b/chromeos/ash/services/ime/ime_service.cc
index 62764eb..ee246c1 100644
--- a/chromeos/ash/services/ime/ime_service.cc
+++ b/chromeos/ash/services/ime/ime_service.cc
@@ -14,7 +14,7 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "chromeos/ash/services/ime/constants.h"
 #include "chromeos/ash/services/ime/decoder/decoder_engine.h"
diff --git a/chromeos/ash/services/nearby/public/cpp/fake_nearby_process_manager.cc b/chromeos/ash/services/nearby/public/cpp/fake_nearby_process_manager.cc
index 6ae865d5..6823030 100644
--- a/chromeos/ash/services/nearby/public/cpp/fake_nearby_process_manager.cc
+++ b/chromeos/ash/services/nearby/public/cpp/fake_nearby_process_manager.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "chromeos/ash/services/nearby/public/cpp/fake_nearby_presence.h"
 #include "chromeos/ash/services/nearby/public/cpp/mock_nearby_connections.h"
 #include "chromeos/ash/services/nearby/public/cpp/mock_nearby_sharing_decoder.h"
diff --git a/chromeos/ash/services/nearby/public/cpp/fake_tcp_connected_socket.cc b/chromeos/ash/services/nearby/public/cpp/fake_tcp_connected_socket.cc
index 3a415834..2de3a14 100644
--- a/chromeos/ash/services/nearby/public/cpp/fake_tcp_connected_socket.cc
+++ b/chromeos/ash/services/nearby/public/cpp/fake_tcp_connected_socket.cc
@@ -4,7 +4,7 @@
 
 #include "chromeos/ash/services/nearby/public/cpp/fake_tcp_connected_socket.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace ash {
 namespace nearby {
diff --git a/chromeos/ash/services/secure_channel/ble_weave_client_connection_unittest.cc b/chromeos/ash/services/secure_channel/ble_weave_client_connection_unittest.cc
index d2a7767..18d7d26 100644
--- a/chromeos/ash/services/secure_channel/ble_weave_client_connection_unittest.cc
+++ b/chromeos/ash/services/secure_channel/ble_weave_client_connection_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/test/gmock_move_support.h"
 #include "base/test/metrics/histogram_tester.h"
diff --git a/chromeos/services/machine_learning/public/cpp/fake_service_connection.cc b/chromeos/services/machine_learning/public/cpp/fake_service_connection.cc
index a87d01f..1832e84 100644
--- a/chromeos/services/machine_learning/public/cpp/fake_service_connection.cc
+++ b/chromeos/services/machine_learning/public/cpp/fake_service_connection.cc
@@ -8,7 +8,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace chromeos {
 namespace machine_learning {
diff --git a/clank b/clank
index 682a9b9..ceeb89e 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 682a9b98153aec09a8df5d129561a604cd409d68
+Subproject commit ceeb89e0f8224ca96ca05598cf0cfc1a7b652963
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 63a8524..28304e4 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -1115,6 +1115,7 @@
       "//content/public/browser",
       "//content/shell:content_shell_lib",
       "//content/test:browsertest_support",
+      "//content/test:content_test_entry",
       "//content/test:default_content_test_launcher",
       "//content/test:test_support",
       "//device/bluetooth",
@@ -1150,15 +1151,17 @@
 
     if (is_ios) {
       entitlements_path = "//content/app/ios/appex/app.entitlements"
+      deps += [
+        "//content/test/ios/appex:test_content_process_bundle",
+        "//content/test/ios/appex:test_gpu_process_bundle",
+        "//content/test/ios/appex:test_network_process_bundle",
+      ]
       bundle_deps = [
         ":components_tests_distiller_bundle_data",
         ":components_tests_pak_bundle_data",
         "test:dom_distiller_test_bundle_data",
         "test:url_rewrite_test_bundle_data",
-        "//content/test:content_process_bundle",
         "//content/test:content_test_bundle_data",
-        "//content/test:gpu_process_bundle",
-        "//content/test:network_process_bundle",
         "//testing/buildbot/filters:components_browsertests_use_blink_filters_bundle_data",
       ]
     }
diff --git a/components/account_id/account_id.cc b/components/account_id/account_id.cc
index c55ff04..a5d0820 100644
--- a/components/account_id/account_id.cc
+++ b/components/account_id/account_id.cc
@@ -12,6 +12,7 @@
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 295b6b8a..b7938d2 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -29,6 +29,7 @@
 #include "base/memory/raw_ref.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/components/autofill/core/browser/form_import/form_data_importer_unittest.cc b/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
index 152eec4..d62de85a 100644
--- a/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
@@ -23,6 +23,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/not_fatal_until.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/metrics/histogram_tester.h"
diff --git a/components/autofill/core/browser/foundations/autofill_client.cc b/components/autofill/core/browser/foundations/autofill_client.cc
index d2aeda6..2fce97dc 100644
--- a/components/autofill/core/browser/foundations/autofill_client.cc
+++ b/components/autofill/core/browser/foundations/autofill_client.cc
@@ -10,6 +10,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/filling/filling_product.h"
 #include "components/autofill/core/browser/integrators/autofill_ai/autofill_ai_manager.h"
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_mandatory_reauth_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_mandatory_reauth_unittest.cc
index 796d3116..d6a0d15 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager_mandatory_reauth_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_mandatory_reauth_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
diff --git a/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc b/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc
index 293a3b6..1b65bdf 100644
--- a/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc
@@ -5,6 +5,7 @@
 #include "components/autofill/core/browser/payments/payments_requests/upload_iban_request.h"
 
 #include "base/json/json_writer.h"
+#include "base/notimplemented.h"
 #include "base/strings/escape.h"
 #include "base/strings/stringprintf.h"
 
diff --git a/components/autofill/core/browser/webdata/addresses/autofill_profile_sync_bridge.cc b/components/autofill/core/browser/webdata/addresses/autofill_profile_sync_bridge.cc
index a926281..3381290 100644
--- a/components/autofill/core/browser/webdata/addresses/autofill_profile_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/addresses/autofill_profile_sync_bridge.cc
@@ -10,6 +10,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
 #include "components/autofill/core/browser/proto/autofill_sync.pb.h"
diff --git a/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc b/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc
index c8d0768..c3a1a6fe 100644
--- a/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc
@@ -8,7 +8,7 @@
 #include <utility>
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "components/autofill/core/browser/webdata/autofill_sync_metadata_table.h"
diff --git a/components/autofill/core/browser/webdata/payments/autofill_wallet_metadata_sync_bridge.cc b/components/autofill/core/browser/webdata/payments/autofill_wallet_metadata_sync_bridge.cc
index cb52e369..7377d61 100644
--- a/components/autofill/core/browser/webdata/payments/autofill_wallet_metadata_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/payments/autofill_wallet_metadata_sync_bridge.cc
@@ -16,6 +16,7 @@
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/pickle.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.cc b/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.cc
index 1b38f2e0..78123b8 100644
--- a/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.cc
@@ -13,6 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/autofill/core/browser/data_model/payments/bank_account.h"
diff --git a/components/autofill/ios/browser/autofill_driver_ios.mm b/components/autofill/ios/browser/autofill_driver_ios.mm
index 0675239..bbecffb4 100644
--- a/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -16,6 +16,7 @@
 #import "base/memory/weak_ptr.h"
 #import "base/metrics/histogram.h"
 #import "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #import "base/observer_list.h"
 #import "components/autofill/core/browser/filling/form_filler.h"
 #import "components/autofill/core/browser/form_structure.h"
diff --git a/components/cast_streaming/browser/control/renderer_control_multiplexer.cc b/components/cast_streaming/browser/control/renderer_control_multiplexer.cc
index 334120b..74b5d33 100644
--- a/components/cast_streaming/browser/control/renderer_control_multiplexer.cc
+++ b/components/cast_streaming/browser/control/renderer_control_multiplexer.cc
@@ -4,6 +4,7 @@
 
 #include "components/cast_streaming/browser/control/renderer_control_multiplexer.h"
 
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
diff --git a/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc b/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc
index 1db9121..7b8067c 100644
--- a/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc
+++ b/components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc
@@ -5,6 +5,7 @@
 #include "components/cast_streaming/renderer/control/playback_command_forwarding_renderer.h"
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc b/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc
index a3bd8e4..a4d6977ff 100644
--- a/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc
+++ b/components/chromeos_camera/fake_mjpeg_decode_accelerator.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/single_thread_task_runner.h"
 #include "media/base/video_frame.h"
diff --git a/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc b/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc
index bc1f7fe6..9269556 100644
--- a/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc
+++ b/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc
@@ -16,6 +16,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/components/component_updater/ash/fake_component_manager_ash.cc b/components/component_updater/ash/fake_component_manager_ash.cc
index f0d5155..55c93b4 100644
--- a/components/component_updater/ash/fake_component_manager_ash.cc
+++ b/components/component_updater/ash/fake_component_manager_ash.cc
@@ -10,6 +10,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/version.h"
 
diff --git a/components/consent_auditor/fake_consent_auditor.cc b/components/consent_auditor/fake_consent_auditor.cc
index 8ef4e8d..f0e60da 100644
--- a/components/consent_auditor/fake_consent_auditor.cc
+++ b/components/consent_auditor/fake_consent_auditor.cc
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/consent_auditor/fake_consent_auditor.h"
+
 #include <string>
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "components/consent_auditor/consent_auditor.h"
-#include "components/consent_auditor/fake_consent_auditor.h"
 #include "components/sync/protocol/user_consent_specifics.pb.h"
 #include "components/sync/protocol/user_consent_types.pb.h"
 
diff --git a/components/constrained_window/constrained_window_views.cc b/components/constrained_window/constrained_window_views.cc
index ca7bbaf2..521974d 100644
--- a/components/constrained_window/constrained_window_views.cc
+++ b/components/constrained_window/constrained_window_views.cc
@@ -80,17 +80,11 @@
     }
   }
   void OnHostDestroying() override {
-    auto self = weak_ptr_factory_.GetWeakPtr();
-    dialog_widget_->Close();
-
-    // Widget::Close() might synchronously destroy the widget and `this`,
-    // e.g. if Widget::MakeCloseSynchronous() is used.
-    if (!self) {
-      return;
-    }
-
+    // Synchronously close the dialog widget to avoid dangling references to the
+    // host.
     modal_dialog_host_observation_.Reset();
     host_ = nullptr;
+    dialog_widget_->CloseNow();
   }
 
  private:
@@ -105,8 +99,6 @@
 
   base::ScopedObservation<ModalDialogHost, ModalDialogHostObserver>
       modal_dialog_host_observation_{this};
-
-  base::WeakPtrFactory<ModalDialogHostObserverViews> weak_ptr_factory_{this};
 };
 
 gfx::Rect GetModalDialogBounds(views::Widget* widget,
diff --git a/components/cronet/cronet_global_state_stubs.cc b/components/cronet/cronet_global_state_stubs.cc
index e1162a78..feb6bd5 100644
--- a/components/cronet/cronet_global_state_stubs.cc
+++ b/components/cronet/cronet_global_state_stubs.cc
@@ -8,6 +8,7 @@
 
 #include "base/at_exit.h"
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
diff --git a/components/dbus/menu/menu_property_list.cc b/components/dbus/menu/menu_property_list.cc
index 4098374..bb7269f 100644
--- a/components/dbus/menu/menu_property_list.cc
+++ b/components/dbus/menu/menu_property_list.cc
@@ -9,6 +9,7 @@
 
 #include "base/containers/contains.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "ui/base/accelerators/accelerator.h"
diff --git a/components/dbus/menu/menu_property_list_unittest.cc b/components/dbus/menu/menu_property_list_unittest.cc
index d829b44..4134bc2e 100644
--- a/components/dbus/menu/menu_property_list_unittest.cc
+++ b/components/dbus/menu/menu_property_list_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/memory/ref_counted_memory.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
diff --git a/components/dbus/properties/dbus_properties.cc b/components/dbus/properties/dbus_properties.cc
index d02773934..3f9ca989 100644
--- a/components/dbus/properties/dbus_properties.cc
+++ b/components/dbus/properties/dbus_properties.cc
@@ -8,6 +8,7 @@
 
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "components/dbus/properties/success_barrier_callback.h"
 #include "dbus/exported_object.h"
 #include "dbus/message.h"
diff --git a/components/device_reauth/device_authenticator_common_unittest.cc b/components/device_reauth/device_authenticator_common_unittest.cc
index 4225540..8efcb3348 100644
--- a/components/device_reauth/device_authenticator_common_unittest.cc
+++ b/components/device_reauth/device_authenticator_common_unittest.cc
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "components/device_reauth/device_authenticator.h"
diff --git a/components/download/internal/background_service/ios/background_download_task_helper.mm b/components/download/internal/background_service/ios/background_download_task_helper.mm
index e70de60..b688695 100644
--- a/components/download/internal/background_service/ios/background_download_task_helper.mm
+++ b/components/download/internal/background_service/ios/background_download_task_helper.mm
@@ -16,6 +16,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
index 807f43c..19d24499 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -10,6 +10,7 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "components/embedder_support/android/delegate/color_picker_bridge.h"
 #include "components/input/native_web_keyboard_event.h"
diff --git a/components/enterprise/client_certificates/core/ec_private_key.cc b/components/enterprise/client_certificates/core/ec_private_key.cc
index 4e996d1b..174ab8f56 100644
--- a/components/enterprise/client_certificates/core/ec_private_key.cc
+++ b/components/enterprise/client_certificates/core/ec_private_key.cc
@@ -11,43 +11,29 @@
 #include "base/check.h"
 #include "components/enterprise/client_certificates/core/private_key_types.h"
 #include "components/enterprise/client_certificates/core/ssl_key_converter.h"
-#include "crypto/ec_private_key.h"
-#include "crypto/ec_signature_creator.h"
+#include "crypto/keypair.h"
+#include "crypto/sign.h"
 #include "net/ssl/openssl_private_key.h"
 #include "net/ssl/ssl_private_key.h"
 #include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace client_certificates {
 
-ECPrivateKey::ECPrivateKey(std::unique_ptr<crypto::ECPrivateKey> key)
+ECPrivateKey::ECPrivateKey(crypto::keypair::PrivateKey key)
     : PrivateKey(PrivateKeySource::kSoftwareKey,
-                 net::WrapOpenSSLPrivateKey(bssl::UpRef(key->key()))),
-      key_(std::move(key)) {
-  CHECK(key_);
-}
+                 net::WrapOpenSSLPrivateKey(bssl::UpRef(key.key()))),
+      key_(std::move(key)) {}
 
 ECPrivateKey::~ECPrivateKey() = default;
 
 std::optional<std::vector<uint8_t>> ECPrivateKey::SignSlowly(
     base::span<const uint8_t> data) const {
-  auto signer = crypto::ECSignatureCreator::Create(key_.get());
-  if (!signer) {
-    return std::nullopt;
-  }
-
-  std::vector<uint8_t> signature;
-  if (!signer->Sign(data, &signature)) {
-    return std::nullopt;
-  }
-  return signature;
+  return crypto::sign::Sign(crypto::sign::SignatureKind::ECDSA_SHA256, key_,
+                            data);
 }
 
 std::vector<uint8_t> ECPrivateKey::GetSubjectPublicKeyInfo() const {
-  std::vector<uint8_t> pubkey;
-  if (!key_->ExportPublicKey(&pubkey)) {
-    return std::vector<uint8_t>();
-  }
-  return pubkey;
+  return key_.ToSubjectPublicKeyInfo();
 }
 
 crypto::SignatureVerifier::SignatureAlgorithm ECPrivateKey::GetAlgorithm()
@@ -59,20 +45,14 @@
   client_certificates_pb::PrivateKey private_key;
   private_key.set_source(ToProtoKeySource(source_));
 
-  std::vector<uint8_t> wrapped;
-  key_->ExportPrivateKey(&wrapped);
+  std::vector<uint8_t> wrapped = key_.ToPrivateKeyInfo();
   private_key.set_wrapped_key(std::string(wrapped.begin(), wrapped.end()));
 
   return private_key;
 }
 
 base::Value::Dict ECPrivateKey::ToDict() const {
-  std::vector<uint8_t> wrapped;
-  if (!key_->ExportPrivateKey(&wrapped)) {
-    return base::Value::Dict();
-  }
-
-  return BuildSerializedPrivateKey(wrapped);
+  return BuildSerializedPrivateKey(key_.ToPrivateKeyInfo());
 }
 
 }  // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/ec_private_key.h b/components/enterprise/client_certificates/core/ec_private_key.h
index ea325c9..c1df0da 100644
--- a/components/enterprise/client_certificates/core/ec_private_key.h
+++ b/components/enterprise/client_certificates/core/ec_private_key.h
@@ -10,16 +10,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/values.h"
 #include "components/enterprise/client_certificates/core/private_key.h"
-
-namespace crypto {
-class ECPrivateKey;
-}  // namespace crypto
+#include "crypto/keypair.h"
 
 namespace client_certificates {
 
 class ECPrivateKey : public PrivateKey {
  public:
-  explicit ECPrivateKey(std::unique_ptr<crypto::ECPrivateKey> key);
+  explicit ECPrivateKey(crypto::keypair::PrivateKey key);
 
   // PrivateKey:
   std::optional<std::vector<uint8_t>> SignSlowly(
@@ -34,7 +31,7 @@
 
   ~ECPrivateKey() override;
 
-  std::unique_ptr<crypto::ECPrivateKey> key_;
+  crypto::keypair::PrivateKey key_;
 };
 
 }  // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/ec_private_key_factory.cc b/components/enterprise/client_certificates/core/ec_private_key_factory.cc
index 52d769d..d8e0d6a 100644
--- a/components/enterprise/client_certificates/core/ec_private_key_factory.cc
+++ b/components/enterprise/client_certificates/core/ec_private_key_factory.cc
@@ -18,7 +18,7 @@
 #include "components/enterprise/client_certificates/core/ec_private_key.h"
 #include "components/enterprise/client_certificates/core/private_key.h"
 #include "components/enterprise/client_certificates/core/private_key_types.h"
-#include "crypto/ec_private_key.h"
+#include "crypto/keypair.h"
 #include "net/ssl/ssl_private_key.h"
 
 namespace client_certificates {
@@ -26,22 +26,18 @@
 namespace {
 
 scoped_refptr<ECPrivateKey> CreateKey() {
-  auto key = crypto::ECPrivateKey::Create();
-  if (!key) {
-    return nullptr;
-  }
-
-  return base::MakeRefCounted<ECPrivateKey>(std::move(key));
+  return base::MakeRefCounted<ECPrivateKey>(
+      crypto::keypair::PrivateKey::GenerateEcP256());
 }
 
 scoped_refptr<ECPrivateKey> LoadKeyFromWrapped(
     const std::vector<uint8_t>& wrapped_key) {
-  auto key = crypto::ECPrivateKey::CreateFromPrivateKeyInfo(wrapped_key);
-  if (!key) {
+  auto key = crypto::keypair::PrivateKey::FromPrivateKeyInfo(wrapped_key);
+  if (!key || !key->IsEc()) {
     return nullptr;
   }
 
-  return base::MakeRefCounted<ECPrivateKey>(std::move(key));
+  return base::MakeRefCounted<ECPrivateKey>(std::move(*key));
 }
 
 }  // namespace
diff --git a/components/enterprise/client_certificates/core/ec_private_key_factory_unittest.cc b/components/enterprise/client_certificates/core/ec_private_key_factory_unittest.cc
index 01eb2bc..018a0a7a 100644
--- a/components/enterprise/client_certificates/core/ec_private_key_factory_unittest.cc
+++ b/components/enterprise/client_certificates/core/ec_private_key_factory_unittest.cc
@@ -13,7 +13,7 @@
 #include "components/enterprise/client_certificates/core/private_key.h"
 #include "components/enterprise/client_certificates/core/private_key_types.h"
 #include "components/enterprise/client_certificates/core/scoped_ssl_key_converter.h"
-#include "crypto/ec_private_key.h"
+#include "crypto/keypair.h"
 #include "net/ssl/ssl_private_key.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/enterprise/client_certificates/core/ec_private_key_unittest.cc b/components/enterprise/client_certificates/core/ec_private_key_unittest.cc
index d054b96..aa2a389 100644
--- a/components/enterprise/client_certificates/core/ec_private_key_unittest.cc
+++ b/components/enterprise/client_certificates/core/ec_private_key_unittest.cc
@@ -7,15 +7,15 @@
 #include "base/memory/scoped_refptr.h"
 #include "components/enterprise/client_certificates/core/constants.h"
 #include "components/enterprise/client_certificates/core/private_key.h"
-#include "crypto/ec_private_key.h"
+#include "crypto/keypair.h"
 #include "net/ssl/ssl_private_key.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace client_certificates {
 
 TEST(ECPrivateKeyTest, KeyWorksAsExpected) {
-  auto ec_private_key =
-      base::MakeRefCounted<ECPrivateKey>(crypto::ECPrivateKey::Create());
+  auto ec_private_key = base::MakeRefCounted<ECPrivateKey>(
+      crypto::keypair::PrivateKey::GenerateEcP256());
 
   EXPECT_EQ(ec_private_key->GetAlgorithm(),
             crypto::SignatureVerifier::ECDSA_SHA256);
diff --git a/components/enterprise/client_certificates/core/ssl_key_converter.h b/components/enterprise/client_certificates/core/ssl_key_converter.h
index 3e59a23..6f0c4e2b 100644
--- a/components/enterprise/client_certificates/core/ssl_key_converter.h
+++ b/components/enterprise/client_certificates/core/ssl_key_converter.h
@@ -7,7 +7,6 @@
 
 #include "base/functional/callback.h"
 #include "base/memory/scoped_refptr.h"
-#include "crypto/ec_private_key.h"
 #include "crypto/unexportable_key.h"
 
 namespace net {
diff --git a/components/enterprise/connectors/core/reporting_constants.h b/components/enterprise/connectors/core/reporting_constants.h
index a05dec9..2d48bf2 100644
--- a/components/enterprise/connectors/core/reporting_constants.h
+++ b/components/enterprise/connectors/core/reporting_constants.h
@@ -30,6 +30,13 @@
 inline constexpr char kKeyLoginEvent[] = "loginEvent";
 inline constexpr char kKeyPasswordBreachEvent[] = "passwordBreachEvent";
 
+inline constexpr char kEnterpriseWarnedSeenThreatType[] =
+    "ENTERPRISE_WARNED_SEEN";
+inline constexpr char kEnterpriseWarnedBypassTheatType[] =
+    "ENTERPRISE_WARNED_BYPASS";
+inline constexpr char kEnterpriseBlockedSeenThreatType[] =
+    "ENTERPRISE_BLOCKED_SEEN";
+
 // All the reporting events that can be set in the `enabled_events_names` field
 // of `ReportingSettings`
 inline constexpr std::array<const char*, 9> kAllReportingEnabledEvents = {
diff --git a/components/enterprise/connectors/core/reporting_utils.cc b/components/enterprise/connectors/core/reporting_utils.cc
index e1972ad..c043fdd 100644
--- a/components/enterprise/connectors/core/reporting_utils.cc
+++ b/components/enterprise/connectors/core/reporting_utils.cc
@@ -11,6 +11,7 @@
 #include "components/enterprise/connectors/core/common.h"
 #include "components/enterprise/connectors/core/reporting_constants.h"
 #include "components/safe_browsing/core/common/features.h"
+#include "components/safe_browsing/core/common/proto/realtimeapi.pb.h"
 #include "components/url_matcher/url_util.h"
 #include "net/base/network_interfaces.h"
 
@@ -29,6 +30,11 @@
 using InterstitialReason = ::chrome::cros::reporting::proto::
     SafeBrowsingInterstitialEvent::InterstitialReason;
 
+// Alias to reduce verbosity when using
+//  UrlFilteringInterstitialEvent::InterstitialThreatType;
+using InterstitialThreatType = ::chrome::cros::reporting::proto::
+    UrlFilteringInterstitialEvent::InterstitialThreatType;
+
 // Alias to reduce verbosity when using EventResult and to differentiate from
 // the EventResult struct.
 using ProtoEventResult = ::chrome::cros::reporting::proto::EventResult;
@@ -82,6 +88,38 @@
   }
 }
 
+proto::TriggeredRuleInfo::Action ActionProtoFromVerdictType(
+    safe_browsing::RTLookupResponse::ThreatInfo::VerdictType verdict_type) {
+  switch (verdict_type) {
+    case safe_browsing::RTLookupResponse::ThreatInfo::DANGEROUS:
+      return proto::TriggeredRuleInfo::BLOCK;
+    case safe_browsing::RTLookupResponse::ThreatInfo::WARN:
+      return proto::TriggeredRuleInfo::WARN;
+    case safe_browsing::RTLookupResponse::ThreatInfo::SAFE:
+      return proto::TriggeredRuleInfo::REPORT_ONLY;
+    case safe_browsing::RTLookupResponse::ThreatInfo::SUSPICIOUS:
+    case safe_browsing::RTLookupResponse::ThreatInfo::VERDICT_TYPE_UNSPECIFIED:
+      return proto::TriggeredRuleInfo::ACTION_UNKNOWN;
+  }
+}
+
+InterstitialThreatType ConvertThreatTypeToProto(std::string threat_type) {
+  if (threat_type == kEnterpriseWarnedSeenThreatType) {
+    return proto::UrlFilteringInterstitialEvent::ENTERPRISE_WARNED_SEEN;
+  }
+  if (threat_type == kEnterpriseWarnedBypassTheatType) {
+    return proto::UrlFilteringInterstitialEvent::ENTERPRISE_WARNED_BYPASS;
+  }
+  if (threat_type == kEnterpriseBlockedSeenThreatType) {
+    return proto::UrlFilteringInterstitialEvent::ENTERPRISE_BLOCKED_SEEN;
+  }
+  if (threat_type.empty()) {
+    return proto::UrlFilteringInterstitialEvent::
+        UNKNOWN_INTERSTITIAL_THREAT_TYPE;
+  }
+  NOTREACHED();
+}
+
 }  // namespace
 
 std::string MaskUsername(const std::u16string& username) {
@@ -124,13 +162,13 @@
 }
 
 EventResult GetEventResultFromThreatType(std::string threat_type) {
-  if (threat_type == "ENTERPRISE_WARNED_SEEN") {
+  if (threat_type == kEnterpriseWarnedSeenThreatType) {
     return EventResult::WARNED;
   }
-  if (threat_type == "ENTERPRISE_WARNED_BYPASS") {
+  if (threat_type == kEnterpriseWarnedBypassTheatType) {
     return EventResult::BYPASSED;
   }
-  if (threat_type == "ENTERPRISE_BLOCKED_SEEN") {
+  if (threat_type == kEnterpriseBlockedSeenThreatType) {
     return EventResult::BLOCKED;
   }
   if (threat_type.empty()) {
@@ -139,6 +177,23 @@
   NOTREACHED();
 }
 
+proto::TriggeredRuleInfo ConvertMatchedUrlNavigationRuleToTriggeredRuleInfo(
+    const safe_browsing::MatchedUrlNavigationRule& navigation_rule,
+    const safe_browsing::RTLookupResponse::ThreatInfo::VerdictType&
+        verdict_type) {
+  proto::TriggeredRuleInfo triggered_rule_info;
+  triggered_rule_info.set_rule_name(navigation_rule.rule_name());
+  int rule_id = 0;
+  if (base::StringToInt(navigation_rule.rule_id(), &rule_id)) {
+    triggered_rule_info.set_rule_id(rule_id);
+  }
+  triggered_rule_info.set_url_category(navigation_rule.matched_url_category());
+  triggered_rule_info.set_action(ActionProtoFromVerdictType(verdict_type));
+  triggered_rule_info.set_has_watermarking(
+      navigation_rule.has_watermark_message());
+  return triggered_rule_info;
+}
+
 void AddTriggeredRuleInfoToUrlFilteringInterstitialEvent(
     const safe_browsing::RTLookupResponse& response,
     base::Value::Dict& event) {
@@ -266,7 +321,51 @@
   if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
     for (const auto& referrer : referrer_chain) {
       proto::UrlInfo url_info;
-      url_info.set_ip(referrer.ip_addresses()[0]);
+      if (referrer.ip_addresses().size() > 0) {
+        url_info.set_ip(referrer.ip_addresses()[0]);
+      }
+      url_info.set_url(referrer.url());
+      *event.add_referrers() = url_info;
+    }
+  }
+
+  return event;
+}
+
+proto::UrlFilteringInterstitialEvent GetUrlFilteringInterstitialEvent(
+    const GURL& url,
+    const std::string& threat_type,
+    const safe_browsing::RTLookupResponse& response,
+    const std::string& profile_identifier,
+    const std::string& profile_username,
+    const ReferrerChain& referrer_chain) {
+  proto::UrlFilteringInterstitialEvent event;
+  event.set_url(url.spec());
+  EventResult event_result = GetEventResultFromThreatType(threat_type);
+  event.set_clicked_through(event_result ==
+                            enterprise_connectors::EventResult::BYPASSED);
+  if (!threat_type.empty()) {
+    event.set_threat_type(ConvertThreatTypeToProto(threat_type));
+  }
+  event.set_event_result(GetEventResult(event_result));
+  event.set_profile_identifier(profile_identifier);
+  event.set_profile_user_name(profile_username);
+
+  for (const safe_browsing::RTLookupResponse::ThreatInfo& threat_info :
+       response.threat_info()) {
+    proto::TriggeredRuleInfo triggered_rule_info =
+        ConvertMatchedUrlNavigationRuleToTriggeredRuleInfo(
+            threat_info.matched_url_navigation_rule(),
+            threat_info.verdict_type());
+    *event.add_triggered_rule_info() = triggered_rule_info;
+  }
+
+  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
+    for (const auto& referrer : referrer_chain) {
+      proto::UrlInfo url_info;
+      if (referrer.ip_addresses().size() > 0) {
+        url_info.set_ip(referrer.ip_addresses()[0]);
+      }
       url_info.set_url(referrer.url());
       *event.add_referrers() = url_info;
     }
diff --git a/components/enterprise/connectors/core/reporting_utils.h b/components/enterprise/connectors/core/reporting_utils.h
index cd14090..f38f40af 100644
--- a/components/enterprise/connectors/core/reporting_utils.h
+++ b/components/enterprise/connectors/core/reporting_utils.h
@@ -89,6 +89,15 @@
                      const std::string& profile_username,
                      const ReferrerChain& referrer_chain);
 
+chrome::cros::reporting::proto::UrlFilteringInterstitialEvent
+GetUrlFilteringInterstitialEvent(
+    const GURL& url,
+    const std::string& threat_type,
+    const safe_browsing::RTLookupResponse& response,
+    const std::string& profile_identifier,
+    const std::string& profile_username,
+    const ReferrerChain& referrer_chain);
+
 chrome::cros::reporting::proto::BrowserCrashEvent GetBrowserCrashEvent(
     const std::string& channel,
     const std::string& version,
diff --git a/components/enterprise/connectors/core/reporting_utils_unittest.cc b/components/enterprise/connectors/core/reporting_utils_unittest.cc
index 51b505a..26ef694d 100644
--- a/components/enterprise/connectors/core/reporting_utils_unittest.cc
+++ b/components/enterprise/connectors/core/reporting_utils_unittest.cc
@@ -138,6 +138,57 @@
   }
 }
 
+TEST(ReportingUtilsTest, GetUrlFilteringInterstitialEvent) {
+  ReferrerChain referrer_chain;
+  referrer_chain.Add(test::MakeReferrerChainEntry());
+
+  safe_browsing::RTLookupResponse response;
+  auto* threat_info = response.add_threat_info();
+  threat_info->set_verdict_type(
+      safe_browsing::RTLookupResponse::ThreatInfo::DANGEROUS);
+  auto* matched_url_navigation_rule =
+      threat_info->mutable_matched_url_navigation_rule();
+  matched_url_navigation_rule->set_rule_id("123");
+  matched_url_navigation_rule->set_rule_name("test rule name");
+  matched_url_navigation_rule->set_matched_url_category("test rule category");
+
+  auto event = GetUrlFilteringInterstitialEvent(
+      /*url=*/GURL("https://filteredurl.com"),
+      /*threat_type=*/"ENTERPRISE_BLOCKED_SEEN", /*response=*/response,
+      /*profile_identifier=*/"identifier",
+      /*profile_username=*/"profile_username",
+      /*referrer_chain=*/referrer_chain);
+
+  ASSERT_EQ(event.url(), "https://filteredurl.com/");
+  ASSERT_FALSE(event.clicked_through());
+  ASSERT_EQ(event.threat_type(),
+            chrome::cros::reporting::proto::UrlFilteringInterstitialEvent::
+                ENTERPRISE_BLOCKED_SEEN);
+  ASSERT_EQ(event.event_result(),
+            chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BLOCKED);
+  ASSERT_EQ(event.triggered_rule_info_size(), 1);
+
+  chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule_info =
+      event.mutable_triggered_rule_info()->at(0);
+  ASSERT_EQ(triggered_rule_info.rule_name(), "test rule name");
+  ASSERT_EQ(triggered_rule_info.rule_id(), 123);
+  ASSERT_EQ(triggered_rule_info.url_category(), "test rule category");
+  ASSERT_EQ(triggered_rule_info.action(),
+            chrome::cros::reporting::proto::TriggeredRuleInfo::BLOCK);
+  ASSERT_FALSE(triggered_rule_info.has_watermarking());
+  ASSERT_EQ(event.profile_identifier(), "identifier");
+  ASSERT_EQ(event.profile_user_name(), "profile_username");
+
+  if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
+    ASSERT_EQ(event.referrers_size(), 1);
+    auto referrer = event.referrers()[0];
+    ASSERT_EQ(referrer.url(), "https://referrer.com");
+    ASSERT_EQ(referrer.ip(), "1.2.3.4");
+  } else {
+    ASSERT_EQ(event.referrers_size(), 0);
+  }
+}
+
 TEST(ReportingUtilsTest, GetBrowserCrashEvent) {
   auto event =
       GetBrowserCrashEvent(/*channel=*/"canary", /*version=*/"100.0.0000.000",
diff --git a/components/error_page/common/alt_game_images.cc b/components/error_page/common/alt_game_images.cc
index eeea6e0..f970ad1 100644
--- a/components/error_page/common/alt_game_images.cc
+++ b/components/error_page/common/alt_game_images.cc
@@ -11,6 +11,7 @@
 #include "base/base64url.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/strings/string_util.h"
 #include "components/error_page/common/alt_game_image_data.h"
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 8202d40..8e5bb18 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -25,6 +25,7 @@
 #include "base/containers/flat_set.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc
index 61d399f..5c05a983 100644
--- a/components/exo/test/exo_test_helper.cc
+++ b/components/exo/test/exo_test_helper.cc
@@ -10,6 +10,7 @@
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/window_positioner.h"
 #include "ash/wm/window_positioning_utils.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/test/bind.h"
 #include "base/test/test_future.h"
diff --git a/components/exo/text_input.cc b/components/exo/text_input.cc
index af9936b2..1811676 100644
--- a/components/exo/text_input.cc
+++ b/components/exo/text_input.cc
@@ -10,6 +10,7 @@
 
 #include "base/check.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_offset_string_conversions.h"
 #include "components/exo/seat.h"
 #include "components/exo/shell_surface_util.h"
diff --git a/components/exo/wayland/wl_seat.cc b/components/exo/wayland/wl_seat.cc
index 31bbe0e..76789ff 100644
--- a/components/exo/wayland/wl_seat.cc
+++ b/components/exo/wayland/wl_seat.cc
@@ -4,6 +4,7 @@
 
 #include "components/exo/wayland/wl_seat.h"
 
+#include "base/notimplemented.h"
 #include "components/exo/keyboard.h"
 #include "components/exo/pointer.h"
 #include "components/exo/touch.h"
diff --git a/components/exo/wayland/wl_shell.cc b/components/exo/wayland/wl_shell.cc
index fa7ea6346..3378272e 100644
--- a/components/exo/wayland/wl_shell.cc
+++ b/components/exo/wayland/wl_shell.cc
@@ -9,6 +9,7 @@
 
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/exo/display.h"
 #include "components/exo/shell_surface.h"
diff --git a/components/exo/wayland/xdg_shell.cc b/components/exo/wayland/xdg_shell.cc
index d330d43..861b001 100644
--- a/components/exo/wayland/xdg_shell.cc
+++ b/components/exo/wayland/xdg_shell.cc
@@ -15,6 +15,7 @@
 #include "ash/public/cpp/window_properties.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/ui/base/window_state_type.h"
 #include "components/exo/display.h"
diff --git a/components/exo/wayland/zaura_shell.cc b/components/exo/wayland/zaura_shell.cc
index 1fa7ec7..ece7433 100644
--- a/components/exo/wayland/zaura_shell.cc
+++ b/components/exo/wayland/zaura_shell.cc
@@ -31,6 +31,7 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/ui/base/window_properties.h"
diff --git a/components/exo/wayland/zcr_alpha_compositing.cc b/components/exo/wayland/zcr_alpha_compositing.cc
index 3afc508..38002a9 100644
--- a/components/exo/wayland/zcr_alpha_compositing.cc
+++ b/components/exo/wayland/zcr_alpha_compositing.cc
@@ -7,6 +7,7 @@
 #include <alpha-compositing-unstable-v1-server-protocol.h>
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "components/exo/surface.h"
 #include "components/exo/surface_observer.h"
 #include "components/exo/wayland/server_util.h"
diff --git a/components/exo/wayland/zcr_color_manager.cc b/components/exo/wayland/zcr_color_manager.cc
index 73a844a..a22d8e22 100644
--- a/components/exo/wayland/zcr_color_manager.cc
+++ b/components/exo/wayland/zcr_color_manager.cc
@@ -14,7 +14,7 @@
 #include "ash/shell.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "components/exo/surface.h"
 #include "components/exo/surface_observer.h"
diff --git a/components/exo/wayland/zcr_notification_shell.cc b/components/exo/wayland/zcr_notification_shell.cc
index 0296688..045999f5 100644
--- a/components/exo/wayland/zcr_notification_shell.cc
+++ b/components/exo/wayland/zcr_notification_shell.cc
@@ -19,6 +19,7 @@
 #include "base/atomic_sequence_num.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "components/exo/notification.h"
 #include "components/exo/notification_surface.h"
diff --git a/components/exo/wayland/zcr_remote_shell_impl.cc b/components/exo/wayland/zcr_remote_shell_impl.cc
index 8024e43..fa4f9595 100644
--- a/components/exo/wayland/zcr_remote_shell_impl.cc
+++ b/components/exo/wayland/zcr_remote_shell_impl.cc
@@ -10,6 +10,7 @@
 #include "ash/wm/window_resizer.h"
 #include "base/bit_cast.h"
 #include "base/command_line.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/components/exo/wayland/zwp_pointer_gestures.cc b/components/exo/wayland/zwp_pointer_gestures.cc
index 85f08b2..8235aa62 100644
--- a/components/exo/wayland/zwp_pointer_gestures.cc
+++ b/components/exo/wayland/zwp_pointer_gestures.cc
@@ -9,6 +9,7 @@
 #include <wayland-server-protocol-core.h>
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "components/exo/pointer.h"
 #include "components/exo/pointer_gesture_pinch_delegate.h"
 #include "components/exo/surface.h"
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
index 27bf813..8dd17b8e 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
@@ -591,6 +591,14 @@
 
     @Override
     public void onResourceRequestWithGesture() {
+        // Browser-initiated navigations race against renderer-initiated resource requests.
+        // It should be fine to just drop the resource request as it is from the previous page.
+        // In rare cases this could theoretically arrive after a browser-initiated navigation
+        // completes and allow an external navigation that shouldn't have been allowed but this
+        // isn't exploitable so should be fine and not worth all of the complexity required to
+        // properly fix it.
+        if (mPendingShouldIgnore != null) return;
+
         // LINK is the default transition type, and is generally used for everything coming from a
         // renderer that isn't a form submission (or subframe).
         @PageTransition int transition = PageTransition.LINK;
diff --git a/components/facilitated_payments/android/device_delegate_android.cc b/components/facilitated_payments/android/device_delegate_android.cc
index d02fe3d..2327b9d 100644
--- a/components/facilitated_payments/android/device_delegate_android.cc
+++ b/components/facilitated_payments/android/device_delegate_android.cc
@@ -13,20 +13,25 @@
 
 namespace payments::facilitated {
 
-bool IsWalletEligibleForPixAccountLinking() {
+DeviceDelegateAndroid::DeviceDelegateAndroid(content::WebContents* web_contents)
+    : web_contents_(web_contents->GetWeakPtr()) {}
+
+DeviceDelegateAndroid::~DeviceDelegateAndroid() = default;
+
+bool DeviceDelegateAndroid::IsPixAccountLinkingSupported() const {
   JNIEnv* env = base::android::AttachCurrentThread();
   return Java_DeviceDelegate_isWalletEligibleForPixAccountLinking(env);
 }
 
-void OpenPixAccountLinkingPageInWallet(content::WebContents* web_contents) {
-  if (!web_contents || !web_contents->GetNativeView() ||
-      !web_contents->GetNativeView()->GetWindowAndroid()) {
+void DeviceDelegateAndroid::LaunchPixAccountLinkingPage() {
+  if (!web_contents_ || !web_contents_->GetNativeView() ||
+      !web_contents_->GetNativeView()->GetWindowAndroid()) {
     // TODO(crbug.com/419108993): Log metrics.
     return;
   }
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_DeviceDelegate_openPixAccountLinkingPageInWallet(
-      env, web_contents->GetTopLevelNativeWindow()->GetJavaObject());
+      env, web_contents_->GetTopLevelNativeWindow()->GetJavaObject());
 }
 
 }  // namespace payments::facilitated
diff --git a/components/facilitated_payments/android/device_delegate_android.h b/components/facilitated_payments/android/device_delegate_android.h
index 988a9ee..163ed48 100644
--- a/components/facilitated_payments/android/device_delegate_android.h
+++ b/components/facilitated_payments/android/device_delegate_android.h
@@ -5,16 +5,30 @@
 #ifndef COMPONENTS_FACILITATED_PAYMENTS_ANDROID_DEVICE_DELEGATE_ANDROID_H_
 #define COMPONENTS_FACILITATED_PAYMENTS_ANDROID_DEVICE_DELEGATE_ANDROID_H_
 
+#include "base/memory/weak_ptr.h"
+#include "components/facilitated_payments/core/browser/device_delegate.h"
 #include "content/public/browser/web_contents.h"
 
 namespace payments::facilitated {
 
-// Returns true if Google Wallet is installed, and its version supports Pix
-// account linking.
-bool IsWalletEligibleForPixAccountLinking();
+// Android implementation of `DeviceDelegate`.
+class DeviceDelegateAndroid : public DeviceDelegate {
+ public:
+  explicit DeviceDelegateAndroid(content::WebContents* web_contents);
+  DeviceDelegateAndroid(const DeviceDelegateAndroid&) = delete;
+  DeviceDelegateAndroid& operator=(const DeviceDelegateAndroid&) = delete;
+  ~DeviceDelegateAndroid() override;
 
-// Opens the Pix account linking page in Google Wallet.
-void OpenPixAccountLinkingPageInWallet(content::WebContents* web_contents);
+  // Returns true if Google Wallet is installed, and its version supports Pix
+  // account linking.
+  bool IsPixAccountLinkingSupported() const override;
+
+  // Opens the Pix account linking page in Google Wallet.
+  void LaunchPixAccountLinkingPage() override;
+
+ private:
+  base::WeakPtr<content::WebContents> web_contents_;
+};
 
 }  // namespace payments::facilitated
 
diff --git a/components/facilitated_payments/core/browser/BUILD.gn b/components/facilitated_payments/core/browser/BUILD.gn
index dcd4208..16310b4 100644
--- a/components/facilitated_payments/core/browser/BUILD.gn
+++ b/components/facilitated_payments/core/browser/BUILD.gn
@@ -4,6 +4,7 @@
 
 static_library("browser") {
   sources = [
+    "device_delegate.h",
     "facilitated_payments_api_client.h",
     "facilitated_payments_client.cc",
     "facilitated_payments_client.h",
@@ -83,6 +84,8 @@
 static_library("test_support") {
   testonly = true
   sources = [
+    "mock_device_delegate.cc",
+    "mock_device_delegate.h",
     "mock_facilitated_payments_api_client.cc",
     "mock_facilitated_payments_api_client.h",
     "mock_facilitated_payments_client.cc",
diff --git a/components/facilitated_payments/core/browser/device_delegate.h b/components/facilitated_payments/core/browser/device_delegate.h
new file mode 100644
index 0000000..e3af55eb
--- /dev/null
+++ b/components/facilitated_payments/core/browser/device_delegate.h
@@ -0,0 +1,29 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_DEVICE_DELEGATE_H_
+#define COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_DEVICE_DELEGATE_H_
+
+namespace payments::facilitated {
+
+// Abstract base class for device-specific facilitated payments operations.
+// This class defines the interface for operations that require interaction
+// with the underlying device or platform, such as checking and opening other
+// applications.
+
+// It is owned by FacilitatedPaymentsClient, and has the same lifecycle.
+class DeviceDelegate {
+ public:
+  virtual ~DeviceDelegate() = default;
+
+  // Returns true if Pix account linking is supported by the device.
+  virtual bool IsPixAccountLinkingSupported() const = 0;
+
+  // Takes user to the Pix account linking page.
+  virtual void LaunchPixAccountLinkingPage() = 0;
+};
+
+}  // namespace payments::facilitated
+
+#endif  // COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_DEVICE_DELEGATE_H_
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_client.cc b/components/facilitated_payments/core/browser/facilitated_payments_client.cc
index 513d0ab..0cc705d 100644
--- a/components/facilitated_payments/core/browser/facilitated_payments_client.cc
+++ b/components/facilitated_payments/core/browser/facilitated_payments_client.cc
@@ -43,16 +43,10 @@
   pix_account_linking_manager_->MaybeShowPixAccountLinkingPrompt();
 }
 
-bool FacilitatedPaymentsClient::IsPixAccountLinkingSupported() const {
-  return false;
-}
-
 void FacilitatedPaymentsClient::ShowPixAccountLinkingPrompt(
     base::OnceCallback<void()> on_accepted,
     base::OnceCallback<void()> on_declined) {}
 
-void FacilitatedPaymentsClient::OnPixAccountLinkingPromptAccepted() {}
-
 void FacilitatedPaymentsClient::SetPixAccountLinkingManagerForTesting(
     std::unique_ptr<PixAccountLinkingManager> pix_account_linking_manager) {
   pix_account_linking_manager_ = std::move(pix_account_linking_manager);
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_client.h b/components/facilitated_payments/core/browser/facilitated_payments_client.h
index 83ae213a..b1cbc5a 100644
--- a/components/facilitated_payments/core/browser/facilitated_payments_client.h
+++ b/components/facilitated_payments/core/browser/facilitated_payments_client.h
@@ -13,6 +13,7 @@
 #include "base/functional/callback_forward.h"
 #include "components/autofill/core/browser/data_model/payments/ewallet.h"
 #include "components/autofill/core/browser/payments/risk_data_loader.h"
+#include "components/facilitated_payments/core/browser/device_delegate.h"
 #include "components/facilitated_payments/core/utils/facilitated_payments_ui_utils.h"
 #include "components/signin/public/identity_manager/account_info.h"
 
@@ -78,6 +79,9 @@
   virtual optimization_guide::OptimizationGuideDecider*
   GetOptimizationGuideDecider() = 0;
 
+  // Returns the `DeviceDelegate` instance owned by the implementation class.
+  virtual DeviceDelegate* GetDeviceDelegate() = 0;
+
   // Shows the user's PIX accounts from their Google Wallet, and prompts to pay.
   // `bank_account_suggestions` is the list of PIX accounts to be shown to the
   // user for payment. `on_payment_account_selected` is the callback called with
@@ -116,19 +120,12 @@
   // Virtual so it can be overridden in tests.
   virtual void InitPixAccountLinkingFlow();
 
-  // Checks if Pix account linking is supported by the platform.
-  virtual bool IsPixAccountLinkingSupported() const;
-
   // Shows the PIX account linking prompt. Virtual so it can be overridden in
   // tests.
   virtual void ShowPixAccountLinkingPrompt(
       base::OnceCallback<void()> on_accepted,
       base::OnceCallback<void()> on_declined);
 
-  // Action to be performed when the user accepts the Pix account linking
-  // prompt.
-  virtual void OnPixAccountLinkingPromptAccepted();
-
   void SetPixAccountLinkingManagerForTesting(
       std::unique_ptr<PixAccountLinkingManager> pix_account_linking_manager);
 
diff --git a/components/facilitated_payments/core/browser/mock_device_delegate.cc b/components/facilitated_payments/core/browser/mock_device_delegate.cc
new file mode 100644
index 0000000..d24d20e
--- /dev/null
+++ b/components/facilitated_payments/core/browser/mock_device_delegate.cc
@@ -0,0 +1,13 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/facilitated_payments/core/browser/mock_device_delegate.h"
+
+namespace payments::facilitated {
+
+MockDeviceDelegate::MockDeviceDelegate() = default;
+
+MockDeviceDelegate::~MockDeviceDelegate() = default;
+
+}  // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/mock_device_delegate.h b/components/facilitated_payments/core/browser/mock_device_delegate.h
new file mode 100644
index 0000000..eba76b93
--- /dev/null
+++ b/components/facilitated_payments/core/browser/mock_device_delegate.h
@@ -0,0 +1,24 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_MOCK_DEVICE_DELEGATE_H_
+#define COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_MOCK_DEVICE_DELEGATE_H_
+
+#include "components/facilitated_payments/core/browser/device_delegate.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace payments::facilitated {
+
+class MockDeviceDelegate : public DeviceDelegate {
+ public:
+  MockDeviceDelegate();
+  ~MockDeviceDelegate() override;
+
+  MOCK_METHOD(bool, IsPixAccountLinkingSupported, (), (const, override));
+  MOCK_METHOD(void, LaunchPixAccountLinkingPage, (), (override));
+};
+
+}  // namespace payments::facilitated
+
+#endif  // COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_MOCK_DEVICE_DELEGATE_H_
diff --git a/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h b/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h
index a75d566..88f390b 100644
--- a/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h
+++ b/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h
@@ -57,6 +57,7 @@
               GetOptimizationGuideDecider,
               (),
               (override));
+  MOCK_METHOD(DeviceDelegate*, GetDeviceDelegate, (), (override));
   MOCK_METHOD(void,
               ShowPixPaymentPrompt,
               (base::span<const autofill::BankAccount> pix_account_suggestions,
@@ -72,13 +73,11 @@
   MOCK_METHOD(void, DismissPrompt, (), (override));
   MOCK_METHOD(autofill::StrikeDatabase*, GetStrikeDatabase, (), (override));
   MOCK_METHOD(void, InitPixAccountLinkingFlow, (), (override));
-  MOCK_METHOD(bool, IsPixAccountLinkingSupported, (), (const, override));
   MOCK_METHOD(void,
               ShowPixAccountLinkingPrompt,
               (base::OnceCallback<void()> on_accepted,
                base::OnceCallback<void()> on_declined),
               (override));
-  MOCK_METHOD(void, OnPixAccountLinkingPromptAccepted, (), (override));
 };
 
 }  // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager.cc b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
index 707db2b..063621a 100644
--- a/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
+++ b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
@@ -20,7 +20,7 @@
 PixAccountLinkingManager::~PixAccountLinkingManager() = default;
 
 void PixAccountLinkingManager::MaybeShowPixAccountLinkingPrompt() {
-  if (!client_->IsPixAccountLinkingSupported()) {
+  if (!client_->GetDeviceDelegate()->IsPixAccountLinkingSupported()) {
     return;
   }
 
@@ -58,7 +58,7 @@
 void PixAccountLinkingManager::OnAccepted() {
   // TODO(crbug.com/419108993): Add metrics.
   client_->DismissPrompt();
-  client_->OnPixAccountLinkingPromptAccepted();
+  client_->GetDeviceDelegate()->LaunchPixAccountLinkingPage();
 }
 
 void PixAccountLinkingManager::OnDeclined() {
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc b/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc
index 4f4f09b..01a9ffd 100644
--- a/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc
+++ b/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc
@@ -10,6 +10,7 @@
 #include "components/autofill/core/browser/data_manager/payments/test_payments_data_manager.h"
 #include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
 #include "components/autofill/core/common/autofill_prefs.h"
+#include "components/facilitated_payments/core/browser/mock_device_delegate.h"
 #include "components/facilitated_payments/core/browser/mock_facilitated_payments_client.h"
 #include "components/facilitated_payments/core/browser/network_api/mock_facilitated_payments_network_interface.h"
 #include "components/facilitated_payments/core/browser/pix_account_linking_manager_test_api.h"
@@ -41,9 +42,12 @@
     payments_data_manager_->SetSyncServiceForTest(&sync_service_);
     ON_CALL(client_, GetPaymentsDataManager)
         .WillByDefault(testing::Return(payments_data_manager_.get()));
+    mock_device_delegate_ = std::make_unique<MockDeviceDelegate>();
+    ON_CALL(client_, GetDeviceDelegate)
+        .WillByDefault(testing::Return(mock_device_delegate_.get()));
 
     // Success path setup. The Pix account linking user pref is default enabled.
-    ON_CALL(client(), IsPixAccountLinkingSupported)
+    ON_CALL(*mock_device_delegate(), IsPixAccountLinkingSupported)
         .WillByDefault(testing::Return(true));
     ON_CALL(client_, GetMultipleRequestFacilitatedPaymentsNetworkInterface)
         .WillByDefault(testing::Return(
@@ -58,6 +62,9 @@
  protected:
   MockFacilitatedPaymentsClient& client() { return client_; }
   PixAccountLinkingManager* manager() { return manager_.get(); }
+  MockDeviceDelegate* mock_device_delegate() {
+    return mock_device_delegate_.get();
+  }
   inline PixAccountLinkingManagerTestApi test_api() {
     return PixAccountLinkingManagerTestApi(manager_.get());
   }
@@ -77,6 +84,7 @@
   std::unique_ptr<MockMultipleRequestFacilitatedPaymentsNetworkInterface>
       multiple_request_payments_network_interface_;
   signin::IdentityTestEnvironment identity_test_env_;
+  std::unique_ptr<MockDeviceDelegate> mock_device_delegate_;
 };
 
 TEST_F(PixAccountLinkingManagerTest, SuccessPathShowsPrompt) {
@@ -87,7 +95,7 @@
 
 TEST_F(PixAccountLinkingManagerTest,
        PixAccountLinkingNotSupported_PromptNotShown) {
-  ON_CALL(client(), IsPixAccountLinkingSupported)
+  ON_CALL(*mock_device_delegate(), IsPixAccountLinkingSupported)
       .WillByDefault(testing::Return(false));
 
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
@@ -107,7 +115,7 @@
 
 TEST_F(PixAccountLinkingManagerTest, OnAccepted) {
   EXPECT_CALL(client(), DismissPrompt);
-  EXPECT_CALL(client(), OnPixAccountLinkingPromptAccepted);
+  EXPECT_CALL(*mock_device_delegate(), LaunchPixAccountLinkingPage);
 
   test_api().OnAccepted();
 }
diff --git a/components/favicon_base/favicon_url_parser.cc b/components/favicon_base/favicon_url_parser.cc
index 47c007d..a028f22 100644
--- a/components/favicon_base/favicon_url_parser.cc
+++ b/components/favicon_base/favicon_url_parser.cc
@@ -11,6 +11,7 @@
 
 #include <string_view>
 
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/favicon_base/favicon_types.h"
diff --git a/components/feature_engagement/public/android/wrapping_test_tracker.cc b/components/feature_engagement/public/android/wrapping_test_tracker.cc
index 9a35f2a..0a8f56fce 100644
--- a/components/feature_engagement/public/android/wrapping_test_tracker.cc
+++ b/components/feature_engagement/public/android/wrapping_test_tracker.cc
@@ -9,9 +9,8 @@
 #include <utility>
 
 #include "base/android/jni_string.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "components/feature_engagement/public/jni_headers/CppWrappedTestTracker_jni.h"
 
diff --git a/components/feed/core/v2/api_test/feed_api_test.cc b/components/feed/core/v2/api_test/feed_api_test.cc
index f305231..dbd866f 100644
--- a/components/feed/core/v2/api_test/feed_api_test.cc
+++ b/components/feed/core/v2/api_test/feed_api_test.cc
@@ -12,6 +12,7 @@
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
diff --git a/components/gcm_driver/gcm_driver_android.cc b/components/gcm_driver/gcm_driver_android.cc
index 910ad97c..1316d167 100644
--- a/components/gcm_driver/gcm_driver_android.cc
+++ b/components/gcm_driver/gcm_driver_android.cc
@@ -12,9 +12,9 @@
 #include "base/android/jni_string.h"
 #include "base/compiler_specific.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "components/gcm_driver/android/jni_headers/GCMDriver_jni.h"
 
diff --git a/components/global_media_controls/public/views/media_item_ui_device_selector.cc b/components/global_media_controls/public/views/media_item_ui_device_selector.cc
index c49f552..902af75 100644
--- a/components/global_media_controls/public/views/media_item_ui_device_selector.cc
+++ b/components/global_media_controls/public/views/media_item_ui_device_selector.cc
@@ -4,6 +4,7 @@
 
 #include "components/global_media_controls/public/views/media_item_ui_device_selector.h"
 
+#include "base/notimplemented.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 
 namespace global_media_controls {
diff --git a/components/input/web_input_event_builders_mac.mm b/components/input/web_input_event_builders_mac.mm
index 461e16a..aec82e47 100644
--- a/components/input/web_input_event_builders_mac.mm
+++ b/components/input/web_input_event_builders_mac.mm
@@ -32,12 +32,12 @@
 
 #import <ApplicationServices/ApplicationServices.h>
 #import <Cocoa/Cocoa.h>
-
 #include <stdint.h>
 
 #include "base/apple/owned_objc.h"
 #include "base/mac/mac_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
diff --git a/components/live_caption/caption_bubble_context_remote.cc b/components/live_caption/caption_bubble_context_remote.cc
index 301bffe..542a5ff 100644
--- a/components/live_caption/caption_bubble_context_remote.cc
+++ b/components/live_caption/caption_bubble_context_remote.cc
@@ -10,7 +10,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "components/live_caption/caption_bubble_session_observer.h"
 #include "media/mojo/mojom/speech_recognition.mojom.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/components/media_router/common/providers/cast/channel/cast_socket_unittest.cc b/components/media_router/common/providers/cast/channel/cast_socket_unittest.cc
index ac3dd7d..346bda2 100644
--- a/components/media_router/common/providers/cast/channel/cast_socket_unittest.cc
+++ b/components/media_router/common/providers/cast/channel/cast_socket_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/components/mirroring/browser/single_client_video_capture_host.cc b/components/mirroring/browser/single_client_video_capture_host.cc
index be0f932e..a139d86 100644
--- a/components/mirroring/browser/single_client_video_capture_host.cc
+++ b/components/mirroring/browser/single_client_video_capture_host.cc
@@ -7,6 +7,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/token.h"
 #include "content/public/browser/web_contents_media_capture_id.h"
 #include "media/capture/video/video_capture_buffer_pool.h"
diff --git a/components/mirroring/service/media_remoter.cc b/components/mirroring/service/media_remoter.cc
index 99a5e0d9..6a5ce98 100644
--- a/components/mirroring/service/media_remoter.cc
+++ b/components/mirroring/service/media_remoter.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "components/mirroring/service/remoting_sender.h"
 #include "components/mirroring/service/rpc_dispatcher.h"
 #include "media/base/media_switches.h"
diff --git a/components/mirroring/service/video_capture_client.cc b/components/mirroring/service/video_capture_client.cc
index 713c645..7be99d2 100644
--- a/components/mirroring/service/video_capture_client.cc
+++ b/components/mirroring/service/video_capture_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/read_only_shared_memory_region.h"
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
diff --git a/components/nacl/loader/nacl_main.cc b/components/nacl/loader/nacl_main.cc
index 38e4fe1e..cdcd8e9 100644
--- a/components/nacl/loader/nacl_main.cc
+++ b/components/nacl/loader/nacl_main.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/message_loop/message_pump_type.h"
+#include "base/notimplemented.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/power_monitor/power_monitor_source.h"
 #include "base/task/single_thread_task_executor.h"
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios.mm b/components/open_from_clipboard/clipboard_recent_content_ios.mm
index 8aa81624..6e38a30 100644
--- a/components/open_from_clipboard/clipboard_recent_content_ios.mm
+++ b/components/open_from_clipboard/clipboard_recent_content_ios.mm
@@ -15,6 +15,7 @@
 #include <stdint.h>
 
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/system/sys_info.h"
diff --git a/components/openscreen_platform/net_udp_socket.cc b/components/openscreen_platform/net_udp_socket.cc
index 733bf2d..41b5d0c 100644
--- a/components/openscreen_platform/net_udp_socket.cc
+++ b/components/openscreen_platform/net_udp_socket.cc
@@ -13,6 +13,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "components/openscreen_platform/network_util.h"
 #include "net/base/net_errors.h"
 
diff --git a/components/openscreen_platform/tls_connection_factory.cc b/components/openscreen_platform/tls_connection_factory.cc
index ecb2315..302175c 100644
--- a/components/openscreen_platform/tls_connection_factory.cc
+++ b/components/openscreen_platform/tls_connection_factory.cc
@@ -10,9 +10,10 @@
 #include "components/openscreen_platform/tls_connection_factory.h"
 
 #include <openssl/pool.h>
+
 #include <utility>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "components/openscreen_platform/network_context.h"
 #include "components/openscreen_platform/network_util.h"
 #include "components/openscreen_platform/tls_client_connection.h"
diff --git a/components/page_info/android/page_info_controller_android.cc b/components/page_info/android/page_info_controller_android.cc
index b2015b2d..e600e7e2 100644
--- a/components/page_info/android/page_info_controller_android.cc
+++ b/components/page_info/android/page_info_controller_android.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
diff --git a/components/password_manager/core/browser/form_fetcher_impl.cc b/components/password_manager/core/browser/form_fetcher_impl.cc
index 27e42a4..968c717 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -15,6 +15,7 @@
 #include "base/check_op.h"
 #include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc
index d49aac8e..4303dc2 100644
--- a/components/password_manager/core/browser/password_manager_client.cc
+++ b/components/password_manager/core/browser/password_manager_client.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "components/autofill/core/common/password_generation_util.h"
 #include "components/device_reauth/device_authenticator.h"
 #include "components/password_manager/core/browser/field_info_manager.h"
diff --git a/components/password_manager/core/browser/password_store/fake_password_store_backend.cc b/components/password_manager/core/browser/password_store/fake_password_store_backend.cc
index 5e883a5..d516c04 100644
--- a/components/password_manager/core/browser/password_store/fake_password_store_backend.cc
+++ b/components/password_manager/core/browser/password_store/fake_password_store_backend.cc
@@ -13,7 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "components/password_manager/core/browser/affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/password_form.h"
diff --git a/components/password_manager/ios/account_select_fill_data.cc b/components/password_manager/ios/account_select_fill_data.cc
index 326f03de..eb288c1 100644
--- a/components/password_manager/ios/account_select_fill_data.cc
+++ b/components/password_manager/ios/account_select_fill_data.cc
@@ -159,6 +159,14 @@
   std::vector<UsernameAndRealm> usernames;
   for (const Credential& credential : credentials_) {
     usernames.push_back({credential.username, credential.realm});
+    // If `credential` has a backup password, create a separate UsernameAndRealm
+    // entry for it.
+    if (credential.backup_password &&
+        base::FeatureList::IsEnabled(
+            password_manager::features::kIOSFillRecoveryPassword)) {
+      usernames.push_back({credential.username, credential.realm,
+                           /*is_backup_credential=*/true});
+    }
   }
 
   return usernames;
diff --git a/components/password_manager/ios/account_select_fill_data.h b/components/password_manager/ios/account_select_fill_data.h
index a94e528..943d456 100644
--- a/components/password_manager/ios/account_select_fill_data.h
+++ b/components/password_manager/ios/account_select_fill_data.h
@@ -24,6 +24,7 @@
 struct UsernameAndRealm {
   std::u16string username;
   std::string realm;
+  bool is_backup_credential = false;
 };
 
 // Keeps all required for filling information from Password Form.
diff --git a/components/password_manager/ios/account_select_fill_data_unittest.cc b/components/password_manager/ios/account_select_fill_data_unittest.cc
index 13d9252..d65d41a 100644
--- a/components/password_manager/ios/account_select_fill_data_unittest.cc
+++ b/components/password_manager/ios/account_select_fill_data_unittest.cc
@@ -33,6 +33,9 @@
 using password_manager::FormInfoRetrievalResult;
 using password_manager::UsernameAndRealm;
 using test_helpers::SetPasswordFormFillData;
+using ::testing::AllOf;
+using ::testing::ElementsAre;
+using ::testing::Field;
 
 namespace {
 // Test data.
@@ -45,6 +48,7 @@
 const char* kPasswordElements[] = {"password1", "password2"};
 const uint32_t kPasswordUniqueIDs[] = {2, 5};
 const char* kPasswords[] = {"password0", "secret"};
+const char16_t* kBackupPassword = u"backup_password";
 const char* kAdditionalUsernames[] = {"u$er2", nullptr};
 const char* kAdditionalPasswords[] = {"secret", nullptr};
 
@@ -326,6 +330,63 @@
               testing::IsEmpty());
 }
 
+// Tests that the right number of suggestions is created when there's a
+// credential that comes with a backup password.
+TEST_F(AccountSelectFillDataTest, RetrieveSuggestions_WithBackupPasswords) {
+  PasswordFormFillData form_data = form_data_[0];
+  form_data.preferred_login.backup_password_value = kBackupPassword;
+
+  AccountSelectFillData account_select_fill_data;
+  account_select_fill_data.Add(form_data, /*always_populate_realm=*/false);
+
+  auto retrieve_suggestions = [&]() {
+    return account_select_fill_data.RetrieveSuggestions(
+        form_data.form_renderer_id, form_data.username_element_renderer_id,
+        /*is_password_field=*/false);
+  };
+
+  {
+    // Enable the iOS backup password feature.
+    base::test::ScopedFeatureList scoped_feature_list{
+        password_manager::features::kIOSFillRecoveryPassword};
+
+    // There should be three suggestions:
+    //   * 1 for the preferred login.
+    //   * 1 for the preferred login's backup password.
+    //   * 1 for the additional login.
+    EXPECT_THAT(
+        retrieve_suggestions(),
+        ElementsAre(
+            AllOf(Field(&UsernameAndRealm::username,
+                        base::ASCIIToUTF16(kUsernames[0])),
+                  Field(&UsernameAndRealm::is_backup_credential, false)),
+            AllOf(Field(&UsernameAndRealm::username,
+                        base::ASCIIToUTF16(kUsernames[0])),
+                  Field(&UsernameAndRealm::is_backup_credential, true)),
+            AllOf(Field(&UsernameAndRealm::username,
+                        base::ASCIIToUTF16(kAdditionalUsernames[0])),
+                  Field(&UsernameAndRealm::is_backup_credential, false))));
+  }
+  {
+    // Disable the iOS backup password feature.
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndDisableFeature(
+        password_manager::features::kIOSFillRecoveryPassword);
+
+    // An additional suggestion shouldn't have been created for the backup
+    // password.
+    EXPECT_THAT(
+        retrieve_suggestions(),
+        ElementsAre(
+            AllOf(Field(&UsernameAndRealm::username,
+                        base::ASCIIToUTF16(kUsernames[0])),
+                  Field(&UsernameAndRealm::is_backup_credential, false)),
+            AllOf(Field(&UsernameAndRealm::username,
+                        base::ASCIIToUTF16(kAdditionalUsernames[0])),
+                  Field(&UsernameAndRealm::is_backup_credential, false))));
+  }
+}
+
 TEST_F(AccountSelectFillDataTest, RetrievePSLMatchedSuggestions) {
   AccountSelectFillData account_select_fill_data;
   const char* kRealm = "http://a.example.com/";
diff --git a/components/password_manager/ios/ios_password_manager_driver.mm b/components/password_manager/ios/ios_password_manager_driver.mm
index 290fcf6..6859406 100644
--- a/components/password_manager/ios/ios_password_manager_driver.mm
+++ b/components/password_manager/ios/ios_password_manager_driver.mm
@@ -7,6 +7,7 @@
 #import <string>
 
 #import "base/hash/hash.h"
+#include "base/notimplemented.h"
 #import "components/autofill/core/common/password_form_fill_data.h"
 #import "components/autofill/ios/common/field_data_manager_factory_ios.h"
 #import "components/password_manager/core/browser/password_generation_frame_helper.h"
diff --git a/components/password_manager/ios/shared_password_controller.mm b/components/password_manager/ios/shared_password_controller.mm
index 9ca54b8..86915f1 100644
--- a/components/password_manager/ios/shared_password_controller.mm
+++ b/components/password_manager/ios/shared_password_controller.mm
@@ -16,7 +16,6 @@
 #import "base/apple/foundation_util.h"
 #import "base/check_op.h"
 #import "base/containers/to_vector.h"
-#import "base/debug/crash_logging.h"
 #import "base/feature_list.h"
 #import "base/functional/bind.h"
 #import "base/memory/raw_ptr.h"
@@ -739,9 +738,6 @@
                                                         forFrameId:frameId],
           [completion](auto e) {
             base::UmaHistogramEnumeration(kFillDataRetrievalStatusHistogram, e);
-            SCOPED_CRASH_KEY_NUMBER("Bug6401794", "fill_data_status",
-                                    static_cast<int>(e));
-            DUMP_WILL_BE_NOTREACHED();
             completion();
             return;
           });
diff --git a/components/permissions/android/permission_prompt/permission_prompt_android.cc b/components/permissions/android/permission_prompt/permission_prompt_android.cc
index 32735ff1..b6230b8 100644
--- a/components/permissions/android/permission_prompt/permission_prompt_android.cc
+++ b/components/permissions/android/permission_prompt/permission_prompt_android.cc
@@ -11,6 +11,7 @@
 #include "base/android/jni_string.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "components/permissions/features.h"
 #include "components/permissions/permission_request.h"
 #include "components/resources/android/theme_resources.h"
diff --git a/components/permissions/contexts/window_management_permission_context.cc b/components/permissions/contexts/window_management_permission_context.cc
index 6355487..cef1d45 100644
--- a/components/permissions/contexts/window_management_permission_context.cc
+++ b/components/permissions/contexts/window_management_permission_context.cc
@@ -5,6 +5,7 @@
 #include "components/permissions/contexts/window_management_permission_context.h"
 
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/permissions/content_setting_permission_context_base.h"
 #include "components/permissions/features.h"
diff --git a/components/plus_addresses/fake_plus_address_service.cc b/components/plus_addresses/fake_plus_address_service.cc
index 786395f2..31c57186 100644
--- a/components/plus_addresses/fake_plus_address_service.cc
+++ b/components/plus_addresses/fake_plus_address_service.cc
@@ -10,6 +10,7 @@
 
 #include "base/feature_list.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/strings/to_string.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/filling/filling_product.h"
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml
index f6ba852..542ab3f0 100644
--- a/components/policy/resources/templates/policies.yaml
+++ b/components/policy/resources/templates/policies.yaml
@@ -1368,6 +1368,7 @@
   1367: AIModeSettings
   1368: WatermarkStyle
   1369: KioskApplicationLogCollectionEnabled
+  1370: EnableUnsafeSwiftShader
 
 atomic_groups:
   1: Homepage
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/EnableUnsafeSwiftShader.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/EnableUnsafeSwiftShader.yaml
new file mode 100644
index 0000000..b9d72e8
--- /dev/null
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/EnableUnsafeSwiftShader.yaml
@@ -0,0 +1,30 @@
+caption: Allow software WebGL fallback using SwiftShader

+desc: |-

+  A policy that controls if SwiftShader will be used as a WebGL fallback when hardware GPU acceleration is not available.

+

+  SwiftShader has been used to support WebGL on systems without GPU acceleration such as headless systems or virtual machines but has been deprecated due to security issues. Starting in M139, WebGL context creation will fail when it would have otherwise used SwiftShader. This policy allows the browser or administrator to temporarily defer the deprecation.

+

+  Setting the policy to Enabled, SwiftShader will be used as a software WebGL fallback.

+

+  Setting the policy to Disabled or not set, WebGL context creation may fail if hardware GPU acceleration is not available. Web pages may misbehave if they do not gracefully handle WebGL context creation failure.

+

+  This is a temporary policy which will be removed in the future.

+default: false

+example_value: false

+features:

+  dynamic_refresh: false

+  per_profile: false

+items:

+- caption: Enable support for unsafe SwiftShader WebGL fallback

+  value: true

+- caption: Disable support for unsafe SwiftShader WebGL fallback

+  value: false

+owners:

+- geofflang@chromium.org

+- file://gpu/OWNERS

+schema:

+  type: boolean

+supported_on:

+- chrome.*:139-

+tags: []

+type: main

diff --git a/components/policy/test/data/pref_mapping/EnableUnsafeSwiftShader.json b/components/policy/test/data/pref_mapping/EnableUnsafeSwiftShader.json
new file mode 100644
index 0000000..b102dce
--- /dev/null
+++ b/components/policy/test/data/pref_mapping/EnableUnsafeSwiftShader.json
@@ -0,0 +1,18 @@
+[
+  {
+    "os": [
+      "win",
+      "linux",
+      "mac"
+    ],
+    "simple_policy_pref_mapping_test": {
+      "pref_name": "enable_unsafe_swiftshader",
+      "pref_location": "local_state",
+      "default_value": false,
+      "values_to_test": [
+        true,
+        false
+      ]
+    }
+  }
+]
diff --git a/components/prefs/overlay_user_pref_store.cc b/components/prefs/overlay_user_pref_store.cc
index 3cee7ebd..bb6d999 100644
--- a/components/prefs/overlay_user_pref_store.cc
+++ b/components/prefs/overlay_user_pref_store.cc
@@ -12,6 +12,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/values.h"
 #include "components/prefs/in_memory_pref_store.h"
diff --git a/components/remote_cocoa/app_shim/bridged_content_view.mm b/components/remote_cocoa/app_shim/bridged_content_view.mm
index d00cc10..8f572c08 100644
--- a/components/remote_cocoa/app_shim/bridged_content_view.mm
+++ b/components/remote_cocoa/app_shim/bridged_content_view.mm
@@ -9,7 +9,7 @@
 #import "base/apple/foundation_util.h"
 #include "base/apple/owned_objc.h"
 #include "base/check_op.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #import "components/remote_cocoa/app_shim/drag_drop_client.h"
 #import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
diff --git a/components/resources/supervised_user_resources.grdp b/components/resources/supervised_user_resources.grdp
index e691b672..6d8398aa 100644
--- a/components/resources/supervised_user_resources.grdp
+++ b/components/resources/supervised_user_resources.grdp
@@ -2,5 +2,6 @@
 <grit-part>
   <include name="IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_V2_HTML" file="../supervised_user/core/browser/resources/supervised_user_block_interstitial_v2.html" flattenhtml="true" type="BINDATA" compress="brotli" />
   <include name="IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_V3_HTML" file="../supervised_user/core/browser/resources/supervised_user_block_interstitial_v3.html" flattenhtml="true" type="BINDATA" compress="brotli" />
+  <include name="IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_NO_APPROVALS_HTML" file="../supervised_user/core/browser/resources/supervised_user_block_interstitial_no_approvals.html" flattenhtml="true" type="BINDATA" compress="brotli" />
   <include name="IDR_SUPERVISED_USER_ICON" file="../supervised_user/core/browser/resources/supervised_user_icon.png" type="BINDATA" />
 </grit-part>
diff --git a/components/rlz/rlz_tracker.cc b/components/rlz/rlz_tracker.cc
index 85b8273..26a97bb 100644
--- a/components/rlz/rlz_tracker.cc
+++ b/components/rlz/rlz_tracker.cc
@@ -12,6 +12,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/components/rlz/rlz_tracker_unittest.cc b/components/rlz/rlz_tracker_unittest.cc
index d132375..dfba69a4 100644
--- a/components/rlz/rlz_tracker_unittest.cc
+++ b/components/rlz/rlz_tracker_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/task_environment.h"
diff --git a/components/safe_browsing/core/browser/db/test_database_manager.cc b/components/safe_browsing/core/browser/db/test_database_manager.cc
index ee7f0140..5509da4 100644
--- a/components/safe_browsing/core/browser/db/test_database_manager.cc
+++ b/components/safe_browsing/core/browser/db/test_database_manager.cc
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc
index 7de485616..2680817 100644
--- a/components/search/ntp_features.cc
+++ b/components/search/ntp_features.cc
@@ -518,8 +518,6 @@
 }
 
 bool IsNtpComposeboxEnabled() {
-  return (base::FeatureList::IsEnabled(ntp_features::kNtpSearchboxComposebox) &&
-          base::FeatureList::IsEnabled(
-              ntp_features::kNtpSearchboxComposeEntrypoint));
+  return base::FeatureList::IsEnabled(ntp_features::kNtpSearchboxComposebox);
 }
 }  // namespace ntp_features
diff --git a/components/security_interstitials/content/utils.cc b/components/security_interstitials/content/utils.cc
index dda58b23..ae3f07e 100644
--- a/components/security_interstitials/content/utils.cc
+++ b/components/security_interstitials/content/utils.cc
@@ -8,7 +8,7 @@
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/process/launch.h"
 #include "build/build_config.h"
 
diff --git a/components/segmentation_platform/embedder/tab_fetcher.cc b/components/segmentation_platform/embedder/tab_fetcher.cc
index bc0c20e..ed6252a 100644
--- a/components/segmentation_platform/embedder/tab_fetcher.cc
+++ b/components/segmentation_platform/embedder/tab_fetcher.cc
@@ -5,7 +5,7 @@
 #include "components/segmentation_platform/embedder/tab_fetcher.h"
 
 #include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "components/sync_sessions/open_tabs_ui_delegate.h"
 #include "components/sync_sessions/synced_session.h"
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
index 89673ab..67cbcb7 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
@@ -12,7 +12,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/metrics_hashes.h"
 #include "base/metrics/user_metrics.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/clock.h"
diff --git a/components/segmentation_platform/internal/execution/processing/uma_feature_processor.cc b/components/segmentation_platform/internal/execution/processing/uma_feature_processor.cc
index cec655d..5313385 100644
--- a/components/segmentation_platform/internal/execution/processing/uma_feature_processor.cc
+++ b/components/segmentation_platform/internal/execution/processing/uma_feature_processor.cc
@@ -10,6 +10,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/components/send_tab_to_self/send_tab_to_self_infobar_delegate.cc b/components/send_tab_to_self/send_tab_to_self_infobar_delegate.cc
index 22ae76c..623c93c 100644
--- a/components/send_tab_to_self/send_tab_to_self_infobar_delegate.cc
+++ b/components/send_tab_to_self/send_tab_to_self_infobar_delegate.cc
@@ -5,6 +5,7 @@
 #include "components/send_tab_to_self/send_tab_to_self_infobar_delegate.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/send_tab_to_self/send_tab_to_self_entry.h"
 #include "content/public/browser/web_contents.h"
diff --git a/components/sharing_message/fake_sharing_handler_registry.cc b/components/sharing_message/fake_sharing_handler_registry.cc
index cdee754c8..be7d3d0 100644
--- a/components/sharing_message/fake_sharing_handler_registry.cc
+++ b/components/sharing_message/fake_sharing_handler_registry.cc
@@ -4,7 +4,7 @@
 
 #include "components/sharing_message/fake_sharing_handler_registry.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "components/sharing_message/sharing_message_handler.h"
 
 FakeSharingHandlerRegistry::FakeSharingHandlerRegistry() = default;
diff --git a/components/sharing_message/sharing_fcm_handler.cc b/components/sharing_message/sharing_fcm_handler.cc
index 43261e30..9717243 100644
--- a/components/sharing_message/sharing_fcm_handler.cc
+++ b/components/sharing_message/sharing_fcm_handler.cc
@@ -7,6 +7,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
diff --git a/components/signin/public/base/signin_metrics.cc b/components/signin/public/base/signin_metrics.cc
index 03e0bcb..5f416a3 100644
--- a/components/signin/public/base/signin_metrics.cc
+++ b/components/signin/public/base/signin_metrics.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/strcat.h"
diff --git a/components/spellcheck/browser/spellcheck_platform_android.cc b/components/spellcheck/browser/spellcheck_platform_android.cc
index b376f71..26d5a68 100644
--- a/components/spellcheck/browser/spellcheck_platform_android.cc
+++ b/components/spellcheck/browser/spellcheck_platform_android.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "components/spellcheck/common/spellcheck_features.h"
 
 class PlatformSpellChecker;
diff --git a/components/spellcheck/browser/spellcheck_platform_mac.mm b/components/spellcheck/browser/spellcheck_platform_mac.mm
index 451ee3e..2d8f970 100644
--- a/components/spellcheck/browser/spellcheck_platform_mac.mm
+++ b/components/spellcheck/browser/spellcheck_platform_mac.mm
@@ -12,7 +12,7 @@
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
 #include "components/spellcheck/common/spellcheck_common.h"
diff --git a/components/storage_monitor/storage_monitor_fuchsia.cc b/components/storage_monitor/storage_monitor_fuchsia.cc
index 7e3562a..8005441b 100644
--- a/components/storage_monitor/storage_monitor_fuchsia.cc
+++ b/components/storage_monitor/storage_monitor_fuchsia.cc
@@ -4,7 +4,7 @@
 
 #include "components/storage_monitor/storage_monitor.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace storage_monitor {
 
diff --git a/components/supervised_user/android/java/src/org/chromium/components/supervised_user/ContentFiltersObserverBridge.java b/components/supervised_user/android/java/src/org/chromium/components/supervised_user/ContentFiltersObserverBridge.java
index 1567016..21ecca2 100644
--- a/components/supervised_user/android/java/src/org/chromium/components/supervised_user/ContentFiltersObserverBridge.java
+++ b/components/supervised_user/android/java/src/org/chromium/components/supervised_user/ContentFiltersObserverBridge.java
@@ -81,6 +81,11 @@
                 .unregisterContentObserver(mObserver);
     }
 
+    @CalledByNative
+    private boolean isEnabled() {
+        return mIsEnabled;
+    }
+
     private boolean getValue(final String settingsName) {
         try {
             // The setting is considered enabled if the setting's value is positive.
diff --git a/components/supervised_user/core/browser/BUILD.gn b/components/supervised_user/core/browser/BUILD.gn
index 5b9fba2..dcb081e 100644
--- a/components/supervised_user/core/browser/BUILD.gn
+++ b/components/supervised_user/core/browser/BUILD.gn
@@ -44,6 +44,9 @@
     "//testing/gmock",
     "//testing/gtest",
   ]
+  if (is_android) {
+    deps += [ "//components/supervised_user/core/browser/android:content_filters_observer_bridge" ]
+  }
 }
 
 static_library("mocked") {
diff --git a/components/supervised_user/core/browser/android/BUILD.gn b/components/supervised_user/core/browser/android/BUILD.gn
index 1286001..959745b0 100644
--- a/components/supervised_user/core/browser/android/BUILD.gn
+++ b/components/supervised_user/core/browser/android/BUILD.gn
@@ -13,6 +13,7 @@
   ]
   deps = [
     "//base",
+    "//components/prefs",
     "//components/supervised_user/android:jni_headers",
     "//components/supervised_user/core/common",
   ]
diff --git a/components/supervised_user/core/browser/android/content_filters_observer_bridge.cc b/components/supervised_user/core/browser/android/content_filters_observer_bridge.cc
index d7ade706..63e4d71 100644
--- a/components/supervised_user/core/browser/android/content_filters_observer_bridge.cc
+++ b/components/supervised_user/core/browser/android/content_filters_observer_bridge.cc
@@ -4,6 +4,10 @@
 
 #include "components/supervised_user/core/browser/android/content_filters_observer_bridge.h"
 
+#include <memory>
+#include <string_view>
+#include <utility>
+
 #include "base/android/jni_android.h"
 #include "base/logging.h"
 #include "components/supervised_user/core/common/features.h"
@@ -12,7 +16,6 @@
 #include "components/supervised_user/android/jni_headers/ContentFiltersObserverBridge_jni.h"
 
 namespace supervised_user {
-
 ContentFiltersObserverBridge::ContentFiltersObserverBridge(
     std::string_view setting_name,
     base::RepeatingClosure on_enabled,
@@ -20,6 +23,25 @@
     : setting_name_(setting_name),
       on_enabled_(on_enabled),
       on_disabled_(on_disabled) {
+  CreateJavaBridge();
+}
+
+ContentFiltersObserverBridge::~ContentFiltersObserverBridge() {
+  DestroyJavaBridge();
+}
+
+void ContentFiltersObserverBridge::OnChange(JNIEnv* env, bool enabled) {
+  LOG(INFO) << "ContentFiltersObserverBridge received onChange for setting "
+            << setting_name_ << " with value "
+            << (enabled ? "enabled" : "disabled");
+  if (enabled) {
+    on_enabled_.Run();
+  } else {
+    on_disabled_.Run();
+  }
+}
+
+void ContentFiltersObserverBridge::CreateJavaBridge() {
   if (!base::FeatureList::IsEnabled(
           kPropagateDeviceContentFiltersToSupervisedUser)) {
     // TODO(crbug.com/422435683): Link the java bridge class to relevant
@@ -31,32 +53,30 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   bridge_ = Java_ContentFiltersObserverBridge_Constructor(
       env, reinterpret_cast<jlong>(this),
-      base::android::ConvertUTF8ToJavaString(env, setting_name));
+      base::android::ConvertUTF8ToJavaString(env, setting_name_));
 }
 
-ContentFiltersObserverBridge::~ContentFiltersObserverBridge() {
+void ContentFiltersObserverBridge::DestroyJavaBridge() {
   if (!base::FeatureList::IsEnabled(
           kPropagateDeviceContentFiltersToSupervisedUser)) {
     // TODO(crbug.com/422435683): Link the java bridge class to relevant
     // unit-test binaries.
     return;
   }
-
   Java_ContentFiltersObserverBridge_destroy(
       base::android::AttachCurrentThread(), bridge_);
 }
 
-void ContentFiltersObserverBridge::OnChange(JNIEnv* env, bool enabled) {
-  // Logs in this unit are emitted once per external setting change, most likely
-  // once in the browser's process lifetime.
-  LOG(INFO) << "ContentFiltersObserverBridge received onChange for setting "
-            << setting_name_ << " with value "
-            << (enabled ? "enabled" : "disabled");
-  if (enabled) {
-    on_enabled_.Run();
-  } else {
-    on_disabled_.Run();
+bool ContentFiltersObserverBridge::IsEnabled() const {
+  if (!base::FeatureList::IsEnabled(
+          kPropagateDeviceContentFiltersToSupervisedUser)) {
+    // TODO(crbug.com/422435683): Link the java bridge class to relevant
+    // unit-test binaries.
+    return false;
   }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return Java_ContentFiltersObserverBridge_isEnabled(env, bridge_);
 }
 
 }  // namespace supervised_user
diff --git a/components/supervised_user/core/browser/android/content_filters_observer_bridge.h b/components/supervised_user/core/browser/android/content_filters_observer_bridge.h
index 0229ffa..e0628f6 100644
--- a/components/supervised_user/core/browser/android/content_filters_observer_bridge.h
+++ b/components/supervised_user/core/browser/android/content_filters_observer_bridge.h
@@ -5,41 +5,47 @@
 #ifndef COMPONENTS_SUPERVISED_USER_CORE_BROWSER_ANDROID_CONTENT_FILTERS_OBSERVER_BRIDGE_H_
 #define COMPONENTS_SUPERVISED_USER_CORE_BROWSER_ANDROID_CONTENT_FILTERS_OBSERVER_BRIDGE_H_
 
+#include <memory>
 #include <string>
+#include <string_view>
 
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/functional/callback.h"
 
 namespace supervised_user {
-
 // Bridge between the C++ and Java sides for a content filters observer. Used to
 // observe the Android's secure settings, can be a component of a service.
-// observer.
+// observer. Instances of FakeContentFiltersObserverBridge for testing purposes
+// are available from SupervisedUserTestEnvironment.
 class ContentFiltersObserverBridge {
  public:
-  // The `setting_name` is the name of the Android's secure setting to observe.
-  // The `on_enabled` and `on_disabled` closures are called when the setting is
-  // enabled or disabled.
-  explicit ContentFiltersObserverBridge(std::string_view setting_name,
-                                        base::RepeatingClosure on_enabled,
-                                        base::RepeatingClosure on_disabled);
+  ContentFiltersObserverBridge(std::string_view setting_name,
+                               base::RepeatingClosure on_enabled,
+                               base::RepeatingClosure on_disabled);
+
   ContentFiltersObserverBridge(const ContentFiltersObserverBridge&) = delete;
   ContentFiltersObserverBridge& operator=(
       const ContentFiltersObserverBridge&) = delete;
-  ~ContentFiltersObserverBridge();
+  virtual ~ContentFiltersObserverBridge();
 
   // Called after creating the bridge and when the setting is enabled or
   // disabled.
   void OnChange(JNIEnv* env, bool enabled);
 
+  // Reads the last broadcasted value of the setting from the Java side.
+  virtual bool IsEnabled() const;
+
  private:
+  // Create and destroy the Java bridge class.
+  virtual void CreateJavaBridge();
+  virtual void DestroyJavaBridge();
+
   std::string setting_name_;
   base::RepeatingClosure on_enabled_;
   base::RepeatingClosure on_disabled_;
   base::android::ScopedJavaGlobalRef<jobject> bridge_;
 };
-
 }  // namespace supervised_user
 
 #endif  // COMPONENTS_SUPERVISED_USER_CORE_BROWSER_ANDROID_CONTENT_FILTERS_OBSERVER_BRIDGE_H_
diff --git a/components/supervised_user/core/browser/family_link_user_log_record.cc b/components/supervised_user/core/browser/family_link_user_log_record.cc
index 5c72c35..16281f1 100644
--- a/components/supervised_user/core/browser/family_link_user_log_record.cc
+++ b/components/supervised_user/core/browser/family_link_user_log_record.cc
@@ -10,6 +10,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/supervised_user/core/browser/supervised_user_preferences.h"
+#include "components/supervised_user/core/browser/supervised_user_service.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
 #include "components/supervised_user/core/common/features.h"
 #include "components/supervised_user/core/common/pref_names.h"
@@ -36,9 +37,17 @@
 
 std::optional<FamilyLinkUserLogRecord::Segment> GetSupervisionStatus(
     signin::IdentityManager* identity_manager,
-    const PrefService& pref_service) {
+    const PrefService& pref_service,
+    SupervisedUserService* supervised_user_service) {
+  if (supervised_user_service &&
+      supervised_user_service->IsSupervisedLocally()) {
+    // This type of supervision is signin-status independent (but only available
+    // to non-incognito profiles).
+    return FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally;
+  }
+
   if (!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
-    // The user is not signed in to this profile, and is therefore
+    // Unsigned users who are not supervised locally are considered
     // unsupervised.
     return FamilyLinkUserLogRecord::Segment::kUnsupervised;
   }
@@ -87,13 +96,20 @@
              FamilyLinkUserLogRecord::Segment::kParent;
 }
 
+// Returns the web filter type of the primary account user. This function
+// collates both off-the-record profiles and regular profiles without local
+// supervision into the same empty returned value: in the metrics context the
+// difference between these two cases is irrelevant. Locally supervised regular
+// users yield kDisabled filter type when they decide to control other features
+// than browser content.
 std::optional<WebFilterType> GetWebFilterType(
     std::optional<FamilyLinkUserLogRecord::Segment> supervision_status,
-    SupervisedUserURLFilter* supervised_user_filter) {
-  if (!supervised_user_filter || IsUnsupervisedStatus(supervision_status)) {
+    SupervisedUserService* supervised_user_service) {
+  if (!supervised_user_service || IsUnsupervisedStatus(supervision_status)) {
     return std::nullopt;
   }
-  return supervised_user_filter->GetWebFilterType();
+
+  return supervised_user_service->GetURLFilter()->GetWebFilterType();
 }
 
 std::optional<ToggleState> GetPermissionsToggleState(
@@ -161,12 +177,13 @@
     signin::IdentityManager* identity_manager,
     const PrefService& pref_service,
     const HostContentSettingsMap& content_settings_map,
-    SupervisedUserURLFilter* supervised_user_filter) {
+    SupervisedUserService* supervised_user_service) {
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
-      GetSupervisionStatus(identity_manager, pref_service);
+      GetSupervisionStatus(identity_manager, pref_service,
+                           supervised_user_service);
   return FamilyLinkUserLogRecord(
       supervision_status,
-      GetWebFilterType(supervision_status, supervised_user_filter),
+      GetWebFilterType(supervision_status, supervised_user_service),
       GetPermissionsToggleState(supervision_status, pref_service,
                                 content_settings_map),
       GetExtensionToggleState(supervision_status, pref_service));
diff --git a/components/supervised_user/core/browser/family_link_user_log_record.h b/components/supervised_user/core/browser/family_link_user_log_record.h
index c259864a..0e02e0e 100644
--- a/components/supervised_user/core/browser/family_link_user_log_record.h
+++ b/components/supervised_user/core/browser/family_link_user_log_record.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_SUPERVISED_USER_CORE_BROWSER_FAMILY_LINK_USER_LOG_RECORD_H_
 
 #include <optional>
+#include <ostream>
 
 #include "base/memory/raw_ptr.h"
 #include "components/supervised_user/core/common/supervised_user_constants.h"
@@ -18,10 +19,11 @@
 }
 
 namespace supervised_user {
-class SupervisedUserURLFilter;
+class SupervisedUserService;
 
 // Stores information required to log UMA record histograms for a FamilyLink
 // user account.
+// TODO(crbug.com/425685013): Rename to SupervisedUserLogRecord.
 class FamilyLinkUserLogRecord {
  public:
   // These enum values represent the user's supervision type and how the
@@ -44,19 +46,22 @@
     // Profile list contains only primary accounts identified as parents in
     // Family Link.
     kParent = 4,
+    // Profile list contains profiles that had the supervision enabled locally
+    // (e.g. on the device).
+    kSupervisionEnabledLocally = 5,
     // Add future entries above this comment, in sync with
     // "FamilyLinkUserLogSegment" in src/tools/metrics/histograms/enums.xml.
     // Update kMaxValue to the last value.
-    kMaxValue = kParent
+    kMaxValue = kSupervisionEnabledLocally
   };
-  // LINT.ThenChange(//tools/metrics/histograms/enums.xml:FamilyLinkUserLogSegment)
+  // LINT.ThenChange(//tools/metrics/histograms/metadata/families/enums.xml:FamilyLinkUserLogSegment)
 
   // Returns an immutable FamilyLinkUserLogRecord.
   static FamilyLinkUserLogRecord Create(
       signin::IdentityManager* identity_manager,
       const PrefService& pref_service,
       const HostContentSettingsMap& content_settings_map,
-      SupervisedUserURLFilter* supervised_user_filter);
+      SupervisedUserService* supervised_user_service);
 
   // Returns the supervision status of the primary account.
   std::optional<Segment> GetSupervisionStatusForPrimaryAccount() const;
@@ -85,6 +90,9 @@
   std::optional<ToggleState> extensions_toggle_state_;
 };
 
+// Declaration for gtest: defining in prod code is not required.
+void PrintTo(FamilyLinkUserLogRecord::Segment segment, std::ostream* os);
+
 }  // namespace supervised_user
 
 #endif  // COMPONENTS_SUPERVISED_USER_CORE_BROWSER_FAMILY_LINK_USER_LOG_RECORD_H_
diff --git a/components/supervised_user/core/browser/family_link_user_log_record_unittest.cc b/components/supervised_user/core/browser/family_link_user_log_record_unittest.cc
index 66ce2a2..198854f 100644
--- a/components/supervised_user/core/browser/family_link_user_log_record_unittest.cc
+++ b/components/supervised_user/core/browser/family_link_user_log_record_unittest.cc
@@ -5,6 +5,8 @@
 #include "components/supervised_user/core/browser/family_link_user_log_record.h"
 
 #include <memory>
+#include <optional>
+#include <ostream>
 
 #include "base/test/task_environment.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -19,9 +21,32 @@
 
 namespace supervised_user {
 
+void PrintTo(FamilyLinkUserLogRecord::Segment segment, std::ostream* os) {
+  switch (segment) {
+    case FamilyLinkUserLogRecord::Segment::kUnsupervised:
+      *os << "kUnsupervised";
+      break;
+    case FamilyLinkUserLogRecord::Segment::
+        kSupervisionEnabledByFamilyLinkPolicy:
+      *os << "kSupervisionEnabledByFamilyLinkPolicy";
+      break;
+    case FamilyLinkUserLogRecord::Segment::kSupervisionEnabledByFamilyLinkUser:
+      *os << "kSupervisionEnabledByFamilyLinkUser";
+      break;
+    case FamilyLinkUserLogRecord::Segment::kMixedProfile:
+      *os << "kMixedProfile";
+      break;
+    case FamilyLinkUserLogRecord::Segment::kParent:
+      *os << "kParent";
+      break;
+    case FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally:
+      *os << "kSupervisionEnabledLocally";
+      break;
+  }
+}
+
 namespace {
 constexpr char kEmail[] = "name@gmail.com";
-}  // namespace
 
 class FamilyLinkUserLogRecordTest : public ::testing::Test {
  public:
@@ -59,10 +84,12 @@
             identity_test_env_.identity_manager(),
             *supervised_user_test_environment_.pref_service(),
             *host_content_settings_map_,
-            supervised_user_test_environment_.url_filter()));
+            supervised_user_test_environment_.service()));
   }
 
-  void CreateParentUser(kidsmanagement::FamilyRole family_role) {
+  // Creates a regular user account (most likely, an adult) with the given email
+  // address.
+  void CreateRegularUser() {
     AccountInfo account_info =
         GetIdentityTestEnv()->MakePrimaryAccountAvailable(
             kEmail, signin::ConsentLevel::kSignin);
@@ -71,7 +98,11 @@
     mutator.set_is_subject_to_parental_controls(false);
     mutator.set_is_opted_in_to_parental_supervision(false);
     GetIdentityTestEnv()->UpdateAccountInfoForAccount(account_info);
+  }
 
+  // Parent user is a regular (typically an adult) user with a family role.
+  void CreateParentUser(kidsmanagement::FamilyRole family_role) {
+    CreateRegularUser();
     supervised_user_test_environment_.pref_service()->SetString(
         prefs::kFamilyLinkUserMemberRole,
         supervised_user::FamilyRoleToString(family_role));
@@ -109,9 +140,21 @@
             identity_test_env_.identity_manager(),
             *supervised_user_test_environment_.pref_service(),
             *host_content_settings_map_,
-            supervised_user_test_environment_.url_filter()));
+            supervised_user_test_environment_.service()));
   }
 
+#if BUILDFLAG(IS_ANDROID)
+  void EnableSearchContentFilters() {
+    supervised_user_test_environment_.search_content_filters_observer()
+        ->SetEnabled(true);
+  }
+
+  void EnableBrowserContentFilters() {
+    supervised_user_test_environment_.browser_content_filters_observer()
+        ->SetEnabled(true);
+  }
+#endif  // BUILDFLAG(IS_ANDROID)
+
  private:
   base::test::TaskEnvironment task_environment_;
   signin::IdentityTestEnvironment identity_test_env_;
@@ -123,7 +166,7 @@
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
   ASSERT_TRUE(supervision_status.has_value());
-  ASSERT_EQ(supervision_status.value(),
+  EXPECT_EQ(supervision_status.value(),
             FamilyLinkUserLogRecord::Segment::kUnsupervised);
 }
 
@@ -133,7 +176,7 @@
 
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
-  ASSERT_FALSE(supervision_status.has_value());
+  EXPECT_FALSE(supervision_status.has_value());
 }
 
 TEST_F(FamilyLinkUserLogRecordTest, SupervisionEnabledByUser) {
@@ -143,7 +186,7 @@
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
   ASSERT_TRUE(supervision_status.has_value());
-  ASSERT_EQ(
+  EXPECT_EQ(
       supervision_status.value(),
       FamilyLinkUserLogRecord::Segment::kSupervisionEnabledByFamilyLinkUser);
 }
@@ -155,7 +198,7 @@
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
   ASSERT_TRUE(supervision_status.has_value());
-  ASSERT_EQ(
+  EXPECT_EQ(
       supervision_status.value(),
       FamilyLinkUserLogRecord::Segment::kSupervisionEnabledByFamilyLinkPolicy);
 }
@@ -171,14 +214,14 @@
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
   ASSERT_TRUE(supervision_status.has_value());
-  ASSERT_EQ(supervision_status.value(),
+  EXPECT_EQ(supervision_status.value(),
             FamilyLinkUserLogRecord::Segment::kUnsupervised);
 }
 
 TEST_F(FamilyLinkUserLogRecordTest, SignedOutHasNoWebFilter) {
   std::optional<WebFilterType> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetWebFilterTypeForPrimaryAccount();
-  ASSERT_FALSE(supervision_status.has_value());
+  EXPECT_FALSE(supervision_status.has_value());
 }
 
 TEST_F(FamilyLinkUserLogRecordTest, NotSupervisedHasNoWebFilter) {
@@ -191,7 +234,7 @@
 
   std::optional<WebFilterType> web_filter =
       CreateFamilyLinkUserLogRecord()->GetWebFilterTypeForPrimaryAccount();
-  ASSERT_FALSE(web_filter.has_value());
+  EXPECT_FALSE(web_filter.has_value());
 }
 
 TEST_F(FamilyLinkUserLogRecordTest, SupervisedWithMatureSitesFilter) {
@@ -199,7 +242,7 @@
       CreateSupervisedUserWithWebFilter(WebFilterType::kTryToBlockMatureSites)
           ->GetWebFilterTypeForPrimaryAccount();
   ASSERT_TRUE(web_filter.has_value());
-  ASSERT_EQ(web_filter.value(), WebFilterType::kTryToBlockMatureSites);
+  EXPECT_EQ(web_filter.value(), WebFilterType::kTryToBlockMatureSites);
 }
 
 TEST_F(FamilyLinkUserLogRecordTest, SupervisedWithAllowAllFilter) {
@@ -207,7 +250,7 @@
       CreateSupervisedUserWithWebFilter(WebFilterType::kAllowAllSites)
           ->GetWebFilterTypeForPrimaryAccount();
   ASSERT_TRUE(web_filter.has_value());
-  ASSERT_EQ(web_filter.value(), WebFilterType::kAllowAllSites);
+  EXPECT_EQ(web_filter.value(), WebFilterType::kAllowAllSites);
 }
 
 TEST_F(FamilyLinkUserLogRecordTest, SupervisedWithCertainSitesFilter) {
@@ -215,7 +258,7 @@
       CreateSupervisedUserWithWebFilter(WebFilterType::kCertainSites)
           ->GetWebFilterTypeForPrimaryAccount();
   ASSERT_TRUE(web_filter.has_value());
-  ASSERT_EQ(web_filter.value(), WebFilterType::kCertainSites);
+  EXPECT_EQ(web_filter.value(), WebFilterType::kCertainSites);
 }
 
 TEST_F(FamilyLinkUserLogRecordTest, HeadOfHousehold) {
@@ -224,7 +267,7 @@
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
   ASSERT_TRUE(supervision_status.has_value());
-  ASSERT_EQ(supervision_status.value(),
+  EXPECT_EQ(supervision_status.value(),
             FamilyLinkUserLogRecord::Segment::kParent);
 }
 
@@ -234,8 +277,53 @@
   std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
       CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
   ASSERT_TRUE(supervision_status.has_value());
-  ASSERT_EQ(supervision_status.value(),
+  EXPECT_EQ(supervision_status.value(),
             FamilyLinkUserLogRecord::Segment::kParent);
 }
 
+TEST_F(FamilyLinkUserLogRecordTest, RegularUserWithDisabledSupervision) {
+  CreateRegularUser();
+  std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
+      CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
+  ASSERT_TRUE(supervision_status.has_value());
+  EXPECT_EQ(supervision_status.value(),
+            FamilyLinkUserLogRecord::Segment::kUnsupervised);
+}
+
+#if BUILDFLAG(IS_ANDROID)
+TEST_F(FamilyLinkUserLogRecordTest, RegularUserWithSearchFilterEnabled) {
+  CreateRegularUser();
+  EnableSearchContentFilters();
+
+  std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
+      CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
+  ASSERT_TRUE(supervision_status.has_value());
+  EXPECT_EQ(supervision_status.value(),
+            FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally);
+}
+
+TEST_F(FamilyLinkUserLogRecordTest, RegularUserWithContentFiltersEnabled) {
+  CreateRegularUser();
+  EnableBrowserContentFilters();
+
+  std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
+      CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
+  ASSERT_TRUE(supervision_status.has_value());
+  EXPECT_EQ(supervision_status.value(),
+            FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally);
+}
+
+TEST_F(FamilyLinkUserLogRecordTest, RegularUserWithAllLocalFiltersEnabled) {
+  CreateRegularUser();
+  EnableSearchContentFilters();
+  EnableBrowserContentFilters();
+
+  std::optional<FamilyLinkUserLogRecord::Segment> supervision_status =
+      CreateFamilyLinkUserLogRecord()->GetSupervisionStatusForPrimaryAccount();
+  ASSERT_TRUE(supervision_status.has_value());
+  EXPECT_EQ(supervision_status.value(),
+            FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally);
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+}  // namespace
 }  // namespace supervised_user
diff --git a/components/supervised_user/core/browser/resources/BUILD.gn b/components/supervised_user/core/browser/resources/BUILD.gn
index cbb64234d..fef5808 100644
--- a/components/supervised_user/core/browser/resources/BUILD.gn
+++ b/components/supervised_user/core/browser/resources/BUILD.gn
@@ -26,6 +26,7 @@
   in_files = [
     "supervised_user_block_interstitial_v2.js",
     "supervised_user_block_interstitial_v3.js",
+    "supervised_user_block_interstitial_no_approvals.js"
   ]
 }
 
@@ -37,6 +38,7 @@
     in_files = [
       "supervised_user_block_interstitial_v2.js",
       "supervised_user_block_interstitial_v3.js",
+      "supervised_user_block_interstitial_no_approvals.js"
     ]
     deps = [ ":preprocess" ]
   }
diff --git a/components/supervised_user/core/browser/resources/error_page_illustration_no_approvals_dark_theme.svg b/components/supervised_user/core/browser/resources/error_page_illustration_no_approvals_dark_theme.svg
new file mode 100644
index 0000000..023abf8
--- /dev/null
+++ b/components/supervised_user/core/browser/resources/error_page_illustration_no_approvals_dark_theme.svg
@@ -0,0 +1,7 @@
+<svg width="224" height="224" viewBox="0 0 224 224" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M40.966 176.161C9.21025 153.903 8.60134 107.889 28.2251 79.713C47.8489 51.5451 88.3067 40.6286 120.062 62.8941C151.818 85.1519 162.848 127.458 143.224 155.634C123.6 183.809 72.714 198.426 40.966 176.168V176.161Z" fill="#444746"/>
+<path d="M167 168C176.941 168 185 160.165 185 150.5C185 140.835 176.941 133 167 133C157.059 133 149 140.835 149 150.5C149 160.165 157.059 168 167 168Z" fill="#444746"/>
+<path d="M108.275 66C78.2996 66 54 90.2996 54 120.275C54 150.251 78.2996 174.551 108.275 174.551C138.251 174.551 162.551 150.251 162.551 120.275C162.551 90.2996 138.251 66 108.275 66ZM108.275 85.5346C114.35 85.5346 120.065 87.1103 125.038 89.844L77.863 137.019C75.1103 132.046 73.5536 126.331 73.5536 120.256C73.5536 101.083 89.1015 85.5346 108.275 85.5346ZM108.275 154.978C102.201 154.978 96.4863 153.403 91.5125 150.669L138.688 103.494C141.441 108.467 142.997 114.182 142.997 120.256C142.997 139.43 127.449 154.978 108.275 154.978Z" fill="#4C8DF6"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M53.65 120.275C53.65 90.1063 78.1063 65.65 108.275 65.65C138.445 65.65 162.901 90.1063 162.901 120.275C162.901 150.445 138.445 174.901 108.275 174.901C78.1063 174.901 53.65 150.445 53.65 120.275ZM108.275 66.35C78.4929 66.35 54.35 90.4929 54.35 120.275C54.35 150.058 78.4929 174.201 108.275 174.201C138.058 174.201 162.201 150.058 162.201 120.275C162.201 90.4929 138.058 66.35 108.275 66.35ZM108.275 85.8846C89.2948 85.8846 73.9036 101.276 73.9036 120.256C73.9036 126.105 75.3608 131.615 77.9465 136.441L124.459 89.9285C119.632 87.3591 114.123 85.8846 108.275 85.8846ZM73.2036 120.256C73.2036 100.889 88.9082 85.1846 108.275 85.1846C114.412 85.1846 120.184 86.7763 125.207 89.5373C125.303 89.5903 125.369 89.6857 125.385 89.7947C125.4 89.9037 125.364 90.0136 125.286 90.0915L78.1105 137.267C78.0327 137.345 77.923 137.381 77.8141 137.366C77.7053 137.351 77.61 137.285 77.5567 137.189C74.7759 132.164 73.2036 126.392 73.2036 120.256ZM138.737 103.147C138.846 103.162 138.941 103.228 138.994 103.324C141.775 108.349 143.347 114.121 143.347 120.256C143.347 139.624 127.643 155.328 108.275 155.328C102.139 155.328 96.3674 153.737 91.3439 150.976C91.2474 150.923 91.1815 150.827 91.166 150.718C91.1505 150.609 91.1872 150.499 91.265 150.421L138.44 103.246C138.518 103.168 138.628 103.132 138.737 103.147ZM92.092 150.584C96.9189 153.154 102.428 154.628 108.275 154.628C127.256 154.628 142.647 139.237 142.647 120.256C142.647 114.408 141.19 108.898 138.604 104.072L92.092 150.584Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M203.537 78.7881C203.557 78.9292 203.49 79.0682 203.366 79.1396L174.799 95.7033C174.631 95.8002 174.417 95.7433 174.32 95.576C174.223 95.4088 174.28 95.1946 174.447 95.0977L202.27 78.9663L171.886 71.3336C171.782 71.3075 171.696 71.2354 171.652 71.1378C171.608 71.0402 171.611 70.9279 171.661 70.8329L187.813 39.7251L156.18 55.5758C156.093 55.6198 155.99 55.6249 155.899 55.5898C155.807 55.5546 155.734 55.4826 155.698 55.3912L145.482 29.4756L137.327 58.3161C137.274 58.5021 137.081 58.6102 136.895 58.5576C136.709 58.505 136.601 58.3116 136.653 58.1256L145.091 28.2874C145.132 28.1429 145.26 28.0406 145.41 28.0331C145.56 28.0256 145.698 28.1146 145.753 28.2543L156.209 54.7785L188.464 38.6159C188.6 38.548 188.764 38.5751 188.87 38.6831C188.977 38.7912 189.001 38.9555 188.931 39.0901L172.486 70.7626L203.276 78.4974C203.414 78.5321 203.518 78.6471 203.537 78.7881Z" fill="#F2F2F2"/>
+</svg>
diff --git a/components/supervised_user/core/browser/resources/error_page_illustration_no_approvals_light_theme.svg b/components/supervised_user/core/browser/resources/error_page_illustration_no_approvals_light_theme.svg
new file mode 100644
index 0000000..49a634a
--- /dev/null
+++ b/components/supervised_user/core/browser/resources/error_page_illustration_no_approvals_light_theme.svg
@@ -0,0 +1,7 @@
+<svg width="224" height="224" viewBox="0 0 224 224" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M40.966 176.161C9.21025 153.903 8.60134 107.889 28.2251 79.713C47.8489 51.5451 88.3067 40.6286 120.062 62.8941C151.818 85.1519 162.848 127.458 143.224 155.634C123.6 183.809 72.714 198.426 40.966 176.168V176.161Z" fill="#F2F2F2"/>
+<path d="M167 168C176.941 168 185 160.165 185 150.5C185 140.835 176.941 133 167 133C157.059 133 149 140.835 149 150.5C149 160.165 157.059 168 167 168Z" fill="#F2F2F2"/>
+<path d="M108.275 66C78.2996 66 54 90.2996 54 120.275C54 150.251 78.2996 174.551 108.275 174.551C138.251 174.551 162.551 150.251 162.551 120.275C162.551 90.2996 138.251 66 108.275 66ZM108.275 85.5346C114.35 85.5346 120.065 87.1103 125.038 89.844L77.863 137.019C75.1103 132.046 73.5536 126.331 73.5536 120.256C73.5536 101.083 89.1015 85.5346 108.275 85.5346ZM108.275 154.978C102.201 154.978 96.4863 153.403 91.5125 150.669L138.688 103.494C141.441 108.467 142.997 114.182 142.997 120.256C142.997 139.43 127.449 154.978 108.275 154.978Z" fill="#1B6EF3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M53.65 120.275C53.65 90.1063 78.1063 65.65 108.275 65.65C138.445 65.65 162.901 90.1063 162.901 120.275C162.901 150.445 138.445 174.901 108.275 174.901C78.1063 174.901 53.65 150.445 53.65 120.275ZM108.275 66.35C78.4929 66.35 54.35 90.4929 54.35 120.275C54.35 150.058 78.4929 174.201 108.275 174.201C138.058 174.201 162.201 150.058 162.201 120.275C162.201 90.4929 138.058 66.35 108.275 66.35ZM108.275 85.8846C89.2948 85.8846 73.9036 101.276 73.9036 120.256C73.9036 126.105 75.3608 131.615 77.9465 136.441L124.459 89.9285C119.632 87.3591 114.123 85.8846 108.275 85.8846ZM73.2036 120.256C73.2036 100.889 88.9082 85.1846 108.275 85.1846C114.412 85.1846 120.184 86.7763 125.207 89.5373C125.303 89.5903 125.369 89.6857 125.385 89.7947C125.4 89.9037 125.364 90.0136 125.286 90.0915L78.1104 137.267C78.0327 137.345 77.923 137.381 77.8141 137.366C77.7053 137.351 77.6099 137.285 77.5567 137.189C74.7759 132.164 73.2036 126.392 73.2036 120.256ZM138.737 103.147C138.846 103.162 138.941 103.228 138.994 103.324C141.775 108.349 143.347 114.121 143.347 120.256C143.347 139.624 127.643 155.328 108.275 155.328C102.139 155.328 96.3673 153.737 91.3439 150.976C91.2474 150.923 91.1815 150.827 91.166 150.718C91.1505 150.609 91.1871 150.499 91.265 150.421L138.44 103.246C138.518 103.168 138.628 103.132 138.737 103.147ZM92.0919 150.584C96.9189 153.154 102.428 154.628 108.275 154.628C127.256 154.628 142.647 139.237 142.647 120.256C142.647 114.408 141.19 108.898 138.604 104.072L92.0919 150.584Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M203.537 78.7881C203.557 78.9292 203.49 79.0682 203.366 79.1396L174.799 95.7033C174.631 95.8002 174.417 95.7433 174.32 95.576C174.223 95.4088 174.28 95.1946 174.447 95.0977L202.27 78.9663L171.886 71.3336C171.782 71.3075 171.696 71.2354 171.652 71.1378C171.608 71.0402 171.611 70.9279 171.661 70.8329L187.813 39.7251L156.18 55.5758C156.093 55.6198 155.99 55.6249 155.899 55.5898C155.807 55.5546 155.734 55.4826 155.698 55.3912L145.482 29.4756L137.327 58.3161C137.274 58.5021 137.081 58.6102 136.895 58.5576C136.709 58.505 136.601 58.3116 136.653 58.1256L145.091 28.2874C145.132 28.1429 145.26 28.0406 145.41 28.0331C145.56 28.0256 145.698 28.1146 145.753 28.2543L156.209 54.7785L188.464 38.6159C188.6 38.548 188.764 38.5751 188.87 38.6831C188.977 38.7912 189.001 38.9555 188.931 39.0901L172.486 70.7626L203.276 78.4974C203.414 78.5321 203.518 78.6471 203.537 78.7881Z" fill="black"/>
+</svg>
diff --git a/components/supervised_user/core/browser/resources/supervised_user_block_interstitial_no_approvals.html b/components/supervised_user/core/browser/resources/supervised_user_block_interstitial_no_approvals.html
new file mode 100644
index 0000000..f2c999f
--- /dev/null
+++ b/components/supervised_user/core/browser/resources/supervised_user_block_interstitial_no_approvals.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<head>
+<meta charset="utf-8">
+<meta name="viewport"
+    content="initial-scale=1, minimum-scale=1, width=device-width">
+<title>$i18n{blockPageTitle}</title>
+<link rel="stylesheet" href="../../../../../components/security_interstitials/core/common/resources/interstitial_core.css">
+<!-- This is simplified version of v3 interstitial which reuses the styling -->
+<link rel="stylesheet" href="supervised_user_block_interstitial_v3.css">
+<if expr="not optimize_webui">
+  <script src="%ROOT_GEN_DIR%/components/supervised_user/core/browser/resources/preprocessed/supervised_user_block_interstitial_no_approvals.js"></script>
+</if>
+<if expr="optimize_webui">
+  <script src="%ROOT_GEN_DIR%/components/supervised_user/core/browser/resources/minified/supervised_user_block_interstitial_no_approvals.js"></script>
+</if>
+</head>
+<body class="supervised-user-block" <if expr="is_ios">style="font-size: $i18n{fontsize}"</if>>
+<div class="frame-blocked" id="frame-blocked" tabindex="-1">
+  <div class="message-container">
+    <picture id="error-page-illustration">
+      <source
+        srcset="error_page_illustration_no_approvals_dark_theme.svg"
+        media="(prefers-color-scheme: dark)"
+        alt="">
+      <img class="illustration"
+        src="error_page_illustration_no_approvals_light_theme.svg"
+        alt="">
+    </picture>
+    <div id="main-message">
+      <h1 id="block-page-header" tabindex="-1">$i18n{blockPageHeader}</h1>
+      <p id="block-page-message" tabindex="-1">$i18n{blockPageMessage}</p>
+    </div>
+  </div>
+  <div class="button-container">
+    <button id="back-button" class="go-back-button">
+      $i18n{backButton}
+    </button>
+    <button id="back-button" class="learn-more-button secondary-button">
+      $i18n{learnMore}
+    </button>
+  </div>
+</div>
+</body>
+</html>
diff --git a/components/supervised_user/core/browser/resources/supervised_user_block_interstitial_no_approvals.js b/components/supervised_user/core/browser/resources/supervised_user_block_interstitial_no_approvals.js
new file mode 100644
index 0000000..75b38d5
--- /dev/null
+++ b/components/supervised_user/core/browser/resources/supervised_user_block_interstitial_no_approvals.js
@@ -0,0 +1,22 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** Return the element with the given id. */
+function $(id) {
+  return document.body.querySelector(`#${id}`);
+}
+
+/** Perform all initialization that can be done at DOMContentLoaded time. */
+function initialize() {
+  $('back-button').onclick = function(event) {
+    supervisedUserErrorPageController.goBack();
+  };
+  $('learn-more-button').onclick = function(event) {
+    supervisedUserErrorPageController.learnMore();
+  };
+  // Focus the top-level div for screen readers.
+  $('frame-blocked').focus();
+}
+
+document.addEventListener('DOMContentLoaded', initialize);
diff --git a/components/supervised_user/core/browser/supervised_user_error_page.cc b/components/supervised_user/core/browser/supervised_user_error_page.cc
index 2283e00..b0d6a67 100644
--- a/components/supervised_user/core/browser/supervised_user_error_page.cc
+++ b/components/supervised_user/core/browser/supervised_user_error_page.cc
@@ -75,14 +75,43 @@
   return IDS_CHILD_BLOCK_INTERSTITIAL_MESSAGE_V2;
 }
 
-std::string BuildErrorPageHtml(bool allow_access_requests,
-                               std::optional<Custodian> custodian,
-                               std::optional<Custodian> second_custodian,
-                               FilteringBehaviorReason reason,
-                               const std::string& app_locale,
-                               bool already_sent_remote_request,
-                               bool is_main_frame,
-                               std::optional<float> ios_font_size_multiplier) {
+#if BUILDFLAG(IS_ANDROID)
+std::string BuildErrorPageHtmlWithoutApprovals(const GURL& url,
+                                               const std::string& app_locale) {
+  base::Value::Dict load_time_data;
+  load_time_data.Set("blockPageTitle",
+                     l10n_util::GetStringUTF8(IDS_BLOCK_INTERSTITIAL_TITLE));
+  load_time_data.Set("blockPageHeader",
+                     l10n_util::GetStringUTF8(IDS_BLOCK_INTERSTITIAL_TITLE));
+  load_time_data.Set("blockPageMessage",
+                     l10n_util::FormatString(
+                         l10n_util::GetStringUTF16(IDS_NO_APPROVALS_MESSAGE),
+                         {base::UTF8ToUTF16(url.host())}, nullptr));
+  load_time_data.Set("learnMore", l10n_util::GetStringUTF8(
+                                      IDS_NO_APPROVALS_LEARN_MORE_BUTTON));
+  load_time_data.Set("backButton",
+                     l10n_util::GetStringUTF8(IDS_NO_APPROVALS_BACK_BUTTON));
+
+  webui::SetLoadTimeDataDefaults(app_locale, &load_time_data);
+
+  std::string html =
+      ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+          IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_NO_APPROVALS_HTML);
+  webui::AppendWebUiCssTextDefaults(&html);
+  std::string error_html = webui::GetI18nTemplateHtml(html, load_time_data);
+  return error_html;
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
+std::string BuildErrorPageHtmlWithApprovals(
+    bool allow_access_requests,
+    std::optional<Custodian> custodian,
+    std::optional<Custodian> second_custodian,
+    FilteringBehaviorReason reason,
+    const std::string& app_locale,
+    bool already_sent_remote_request,
+    bool is_main_frame,
+    std::optional<float> ios_font_size_multiplier) {
   base::Value::Dict load_time_data;
   load_time_data.Set("blockPageTitle",
                      l10n_util::GetStringUTF8(IDS_BLOCK_INTERSTITIAL_TITLE));
diff --git a/components/supervised_user/core/browser/supervised_user_error_page.h b/components/supervised_user/core/browser/supervised_user_error_page.h
index d5b4fbf..d7a397d96 100644
--- a/components/supervised_user/core/browser/supervised_user_error_page.h
+++ b/components/supervised_user/core/browser/supervised_user_error_page.h
@@ -16,14 +16,20 @@
 
 int GetInterstitialMessageID(FilteringBehaviorReason reason);
 
-std::string BuildErrorPageHtml(bool allow_access_requests,
-                               std::optional<Custodian> custodian,
-                               std::optional<Custodian> second_custodian,
-                               FilteringBehaviorReason reason,
-                               const std::string& app_locale,
-                               bool already_sent_remote_request,
-                               bool is_main_frame,
-                               std::optional<float> ios_font_size_multiplier);
+#if BUILDFLAG(IS_ANDROID)
+std::string BuildErrorPageHtmlWithoutApprovals(const GURL& url,
+                                               const std::string& app_locale);
+#endif  // BUILDFLAG(IS_ANDROID)
+
+std::string BuildErrorPageHtmlWithApprovals(
+    bool allow_access_requests,
+    std::optional<Custodian> custodian,
+    std::optional<Custodian> second_custodian,
+    FilteringBehaviorReason reason,
+    const std::string& app_locale,
+    bool already_sent_remote_request,
+    bool is_main_frame,
+    std::optional<float> ios_font_size_multiplier);
 
 }  //  namespace supervised_user
 
diff --git a/components/supervised_user/core/browser/supervised_user_error_page_unittest.cc b/components/supervised_user/core/browser/supervised_user_error_page_unittest.cc
index 0fc7b30..a302ac2 100644
--- a/components/supervised_user/core/browser/supervised_user_error_page_unittest.cc
+++ b/components/supervised_user/core/browser/supervised_user_error_page_unittest.cc
@@ -193,7 +193,7 @@
   // replacements) plus scripts that plug values into it. The test can't
   // easily check that the scripts are correct, but can check that the output
   // contains the expected values.
-  html_error_page_ = BuildErrorPageHtml(
+  html_error_page_ = BuildErrorPageHtmlWithApprovals(
       param.allow_access_requests, param.custodian, param.second_custodian,
       param.reason,
       /*app_locale=*/"",
diff --git a/components/supervised_user/core/browser/supervised_user_interstitial.cc b/components/supervised_user/core/browser/supervised_user_interstitial.cc
index fcd99df..d3c555a 100644
--- a/components/supervised_user/core/browser/supervised_user_interstitial.cc
+++ b/components/supervised_user/core/browser/supervised_user_interstitial.cc
@@ -69,8 +69,17 @@
   web_content_handler_->MaybeCloseLocalApproval();
 }
 
+#if BUILDFLAG(IS_ANDROID)
 // static
-std::string SupervisedUserInterstitial::GetHTMLContents(
+std::string SupervisedUserInterstitial::GetHTMLContentsWithoutApprovals(
+    const GURL& url,
+    const std::string& application_locale) {
+  return BuildErrorPageHtmlWithoutApprovals(url, application_locale);
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
+// static
+std::string SupervisedUserInterstitial::GetHTMLContentsWithApprovals(
     SupervisedUserService* supervised_user_service,
     PrefService* pref_service,
     FilteringBehaviorReason reason,
@@ -81,7 +90,7 @@
   bool allow_access_requests =
       supervised_user_service->remote_web_approvals_manager()
           .AreApprovalRequestsEnabled();
-  return BuildErrorPageHtml(
+  return BuildErrorPageHtmlWithApprovals(
       allow_access_requests, supervised_user_service->GetCustodian(),
       supervised_user_service->GetSecondCustodian(), reason, application_locale,
       already_sent_request, is_main_frame, ios_font_size_multiplier);
diff --git a/components/supervised_user/core/browser/supervised_user_interstitial.h b/components/supervised_user/core/browser/supervised_user_interstitial.h
index 523cf443..d598bc3 100644
--- a/components/supervised_user/core/browser/supervised_user_interstitial.h
+++ b/components/supervised_user/core/browser/supervised_user_interstitial.h
@@ -75,8 +75,15 @@
       const std::u16string& supervised_user_name,
       FilteringBehaviorReason reason);
 
-  // Returns the HTML contents of the error page.
-  static std::string GetHTMLContents(
+  #if BUILDFLAG(IS_ANDROID)
+  // Returns the HTML contents of the error page without the approvals section.
+  static std::string GetHTMLContentsWithoutApprovals(
+      const GURL& url,
+      const std::string& application_locale);
+  #endif  // BUILDFLAG(IS_ANDROID)
+
+  // Returns the HTML contents of the error page with the approvals section.
+  static std::string GetHTMLContentsWithApprovals(
       SupervisedUserService* supervised_user_service,
       PrefService* pref_service,
       FilteringBehaviorReason reason,
diff --git a/components/supervised_user/core/browser/supervised_user_service.cc b/components/supervised_user/core/browser/supervised_user_service.cc
index 7c5f8c0..8fa717d 100644
--- a/components/supervised_user/core/browser/supervised_user_service.cc
+++ b/components/supervised_user/core/browser/supervised_user_service.cc
@@ -76,6 +76,26 @@
 void PrefChangeNotAllowed(const std::string& pref_name) {
   NOTREACHED() << "Preference change (" << pref_name << ") not allowed.";
 }
+
+#if BUILDFLAG(IS_ANDROID)
+// Convenience factories to create the content filters observer bridges. Android
+// code calls these bridges, which in turn call the native side pref service to
+// enable or disable supervision features.
+std::unique_ptr<ContentFiltersObserverBridge> BrowserContentFiltersObserver(
+    PrefService& user_prefs) {
+  return std::make_unique<ContentFiltersObserverBridge>(
+      kBrowserContentFiltersSettingName,
+      base::BindRepeating(&EnableBrowserContentFilters, std::ref(user_prefs)),
+      base::BindRepeating(&DisableBrowserContentFilters, std::ref(user_prefs)));
+}
+std::unique_ptr<ContentFiltersObserverBridge> SearchContentFiltersObserver(
+    PrefService& user_prefs) {
+  return std::make_unique<ContentFiltersObserverBridge>(
+      kSearchContentFiltersSettingName,
+      base::BindRepeating(&EnableSearchContentFilters, std::ref(user_prefs)),
+      base::BindRepeating(&DisableSearchContentFilters, std::ref(user_prefs)));
+}
+#endif  // BUILDFLAG(IS_ANDROID)
 }  // namespace
 
 Custodian::Custodian(std::string_view name,
@@ -102,6 +122,23 @@
   return url_filter_.get();
 }
 
+bool SupervisedUserService::IsSupervisedLocally() const {
+#if BUILDFLAG(IS_ANDROID)
+  return IsLocalContentFilteringEnabled() ||
+         search_content_filters_observer_->IsEnabled();
+#else
+  return false;
+#endif
+}
+
+bool SupervisedUserService::IsLocalContentFilteringEnabled() const {
+#if BUILDFLAG(IS_ANDROID)
+  return browser_content_filters_observer_->IsEnabled();
+#else
+  return false;
+#endif
+}
+
 std::optional<Custodian> SupervisedUserService::GetCustodian() const {
   return GetCustodianFromPrefs(user_prefs_.get(),
                                prefs::kSupervisedUserCustodianEmail,
@@ -146,7 +183,15 @@
     SupervisedUserSettingsService& settings_service,
     syncer::SyncService* sync_service,
     std::unique_ptr<SupervisedUserURLFilter> url_filter,
-    std::unique_ptr<SupervisedUserService::PlatformDelegate> platform_delegate)
+    std::unique_ptr<SupervisedUserService::PlatformDelegate> platform_delegate
+#if BUILDFLAG(IS_ANDROID)
+    ,
+    std::unique_ptr<ContentFiltersObserverBridge>
+        browser_content_filters_observer,
+    std::unique_ptr<ContentFiltersObserverBridge>
+        search_content_filters_observer
+#endif
+    )
     : user_prefs_(user_prefs),
       settings_service_(settings_service),
       sync_service_(sync_service),
@@ -169,17 +214,13 @@
 #if BUILDFLAG(IS_ANDROID)
       ,
       browser_content_filters_observer_(
-          kBrowserContentFiltersSettingName,
-          base::BindRepeating(&EnableBrowserContentFilters,
-                              std::ref(user_prefs_.get())),
-          base::BindRepeating(&DisableBrowserContentFilters,
-                              std::ref(user_prefs_.get()))),
+          browser_content_filters_observer == nullptr
+              ? BrowserContentFiltersObserver(user_prefs_.get())
+              : std::move(browser_content_filters_observer)),
       search_content_filters_observer_(
-          kSearchContentFiltersSettingName,
-          base::BindRepeating(&EnableSearchContentFilters,
-                              std::ref(user_prefs_.get())),
-          base::BindRepeating(&DisableSearchContentFilters,
-                              std::ref(user_prefs_.get())))
+          search_content_filters_observer == nullptr
+              ? SearchContentFiltersObserver(user_prefs_.get())
+              : std::move(search_content_filters_observer))
 #endif  // BUILDFLAG(IS_ANDROID)
 {
   CHECK(settings_service_->IsReady())
diff --git a/components/supervised_user/core/browser/supervised_user_service.h b/components/supervised_user/core/browser/supervised_user_service.h
index 278f3dcd..d4f84ae 100644
--- a/components/supervised_user/core/browser/supervised_user_service.h
+++ b/components/supervised_user/core/browser/supervised_user_service.h
@@ -120,6 +120,13 @@
   // on the UI thread.
   SupervisedUserURLFilter* GetURLFilter() const;
 
+  // Returns true if the user is supervised locally (e.g. on the device).
+  // Currently, local supervision is only supported on Android.
+  bool IsSupervisedLocally() const;
+  // Returns true if the user is supervised locally (e.g. on the device) and
+  // requested browser content to be filtered.
+  bool IsLocalContentFilteringEnabled() const;
+
   std::optional<Custodian> GetCustodian() const;
   std::optional<Custodian> GetSecondCustodian() const;
 
@@ -152,8 +159,17 @@
       SupervisedUserSettingsService& settings_service,
       syncer::SyncService* sync_service,
       std::unique_ptr<SupervisedUserURLFilter> url_filter,
-      std::unique_ptr<SupervisedUserService::PlatformDelegate>
-          platform_delegate);
+      std::unique_ptr<SupervisedUserService::PlatformDelegate> platform_delegate
+#if BUILDFLAG(IS_ANDROID)
+      ,
+      // The default arguments are substituted with live
+      // ContentFiltersObserverBridge instances.
+      std::unique_ptr<ContentFiltersObserverBridge>
+          browser_content_filters_observer = nullptr,
+      std::unique_ptr<ContentFiltersObserverBridge>
+          search_content_filters_observer = nullptr
+#endif
+  );
 
  private:
   // Activates the service which controls managed settings of url filtering and
@@ -227,8 +243,10 @@
 
 #if BUILDFLAG(IS_ANDROID)
   // Observers for the content filters
-  ContentFiltersObserverBridge browser_content_filters_observer_;
-  ContentFiltersObserverBridge search_content_filters_observer_;
+  std::unique_ptr<ContentFiltersObserverBridge>
+      browser_content_filters_observer_;
+  std::unique_ptr<ContentFiltersObserverBridge>
+      search_content_filters_observer_;
 #endif  // BUILDFLAG(IS_ANDROID)
 
   // True only when |Shutdown()| method has been called.
diff --git a/components/supervised_user/core/browser/supervised_user_test_environment.cc b/components/supervised_user/core/browser/supervised_user_test_environment.cc
index d32fecd..1c953be 100644
--- a/components/supervised_user/core/browser/supervised_user_test_environment.cc
+++ b/components/supervised_user/core/browser/supervised_user_test_environment.cc
@@ -7,14 +7,16 @@
 #include <memory>
 #include <ostream>
 #include <string_view>
+#include <utility>
 
-#include "components/prefs/pref_notifier_impl.h"
 #include "components/policy/core/common/policy_pref_names.h"
+#include "components/prefs/pref_notifier_impl.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_search_api/fake_url_checker_client.h"
 #include "components/supervised_user/core/browser/supervised_user_metrics_service.h"
 #include "components/supervised_user/core/browser/supervised_user_pref_store.h"
 #include "components/supervised_user/core/browser/supervised_user_url_filter.h"
+#include "components/supervised_user/core/common/supervised_user_constants.h"
 #include "components/supervised_user/test_support/supervised_user_url_filter_test_utils.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/model/sync_change_processor.h"
@@ -116,18 +118,25 @@
   SupervisedUserMetricsService::RegisterProfilePrefs(
       syncable_pref_service_->registry());
 
-  // Supervised user infra is not owning this pref but is using it: enable
-  // conditionally to avoid double registration.
+  // Supervised user infra is not owning these prefs but is using them: enable
+  // conditionally only if not already registered (to avoid double
+  // registration).
   if (syncable_pref_service_->FindPreference(
           policy::policy_prefs::kIncognitoModeAvailability) == nullptr) {
     syncable_pref_service_->registry()->RegisterIntegerPref(
         policy::policy_prefs::kIncognitoModeAvailability,
         static_cast<int>(policy::IncognitoModeAvailability::kEnabled));
   }
+  if (syncable_pref_service_->FindPreference(
+          policy::policy_prefs::kForceGoogleSafeSearch) == nullptr) {
+    syncable_pref_service_->registry()->RegisterBooleanPref(
+        policy::policy_prefs::kForceGoogleSafeSearch, false);
+  }
 }
 
 SupervisedUserPrefStoreTestEnvironment::
     ~SupervisedUserPrefStoreTestEnvironment() = default;
+
 void SupervisedUserPrefStoreTestEnvironment::Shutdown() {
   settings_service_.Shutdown();
 }
@@ -145,6 +154,34 @@
       std::make_unique<safe_search_api::FakeURLCheckerClient>();
   url_checker_client_ = client.get();
 
+#if BUILDFLAG(IS_ANDROID)
+  // Bound to properties exactly as in SupervisedUserService.
+  std::unique_ptr<FakeContentFiltersObserverBridge>
+      browser_content_filters_observer =
+          std::make_unique<FakeContentFiltersObserverBridge>(
+              kBrowserContentFiltersSettingName,
+              base::BindRepeating(
+                  &EnableBrowserContentFilters,
+                  std::ref(*pref_store_environment_.pref_service())),
+              base::BindRepeating(
+                  &DisableBrowserContentFilters,
+                  std::ref(*pref_store_environment_.pref_service())));
+  browser_content_filters_observer_ = browser_content_filters_observer.get();
+
+  // Bound to properties exactly as in SupervisedUserService.
+  std::unique_ptr<FakeContentFiltersObserverBridge>
+      search_content_filters_observer =
+          std::make_unique<FakeContentFiltersObserverBridge>(
+              kSearchContentFiltersSettingName,
+              base::BindRepeating(
+                  &EnableSearchContentFilters,
+                  std::ref(*pref_store_environment_.pref_service())),
+              base::BindRepeating(
+                  &DisableSearchContentFilters,
+                  std::ref(*pref_store_environment_.pref_service())));
+  search_content_filters_observer_ = search_content_filters_observer.get();
+#endif  // BUILDFLAG(IS_ANDROID)
+
   service_ = std::make_unique<SupervisedUserService>(
       identity_test_env_.identity_manager(),
       test_url_loader_factory_.GetSafeWeakWrapper(),
@@ -153,7 +190,13 @@
       std::make_unique<SupervisedUserURLFilter>(
           *pref_store_environment_.pref_service(),
           std::make_unique<FakeURLFilterDelegate>(), std::move(client)),
-      std::make_unique<FakePlatformDelegate>());
+      std::make_unique<FakePlatformDelegate>()
+#if BUILDFLAG(IS_ANDROID)
+          ,
+      std::move(browser_content_filters_observer),
+      std::move(search_content_filters_observer)
+#endif  // BUILDFLAG(IS_ANDROID)
+  );
   metrics_service_ = std::make_unique<SupervisedUserMetricsService>(
       pref_store_environment_.pref_service(), *service_.get(),
       std::make_unique<SupervisedUserMetricsServiceExtensionDelegateFake>());
@@ -262,4 +305,33 @@
   return url_checker_client_.get();
 }
 
+#if BUILDFLAG(IS_ANDROID)
+
+FakeContentFiltersObserverBridge*
+SupervisedUserTestEnvironment::browser_content_filters_observer() {
+  return browser_content_filters_observer_.get();
+}
+FakeContentFiltersObserverBridge*
+SupervisedUserTestEnvironment::search_content_filters_observer() {
+  return search_content_filters_observer_.get();
+}
+
+FakeContentFiltersObserverBridge::FakeContentFiltersObserverBridge(
+    std::string_view setting_name,
+    base::RepeatingClosure on_enabled,
+    base::RepeatingClosure on_disabled)
+    : ContentFiltersObserverBridge(setting_name, on_enabled, on_disabled) {}
+FakeContentFiltersObserverBridge::~FakeContentFiltersObserverBridge() = default;
+
+bool FakeContentFiltersObserverBridge::IsEnabled() const {
+  return enabled_;
+}
+
+void FakeContentFiltersObserverBridge::SetEnabled(bool enabled) {
+  enabled_ = enabled;
+  // This is fine: JNIEnv is not used, because OnChange notifies native code.
+  OnChange(/*env=*/nullptr, enabled);
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
 }  // namespace supervised_user
diff --git a/components/supervised_user/core/browser/supervised_user_test_environment.h b/components/supervised_user/core/browser/supervised_user_test_environment.h
index fb67bb8..7e746c69 100644
--- a/components/supervised_user/core/browser/supervised_user_test_environment.h
+++ b/components/supervised_user/core/browser/supervised_user_test_environment.h
@@ -10,7 +10,6 @@
 #include <string_view>
 
 #include "base/memory/ref_counted.h"
-#include "base/test/task_environment.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_store.h"
 #include "components/safe_search_api/fake_url_checker_client.h"
@@ -23,6 +22,10 @@
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "services/network/test/test_url_loader_factory.h"
 
+#if BUILDFLAG(IS_ANDROID)
+#include "components/supervised_user/core/browser/android/content_filters_observer_bridge.h"
+#endif  // BUILDFLAG(IS_ANDROID)
+
 namespace supervised_user {
 
 // Launches the service from empty settings, typically during context
@@ -72,10 +75,40 @@
   bool RecordExtensionsMetrics() override;
 };
 
+#if BUILDFLAG(IS_ANDROID)
+// Fake implementation of ContentFiltersObserverBridge for testing. Imitates
+// events that would normally be produced by the Android's secure settings
+// (which store content filter settings). Content bridge is initialized with
+// "disabled" setting.
+class FakeContentFiltersObserverBridge final
+    : public ContentFiltersObserverBridge {
+ public:
+  FakeContentFiltersObserverBridge(std::string_view setting_name,
+                                   base::RepeatingClosure on_enabled,
+                                   base::RepeatingClosure on_disabled);
+  FakeContentFiltersObserverBridge(const FakeContentFiltersObserverBridge&) =
+      delete;
+  FakeContentFiltersObserverBridge& operator=(
+      const FakeContentFiltersObserverBridge&) = delete;
+  ~FakeContentFiltersObserverBridge() override;
+  bool IsEnabled() const override;
+  void SetEnabled(bool enabled);
+
+ private:
+  // Do not create nor destroy the java bridge in tests.
+  void CreateJavaBridge() override {}
+  void DestroyJavaBridge() override {}
+  // Stores actual value (in place of secure settings storage). Note: In prod
+  // environment there is one setting value for all profiles, but this fake
+  // is bound to a specific profile.
+  bool enabled_ = false;
+};
+#endif  // BUILDFLAG(IS_ANDROID)
+
 // Configures a handy set of components that form supervised user features, for
 // unit testing. This is a lightweight, unit-test oriented alternative to a
 // TestingProfile with enabled supervision.
-// Requires single-threaded task environment for unittests (see
+// Requires single-threaded task environment for unit tests (see
 // base::test::TaskEnvironment), and requires that Shutdown() is called.
 class SupervisedUserTestEnvironment {
  public:
@@ -90,6 +123,10 @@
   PrefService* pref_service();
   sync_preferences::TestingPrefServiceSyncable* pref_service_syncable();
   safe_search_api::FakeURLCheckerClient* url_checker_client();
+#if BUILDFLAG(IS_ANDROID)
+  FakeContentFiltersObserverBridge* browser_content_filters_observer();
+  FakeContentFiltersObserverBridge* search_content_filters_observer();
+#endif  // BUILDFLAG(IS_ANDROID)
 
   // Simulators of parental controls. Instance methods use services from this
   // test environment, while static methods are suitable for heavier testing
@@ -129,9 +166,13 @@
   std::unique_ptr<SupervisedUserService> service_;
   std::unique_ptr<SupervisedUserMetricsService> metrics_service_;
 
-  // The object is actually owned by the
-  // service_::url_filter_::async_url_checker_.
+  // The objects are actually owned by the service_, but are referenced here for
+  // convenience.
   raw_ptr<safe_search_api::FakeURLCheckerClient> url_checker_client_;
+#if BUILDFLAG(IS_ANDROID)
+  raw_ptr<FakeContentFiltersObserverBridge> browser_content_filters_observer_;
+  raw_ptr<FakeContentFiltersObserverBridge> search_content_filters_observer_;
+#endif  // BUILDFLAG(IS_ANDROID)
 };
 }  // namespace supervised_user
 
diff --git a/components/supervised_user/core/browser/supervised_user_url_filter_unittest.cc b/components/supervised_user/core/browser/supervised_user_url_filter_unittest.cc
index 1ce2f8b..b56ecab 100644
--- a/components/supervised_user/core/browser/supervised_user_url_filter_unittest.cc
+++ b/components/supervised_user/core/browser/supervised_user_url_filter_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
 #include "components/safe_search_api/fake_url_checker_client.h"
 #include "components/supervised_user/core/browser/supervised_user_preferences.h"
 #include "components/supervised_user/core/browser/supervised_user_test_environment.h"
diff --git a/components/supervised_user/core/browser/supervised_user_utils.cc b/components/supervised_user/core/browser/supervised_user_utils.cc
index 765f25e..bf9693c3 100644
--- a/components/supervised_user/core/browser/supervised_user_utils.cc
+++ b/components/supervised_user/core/browser/supervised_user_utils.cc
@@ -87,6 +87,7 @@
       return false;
     case FamilyLinkUserLogRecord::Segment::kSupervisionEnabledByFamilyLinkPolicy:
     case FamilyLinkUserLogRecord::Segment::kSupervisionEnabledByFamilyLinkUser:
+    case FamilyLinkUserLogRecord::Segment::kSupervisionEnabledLocally:
       return true;
     case FamilyLinkUserLogRecord::Segment::kMixedProfile:
       NOTREACHED();
diff --git a/components/supervised_user/core/browser/supervised_user_utils.h b/components/supervised_user/core/browser/supervised_user_utils.h
index 952948a..27e1f39 100644
--- a/components/supervised_user/core/browser/supervised_user_utils.h
+++ b/components/supervised_user/core/browser/supervised_user_utils.h
@@ -22,6 +22,7 @@
 class GURL;
 
 namespace supervised_user {
+class SupervisedUserURLFilter;
 
 // Reason for applying the website filtering parental control.
 enum class FilteringBehaviorReason {
diff --git a/components/supervised_user/core/common/features.cc b/components/supervised_user/core/common/features.cc
index a2bc68d..bb2a828 100644
--- a/components/supervised_user/core/common/features.cc
+++ b/components/supervised_user/core/common/features.cc
@@ -127,9 +127,9 @@
 BASE_FEATURE(kPropagateDeviceContentFiltersToSupervisedUser,
              "PropagateDeviceContentFiltersToSupervisedUser",
              base::FEATURE_DISABLED_BY_DEFAULT);
-             BASE_FEATURE(kSupervisedUserInterstitialWithoutApprovals,
-              "SupervisedUserInterstitialWithoutApprovals",
-              base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kSupervisedUserInterstitialWithoutApprovals,
+             "SupervisedUserInterstitialWithoutApprovals",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 #endif
 
 }  // namespace supervised_user
diff --git a/components/supervised_user/core/common/supervised_user_constants.h b/components/supervised_user/core/common/supervised_user_constants.h
index a5c6fb77..5ad2f155 100644
--- a/components/supervised_user/core/common/supervised_user_constants.h
+++ b/components/supervised_user/core/common/supervised_user_constants.h
@@ -56,11 +56,12 @@
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/families/enums.xml:LocalWebApprovalErrorType)
 
-// This enum describes the filter types of Chrome, which is
-// set by Family Link App or at families.google.com/families. These values
-// are logged to UMA. Entries should not be renumbered and numeric values
-// should never be reused. Please keep in sync with "FamilyLinkWebFilterType"
-// in src/tools/metrics/histograms/enums.xml.
+// Describes the current web filter type, which is derived either from Family
+// Link or local settings. The URL filter is present whenever the supervised
+// user service is in use, and consequently offers "disabled" state for those
+// who are not subject to parental controls.
+// Entries must not be renumbered and numeric values should never be reused.
+// LINT.IfChange(FamilyLinkWebFilterType)
 enum class WebFilterType {
   // The web filter is set to "Allow all sites".
   kAllowAllSites = 0,
@@ -74,13 +75,15 @@
   // Used for UMA only. There are multiple web filters on the device.
   kMixed = 3,
 
-  // Web filter is neutralized: it behaves as if there were no filtering.
+  // Web filter is neutralized: it behaves as if there were no filtering and is
+  // not recording metrics.
   kDisabled = 4,
 
   // Used for UMA. Update kMaxValue to the last value. Add future entries
   // above this comment. Sync with enums.xml.
   kMaxValue = kDisabled,
 };
+// LINT.ThenChange(//tools/metrics/histograms/metadata/families/enums.xml:FamilyLinkWebFilterType)
 
 // Returns the string equivalent of a Web Filter type. This is a user-visible
 // string included in the user feedback log.
diff --git a/components/supervised_user_strings.grdp b/components/supervised_user_strings.grdp
index dd3029b..bbea107 100644
--- a/components/supervised_user_strings.grdp
+++ b/components/supervised_user_strings.grdp
@@ -125,4 +125,17 @@
       <message name="IDS_PARENTAL_LOCAL_APPROVAL_SNACKBAR_GENERIC_ERROR_BACK_BUTTON" desc="Button of the error snackbar that is shown when a supervised user asks for parental approval, but the request couldn’t be sent. In this scenario, we don’t know why the request didn’t work, so they need to go back to the previous screen and try again.">
         Close
       </message>
+
+      <if expr="is_android">
+        <message name="IDS_NO_APPROVALS_BACK_BUTTON" desc="Button of the error snackbar that is shown when a supervised user can't request approvals. That's the only way out from the error page.">
+          Back
+        </message>
+        <message name="IDS_NO_APPROVALS_LEARN_MORE_BUTTON" desc="Button of the error snackbar that is shown when a supervised user can't request approvals, that leads to a resource that'll explain what has happened. Displayed below the back button.">
+          Learn more about content filters
+        </message>
+        <message name="IDS_NO_APPROVALS_MESSAGE" desc="A message shown when a supervised user is blocked from accessing a site because of the content filters configured on their device. Followed by the site URL.">
+          Your device's content filters blocked <ph name="BLOCKED_URL">$1</ph>
+        </message>
+      </if>
+
 </grit-part>
diff --git a/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_BACK_BUTTON.png.sha1 b/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_BACK_BUTTON.png.sha1
new file mode 100644
index 0000000..7851c0e
--- /dev/null
+++ b/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_BACK_BUTTON.png.sha1
@@ -0,0 +1 @@
+4d7eb697fc9caa1a5b5e0b7295e93f302c9a80dc
\ No newline at end of file
diff --git a/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_LEARN_MORE_BUTTON.png.sha1 b/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_LEARN_MORE_BUTTON.png.sha1
new file mode 100644
index 0000000..93615aed
--- /dev/null
+++ b/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_LEARN_MORE_BUTTON.png.sha1
@@ -0,0 +1 @@
+ecdc909faf3a41367201666cb27cd9e43f58e8c7
\ No newline at end of file
diff --git a/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_MESSAGE.png.sha1 b/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_MESSAGE.png.sha1
new file mode 100644
index 0000000..1230aae7
--- /dev/null
+++ b/components/supervised_user_strings_grdp/IDS_NO_APPROVALS_MESSAGE.png.sha1
@@ -0,0 +1 @@
+cbfb6695fb5750586898192e3b20dad21c12a13b
\ No newline at end of file
diff --git a/components/sync/engine/syncer_proto_util.cc b/components/sync/engine/syncer_proto_util.cc
index a50a98f..cb856753 100644
--- a/components/sync/engine/syncer_proto_util.cc
+++ b/components/sync/engine/syncer_proto_util.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
diff --git a/components/sync/service/sync_prefs.cc b/components/sync/service/sync_prefs.cc
index e8effb1..1e1e15b 100644
--- a/components/sync/service/sync_prefs.cc
+++ b/components/sync/service/sync_prefs.cc
@@ -295,49 +295,8 @@
           gaia_id_hash, pref_name);
       if (pref_value && pref_value->is_bool()) {
         type_enabled = pref_value->GetBool();
-      } else if (type == UserSelectableType::kHistory ||
-                 type == UserSelectableType::kTabs ||
-                 type == UserSelectableType::kSavedTabGroups) {
-        // History, Tabs, Saved Tab Groups and and Shared Tab Group Data are
-        // disabled by default.
-        type_enabled = false;
-      } else if (type == UserSelectableType::kPasswords ||
-                 type == UserSelectableType::kAutofill) {
-        // kPasswords and kAutofill are only on by default if there was an
-        // explicit sign in recorded.
-        // Otherwise:
-        // - kPasswords requires a dedicated opt-in.
-        // - kAutofill cannot be enabled.
-        // Note: If this changes, also update the migration logic in
-        // MigrateGlobalDataTypePrefsToAccount().
-        type_enabled = IsExplicitBrowserSignin();
-      } else if (type == UserSelectableType::kBookmarks ||
-                 type == UserSelectableType::kReadingList) {
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-        type_enabled =
-            base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos);
-#else
-        // Bookmarks and Reading List require a specific explicit sign in.
-        type_enabled = SigninPrefs(*pref_service_)
-                           .GetBookmarksExplicitBrowserSignin(gaia_id) ||
-                       base::FeatureList::IsEnabled(
-                           kEnableBookmarksSelectedTypeOnSigninForTesting);
-#endif
-      } else if (type == UserSelectableType::kExtensions) {
-        // Extensions require a specific explicit sign in.
-        type_enabled = SigninPrefs(*pref_service_)
-                           .GetExtensionsExplicitBrowserSignin(gaia_id);
-      } else if (type == UserSelectableType::kPreferences ||
-                 type == UserSelectableType::kThemes) {
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-        type_enabled = true;
-#else
-        type_enabled = pref_service_->GetBoolean(
-            ::prefs::kPrefsThemesSearchEnginesAccountStorageEnabled);
-#endif
       } else {
-        // All other types are always enabled by default.
-        type_enabled = true;
+        type_enabled = IsTypeSelectedByDefaultInTransportMode(type, gaia_id);
       }
     }
     if (type_enabled) {
@@ -778,12 +737,7 @@
       // transport mode everywhere.
       return true;
     case UserSelectableType::kHistory:
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
-      return base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos) ||
-             base::FeatureList::IsEnabled(switches::kEnableHistorySyncOptin);
-#else
       return base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos);
-#endif
     case UserSelectableType::kTabs:
       return base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos);
     case UserSelectableType::kProductComparison:
@@ -1156,4 +1110,51 @@
   }
 }
 
+bool SyncPrefs::IsTypeSelectedByDefaultInTransportMode(
+    UserSelectableType type,
+    const GaiaId& gaia_id) const {
+  switch (type) {
+    case UserSelectableType::kPayments:
+      // Payments are enabled in all cases by default.
+      return true;
+    case UserSelectableType::kHistory:
+    case UserSelectableType::kTabs:
+    case UserSelectableType::kSavedTabGroups:
+      // History and tabs require a separate opt in.
+      return false;
+    case UserSelectableType::kPasswords:
+    case UserSelectableType::kAutofill:
+      return IsExplicitBrowserSignin();
+    case UserSelectableType::kBookmarks:
+    case UserSelectableType::kReadingList:
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+      return base::FeatureList::IsEnabled(kReplaceSyncPromosWithSignInPromos);
+#else
+      // Bookmarks and Reading List require a specific explicit sign in.
+      return SigninPrefs(*pref_service_)
+                 .GetBookmarksExplicitBrowserSignin(gaia_id) ||
+             base::FeatureList::IsEnabled(
+                 kEnableBookmarksSelectedTypeOnSigninForTesting);
+#endif
+    case UserSelectableType::kPreferences:
+    case UserSelectableType::kThemes:
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+      return true;
+#else
+      return pref_service_->GetBoolean(
+          ::prefs::kPrefsThemesSearchEnginesAccountStorageEnabled);
+#endif
+    case UserSelectableType::kExtensions:
+      // Extensions require a specific explicit sign in.
+      return SigninPrefs(*pref_service_)
+          .GetExtensionsExplicitBrowserSignin(gaia_id);
+    case UserSelectableType::kApps:
+    case UserSelectableType::kProductComparison:
+    case UserSelectableType::kCookies:
+      // All other types are always enabled by default.
+      return true;
+  }
+  NOTREACHED();
+}
+
 }  // namespace syncer
diff --git a/components/sync/service/sync_prefs.h b/components/sync/service/sync_prefs.h
index 3171264..d636ba47 100644
--- a/components/sync/service/sync_prefs.h
+++ b/components/sync/service/sync_prefs.h
@@ -290,6 +290,11 @@
   static void MaybeMigrateAutofillToPerAccountPref(PrefService* pref_service);
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
+  // Returns whether a UserSelectableType is enabled by default in transport
+  // mode, that is, without an explicit value stored in prefs.
+  bool IsTypeSelectedByDefaultInTransportMode(UserSelectableType type,
+                                              const GaiaId& gaia_id) const;
+
  private:
   static void RegisterTypeSelectedPref(PrefRegistrySimple* prefs,
                                        UserSelectableType type);
diff --git a/components/sync/test/fake_sync_manager.cc b/components/sync/test/fake_sync_manager.cc
index 662ed78..d2559ae 100644
--- a/components/sync/test/fake_sync_manager.cc
+++ b/components/sync/test/fake_sync_manager.cc
@@ -11,6 +11,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/task/sequenced_task_runner.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
diff --git a/components/sync_device_info/device_info_sync_bridge_unittest.cc b/components/sync_device_info/device_info_sync_bridge_unittest.cc
index 8a858cc..c6c794b 100644
--- a/components/sync_device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync_device_info/device_info_sync_bridge_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
diff --git a/components/sync_device_info/fake_local_device_info_provider.cc b/components/sync_device_info/fake_local_device_info_provider.cc
index d76b255..54ff30a 100644
--- a/components/sync_device_info/fake_local_device_info_provider.cc
+++ b/components/sync_device_info/fake_local_device_info_provider.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync_device_info/fake_local_device_info_provider.h"
 
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/protocol/sync_enums.pb.h"
diff --git a/components/system_media_controls/mac/system_media_controls_mac.mm b/components/system_media_controls/mac/system_media_controls_mac.mm
index c808c22..3fa6d5d 100644
--- a/components/system_media_controls/mac/system_media_controls_mac.mm
+++ b/components/system_media_controls/mac/system_media_controls_mac.mm
@@ -5,6 +5,7 @@
 #include "components/system_media_controls/mac/system_media_controls_mac.h"
 
 #include "base/check_is_test.h"
+#include "base/notimplemented.h"
 #include "components/remote_cocoa/browser/application_host.h"
 #include "components/system_media_controls/mac/remote_cocoa/system_media_controls_bridge.h"
 #include "components/system_media_controls/system_media_controls_observer.h"
diff --git a/components/ui_devtools/devtools_client.cc b/components/ui_devtools/devtools_client.cc
index d70231f..dce60d6 100644
--- a/components/ui_devtools/devtools_client.cc
+++ b/components/ui_devtools/devtools_client.cc
@@ -6,6 +6,7 @@
 
 #include <string_view>
 
+#include "base/notimplemented.h"
 #include "components/ui_devtools/devtools_server.h"
 #include "third_party/inspector_protocol/crdtp/dispatch.h"
 #include "third_party/inspector_protocol/crdtp/json.h"
diff --git a/components/ui_devtools/devtools_server.cc b/components/ui_devtools/devtools_server.cc
index 1ff9f03d..c2825f5 100644
--- a/components/ui_devtools/devtools_server.cc
+++ b/components/ui_devtools/devtools_server.cc
@@ -15,6 +15,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/components/user_data_importer/utility/zip_ffi_glue.rs b/components/user_data_importer/utility/zip_ffi_glue.rs
index 7e01071..c2fca9bd 100644
--- a/components/user_data_importer/utility/zip_ffi_glue.rs
+++ b/components/user_data_importer/utility/zip_ffi_glue.rs
@@ -220,14 +220,6 @@
     }
 }
 
-// Consume the rest of the map to avoid getting errors from deserialize_map.
-fn consume_map<'de, M: de::MapAccess<'de>>(mut map: M) -> Result<(), M::Error> {
-    while map.next_key::<de::IgnoredAny>()?.is_some() {
-        let de::IgnoredAny = map.next_value()?;
-    }
-    Ok(())
-}
-
 /// A custom reader that wraps a `zip::read::ZipFile` to implement
 /// `io::BufRead`. This allows `serde_json_lenient` to efficiently read from the
 /// zip entry without loading the entire entry into memory.
@@ -295,6 +287,8 @@
     T: Deserialize<'de> + 'de,
     R: std::io::Read,
 {
+    const VALID_PARTIAL_DESERIALIZATION: &'static str = "Valid partial deserialization";
+
     struct MapVisitor<'de, T>
     where
         T: Deserialize<'de>,
@@ -337,16 +331,24 @@
                     if !has_expected_data_type {
                         return Err(DeserializerError::custom("Unexpected data type"));
                     } else if self.metadata_only {
-                        consume_map(map)?;
-                        return Ok(());
+                        // If only the data type check is required, it has been performed
+                        // successfully, so no further deserialization is required. To prevent
+                        // deserialize_map from generating an error caused by the deserialization
+                        // being incomplete, a valid partial deserialization error is returned here
+                        // and will be interpreted as a valid result below.
+                        return Err(DeserializerError::custom(VALID_PARTIAL_DESERIALIZATION));
                     }
                 } else if actual_key == expected_key {
                     if !has_expected_data_type {
                         return Err(DeserializerError::custom("Found array before metadata"));
                     }
                     map.next_value_seed(ArrayDeserializerSeed(Box::new(self.callback)))?;
-                    consume_map(map)?;
-                    return Ok(());
+                    // At this point, the user data array has been parsed successfully, so no
+                    // further deserialization is required. To prevent deserialize_map from
+                    // generating an error caused by the deserialization being incomplete, a valid
+                    // partial deserialization error is returned here and will be interpreted as a
+                    // valid result below.
+                    return Err(DeserializerError::custom(VALID_PARTIAL_DESERIALIZATION));
                 } else {
                     let de::IgnoredAny = map.next_value()?;
                 }
@@ -360,7 +362,16 @@
     let mut d = serde_json_lenient::Deserializer::from_reader(&mut stream_reader);
     match d.deserialize_map(MapVisitor { file_type, callback, metadata_only }) {
         Ok(_) => Ok(()),
-        Err(e) => Err(anyhow!("JSON parsing error: {}", e)),
+        Err(e) => {
+            // If the error is a valid partial deserialization error, then all the required
+            // tasks have been completed successfully and deserialization was stopped early
+            // to prevent any further unnecessary work, so Ok(()) can be returned in this
+            // case.
+            if e.to_string().starts_with(VALID_PARTIAL_DESERIALIZATION) {
+                return Ok(());
+            }
+            return Err(anyhow!("JSON parsing error: {}", e));
+        }
     }
 }
 
diff --git a/components/user_education/common/user_education_features.cc b/components/user_education/common/user_education_features.cc
index bbb93d5c..4c1aa802 100644
--- a/components/user_education/common/user_education_features.cc
+++ b/components/user_education/common/user_education_features.cc
@@ -165,4 +165,12 @@
       kDefaultPollingInterval);
 }
 
+BASE_FEATURE(kEnableNtpBrowserPromos,
+             "EnableNtpBrowserPromos",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+bool NtpBrowserPromosEnabled() {
+  return base::FeatureList::IsEnabled(kEnableNtpBrowserPromos);
+}
+
 }  // namespace user_education::features
diff --git a/components/user_education/common/user_education_features.h b/components/user_education/common/user_education_features.h
index debea6a1..0509f57 100644
--- a/components/user_education/common/user_education_features.h
+++ b/components/user_education/common/user_education_features.h
@@ -89,6 +89,11 @@
 // Returns the polling interval for the promo controller for User Education 2.5.
 extern base::TimeDelta GetPromoControllerPollingInterval();
 
+// Advertises browser features in New Tab Page promos.
+BASE_DECLARE_FEATURE(kEnableNtpBrowserPromos);
+
+extern bool NtpBrowserPromosEnabled();
+
 }  // namespace user_education::features
 
 #endif  // COMPONENTS_USER_EDUCATION_COMMON_USER_EDUCATION_FEATURES_H_
diff --git a/components/user_education/webui/help_bubble_handler.cc b/components/user_education/webui/help_bubble_handler.cc
index 25d0e5d..480ef12 100644
--- a/components/user_education/webui/help_bubble_handler.cc
+++ b/components/user_education/webui/help_bubble_handler.cc
@@ -20,6 +20,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/components/viz/common/frame_sinks/copy_output_result.cc b/components/viz/common/frame_sinks/copy_output_result.cc
index ee545c1..799fc65 100644
--- a/components/viz/common/frame_sinks/copy_output_result.cc
+++ b/components/viz/common/frame_sinks/copy_output_result.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/check_op.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "third_party/libyuv/include/libyuv.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
 #include "third_party/skia/include/core/SkPixelRef.h"
diff --git a/components/viz/demo/demo_main.cc b/components/viz/demo/demo_main.cc
index dc70376..4cf36b0 100644
--- a/components/viz/demo/demo_main.cc
+++ b/components/viz/demo/demo_main.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/i18n/icu_util.h"
 #include "base/message_loop/message_pump_type.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_executor.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
diff --git a/components/viz/host/client_frame_sink_video_capturer.cc b/components/viz/host/client_frame_sink_video_capturer.cc
index 64df2e7..607df1f 100644
--- a/components/viz/host/client_frame_sink_video_capturer.cc
+++ b/components/viz/host/client_frame_sink_video_capturer.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "media/capture/mojom/video_capture_buffer.mojom.h"
 #include "media/capture/mojom/video_capture_types.mojom.h"
diff --git a/components/viz/host/host_display_client.cc b/components/viz/host/host_display_client.cc
index b84296c..aed83541 100644
--- a/components/viz/host/host_display_client.cc
+++ b/components/viz/host/host_display_client.cc
@@ -4,6 +4,7 @@
 
 #include "components/viz/host/host_display_client.h"
 
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
 
diff --git a/components/viz/service/display/copy_output_scaling_pixeltest.cc b/components/viz/service/display/copy_output_scaling_pixeltest.cc
index b45e1ac..edc5f974 100644
--- a/components/viz/service/display/copy_output_scaling_pixeltest.cc
+++ b/components/viz/service/display/copy_output_scaling_pixeltest.cc
@@ -10,6 +10,7 @@
 
 #include "base/containers/heap_array.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc
index 7195dc7..9f354bc 100644
--- a/components/viz/service/display/display_scheduler.cc
+++ b/components/viz/service/display/display_scheduler.cc
@@ -11,6 +11,7 @@
 #include "base/auto_reset.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/task/delay_policy.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
diff --git a/components/viz/service/display/output_surface.cc b/components/viz/service/display/output_surface.cc
index 4a3029a..ff795eb 100644
--- a/components/viz/service/display/output_surface.cc
+++ b/components/viz/service/display/output_surface.cc
@@ -10,6 +10,7 @@
 
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "components/viz/common/features.h"
 #include "components/viz/service/display/output_surface_client.h"
diff --git a/components/viz/service/display_embedder/skia_output_device.cc b/components/viz/service/display_embedder/skia_output_device.cc
index 712eb06..8763479f 100644
--- a/components/viz/service/display_embedder/skia_output_device.cc
+++ b/components/viz/service/display_embedder/skia_output_device.cc
@@ -8,7 +8,7 @@
 #include <utility>
 
 #include "base/check_op.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/common/task_annotator.h"
 #include "gpu/command_buffer/service/graphite_shared_context.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
index b7ae4fc..bccb52ba 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -12,6 +12,7 @@
 
 #include "base/debug/alias.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "components/viz/common/switches.h"
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index e3c3ce2b..34c4fa2 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
diff --git a/components/viz/test/fake_skia_output_surface.cc b/components/viz/test/fake_skia_output_surface.cc
index 680c7b9..429cac6a 100644
--- a/components/viz/test/fake_skia_output_surface.cc
+++ b/components/viz/test/fake_skia_output_surface.cc
@@ -10,6 +10,7 @@
 
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/components/viz/test/test_context_support.cc b/components/viz/test/test_context_support.cc
index 16c9470c..2b449263 100644
--- a/components/viz/test/test_context_support.cc
+++ b/components/viz/test/test_context_support.cc
@@ -12,6 +12,7 @@
 
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 
 namespace viz {
diff --git a/components/webauthn/core/browser/test_passkey_model.cc b/components/webauthn/core/browser/test_passkey_model.cc
index 059ddf6..031c2d6 100644
--- a/components/webauthn/core/browser/test_passkey_model.cc
+++ b/components/webauthn/core/browser/test_passkey_model.cc
@@ -8,7 +8,7 @@
 #include <iterator>
 #include <optional>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/time/time.h"
 #include "components/sync/protocol/webauthn_credential_specifics.pb.h"
diff --git a/components/webrtc/fake_ssl_client_socket.cc b/components/webrtc/fake_ssl_client_socket.cc
index db7f9f4..b00f57cc 100644
--- a/components/webrtc/fake_ssl_client_socket.cc
+++ b/components/webrtc/fake_ssl_client_socket.cc
@@ -21,6 +21,7 @@
 #include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 
diff --git a/components/webrtc/media_stream_device_enumerator_impl.cc b/components/webrtc/media_stream_device_enumerator_impl.cc
index eb422908..25398980 100644
--- a/components/webrtc/media_stream_device_enumerator_impl.cc
+++ b/components/webrtc/media_stream_device_enumerator_impl.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/media_capture_devices.h"
diff --git a/components/wifi/wifi_service_fuchsia.cc b/components/wifi/wifi_service_fuchsia.cc
index 4a55a08..7361856 100644
--- a/components/wifi/wifi_service_fuchsia.cc
+++ b/components/wifi/wifi_service_fuchsia.cc
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/notreached.h"
+#include "components/wifi/wifi_service.h"
+
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
-#include "components/wifi/wifi_service.h"
 
 namespace wifi {
 
diff --git a/content/browser/accessibility/accessibility_tree_formatter_fuchsia.cc b/content/browser/accessibility/accessibility_tree_formatter_fuchsia.cc
index e649ec0..4ef08a2 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_fuchsia.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_fuchsia.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/accessibility/accessibility_tree_formatter_fuchsia.h"
 
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/content/browser/ai/echo_ai_language_model.cc b/content/browser/ai/echo_ai_language_model.cc
index a112fd9..301e396 100644
--- a/content/browser/ai/echo_ai_language_model.cc
+++ b/content/browser/ai/echo_ai_language_model.cc
@@ -9,6 +9,7 @@
 #include "base/containers/to_vector.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "content/browser/ai/echo_ai_manager_impl.h"
diff --git a/content/browser/bluetooth/web_bluetooth_pairing_manager_impl.cc b/content/browser/bluetooth/web_bluetooth_pairing_manager_impl.cc
index f72ff9c..d7c9e50 100644
--- a/content/browser/bluetooth/web_bluetooth_pairing_manager_impl.cc
+++ b/content/browser/bluetooth/web_bluetooth_pairing_manager_impl.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/bluetooth/web_bluetooth_pairing_manager_delegate.h"
diff --git a/content/browser/find_request_manager.cc b/content/browser/find_request_manager.cc
index 9bc4ba1..33adf34 100644
--- a/content/browser/find_request_manager.cc
+++ b/content/browser/find_request_manager.cc
@@ -11,6 +11,7 @@
 #include "base/containers/queue.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
 #include "content/browser/find_in_page_client.h"
diff --git a/content/browser/font_access/font_enumeration_data_source_fuchsia.cc b/content/browser/font_access/font_enumeration_data_source_fuchsia.cc
index 924fee31..b15206c0 100644
--- a/content/browser/font_access/font_enumeration_data_source_fuchsia.cc
+++ b/content/browser/font_access/font_enumeration_data_source_fuchsia.cc
@@ -4,7 +4,7 @@
 
 #include "content/browser/font_access/font_enumeration_data_source_fuchsia.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/sequence_checker.h"
 #include "third_party/blink/public/common/font_access/font_enumeration_table.pb.h"
 
diff --git a/content/browser/memory/swap_metrics_driver_impl_fuchsia.cc b/content/browser/memory/swap_metrics_driver_impl_fuchsia.cc
index 161615c..1c2ba60 100644
--- a/content/browser/memory/swap_metrics_driver_impl_fuchsia.cc
+++ b/content/browser/memory/swap_metrics_driver_impl_fuchsia.cc
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/browser/swap_metrics_driver.h"
-
 #include <memory>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
+#include "content/public/browser/swap_metrics_driver.h"
 
 namespace content {
 
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc
index 3ee8eec..020fb66d 100644
--- a/content/browser/preloading/prefetch/prefetch_container.cc
+++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -11,6 +11,7 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
diff --git a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc
index 9448e7d..62a22e4 100644
--- a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc
+++ b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc
@@ -14,6 +14,7 @@
 #include "base/command_line.h"
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/fuchsia/process_context.h"
+#include "base/notimplemented.h"
 #include "media/base/supported_video_decoder_config.h"
 #include "media/base/video_codecs.h"
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 47bd43d..5a6d554 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -35,6 +35,7 @@
 #include "base/metrics/metrics_hashes.h"
 #include "base/metrics/user_metrics.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/process/kill.h"
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 5bd8edb..860e570 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -25,6 +25,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index e623561..45348adb 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -17,6 +17,7 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index 7caab47..2784ede8 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -11,6 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index 1f166a7..ece9868 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/browser/service_worker/fake_service_worker.cc b/content/browser/service_worker/fake_service_worker.cc
index 58a014b..91870fe 100644
--- a/content/browser/service_worker/fake_service_worker.cc
+++ b/content/browser/service_worker/fake_service_worker.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index d171fc8..f2cfb5f 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -15,6 +15,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_split.h"
diff --git a/content/browser/tracing/test_tracing_session.cc b/content/browser/tracing/test_tracing_session.cc
index d84e32b..8373ad11 100644
--- a/content/browser/tracing/test_tracing_session.cc
+++ b/content/browser/tracing/test_tracing_session.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/tracing/test_tracing_session.h"
 
+#include "base/notimplemented.h"
 #include "base/task/thread_pool.h"
 #include "third_party/perfetto/protos/perfetto/config/data_source_config.gen.h"
 #include "third_party/perfetto/protos/perfetto/config/trace_config.gen.h"
diff --git a/content/browser/tracing/tracing_scenario_unittest.cc b/content/browser/tracing/tracing_scenario_unittest.cc
index 384c576..6d117a8 100644
--- a/content/browser/tracing/tracing_scenario_unittest.cc
+++ b/content/browser/tracing/tracing_scenario_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/files/file_path.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/task/thread_pool.h"
 #include "base/test/gmock_callback_support.h"
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 047a728..9d30d71 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2091,6 +2091,25 @@
   return GetRenderManager()->GetRenderWidgetHostView();
 }
 
+RenderWidgetHost* WebContentsImpl::FindWidgetAtPoint(const gfx::PointF& point) {
+  if (GetOuterWebContents()) {
+    return GetOuterWebContents()->FindWidgetAtPoint(point);
+  }
+  gfx::PointF transformed_point;
+  input::RenderWidgetHostViewInput* rwhvi =
+      GetInputEventRouter()->GetRenderWidgetHostViewInputAtPoint(
+          static_cast<RenderWidgetHostViewBase*>(
+              GetTopLevelRenderWidgetHostView()),
+          point, &transformed_point);
+
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      static_cast<RenderWidgetHostViewBase*>(rwhvi)->GetRenderWidgetHost());
+  if (!widget_host) {
+    return nullptr;
+  }
+  return widget_host;
+}
+
 WebContentsView* WebContentsImpl::GetView() const {
   return view_.get();
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index b3b676a..64afb1a 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -406,6 +406,7 @@
   RenderViewHostImpl* GetRenderViewHost() override;
   RenderWidgetHostView* GetRenderWidgetHostView() override;
   RenderWidgetHostView* GetTopLevelRenderWidgetHostView() override;
+  RenderWidgetHost* FindWidgetAtPoint(const gfx::PointF& point) override;
   void ClosePage() override;
   std::optional<SkColor> GetThemeColor() override;
   std::optional<SkColor> GetBackgroundColor() override;
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 4917393..c090e7ef 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -13,7 +13,7 @@
 #include "base/check.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "cc/layers/layer.h"
 #include "cc/slim/layer.h"
 #include "components/input/features.h"
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 2e510ad..4d46b2af 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -20,6 +20,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/current_thread.h"
 #include "base/task/thread_pool.h"
diff --git a/content/common/color_parser.cc b/content/common/color_parser.cc
index 945cf64..7122237 100644
--- a/content/common/color_parser.cc
+++ b/content/common/color_parser.cc
@@ -10,7 +10,7 @@
 #include <cmath>
 
 #include "base/containers/contains.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/content/common/features.cc b/content/common/features.cc
index 7e720c8e..7b2bf19 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -197,7 +197,7 @@
 // Enables installed web app matching for getInstalledRelatedApps API.
 BASE_FEATURE(kFilterInstalledAppsWebAppMatching,
              "FilterInstalledAppsWebAppMatching",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 #if BUILDFLAG(IS_WIN)
 // Enables installed windows app matching for getInstalledRelatedApps API.
 // Note: This is enabled by default as a kill switch, since the functionality
diff --git a/content/common/input/synthetic_mouse_driver.cc b/content/common/input/synthetic_mouse_driver.cc
index 29d7314..3dc8127 100644
--- a/content/common/input/synthetic_mouse_driver.cc
+++ b/content/common/input/synthetic_mouse_driver.cc
@@ -5,6 +5,7 @@
 #include "content/common/input/synthetic_mouse_driver.h"
 
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/common/input/synthetic_gesture_target.h"
diff --git a/content/common/input/synthetic_pointer_action_unittest.cc b/content/common/input/synthetic_pointer_action_unittest.cc
index 0a3ed688..6d5c1e64 100644
--- a/content/common/input/synthetic_pointer_action_unittest.cc
+++ b/content/common/input/synthetic_pointer_action_unittest.cc
@@ -7,6 +7,7 @@
 #include <array>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
diff --git a/content/common/input/synthetic_touch_driver.cc b/content/common/input/synthetic_touch_driver.cc
index 4d38e5ac..ac567283 100644
--- a/content/common/input/synthetic_touch_driver.cc
+++ b/content/common/input/synthetic_touch_driver.cc
@@ -4,6 +4,7 @@
 
 #include "content/common/input/synthetic_touch_driver.h"
 
+#include "base/notimplemented.h"
 #include "content/common/input/synthetic_gesture_target.h"
 
 namespace content {
diff --git a/content/common/service_worker/race_network_request_url_loader_client.cc b/content/common/service_worker/race_network_request_url_loader_client.cc
index 9a47127b..bde75230 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client.cc
@@ -9,6 +9,7 @@
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/system/sys_info.h"
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 9337d9d..acedc33 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -14,6 +14,7 @@
 #include "base/files/file_path.h"
 #include "base/functional/callback_helpers.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/supports_user_data.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 778e245..ff12574 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -112,6 +112,10 @@
 class ColorProviderSource;
 }  // namespace ui
 
+namespace gfx {
+class PointF;
+}  // namespace gfx
+
 namespace content {
 
 class BackForwardTransitionAnimationManager;
@@ -120,6 +124,7 @@
 class GuestPageHolder;
 class RenderFrameHost;
 class RenderViewHost;
+class RenderWidgetHost;
 class RenderWidgetHostView;
 class ScreenOrientationDelegate;
 class SiteInstance;
@@ -549,6 +554,10 @@
   // menus.
   virtual RenderWidgetHostView* GetTopLevelRenderWidgetHostView() = 0;
 
+  // Returns the RenderWidgetHost at the point in web contents coordinate space.
+  // Might be nullptr if nothing hits.
+  virtual RenderWidgetHost* FindWidgetAtPoint(const gfx::PointF& point) = 0;
+
   // This determines which RenderFrameHosts will contribute to the
   // `AXTreeUpdate` generated by the `RequestAXTreeSnapshot` call:
   // - kAll will use all reachable RenderFrameHosts.
diff --git a/content/public/common/content_client.cc b/content/public/common/content_client.cc
index b1052ec..dcd1080 100644
--- a/content/public/common/content_client.cc
+++ b/content/public/common/content_client.cc
@@ -8,7 +8,7 @@
 
 #include "base/memory/ref_counted_memory.h"
 #include "base/no_destructor.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_view_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h
index 97dd00c..ae9fb985 100644
--- a/content/public/test/mock_navigation_handle.h
+++ b/content/public/test/mock_navigation_handle.h
@@ -11,6 +11,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/types/optional_util.h"
 #include "content/public/browser/child_process_host.h"
 #include "content/public/browser/global_request_id.h"
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 9d48e47..974bfd2 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -14,7 +14,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/process/process_handle.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/content/public/test/test_image_transport_factory.cc b/content/public/test/test_image_transport_factory.cc
index d9f6b91..946c50c 100644
--- a/content/public/test/test_image_transport_factory.cc
+++ b/content/public/test/test_image_transport_factory.cc
@@ -7,6 +7,7 @@
 #include <limits>
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "components/viz/test/test_in_process_context_provider.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/content/public/test/test_web_ui.cc b/content/public/test/test_web_ui.cc
index e66ed6e..4fc609fe 100644
--- a/content/public/test/test_web_ui.cc
+++ b/content/public/test/test_web_ui.cc
@@ -10,7 +10,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/no_destructor.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.cc b/content/renderer/pepper/mock_renderer_ppapi_host.cc
index 9b90b1f..402d7c0 100644
--- a/content/renderer/pepper/mock_renderer_ppapi_host.cc
+++ b/content/renderer/pepper/mock_renderer_ppapi_host.cc
@@ -4,6 +4,7 @@
 
 #include "content/renderer/pepper/mock_renderer_ppapi_host.h"
 
+#include "base/notimplemented.h"
 #include "content/renderer/pepper/fake_pepper_plugin_instance.h"
 #include "ui/gfx/geometry/point.h"
 
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 76b2e50..59fb9fbd 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -19,6 +19,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_offset_string_conversions.h"
diff --git a/content/renderer/pepper/pepper_video_encoder_host.cc b/content/renderer/pepper/pepper_video_encoder_host.cc
index b9b0f08..7231220 100644
--- a/content/renderer/pepper/pepper_video_encoder_host.cc
+++ b/content/renderer/pepper/pepper_video_encoder_host.cc
@@ -8,6 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_math.h"
 #include "build/build_config.h"
 #include "content/common/pepper_file_util.h"
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
index dfde8459..5c706a24 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -15,6 +15,7 @@
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/content/renderer/pepper/v8_var_converter_unittest.cc b/content/renderer/pepper/v8_var_converter_unittest.cc
index 1df5824..e0dc17c 100644
--- a/content/renderer/pepper/v8_var_converter_unittest.cc
+++ b/content/renderer/pepper/v8_var_converter_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 73b4ea2..98fc086 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -21,6 +21,7 @@
 #include "base/json/json_writer.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
index 8de767f..f533cd03 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -12,6 +12,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "content/public/common/content_features.h"
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index be10cdb..ac8393fa 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/services/auction_worklet/auction_v8_devtools_agent.cc b/content/services/auction_worklet/auction_v8_devtools_agent.cc
index 092c419..875ba19 100644
--- a/content/services/auction_worklet/auction_v8_devtools_agent.cc
+++ b/content/services/auction_worklet/auction_v8_devtools_agent.cc
@@ -9,7 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "content/services/auction_worklet/auction_v8_devtools_session.h"
 #include "content/services/auction_worklet/auction_v8_helper.h"
diff --git a/content/services/auction_worklet/auction_v8_devtools_session.cc b/content/services/auction_worklet/auction_v8_devtools_session.cc
index 0b74e4b..ccbd3ce 100644
--- a/content/services/auction_worklet/auction_v8_devtools_session.cc
+++ b/content/services/auction_worklet/auction_v8_devtools_session.cc
@@ -14,6 +14,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/sequence_checker.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/shell/browser/shell_download_manager_delegate.cc b/content/shell/browser/shell_download_manager_delegate.cc
index 2476f25..78dec2a 100644
--- a/content/shell/browser/shell_download_manager_delegate.cc
+++ b/content/shell/browser/shell_download_manager_delegate.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/files/file_path.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "components/download/public/common/download_target_info.h"
 
diff --git a/content/shell/common/shell_paths.cc b/content/shell/common/shell_paths.cc
index 4552a44..a6cf42f 100644
--- a/content/shell/common/shell_paths.cc
+++ b/content/shell/common/shell_paths.cc
@@ -9,6 +9,7 @@
 #include "base/environment.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 41ced95..76e9ac74 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1390,6 +1390,12 @@
   }
 }
 
+static_library("content_test_entry") {
+  testonly = true
+
+  sources = [ "content_test_launcher_exe.cc" ]
+}
+
 test("content_browsertests") {
   use_xvfb = use_xvfb_in_this_config
 
@@ -1837,6 +1843,7 @@
 
   deps = [
     ":browsertest_support",
+    ":content_test_entry",
     ":content_test_mojo_bindings",
     ":default_content_test_launcher",
     ":test_support",
@@ -2012,10 +2019,10 @@
     ]
 
     if (target_platform == "iphoneos") {
-      bundle_deps += [
-        ":content_process_bundle",
-        ":gpu_process_bundle",
-        ":network_process_bundle",
+      deps += [
+        "//content/test/ios/appex:test_content_process_bundle",
+        "//content/test/ios/appex:test_gpu_process_bundle",
+        "//content/test/ios/appex:test_network_process_bundle",
       ]
     }
   } else {
@@ -3643,29 +3650,6 @@
     testonly = true
     filelist_name = "content_test_bundle_data.filelist"
   }
-
-  if (current_toolchain == default_toolchain) {
-    _extension_toolchain = "${current_toolchain}_blink_app_ext"
-    extension_bundle_data("content_process_bundle") {
-      testonly = true
-      extension_dir = "Extensions"
-      extension_name = "test_content_process.appex"
-      extension_target = "//content/test/ios/appex:test_content_process(${_extension_toolchain})"
-    }
-    extension_bundle_data("network_process_bundle") {
-      testonly = true
-      extension_dir = "Extensions"
-      extension_name = "test_network_process.appex"
-      extension_target = "//content/test/ios/appex:test_network_process(${_extension_toolchain})"
-    }
-    extension_bundle_data("gpu_process_bundle") {
-      testonly = true
-      extension_dir = "Extensions"
-      extension_name = "test_gpu_process.appex"
-      extension_target =
-          "//content/test/ios/appex:test_gpu_process(${_extension_toolchain})"
-    }
-  }
 }
 if (is_apple) {
   bundle_data("content_test_perfetto_bundle_data") {
diff --git a/content/test/content_test_launcher.cc b/content/test/content_test_launcher.cc
index 436b873c..536144f 100644
--- a/content/test/content_test_launcher.cc
+++ b/content/test/content_test_launcher.cc
@@ -80,12 +80,7 @@
 
 }  // namespace content
 
-#if BUILDFLAG(IS_IOS) && BUILDFLAG(IS_IOS_APP_EXTENSION)
-extern "C" int ChildProcessMain(int argc, const char** argv)
-#else
-int main(int argc, char** argv)
-#endif
-{
+extern "C" int ContentTestMain(int argc, const char** argv) {
   base::CommandLine::Init(argc, argv);
   size_t parallel_jobs = base::NumParallelJobs(/*cores_per_job=*/2);
   if (parallel_jobs == 0U)
@@ -108,3 +103,9 @@
   return LaunchTests(&launcher_delegate, parallel_jobs, argc,
                      const_cast<char**>(argv));
 }
+
+#if BUILDFLAG(IS_IOS)
+extern "C" int ChildProcessMain(int argc, const char** argv) {
+  return ContentTestMain(argc, argv);
+}
+#endif
diff --git a/content/test/content_test_launcher_exe.cc b/content/test/content_test_launcher_exe.cc
new file mode 100644
index 0000000..547c89f1
--- /dev/null
+++ b/content/test/content_test_launcher_exe.cc
@@ -0,0 +1,9 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern "C" int ContentTestMain(int argc, const char** argv);
+
+int main(int argc, const char** argv) {
+  return ContentTestMain(argc, argv);
+}
diff --git a/content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.cc b/content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.cc
index 84ceedb..e6c65a2 100644
--- a/content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.cc
+++ b/content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.h"
+
 #include <memory>
 #include <string>
 #include <utility>
 
-#include "content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.h"
-
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/blink/public/mojom/presentation/presentation.mojom-mojolpm.h"
diff --git a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
index 4c14fb3..2ed72bed 100644
--- a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
@@ -108,6 +108,7 @@
 # Failures/Flakes #
 ###################
 # Non-"Skip" expectations go here to suppress regular flakes/failures.
+crbug.com/426232297 [ mac intel-0x3e9b angle-metal asan ] HardwareAcceleratedFeature_2d_canvas_accelerated [ Slow ]
 
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
index 9f4ded60..efa07ac 100644
--- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -233,6 +233,9 @@
 crbug.com/398149367 [ win11 amd-0x7480 ] WebGPUCachingTraceTest_RenderPipelineDifferentOrigins [ Failure ]
 crbug.com/398149367 [ win11 amd-0x7480 ] WebGPUCachingTraceTest_RenderPipelineIncognito [ Failure ]
 
+# Win10/Intel failures
+crbug.com/398218431 [ win11 intel-0x9bc5 ] TraceTest_MediaFoundationD3D11VideoCapture [ Failure ]
+
 # DirectionComposition seems to flakily fail
 crbug.com/403536258 [ win angle-d3d11 intel-0x4680 graphite-enabled passthrough ] VideoPathTraceTest_DirectComposition_Video_MP4_NV12 [ RetryOnFailure ]
 crbug.com/419617732 [ win angle-d3d11 nvidia-0x2184 graphite-enabled passthrough ] VideoPathTraceTest_DirectComposition_Video_MP4_NV12 [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index 6586c12..e917f43e 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -192,6 +192,19 @@
 crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_offscreen [ Failure ]
 crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_sw_decoder [ Failure ]
 
+# Mac Intel SharedImage Synchronization Flakes
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_DrawImage_camera [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_EncodeDecode_arraybuffer_hvc1.1.6.L123.00_prefer-software [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_EncodeDecode_offscreen_avc1.42001E_prefer-* [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_EncodeDecode_offscreen_hvc1.1.6.L123.00_prefer-software [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_EncodeDecode_offscreen_vp09.00.10.08_prefer-software [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_EncodingRateControl_hvc1.1.6.L123.00_prefer-software_* [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_EncodingRateControl_vp8_prefer-software_constant_2000000 [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_ManualSVC_av01.0.04M.08_prefer-software_layers_* [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_SVC_avc1.42001E_prefer-* [ Failure ]
+crbug.com/417899571 [ mac intel-0x3e9b angle-metal ] WebCodecs_SVC_vp09.00.10.08_prefer-software_layers_* [ Failure ]
+
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 4d871ed..df40345 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -753,31 +753,16 @@
 # Canvas missing colored squares - synchronization issue.
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ]
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-2d-rgb565-rgb-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-2d-rgb5_a1-rgba-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-2d-rg8-rg-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-3d-rgb9_e5-rgb-float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-3d-rgb9_e5-rgb-half_float.html [ Failure ]
+crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-2d* [ Failure ]
+crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas/tex-3d* [ Failure ]
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas_sub_rectangle/tex-2d-rgb5_a1-rgba-unsigned_byte.html [ Failure ]
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/canvas_sub_rectangle/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html [ Failure ]
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_canvas/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-2d-r32f-red-float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-2d-rgb16f-rgb-half_float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-2d-rgb565-rgb-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-3d-r11f_g11f_b10f-rgb-half_float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-3d-rg16f-rg-half_float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-3d-rgb565-rgb-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-3d-rgb9_e5-rgb-half_float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-3d-rgba16f-rgba-float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/tex-3d-rgba32f-rgba-float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/video/tex-2d-r11f_g11f_b10f-rgb-float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/video/tex-3d-rgba16f-rgba-float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/webgl_canvas/tex-3d-rg8ui-rg_integer-unsigned_byte.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/webgl_canvas/tex-3d-rgba16f-rgba-float.html [ Failure ]
-crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/webgl_canvas/tex-3d-rgba32f-rgba-float.html [ Failure ]
+crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
+crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/image_bitmap_from_video/* [ Failure ]
+crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/video/tex-2d* [ Failure ]
+crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/video/tex-3d* [ Failure ]
+crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] conformance2/textures/webgl_canvas/tex-3d* [ Failure ]
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] deqp/functional/gles3/fbomultisample.4_samples.html [ Failure ]
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] deqp/functional/gles3/fbomultisample.8_samples.html [ Failure ]
 crbug.com/425671158 [ mac intel-0x3e9b angle-metal ] deqp/functional/gles3/framebufferblit/conversion_24.html [ Failure ]
diff --git a/content/test/ios/appex/BUILD.gn b/content/test/ios/appex/BUILD.gn
index ddcdbd5..59e158af 100644
--- a/content/test/ios/appex/BUILD.gn
+++ b/content/test/ios/appex/BUILD.gn
@@ -2,108 +2,19 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/apple/compile_entitlements.gni")
-import("//build/apple/tweak_info_plist.gni")
-import("//build/config/ios/rules.gni")
-import("//ios/build/chrome_build.gni")
-import("//ios/build/config.gni")
+import("//content/test/ios/appex/extensions.gni")
 
-tweak_info_plist("tweak_content_process_plist") {
-  info_plist = "../../../app/ios/appex/content_process.plist"
-}
-
-tweak_info_plist("tweak_network_process_plist") {
-  info_plist = "../../../app/ios/appex/network_process.plist"
-}
-tweak_info_plist("tweak_gpu_process_plist") {
-  info_plist = "../../../app/ios/appex/gpu_process.plist"
-}
-
-compile_entitlements("content_process_entitlements") {
-  substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
-  output_name = "$target_gen_dir/content_process.appex.entitlements"
-  entitlements_templates =
-      [ "../../../app/ios/appex/content_process.appex.entitlements" ]
-}
-
-compile_entitlements("network_process_entitlements") {
-  substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
-  output_name = "$target_gen_dir/network_process.appex.entitlements"
-  entitlements_templates =
-      [ "../../../app/ios/appex/network_process.appex.entitlements" ]
-}
-
-compile_entitlements("gpu_process_entitlements") {
-  substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
-  output_name = "$target_gen_dir/gpu_process.appex.entitlements"
-  entitlements_templates =
-      [ "../../../app/ios/appex/gpu_process.appex.entitlements" ]
-}
-
-ios_appex_bundle("test_content_process") {
+browserkit_extension("gpu_process") {
   testonly = true
-  output_name = "test_content_process"
-
-  ldflags = [ "-Wl,--ignore-auto-link-option=CoreAudioTypes" ]
-
-  deps = [
-    "//content/app/ios/appex:content_process",
-    "//content/public/app",
-    "//content/shell:content_shell_lib",
-    "//content/test:default_content_test_launcher",
-  ]
-  bundle_deps = [
-    "//content/shell:content_shell_framework_resources",
-    "//content/shell/app/ios/resources",
-  ]
-
-  entitlements_target = ":content_process_entitlements"
-  info_plist_target = ":tweak_content_process_plist"
-  bundle_identifier = "$shared_bundle_id_for_test_apps.ContentProcessExtension"
+  bundle_identifier = "$shared_bundle_id_for_test_apps.GPUProcessExtension"
 }
 
-ios_appex_bundle("test_network_process") {
+browserkit_extension("network_process") {
   testonly = true
-  output_name = "test_network_process"
-
-  ldflags = [ "-Wl,--ignore-auto-link-option=CoreAudioTypes" ]
-
-  deps = [
-    "//content/app/ios/appex:network_process",
-    "//content/public/app",
-    "//content/shell:content_shell_app",
-    "//content/shell:content_shell_lib",
-    "//content/test:default_content_test_launcher",
-  ]
-  bundle_deps = [
-    "//content/shell:content_shell_framework_resources",
-    "//content/shell/app/ios/resources",
-  ]
-
-  entitlements_target = ":network_process_entitlements"
-  info_plist_target = ":tweak_network_process_plist"
   bundle_identifier = "$shared_bundle_id_for_test_apps.NetworkProcessExtension"
 }
 
-ios_appex_bundle("test_gpu_process") {
+browserkit_extension("content_process") {
   testonly = true
-  output_name = "test_gpu_process"
-
-  ldflags = [ "-Wl,--ignore-auto-link-option=CoreAudioTypes" ]
-
-  deps = [
-    "//content/app/ios/appex:gpu_process",
-    "//content/public/app",
-    "//content/shell:content_shell_app",
-    "//content/shell:content_shell_lib",
-    "//content/test:default_content_test_launcher",
-  ]
-  bundle_deps = [
-    "//content/shell:content_shell_framework_resources",
-    "//content/shell/app/ios/resources",
-  ]
-
-  entitlements_target = ":gpu_process_entitlements"
-  info_plist_target = ":tweak_gpu_process_plist"
-  bundle_identifier = "$shared_bundle_id_for_test_apps.GPUProcessExtension"
+  bundle_identifier = "$shared_bundle_id_for_test_apps.ContentProcessExtension"
 }
diff --git a/content/test/ios/appex/extensions.gni b/content/test/ios/appex/extensions.gni
new file mode 100644
index 0000000..3265348
--- /dev/null
+++ b/content/test/ios/appex/extensions.gni
@@ -0,0 +1,81 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/apple/compile_entitlements.gni")
+import("//build/apple/tweak_info_plist.gni")
+import("//build/config/ios/rules.gni")
+import("//build/ios/extension_bundle_data.gni")
+import("//ios/build/chrome_build.gni")
+import("//ios/build/config.gni")
+
+template("browserkit_extension") {
+  _process_target = target_name
+  _bundle_name = "test_${_process_target}"
+  target_name = _bundle_name
+  tweak_info_plist("tweak_${target_name}_plist") {
+    info_plist = "//content/app/ios/appex/${_process_target}.plist"
+  }
+
+  extension_bundle_data("${target_name}_bundle") {
+    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
+    extension_dir = "Extensions"
+    extension_name = "${_bundle_name}.appex"
+    extension_target = ":${_bundle_name}"
+  }
+
+  compile_entitlements("${target_name}_entitlements") {
+    substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
+    output_name = "$target_gen_dir/${_process_target}.appex.entitlements"
+    entitlements_templates =
+        [ "//content/app/ios/appex/${_process_target}.appex.entitlements" ]
+  }
+
+  # We don't use ios_appex_bundle here because we don't want to mess with multiple
+  # toolkits as the core framework is built with the default toolkit.
+  ios_app_bundle(target_name) {
+    forward_variables_from(invoker,
+                           "*",
+                           [
+                             "defines",
+                             "deps",
+                             "framework_dirs",
+                             "frameworks",
+                             "public_deps",
+                             "sources",
+                             "target_name",
+                           ])
+    output_name = target_name
+    transparent = true
+
+    deps = [
+      "//content/app/ios/appex:${_process_target}",
+      "//content/public/app",
+      "//content/public/app",
+      "//content/public/common",
+      "//content/shell:content_shell_app",
+      "//content/shell:content_shell_lib",
+      "//content/test:browsertest_support",
+      "//content/test:default_content_test_launcher",
+      "//third_party/icu:icudata",
+    ]
+
+    if (!defined(ldflags)) {
+      ldflags = []
+    }
+
+    ldflags += [
+      "-Wl,--ignore-auto-link-option=CoreAudioTypes",
+      "-Wl,-no_application_extension",
+      "-Wl,-rpath,@executable_path/../../Frameworks",
+    ]
+
+    product_type = "com.apple.product-type.app-extension"
+    entitlements_target = ":${target_name}_entitlements"
+    info_plist_target = ":tweak_${target_name}_plist"
+  }
+}
+
+set_defaults("browserkit_extension") {
+  configs = [ "//build/config/ios:ios_extension_executable_flags" ]
+}
diff --git a/content/test/mock_keyboard.cc b/content/test/mock_keyboard.cc
index c9200ce1..791808fd 100644
--- a/content/test/mock_keyboard.cc
+++ b/content/test/mock_keyboard.cc
@@ -5,7 +5,7 @@
 #include "content/test/mock_keyboard.h"
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc
index de480e2..87909c35 100644
--- a/content/test/test_render_view_host.cc
+++ b/content/test/test_render_view_host.cc
@@ -8,6 +8,7 @@
 #include <optional>
 #include <tuple>
 
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "components/input/render_widget_host_input_event_router.h"
diff --git a/crypto/secure_hash.cc b/crypto/secure_hash.cc
index dd58ccd..61896e1 100644
--- a/crypto/secure_hash.cc
+++ b/crypto/secure_hash.cc
@@ -12,7 +12,7 @@
 #include <stddef.h>
 
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/pickle.h"
 #include "crypto/openssl_util.h"
 #include "third_party/boringssl/src/include/openssl/mem.h"
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc
index bcebb4a..b167d89 100644
--- a/device/bluetooth/bluetooth_adapter.cc
+++ b/device/bluetooth/bluetooth_adapter.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/device/bluetooth/bluetooth_adapter_android.cc b/device/bluetooth/bluetooth_adapter_android.cc
index 57bba0ef..95f13d6 100644
--- a/device/bluetooth/bluetooth_adapter_android.cc
+++ b/device/bluetooth/bluetooth_adapter_android.cc
@@ -15,6 +15,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "device/base/features.h"
 #include "device/bluetooth/android/wrappers.h"
@@ -24,7 +25,6 @@
 #include "device/bluetooth/bluetooth_device_android.h"
 #include "device/bluetooth/bluetooth_discovery_session_outcome.h"
 #include "device/bluetooth/bluetooth_socket_thread.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "device/bluetooth/jni_headers/ChromeBluetoothAdapter_jni.h"
 #include "device/bluetooth/jni_headers/ChromeBluetoothScanFilterBuilder_jni.h"
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index bec1f2e..f300e8d3 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -23,6 +23,7 @@
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_ioobject.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc
index 4d930ddc..1bbe729 100644
--- a/device/bluetooth/bluetooth_adapter_win.cc
+++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/stl_util.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/device/bluetooth/bluetooth_adapter_winrt.cc b/device/bluetooth/bluetooth_adapter_winrt.cc
index 60e9d90..4c5c34f 100644
--- a/device/bluetooth/bluetooth_adapter_winrt.cc
+++ b/device/bluetooth/bluetooth_adapter_winrt.cc
@@ -21,6 +21,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/scoped_native_library.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/device/bluetooth/bluetooth_classic_device_mac.mm b/device/bluetooth/bluetooth_classic_device_mac.mm
index 5a57357..aa7cb3e0e 100644
--- a/device/bluetooth/bluetooth_classic_device_mac.mm
+++ b/device/bluetooth/bluetooth_classic_device_mac.mm
@@ -8,6 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/hash/hash.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
diff --git a/device/bluetooth/bluetooth_classic_win_fake.cc b/device/bluetooth/bluetooth_classic_win_fake.cc
index 98483bd..409d8f1 100644
--- a/device/bluetooth/bluetooth_classic_win_fake.cc
+++ b/device/bluetooth/bluetooth_classic_win_fake.cc
@@ -6,7 +6,7 @@
 
 #include "base/check_op.h"
 #include "base/compiler_specific.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 
 namespace device {
diff --git a/device/bluetooth/bluetooth_device_android.cc b/device/bluetooth/bluetooth_device_android.cc
index e7c6d23c..a37853f 100644
--- a/device/bluetooth/bluetooth_device_android.cc
+++ b/device/bluetooth/bluetooth_device_android.cc
@@ -15,6 +15,7 @@
 #include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/stl_util.h"
 #include "base/task/sequenced_task_runner.h"
 #include "device/base/features.h"
@@ -23,7 +24,6 @@
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service_android.h"
 #include "device/bluetooth/bluetooth_socket_android.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "device/bluetooth/jni_headers/ChromeBluetoothDevice_jni.h"
 
diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc
index 507e180..0261181 100644
--- a/device/bluetooth/bluetooth_device_win.cc
+++ b/device/bluetooth/bluetooth_device_win.cc
@@ -10,7 +10,7 @@
 #include "base/check_op.h"
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "device/bluetooth/bluetooth_adapter_win.h"
 #include "device/bluetooth/bluetooth_service_record_win.h"
diff --git a/device/bluetooth/bluetooth_device_winrt.cc b/device/bluetooth/bluetooth_device_winrt.cc
index ba62b48..3ae0b8f 100644
--- a/device/bluetooth/bluetooth_device_winrt.cc
+++ b/device/bluetooth/bluetooth_device_winrt.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/win/core_winrt_util.h"
diff --git a/device/bluetooth/bluetooth_local_gatt_descriptor.cc b/device/bluetooth/bluetooth_local_gatt_descriptor.cc
index 03c7a744..170d521 100644
--- a/device/bluetooth/bluetooth_local_gatt_descriptor.cc
+++ b/device/bluetooth/bluetooth_local_gatt_descriptor.cc
@@ -4,7 +4,7 @@
 
 #include "device/bluetooth/bluetooth_local_gatt_descriptor.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \
     !defined(LINUX_WITHOUT_DBUS)
diff --git a/device/bluetooth/bluetooth_low_energy_adapter_apple.mm b/device/bluetooth/bluetooth_low_energy_adapter_apple.mm
index 21216c8..9a94049 100644
--- a/device/bluetooth/bluetooth_low_energy_adapter_apple.mm
+++ b/device/bluetooth/bluetooth_low_energy_adapter_apple.mm
@@ -25,6 +25,7 @@
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.mm b/device/bluetooth/bluetooth_low_energy_device_mac.mm
index b0e1c544..e6b6fe4 100644
--- a/device/bluetooth/bluetooth_low_energy_device_mac.mm
+++ b/device/bluetooth/bluetooth_low_energy_device_mac.mm
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "crypto/hash.h"
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
index cf029322..a93cd16 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
@@ -13,11 +13,11 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "device/bluetooth/bluetooth_adapter_android.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_android.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service_android.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "device/bluetooth/jni_headers/ChromeBluetoothRemoteGattCharacteristic_jni.h"
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
index d0e334e..1210f576 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/task/single_thread_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
index 7838872a..dca5f13 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
@@ -15,6 +15,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/win/post_async_results.h"
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
index 02620e6..67f82911 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
@@ -11,10 +11,9 @@
 #include "base/android/jni_string.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service_android.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "device/bluetooth/jni_headers/ChromeBluetoothRemoteGattDescriptor_jni.h"
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
index 75e4931..169dab0 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
@@ -6,6 +6,7 @@
 
 #import "base/apple/foundation_util.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/task/single_thread_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.cc b/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.cc
index df73fbfd..f14aab3 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/win/post_async_results.h"
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_android.cc b/device/bluetooth/bluetooth_remote_gatt_service_android.cc
index c010074..6386b0e 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_service_android.cc
@@ -10,10 +10,10 @@
 #include "base/android/jni_string.h"
 #include "base/containers/contains.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "device/bluetooth/bluetooth_adapter_android.h"
 #include "device/bluetooth/bluetooth_device_android.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_android.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "device/bluetooth/jni_headers/ChromeBluetoothRemoteGattService_jni.h"
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_mac.mm b/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
index ab80f9f..1a51be0 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
@@ -11,6 +11,7 @@
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "device/bluetooth/bluetooth_low_energy_adapter_apple.h"
 #include "device/bluetooth/bluetooth_low_energy_device_mac.h"
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_winrt.cc b/device/bluetooth/bluetooth_remote_gatt_service_winrt.cc
index fb5bf9b..b7ce095 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_winrt.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_service_winrt.cc
@@ -10,6 +10,7 @@
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_gatt_discoverer_winrt.h"
diff --git a/device/bluetooth/bluez/bluetooth_device_bluez.cc b/device/bluetooth/bluez/bluetooth_device_bluez.cc
index 5730838..223b0663 100644
--- a/device/bluetooth/bluez/bluetooth_device_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_device_bluez.cc
@@ -19,6 +19,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/device/bluetooth/cast/bluetooth_adapter_cast.cc b/device/bluetooth/cast/bluetooth_adapter_cast.cc
index 1f7ce72b5..d33a68e 100644
--- a/device/bluetooth/cast/bluetooth_adapter_cast.cc
+++ b/device/bluetooth/cast/bluetooth_adapter_cast.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "chromecast/device/bluetooth/bluetooth_util.h"
 #include "chromecast/device/bluetooth/le/gatt_client_manager.h"
 #include "chromecast/device/bluetooth/le/le_scan_manager.h"
diff --git a/device/bluetooth/cast/bluetooth_device_cast.cc b/device/bluetooth/cast/bluetooth_device_cast.cc
index 37f488dd..17858b8 100644
--- a/device/bluetooth/cast/bluetooth_device_cast.cc
+++ b/device/bluetooth/cast/bluetooth_device_cast.cc
@@ -11,6 +11,7 @@
 
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "chromecast/device/bluetooth/bluetooth_util.h"
 #include "chromecast/device/bluetooth/le/remote_characteristic.h"
 #include "chromecast/device/bluetooth/le/remote_service.h"
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc b/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc
index 24b34059..97166d30 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc
@@ -11,6 +11,7 @@
 #include "base/containers/to_vector.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "chromecast/device/bluetooth/le/remote_descriptor.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
 #include "device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h"
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc b/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc
index 4abca92..d7eda19b 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "chromecast/device/bluetooth/le/remote_characteristic.h"
 #include "chromecast/device/bluetooth/le/remote_service.h"
 #include "device/bluetooth/cast/bluetooth_device_cast.h"
diff --git a/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc b/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
index 598003e..3341a25 100644
--- a/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
@@ -11,6 +11,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/device/bluetooth/dbus/fake_bluetooth_advertisement_monitor_manager_client.cc b/device/bluetooth/dbus/fake_bluetooth_advertisement_monitor_manager_client.cc
index fc3c2d2b..b77da5ac 100644
--- a/device/bluetooth/dbus/fake_bluetooth_advertisement_monitor_manager_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_advertisement_monitor_manager_client.cc
@@ -6,7 +6,7 @@
 
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
diff --git a/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc b/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc
index 64371dae..0db6208 100644
--- a/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc
+++ b/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc
@@ -11,6 +11,7 @@
 
 #include "base/containers/to_vector.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_runner.h"
 #include "device/bluetooth/emulation/fake_central.h"
diff --git a/device/bluetooth/floss/bluetooth_adapter_floss.cc b/device/bluetooth/floss/bluetooth_adapter_floss.cc
index 0269ffa3..ca672f6 100644
--- a/device/bluetooth/floss/bluetooth_adapter_floss.cc
+++ b/device/bluetooth/floss/bluetooth_adapter_floss.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/observer_list.h"
 #include "base/strings/string_util.h"
diff --git a/device/bluetooth/floss/bluetooth_device_floss.cc b/device/bluetooth/floss/bluetooth_device_floss.cc
index 564c791..5115a458 100644
--- a/device/bluetooth/floss/bluetooth_device_floss.cc
+++ b/device/bluetooth/floss/bluetooth_device_floss.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/task/sequenced_task_runner.h"
 #include "components/device_event_log/device_event_log.h"
diff --git a/device/bluetooth/gatt_service.cc b/device/bluetooth/gatt_service.cc
index a880ebe..36fe121 100644
--- a/device/bluetooth/gatt_service.cc
+++ b/device/bluetooth/gatt_service.cc
@@ -6,6 +6,7 @@
 
 #include "base/containers/contains.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_local_gatt_characteristic.h"
 #include "device/bluetooth/device.h"
diff --git a/device/bluetooth/test/bluetooth_test.cc b/device/bluetooth/test/bluetooth_test.cc
index 98f698a..27a4887 100644
--- a/device/bluetooth/test/bluetooth_test.cc
+++ b/device/bluetooth/test/bluetooth_test.cc
@@ -10,6 +10,7 @@
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
diff --git a/device/bluetooth/test/fake_local_gatt_characteristic.cc b/device/bluetooth/test/fake_local_gatt_characteristic.cc
index 91d5b52..93db9f7 100644
--- a/device/bluetooth/test/fake_local_gatt_characteristic.cc
+++ b/device/bluetooth/test/fake_local_gatt_characteristic.cc
@@ -4,6 +4,7 @@
 
 #include "device/bluetooth/test/fake_local_gatt_characteristic.h"
 
+#include "base/notimplemented.h"
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
 
 namespace bluetooth {
diff --git a/device/bluetooth/test/fake_local_gatt_service.cc b/device/bluetooth/test/fake_local_gatt_service.cc
index 55a7380..f1d4f299 100644
--- a/device/bluetooth/test/fake_local_gatt_service.cc
+++ b/device/bluetooth/test/fake_local_gatt_service.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "device/bluetooth/test/fake_local_gatt_service.h"
+
 #include "base/containers/contains.h"
+#include "base/notimplemented.h"
 
 namespace bluetooth {
 
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
index 59219e8..f843d920 100644
--- a/device/fido/cable/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -20,6 +20,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/device/fido/cable/v2_handshake.cc b/device/fido/cable/v2_handshake.cc
index 3f7366b..1ebea4a 100644
--- a/device/fido/cable/v2_handshake.cc
+++ b/device/fido/cable/v2_handshake.cc
@@ -684,8 +684,8 @@
 bool ShouldOfferLinking(RequestType request_type) {
   return std::visit(
       absl::Overload{[](const FidoRequestType&) {
-                       return base::FeatureList::IsEnabled(
-                           device::kWebAuthnHybridLinking);
+                       // Hybrid linking is not supported for WebAuthn.
+                       return false;
                      },
                      [](const CredentialRequestType&) {
                        return base::FeatureList::IsEnabled(
diff --git a/device/fido/cable/v2_handshake_unittest.cc b/device/fido/cable/v2_handshake_unittest.cc
index 1ff384c..1b5c3ee 100644
--- a/device/fido/cable/v2_handshake_unittest.cc
+++ b/device/fido/cable/v2_handshake_unittest.cc
@@ -90,35 +90,30 @@
 }
 
 TEST(CableV2Encoding, QRs) {
-  for (bool supports_linking : {false, true}) {
-    SCOPED_TRACE(supports_linking);
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatureState(device::kWebAuthnHybridLinking,
-                                             supports_linking);
-    std::array<uint8_t, kQRKeySize> qr_key;
-    crypto::RandBytes(qr_key);
-    std::string url = qr::Encode(qr_key, FidoRequestType::kMakeCredential);
-    const std::optional<qr::Components> decoded = qr::Parse(url);
-    ASSERT_TRUE(decoded.has_value()) << url;
-    static_assert(kQRKeySize >= std::tuple_size_v<decltype(decoded->secret)>);
-    EXPECT_EQ(memcmp(decoded->secret.data(),
-                     &qr_key[qr_key.size() - decoded->secret.size()],
-                     decoded->secret.size()),
-              0);
-    // There are two registered domains at the time of writing the test. That
-    // number should only grow over time.
-    EXPECT_GE(decoded->num_known_domains, 2u);
+  base::test::ScopedFeatureList scoped_feature_list;
+  std::array<uint8_t, kQRKeySize> qr_key;
+  crypto::RandBytes(qr_key);
+  std::string url = qr::Encode(qr_key, FidoRequestType::kMakeCredential);
+  const std::optional<qr::Components> decoded = qr::Parse(url);
+  ASSERT_TRUE(decoded.has_value()) << url;
+  static_assert(kQRKeySize >= std::tuple_size_v<decltype(decoded->secret)>);
+  EXPECT_EQ(memcmp(decoded->secret.data(),
+                   &qr_key[qr_key.size() - decoded->secret.size()],
+                   decoded->secret.size()),
+            0);
+  // There are two registered domains at the time of writing the test. That
+  // number should only grow over time.
+  EXPECT_GE(decoded->num_known_domains, 2u);
 
-    // Chromium always sets this flag.
-    EXPECT_EQ(decoded->supports_linking.value_or(false), supports_linking);
+  // Chromium never offers linking for WebAuthn.
+  EXPECT_FALSE(*decoded->supports_linking);
 
-    EXPECT_EQ(decoded->request_type,
-              RequestType(FidoRequestType::kMakeCredential));
+  EXPECT_EQ(decoded->request_type,
+            RequestType(FidoRequestType::kMakeCredential));
 
-    url[0] ^= 4;
-    EXPECT_FALSE(qr::Parse(url));
-    EXPECT_FALSE(qr::Parse("nonsense"));
-  }
+  url[0] ^= 4;
+  EXPECT_FALSE(qr::Parse(url));
+  EXPECT_FALSE(qr::Parse("nonsense"));
 }
 
 TEST(CableV2Encoding, KnownQRs) {
@@ -319,21 +314,18 @@
 }
 
 TEST(CableV2Encoding, ShouldOfferLinking) {
-  const struct TestCase {
-    device::cablev2::RequestType request_type;
-    base::test::FeatureRef feature;
-  } kTestCases[] = {
-      {FidoRequestType::kMakeCredential, device::kWebAuthnHybridLinking},
-      {FidoRequestType::kGetAssertion, device::kWebAuthnHybridLinking},
-      {CredentialRequestType::kPresentation,
-       device::kDigitalCredentialsHybridLinking}};
-  for (const TestCase& test_case : kTestCases) {
-    for (bool enabled : {false, true}) {
-      base::test::ScopedFeatureList scoped_feature_list;
-      scoped_feature_list.InitWithFeatureState(*test_case.feature, enabled);
-      EXPECT_EQ(ShouldOfferLinking(test_case.request_type), enabled);
-    }
+  {
+    base::test::ScopedFeatureList scoped_feature_list{
+        kDigitalCredentialsHybridLinking};
+    EXPECT_TRUE(ShouldOfferLinking(CredentialRequestType::kPresentation));
   }
+  {
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndDisableFeature(kDigitalCredentialsHybridLinking);
+    EXPECT_FALSE(ShouldOfferLinking(CredentialRequestType::kPresentation));
+  }
+  EXPECT_FALSE(ShouldOfferLinking(FidoRequestType::kGetAssertion));
+  EXPECT_FALSE(ShouldOfferLinking(FidoRequestType::kMakeCredential));
 }
 
 TEST(CableV2Encoding, PaddedCBOR) {
diff --git a/device/fido/features.cc b/device/fido/features.cc
index 7150204f..d5589f5 100644
--- a/device/fido/features.cc
+++ b/device/fido/features.cc
@@ -103,11 +103,6 @@
              "WebAuthenticationAmbientSignin",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// This is a deprecation flag. Disabled in M136. Remove in or after M139.
-BASE_FEATURE(kWebAuthnHybridLinking,
-             "WebAuthenticationHybridLinking",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // This is a deprecation flag. It is now enabled by default, but we want to
 // disable it eventually.
 // Must not be disabled until kWebAuthnHybridLinking is disabled by default.
diff --git a/device/fido/features.h b/device/fido/features.h
index bb35c39..2dd0766e 100644
--- a/device/fido/features.h
+++ b/device/fido/features.h
@@ -64,11 +64,6 @@
 COMPONENT_EXPORT(DEVICE_FIDO)
 BASE_DECLARE_FEATURE(kWebAuthnAmbientSignin);
 
-// Enables linking of hybrid devices to Chrome, both pre-linking (i.e. through
-// Sync) and through hybrid.
-COMPONENT_EXPORT(DEVICE_FIDO)
-BASE_DECLARE_FEATURE(kWebAuthnHybridLinking);
-
 // Enables publishing prelinking information on Android.
 #if BUILDFLAG(IS_ANDROID)
 COMPONENT_EXPORT(DEVICE_FIDO)
diff --git a/device/gamepad/test_support/fake_igamepad.cc b/device/gamepad/test_support/fake_igamepad.cc
index 0d184af..9b941e37 100644
--- a/device/gamepad/test_support/fake_igamepad.cc
+++ b/device/gamepad/test_support/fake_igamepad.cc
@@ -5,7 +5,7 @@
 #include "device/gamepad/test_support/fake_igamepad.h"
 
 #include "base/containers/flat_map.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "device/gamepad/test_support/fake_winrt_wgi_environment.h"
 
 using ABI::Windows::Foundation::ITypedEventHandler;
diff --git a/device/gamepad/test_support/fake_igamepad_statics.cc b/device/gamepad/test_support/fake_igamepad_statics.cc
index 6e50824..46646a8 100644
--- a/device/gamepad/test_support/fake_igamepad_statics.cc
+++ b/device/gamepad/test_support/fake_igamepad_statics.cc
@@ -4,7 +4,7 @@
 
 #include "device/gamepad/test_support/fake_igamepad_statics.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
diff --git a/device/gamepad/test_support/fake_iraw_game_controller.cc b/device/gamepad/test_support/fake_iraw_game_controller.cc
index 460bbba..33fc0f91 100644
--- a/device/gamepad/test_support/fake_iraw_game_controller.cc
+++ b/device/gamepad/test_support/fake_iraw_game_controller.cc
@@ -4,7 +4,7 @@
 
 #include "device/gamepad/test_support/fake_iraw_game_controller.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/win/scoped_hstring.h"
 #include "device/gamepad/test_support/fake_winrt_wgi_environment.h"
 
diff --git a/device/gamepad/test_support/fake_winrt_wgi_environment.cc b/device/gamepad/test_support/fake_winrt_wgi_environment.cc
index 68a3bad..d6a88a3c 100644
--- a/device/gamepad/test_support/fake_winrt_wgi_environment.cc
+++ b/device/gamepad/test_support/fake_winrt_wgi_environment.cc
@@ -4,7 +4,7 @@
 
 #include "device/gamepad/test_support/fake_winrt_wgi_environment.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/test/bind.h"
 #include "base/win/scoped_hstring.h"
 #include "device/gamepad/test_support/fake_igamepad_statics.h"
diff --git a/extensions/browser/api/file_system/file_system_api.cc b/extensions/browser/api/file_system/file_system_api.cc
index 6302e708..8f09c2f 100644
--- a/extensions/browser/api/file_system/file_system_api.cc
+++ b/extensions/browser/api/file_system/file_system_api.cc
@@ -22,6 +22,7 @@
 #include "base/json/values_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc b/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
index d138d1e..65127f0 100644
--- a/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
+++ b/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
@@ -5,6 +5,7 @@
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chromeos/ash/components/dbus/media_analytics/fake_media_analytics_client.h"
 #include "chromeos/ash/components/dbus/media_analytics/media_analytics_client.h"
diff --git a/extensions/browser/api/messaging/messaging_delegate.cc b/extensions/browser/api/messaging/messaging_delegate.cc
index 9e0415c..a4c1a19 100644
--- a/extensions/browser/api/messaging/messaging_delegate.cc
+++ b/extensions/browser/api/messaging/messaging_delegate.cc
@@ -5,7 +5,7 @@
 #include "extensions/browser/api/messaging/messaging_delegate.h"
 
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "extensions/common/extension_id.h"
 
 namespace extensions {
diff --git a/extensions/browser/api/serial/serial_apitest.cc b/extensions/browser/api/serial/serial_apitest.cc
index 7fffd44..a294963 100644
--- a/extensions/browser/api/serial/serial_apitest.cc
+++ b/extensions/browser/api/serial/serial_apitest.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/unguessable_token.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/extensions/browser/api/system_cpu/cpu_info_provider_fuchsia.cc b/extensions/browser/api/system_cpu/cpu_info_provider_fuchsia.cc
index 5739cd0..58cd02d7 100644
--- a/extensions/browser/api/system_cpu/cpu_info_provider_fuchsia.cc
+++ b/extensions/browser/api/system_cpu/cpu_info_provider_fuchsia.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/browser/api/system_cpu/cpu_info_provider.h"
 
+#include "base/notimplemented.h"
+
 namespace extensions {
 
 bool CpuInfoProvider::QueryCpuTimePerProcessor(
diff --git a/extensions/browser/api/system_display/display_info_provider.cc b/extensions/browser/api/system_display/display_info_provider.cc
index 4704b4c..8fd2ecf 100644
--- a/extensions/browser/api/system_display/display_info_provider.cc
+++ b/extensions/browser/api/system_display/display_info_provider.cc
@@ -5,6 +5,7 @@
 #include "extensions/browser/api/system_display/display_info_provider.h"
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc
index f40aba60..38eb1cc 100644
--- a/extensions/browser/api/web_request/web_request_info.cc
+++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -14,6 +14,7 @@
 #include "base/check_op.h"
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/types/zip.h"
 #include "base/values.h"
 #include "components/guest_view/buildflags/buildflags.h"
diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc
index 372536b2..2a56816f 100644
--- a/extensions/shell/app/shell_main_delegate.cc
+++ b/extensions/shell/app/shell_main_delegate.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
diff --git a/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc b/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc
index 42fccb68..625bfea 100644
--- a/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc
+++ b/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc
@@ -6,7 +6,7 @@
 
 #include <string>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 #include "build/chromeos_buildflags.h"
 #include "components/feedback/content/feedback_uploader_factory.h"
diff --git a/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc b/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
index e1da868..0451abbb 100644
--- a/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
+++ b/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
@@ -7,7 +7,7 @@
 #include "apps/saved_files_service.h"
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "extensions/browser/api/file_system/saved_files_service_interface.h"
 #include "extensions/browser/extension_function.h"
 
diff --git a/extensions/shell/browser/shell_app_delegate.cc b/extensions/shell/browser/shell_app_delegate.cc
index 31b3b68..010bbae 100644
--- a/extensions/shell/browser/shell_app_delegate.cc
+++ b/extensions/shell/browser/shell_app_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/shell/browser/shell_app_delegate.h"
 
+#include "base/notimplemented.h"
 #include "content/public/browser/color_chooser.h"
 #include "content/public/browser/file_select_listener.h"
 #include "content/public/browser/web_contents.h"
diff --git a/extensions/shell/browser/shell_app_window_client.cc b/extensions/shell/browser/shell_app_window_client.cc
index a86c201..1d6c7bff 100644
--- a/extensions/shell/browser/shell_app_window_client.cc
+++ b/extensions/shell/browser/shell_app_window_client.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "base/notimplemented.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/shell/browser/shell_app_delegate.h"
 
diff --git a/extensions/shell/browser/shell_native_app_window.cc b/extensions/shell/browser/shell_native_app_window.cc
index 982749a9..0621d06 100644
--- a/extensions/shell/browser/shell_native_app_window.cc
+++ b/extensions/shell/browser/shell_native_app_window.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/shell/browser/shell_native_app_window.h"
 
+#include "base/notimplemented.h"
 #include "extensions/shell/browser/desktop_controller.h"
 #include "third_party/blink/public/mojom/page/draggable_region.mojom.h"
 #include "third_party/skia/include/core/SkRegion.h"
diff --git a/extensions/shell/browser/shell_native_app_window_mac.mm b/extensions/shell/browser/shell_native_app_window_mac.mm
index e940ca4..3843417 100644
--- a/extensions/shell/browser/shell_native_app_window_mac.mm
+++ b/extensions/shell/browser/shell_native_app_window_mac.mm
@@ -8,7 +8,7 @@
 
 #include "base/apple/foundation_util.h"
 #include "base/memory/raw_ptr_exclusion.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/display/display.h"
diff --git a/extensions/shell/browser/shell_virtual_keyboard_delegate.cc b/extensions/shell/browser/shell_virtual_keyboard_delegate.cc
index 51d2d90a..d1814cd 100644
--- a/extensions/shell/browser/shell_virtual_keyboard_delegate.cc
+++ b/extensions/shell/browser/shell_virtual_keyboard_delegate.cc
@@ -7,7 +7,7 @@
 #include <memory>
 #include <utility>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 
 namespace extensions {
diff --git a/extensions/shell/common/shell_extensions_client.cc b/extensions/shell/common/shell_extensions_client.cc
index 692bf7c..5317db08 100644
--- a/extensions/shell/common/shell_extensions_client.cc
+++ b/extensions/shell/common/shell_extensions_client.cc
@@ -9,6 +9,7 @@
 
 #include "base/check.h"
 #include "base/lazy_instance.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "components/version_info/version_info.h"
 #include "extensions/common/core_extensions_api_provider.h"
diff --git a/fuchsia_web/runners/cast/cast_resolver.cc b/fuchsia_web/runners/cast/cast_resolver.cc
index fe29ffa1..789ea08 100644
--- a/fuchsia_web/runners/cast/cast_resolver.cc
+++ b/fuchsia_web/runners/cast/cast_resolver.cc
@@ -8,7 +8,6 @@
 #include <fidl/fuchsia.component/cpp/fidl.h>
 #include <fidl/fuchsia.ui.app/cpp/wire_messaging.h>
 #include <lib/fidl/cpp/natural_types.h>
-
 #include <stdint.h>
 
 #include <string>
@@ -17,7 +16,7 @@
 
 #include "base/files/file_util.h"
 #include "base/fuchsia/fuchsia_logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/numerics/byte_conversions.h"
 
 namespace {
diff --git a/fuchsia_web/webengine/browser/fake_navigation_policy_provider.cc b/fuchsia_web/webengine/browser/fake_navigation_policy_provider.cc
index ec1dc0fe4..4f86166 100644
--- a/fuchsia_web/webengine/browser/fake_navigation_policy_provider.cc
+++ b/fuchsia_web/webengine/browser/fake_navigation_policy_provider.cc
@@ -4,7 +4,7 @@
 
 #include "fuchsia_web/webengine/browser/fake_navigation_policy_provider.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 FakeNavigationPolicyProvider::FakeNavigationPolicyProvider() = default;
diff --git a/fuchsia_web/webengine/browser/fake_semantic_tree.cc b/fuchsia_web/webengine/browser/fake_semantic_tree.cc
index e637fd9..3bf98402 100644
--- a/fuchsia_web/webengine/browser/fake_semantic_tree.cc
+++ b/fuchsia_web/webengine/browser/fake_semantic_tree.cc
@@ -10,7 +10,7 @@
 #include <string_view>
 
 #include "base/auto_reset.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/fuchsia_web/webengine/browser/fake_semantics_manager.cc b/fuchsia_web/webengine/browser/fake_semantics_manager.cc
index 2f8044cf..c256612b 100644
--- a/fuchsia_web/webengine/browser/fake_semantics_manager.cc
+++ b/fuchsia_web/webengine/browser/fake_semantics_manager.cc
@@ -5,7 +5,7 @@
 #include "fuchsia_web/webengine/browser/fake_semantics_manager.h"
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 
 FakeSemanticsManager::FakeSemanticsManager() = default;
diff --git a/fuchsia_web/webengine/browser/frame_impl.cc b/fuchsia_web/webengine/browser/frame_impl.cc
index bd09d0f3..570cfeb 100644
--- a/fuchsia_web/webengine/browser/frame_impl.cc
+++ b/fuchsia_web/webengine/browser/frame_impl.cc
@@ -24,6 +24,7 @@
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/metrics/user_metrics.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
diff --git a/fuchsia_web/webengine/browser/media_player_impl.cc b/fuchsia_web/webengine/browser/media_player_impl.cc
index c08e74a..e5da63e 100644
--- a/fuchsia_web/webengine/browser/media_player_impl.cc
+++ b/fuchsia_web/webengine/browser/media_player_impl.cc
@@ -10,6 +10,7 @@
 
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "content/public/browser/media_session.h"
diff --git a/fuchsia_web/webengine/browser/web_engine_browser_context.cc b/fuchsia_web/webengine/browser/web_engine_browser_context.cc
index 845d94f..5e7bd2e 100644
--- a/fuchsia_web/webengine/browser/web_engine_browser_context.cc
+++ b/fuchsia_web/webengine/browser/web_engine_browser_context.cc
@@ -14,6 +14,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/fuchsia/fuchsia_logging.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/strings/string_split.h"
 #include "base/threading/thread_restrictions.h"
diff --git a/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc b/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc
index 47f23a58..0a529c3 100644
--- a/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc
+++ b/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc
@@ -8,7 +8,7 @@
 
 #include "base/check_op.h"
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "components/permissions/permission_util.h"
 #include "content/public/browser/permission_controller.h"
 #include "fuchsia_web/webengine/browser/frame_impl.h"
diff --git a/fuchsia_web/webengine/renderer/web_engine_audio_renderer.cc b/fuchsia_web/webengine/renderer/web_engine_audio_renderer.cc
index ad133da..111616da 100644
--- a/fuchsia_web/webengine/renderer/web_engine_audio_renderer.cc
+++ b/fuchsia_web/webengine/renderer/web_engine_audio_renderer.cc
@@ -14,6 +14,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
diff --git a/google_apis/gcm/base/socket_stream.cc b/google_apis/gcm/base/socket_stream.cc
index 7d7b5ff..3034292 100644
--- a/google_apis/gcm/base/socket_stream.cc
+++ b/google_apis/gcm/base/socket_stream.cc
@@ -16,6 +16,7 @@
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "net/base/io_buffer.h"
 #include "net/socket/stream_socket.h"
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index dea4b21..da1a636 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -31,6 +31,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/stack_allocated.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_math.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_manager.h"
diff --git a/gpu/command_buffer/client/shared_image_interface.cc b/gpu/command_buffer/client/shared_image_interface.cc
index 2287acf..50b6b93e 100644
--- a/gpu/command_buffer/client/shared_image_interface.cc
+++ b/gpu/command_buffer/client/shared_image_interface.cc
@@ -7,6 +7,7 @@
 #include <GLES2/gl2.h>
 
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/process/memory.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
diff --git a/gpu/command_buffer/client/webgpu_implementation.cc b/gpu/command_buffer/client/webgpu_implementation.cc
index 00fb4a9..dc1affbc 100644
--- a/gpu/command_buffer/client/webgpu_implementation.cc
+++ b/gpu/command_buffer/client/webgpu_implementation.cc
@@ -14,6 +14,7 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/run_loop.h"
 #include "base/trace_event/trace_event.h"
diff --git a/gpu/command_buffer/service/command_buffer_direct.cc b/gpu/command_buffer/service/command_buffer_direct.cc
index 2977288f..2286ca8 100644
--- a/gpu/command_buffer/service/command_buffer_direct.cc
+++ b/gpu/command_buffer/service/command_buffer_direct.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 52f741c..d475242d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -42,6 +42,7 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_math.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index 091d7c1..71c2d77 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -18,6 +18,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_split.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index 6fb0765..724b517 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -16,6 +16,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 6ab51ce..31a3c6a 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -32,6 +32,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index c4050eb..ab5f883 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -12,6 +12,7 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/immediate_crash.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/observer_list.h"
 #include "base/strings/string_split.h"
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
index 621bed47..ade9e9f5 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
@@ -14,6 +14,7 @@
 
 #include "base/bits.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
diff --git a/gpu/command_buffer/service/shared_image/ozone_image_backing.cc b/gpu/command_buffer/service/shared_image/ozone_image_backing.cc
index c3a85be..4df41f1f 100644
--- a/gpu/command_buffer/service/shared_image/ozone_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/ozone_image_backing.cc
@@ -13,6 +13,7 @@
 #include "base/debug/crash_logging.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "build/build_config.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
diff --git a/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc b/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc
index 739b16b..75e1351 100644
--- a/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc
@@ -5,6 +5,7 @@
 #include "gpu/command_buffer/service/shared_image/raw_draw_image_backing.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/types/optional_util.h"
 #include "cc/paint/paint_op_buffer.h"
 #include "components/viz/common/resources/resource_sizes.h"
diff --git a/gpu/command_buffer/service/shared_image/shared_image_backing.cc b/gpu/command_buffer/service/shared_image/shared_image_backing.cc
index 5abd9ca8..3491ad5 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_backing.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "build/build_config.h"
diff --git a/gpu/command_buffer/service/shared_image/shared_memory_image_backing.cc b/gpu/command_buffer/service/shared_image/shared_memory_image_backing.cc
index 0a63273..626002a 100644
--- a/gpu/command_buffer/service/shared_image/shared_memory_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/shared_memory_image_backing.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "components/viz/common/resources/resource_sizes.h"
diff --git a/gpu/command_buffer/service/shared_image/video_image_reader_image_backing.cc b/gpu/command_buffer/service/shared_image/video_image_reader_image_backing.cc
index afa613b3..e14779c 100644
--- a/gpu/command_buffer/service/shared_image/video_image_reader_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/video_image_reader_image_backing.cc
@@ -9,6 +9,7 @@
 #include "base/android/android_hardware_buffer_compat.h"
 #include "base/android/scoped_hardware_buffer_fence_sync.h"
 #include "base/android/scoped_hardware_buffer_handle.h"
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/single_thread_task_runner.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index 03368c8d..eaba446 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -22,6 +22,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ref.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/checked_math.h"
 #include "base/power_monitor/power_monitor.h"
diff --git a/gpu/config/gpu_driver_bug_workarounds.cc b/gpu/config/gpu_driver_bug_workarounds.cc
index 09afc3e..e2aa911 100644
--- a/gpu/config/gpu_driver_bug_workarounds.cc
+++ b/gpu/config/gpu_driver_bug_workarounds.cc
@@ -7,7 +7,7 @@
 #include <algorithm>
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace {
 // Construct GpuDriverBugWorkarounds from a set of enabled workaround IDs.
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc b/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc
index c6c8275..ca3fee9bd 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc
@@ -10,6 +10,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/mac/io_surface.h"
 
diff --git a/gpu/ipc/service/image_decode_accelerator_stub.cc b/gpu/ipc/service/image_decode_accelerator_stub.cc
index 827b363c..7d332b7 100644
--- a/gpu/ipc/service/image_decode_accelerator_stub.cc
+++ b/gpu/ipc/service/image_decode_accelerator_stub.cc
@@ -18,6 +18,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/gpu/ipc/service/webgpu_command_buffer_stub.cc b/gpu/ipc/service/webgpu_command_buffer_stub.cc
index 686fe2c..2c44777ea 100644
--- a/gpu/ipc/service/webgpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/webgpu_command_buffer_stub.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/constants.h"
diff --git a/gpu/vulkan/android/vulkan_implementation_android.cc b/gpu/vulkan/android/vulkan_implementation_android.cc
index 9bbdf22..cf50805 100644
--- a/gpu/vulkan/android/vulkan_implementation_android.cc
+++ b/gpu/vulkan/android/vulkan_implementation_android.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
diff --git a/gpu/vulkan/mac/vulkan_implementation_mac.cc b/gpu/vulkan/mac/vulkan_implementation_mac.cc
index a517806..509b56f6 100644
--- a/gpu/vulkan/mac/vulkan_implementation_mac.cc
+++ b/gpu/vulkan/mac/vulkan_implementation_mac.cc
@@ -6,6 +6,7 @@
 
 #include "base/check.h"
 #include "base/files/file_path.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
 #include "gpu/vulkan/vulkan_image.h"
diff --git a/gpu/vulkan/tests/native_window.cc b/gpu/vulkan/tests/native_window.cc
index f2c7101..cc303db 100644
--- a/gpu/vulkan/tests/native_window.cc
+++ b/gpu/vulkan/tests/native_window.cc
@@ -5,6 +5,7 @@
 #include "gpu/vulkan/tests/native_window.h"
 
 #include "base/containers/flat_map.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "ui/platform_window/platform_window_delegate.h"
 #include "ui/platform_window/platform_window_init_properties.h"
diff --git a/gpu/vulkan/vulkan_image_fuchsia.cc b/gpu/vulkan/vulkan_image_fuchsia.cc
index 14f4e6f..83e84f92 100644
--- a/gpu/vulkan/vulkan_image_fuchsia.cc
+++ b/gpu/vulkan/vulkan_image_fuchsia.cc
@@ -5,6 +5,7 @@
 #include "gpu/vulkan/vulkan_image.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "gpu/vulkan/fuchsia/vulkan_fuchsia_ext.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
diff --git a/gpu/vulkan/vulkan_image_mac.cc b/gpu/vulkan/vulkan_image_mac.cc
index 63907fd..7108e4c 100644
--- a/gpu/vulkan/vulkan_image_mac.cc
+++ b/gpu/vulkan/vulkan_image_mac.cc
@@ -4,7 +4,7 @@
 
 #include "gpu/vulkan/vulkan_image.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace gpu {
 
diff --git a/gpu/vulkan/vulkan_image_win.cc b/gpu/vulkan/vulkan_image_win.cc
index d3b6472..1d0440c5 100644
--- a/gpu/vulkan/vulkan_image_win.cc
+++ b/gpu/vulkan/vulkan_image_win.cc
@@ -5,6 +5,7 @@
 #include "gpu/vulkan/vulkan_image.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
 
diff --git a/gpu/vulkan/win32/vulkan_implementation_win32.cc b/gpu/vulkan/win32/vulkan_implementation_win32.cc
index 5e9d1c2..61dd7bc 100644
--- a/gpu/vulkan/win32/vulkan_implementation_win32.cc
+++ b/gpu/vulkan/win32/vulkan_implementation_win32.cc
@@ -8,6 +8,7 @@
 
 #include "base/check.h"
 #include "base/files/file_path.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
 #include "gpu/vulkan/vulkan_image.h"
diff --git a/headless/lib/browser/headless_window_tree_host.cc b/headless/lib/browser/headless_window_tree_host.cc
index c961d3a..cb0a0d1 100644
--- a/headless/lib/browser/headless_window_tree_host.cc
+++ b/headless/lib/browser/headless_window_tree_host.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/containers/flat_set.h"
+#include "base/notimplemented.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "headless/lib/browser/headless_focus_client.h"
 #include "headless/lib/browser/headless_window_parenting_client.h"
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc
index 5936642..b6134d8 100644
--- a/headless/lib/headless_content_main_delegate.cc
+++ b/headless/lib/headless_content_main_delegate.cc
@@ -21,6 +21,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/process/current_process.h"
 #include "base/run_loop.h"
diff --git "a/infra/config/generated/builders/ci/Android FYI Release \050Pixel 2\051/targets/chromium.gpu.fyi.json" "b/infra/config/generated/builders/ci/Android FYI Release \050Pixel 2\051/targets/chromium.gpu.fyi.json"
index d3332947..3b38e3a 100644
--- "a/infra/config/generated/builders/ci/Android FYI Release \050Pixel 2\051/targets/chromium.gpu.fyi.json"
+++ "b/infra/config/generated/builders/ci/Android FYI Release \050Pixel 2\051/targets/chromium.gpu.fyi.json"
@@ -334,6 +334,47 @@
         },
         "test": "telemetry_gpu_integration_test_android_chrome",
         "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/"
+      },
+      {
+        "args": [
+          "webgl1_conformance",
+          "--show-stdout",
+          "--browser=android-chromium",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=gles --use-cmd-decoder=passthrough --use-gl=angle --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_android_runtimes.json",
+          "--jobs=1",
+          "--initial-find-device-attempts=3"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gles_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "device_os": "QQ1A.191205.008",
+            "device_os_flavor": "google",
+            "device_os_type": "userdebug",
+            "device_type": "walleye",
+            "os": "Android",
+            "pool": "chromium.tests"
+          },
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "telemetry_gpu_integration_test_android_chrome",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/"
       }
     ]
   }
diff --git a/infra/config/generated/builders/ci/GPU FYI Android arm Builder/targets/chromium.gpu.fyi.json b/infra/config/generated/builders/ci/GPU FYI Android arm Builder/targets/chromium.gpu.fyi.json
index 548d9f47..dc7f17b9 100644
--- a/infra/config/generated/builders/ci/GPU FYI Android arm Builder/targets/chromium.gpu.fyi.json
+++ b/infra/config/generated/builders/ci/GPU FYI Android arm Builder/targets/chromium.gpu.fyi.json
@@ -862,6 +862,47 @@
         },
         "test": "telemetry_gpu_integration_test_android_chrome",
         "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/"
+      },
+      {
+        "args": [
+          "webgl1_conformance",
+          "--show-stdout",
+          "--browser=android-chromium",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=gles --use-cmd-decoder=passthrough --use-gl=angle --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_android_runtimes.json",
+          "--jobs=1",
+          "--initial-find-device-attempts=3"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gles_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "device_os": "QQ1A.191205.008",
+            "device_os_flavor": "google",
+            "device_os_type": "userdebug",
+            "device_type": "walleye",
+            "os": "Android",
+            "pool": "chromium.tests"
+          },
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "telemetry_gpu_integration_test_android_chrome",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/"
       }
     ]
   },
diff --git a/infra/config/generated/builders/ci/android-angle-chromium-arm64-builder/targets/chromium.angle.json b/infra/config/generated/builders/ci/android-angle-chromium-arm64-builder/targets/chromium.angle.json
index 4ca45fa8..ee02964 100644
--- a/infra/config/generated/builders/ci/android-angle-chromium-arm64-builder/targets/chromium.angle.json
+++ b/infra/config/generated/builders/ci/android-angle-chromium-arm64-builder/targets/chromium.angle.json
@@ -27,7 +27,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
diff --git a/infra/config/generated/builders/ci/android-angle-chromium-arm64-pixel2/targets/chromium.angle.json b/infra/config/generated/builders/ci/android-angle-chromium-arm64-pixel2/targets/chromium.angle.json
index 09ce55a..5bd800fb 100644
--- a/infra/config/generated/builders/ci/android-angle-chromium-arm64-pixel2/targets/chromium.angle.json
+++ b/infra/config/generated/builders/ci/android-angle-chromium-arm64-pixel2/targets/chromium.angle.json
@@ -26,7 +26,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
diff --git a/infra/config/generated/builders/try/android-angle-chromium-try/targets/chromium.angle.json b/infra/config/generated/builders/try/android-angle-chromium-try/targets/chromium.angle.json
index 4ca45fa8..ee02964 100644
--- a/infra/config/generated/builders/try/android-angle-chromium-try/targets/chromium.angle.json
+++ b/infra/config/generated/builders/try/android-angle-chromium-try/targets/chromium.angle.json
@@ -27,7 +27,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
diff --git a/infra/config/generated/builders/try/gpu-fyi-try-android-q-pixel-2-32/targets/chromium.gpu.fyi.json b/infra/config/generated/builders/try/gpu-fyi-try-android-q-pixel-2-32/targets/chromium.gpu.fyi.json
index 172d3c6..8bf78d04 100644
--- a/infra/config/generated/builders/try/gpu-fyi-try-android-q-pixel-2-32/targets/chromium.gpu.fyi.json
+++ b/infra/config/generated/builders/try/gpu-fyi-try-android-q-pixel-2-32/targets/chromium.gpu.fyi.json
@@ -334,6 +334,47 @@
         },
         "test": "telemetry_gpu_integration_test_android_chrome",
         "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/"
+      },
+      {
+        "args": [
+          "webgl1_conformance",
+          "--show-stdout",
+          "--browser=android-chromium",
+          "--passthrough",
+          "-v",
+          "--stable-jobs",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=gles --use-cmd-decoder=passthrough --use-gl=angle --force_high_performance_gpu",
+          "--enforce-browser-version",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_android_runtimes.json",
+          "--jobs=1",
+          "--initial-find-device-attempts=3"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gles_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "device_os": "QQ1A.191205.008",
+            "device_os_flavor": "google",
+            "device_os_type": "userdebug",
+            "device_type": "walleye",
+            "os": "Android",
+            "pool": "chromium.tests"
+          },
+          "hard_timeout": 1800,
+          "idempotent": false,
+          "io_timeout": 1800,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "telemetry_gpu_integration_test_android_chrome",
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/"
       }
     ]
   },
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg
index fc94e9c..03a10c10 100644
--- a/infra/config/generated/luci/project.cfg
+++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@
 name: "chromium"
 access: "group:all"
 lucicfg {
-  version: "1.45.3"
+  version: "1.45.4"
   package_dir: "../.."
   config_dir: "generated/luci"
   entry_point: "main.star"
diff --git a/infra/config/subprojects/chromium/ci/chromium.angle.star b/infra/config/subprojects/chromium/ci/chromium.angle.star
index ffb4ea1..e0b2fc8 100644
--- a/infra/config/subprojects/chromium/ci/chromium.angle.star
+++ b/infra/config/subprojects/chromium/ci/chromium.angle.star
@@ -136,7 +136,7 @@
             "gpu_webgl_conformance_gles_passthrough_telemetry_tests",
         ],
         mixins = [
-            "chromium_pixel_2_pie",
+            "chromium_pixel_2_q",
             "has_native_resultdb_integration",
         ],
     ),
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
index 985b329c..69dfd35 100644
--- a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
@@ -151,11 +151,9 @@
         ),
     ),
     targets = targets.bundle(
-        # We currently only want to run the WebGL 2.0 conformance tests on
-        # this until additional Pixel 2 capacity is added.
         targets = [
             "gpu_fyi_android_gtests",
-            "gpu_fyi_android_webgl2_and_gold_telemetry_tests",
+            "gpu_pixel_2_telemetry_tests",
         ],
         mixins = [
             "chromium_pixel_2_q",
diff --git a/infra/config/targets/bundles.star b/infra/config/targets/bundles.star
index e5e6d5df..7aa3180c 100644
--- a/infra/config/targets/bundles.star
+++ b/infra/config/targets/bundles.star
@@ -4204,15 +4204,6 @@
     ],
 )
 
-targets.bundle(
-    name = "gpu_fyi_android_webgl2_and_gold_telemetry_tests",
-    targets = [
-        "gpu_validating_telemetry_tests",
-        "gpu_webgl2_conformance_gles_passthrough_telemetry_tests",
-        "gpu_webgl2_conformance_validating_telemetry_tests",
-    ],
-)
-
 # TODO(crbug.com/40130073): Merge with an existing set of tests such as
 # gpu_fyi_linux_release_gtests once all CrOS tests have been enabled.
 targets.bundle(
@@ -4608,6 +4599,16 @@
 )
 
 targets.bundle(
+    name = "gpu_pixel_2_telemetry_tests",
+    targets = [
+        "gpu_validating_telemetry_tests",
+        "gpu_webgl_conformance_gles_passthrough_telemetry_tests",
+        "gpu_webgl2_conformance_gles_passthrough_telemetry_tests",
+        "gpu_webgl2_conformance_validating_telemetry_tests",
+    ],
+)
+
+targets.bundle(
     name = "gpu_pixel_4_telemetry_tests",
     targets = [
         "gpu_common_and_optional_telemetry_tests",
diff --git a/ios/chrome/browser/ai_prototyping/coordinator/ai_prototyping_mediator.mm b/ios/chrome/browser/ai_prototyping/coordinator/ai_prototyping_mediator.mm
index 8629734..1926da2 100644
--- a/ios/chrome/browser/ai_prototyping/coordinator/ai_prototyping_mediator.mm
+++ b/ios/chrome/browser/ai_prototyping/coordinator/ai_prototyping_mediator.mm
@@ -152,13 +152,15 @@
     return;
   }
 
-  base::OnceCallback<void(
-      std::unique_ptr<optimization_guide::proto::PageContext>)>
-      page_context_completion_callback = base::BindOnce(
-          ^void(std::unique_ptr<optimization_guide::proto::PageContext>
-                    page_context) {
-            [weakSelf executeServerQueryWithPageContext:std::move(page_context)
-                                        freeformRequest:request];
+  base::OnceCallback<void(PageContextWrapperCallbackResponse)>
+      page_context_completion_callback =
+          base::BindOnce(^void(PageContextWrapperCallbackResponse response) {
+            // TODO(crbug.com/425736226): Handle PageContextWrapper errors.
+            if (response.has_value()) {
+              [weakSelf
+                  executeServerQueryWithPageContext:std::move(response.value())
+                                    freeformRequest:request];
+            }
           });
 
   // Populate the PageContext proto and then execute the query.
diff --git a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm
index 7e5ff47..1085094 100644
--- a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm
+++ b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm
@@ -121,13 +121,15 @@
 
   // Configure the callback to be executed once the page context is ready.
   __weak __typeof(self) weakSelf = self;
-  base::OnceCallback<void(
-      std::unique_ptr<optimization_guide::proto::PageContext>)>
-      page_context_completion_callback = base::BindOnce(
-          ^void(std::unique_ptr<optimization_guide::proto::PageContext>
-                    page_context) {
+  base::OnceCallback<void(PageContextWrapperCallbackResponse)>
+      page_context_completion_callback =
+          base::BindOnce(^void(PageContextWrapperCallbackResponse response) {
             BWGMediator* strongSelf = weakSelf;
-            [strongSelf openBWGOverlayForPage:std::move(page_context)];
+            // TODO(crbug.com/422506000): Handle PageContextWrapper error
+            // states, and pipe them down.
+            if (response.has_value()) {
+              [strongSelf openBWGOverlayForPage:std::move(response.value())];
+            }
             strongSelf->_pageContextWrapper = nil;
           });
 
diff --git a/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.h b/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.h
index 8d92e88..25dd7b34 100644
--- a/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.h
+++ b/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.h
@@ -23,6 +23,8 @@
 }  // namespace proto
 }  // namespace optimization_guide
 
+enum class PageContextWrapperError;
+
 @class PageContextWrapper;
 
 namespace web {
@@ -58,7 +60,8 @@
   // request.
   void OnPageContextGenerated(
       optimization_guide::proto::EnhancedCalendarRequest request,
-      std::unique_ptr<optimization_guide::proto::PageContext> page_context);
+      base::expected<std::unique_ptr<optimization_guide::proto::PageContext>,
+                     PageContextWrapperError> response);
 
   // Handles the Enhanced Calendar response (calls `request_callback` with the
   // response proto or error).
diff --git a/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.mm b/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.mm
index 5c0854d..cd61c26f 100644
--- a/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.mm
+++ b/ios/chrome/browser/intelligence/enhanced_calendar/model/enhanced_calendar_service_impl.mm
@@ -115,15 +115,16 @@
 // Execute the Enhanced Calendar request with the generated Page Context.
 void EnhancedCalendarServiceImpl::OnPageContextGenerated(
     optimization_guide::proto::EnhancedCalendarRequest request,
-    std::unique_ptr<optimization_guide::proto::PageContext> page_context) {
+    PageContextWrapperCallbackResponse response) {
   page_context_wrapper_ = nil;
 
   // The request might have been cancelled.
-  if (!pending_request_callback_) {
+  // TODO(crbug.com/425736226): Handle PageContextWrapper errors.
+  if (!pending_request_callback_ || !response.has_value()) {
     return;
   }
 
-  request.set_allocated_page_context(page_context.release());
+  request.set_allocated_page_context(response.value().release());
 
   service_->ExecuteModel(
       optimization_guide::ModelBasedCapabilityKey::kEnhancedCalendar, request,
diff --git a/ios/chrome/browser/intelligence/proto_wrappers/BUILD.gn b/ios/chrome/browser/intelligence/proto_wrappers/BUILD.gn
index 4958ef3b..a35222b 100644
--- a/ios/chrome/browser/intelligence/proto_wrappers/BUILD.gn
+++ b/ios/chrome/browser/intelligence/proto_wrappers/BUILD.gn
@@ -17,6 +17,7 @@
     "//components/optimization_guide/proto:optimization_guide_proto",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/snapshots/model",
+    "//ios/public/provider/chrome/browser/bwg:bwg_api",
     "//ios/web/find_in_page",
     "//ios/web/public",
     "//ios/web/public/js_messaging",
diff --git a/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.h b/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.h
index 665f12d..8658666 100644
--- a/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.h
+++ b/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.h
@@ -7,13 +7,35 @@
 
 #import <Foundation/Foundation.h>
 
+#import <memory>
+
 #import "base/functional/callback_forward.h"
+#import "base/types/expected.h"
 #import "components/optimization_guide/proto/features/common_quality_data.pb.h"
 
 namespace web {
 class WebState;
 }  // namespace web
 
+// PageContextWrapper error states, for when no PageContext is provided to the
+// caller.
+enum class PageContextWrapperError {
+  // Generic error.
+  kGenericError,
+  // APC was expected, but none was extracted.
+  kAPCError,
+  // Screenshot was expected, but none could be taken.
+  kScreenshotError,
+  // PDF data was expected, but none could be extracted.
+  kPDFDataError,
+  // The webpage is protected, PageContext was force-detached.
+  kForceDetachError,
+};
+
+using PageContextWrapperCallbackResponse =
+    base::expected<std::unique_ptr<optimization_guide::proto::PageContext>,
+                   PageContextWrapperError>;
+
 // A wrapper/helper around the `optimization_guide::proto::PageContext` proto
 // which handles populating all the necessary PageContext fields asynchronously.
 // By default, no async tasks will be executed, only the title and URL fields
@@ -25,15 +47,12 @@
 // disable-by-default behaviour.
 @interface PageContextWrapper : NSObject
 
-
 // Initializer which takes everything needed to construct the PageContext proto
 // as arguments.
-- (instancetype)
-      initWithWebState:(web::WebState*)webState
-    completionCallback:
-        (base::OnceCallback<
-            void(std::unique_ptr<::optimization_guide::proto::PageContext>)>)
-            completionCallback NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithWebState:(web::WebState*)webState
+              completionCallback:
+                  (base::OnceCallback<void(PageContextWrapperCallbackResponse)>)
+                      completionCallback NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
 
diff --git a/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.mm b/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.mm
index 0ec6034..33f1561 100644
--- a/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.mm
+++ b/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.mm
@@ -23,6 +23,7 @@
 #import "components/optimization_guide/core/page_content_proto_serializer.h"
 #import "components/optimization_guide/proto/features/common_quality_data.pb.h"
 #import "ios/chrome/browser/snapshots/model/snapshot_tab_helper.h"
+#import "ios/public/provider/chrome/browser/bwg/bwg_api.h"
 #import "ios/web/find_in_page/find_in_page_java_script_feature.h"
 #import "ios/web/public/js_messaging/web_frame.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
@@ -31,27 +32,46 @@
 
 namespace {
 
-// The key for the current node's innerText in the JavaScript object.
-const char kCurrentNodeInnerTextDictKey[] = "currentNodeInnerText";
+// The key for whether the PageContext should be detached. The value is a bool.
+constexpr const char kShouldDetachPageContext[] = "shouldDetachPageContext";
 
-// The key for the children frames in the JavaScript object.
-const char kChildrenFramesDictKey[] = "children";
+// The key for the current node's innerText in the JavaScript object. The value
+// is a string.
+constexpr const char kCurrentNodeInnerTextDictKey[] = "currentNodeInnerText";
 
-// The key for the source URL of the frame in the JavaScript object.
-const char kSourceURLDictKey[] = "sourceURL";
+// The key for the children frames in the JavaScript object. The value is an
+// array of objects.
+constexpr const char kChildrenFramesDictKey[] = "children";
 
-// The key for the title of the frame in the JavaScript object.
-const char kFrameTitleDictKey[] = "title";
+// The key for the source URL of the frame in the JavaScript object. The value
+// is a string.
+constexpr const char kSourceURLDictKey[] = "sourceURL";
+
+// The key for the title of the frame in the JavaScript object. The value is a
+// string.
+constexpr const char kFrameTitleDictKey[] = "title";
 
 // The JavaScript to be executed on each WebState's WebFrames, which retrieves
 // the innerText of the document body, and recursively traverses through
 // same-origin nested iframes to retrieve their innerTexts as well, constructing
 // a tree structure. iframes are marked as processed with a nonce to avoid
-// duplicate text from frames, but only for the current run.
+// duplicate text from frames, but only for the current run. Early returns if
+// the PageContext should be detached, or the frame is not the top-most
+// same-origin frame.
 // TODO(crbug.com/423681226): Write this in TypeScript and create a JS Feature
 // for it.
-const char16_t* kInnerTextTreeJavaScript = uR"DELIM(
+constexpr const char16_t* kInnerTextTreeJavaScript = uR"DELIM(
 (() => {
+    // Checks whether the PageContext should be detached.
+    const shouldDetachPageContext = () => {
+        $1
+    };
+
+    // If the PageContext should be detached, early return.
+    if (shouldDetachPageContext()) {
+        return { shouldDetachPageContext: true };
+    }
+
     // The script should only run if it has no same-origin parent. (The script
     // should only start execution on top-most nodes of a given origin).
     if (window.self !== window.top &&
@@ -60,6 +80,8 @@
         return null;
     }
 
+    // Recursively constructs the innerText tree for the passed node and its
+    // children same-origin iframes.
     const constructSameOriginInnerTextTree = (node, frameURL, frameTitle, nonceAttributeValue) => {
         // Early return if the node is null or already processed.
         if (!node || node.getAttribute('data-__gCrWeb-innerText-processed') === nonceAttributeValue) {
@@ -97,7 +119,7 @@
         };
     };
 
-    return constructSameOriginInnerTextTree(document.body, window.location.href, document.title, "$1");
+    return constructSameOriginInnerTextTree(document.body, window.location.href, document.title, "$2");
 })();
   )DELIM";
 }  // namespace
@@ -115,22 +137,22 @@
   // the fly as values are returned from JavaScript.
   std::unique_ptr<optimization_guide::proto::AnnotatedPageContent> _rootAPCNode;
 
+  // Whether the PageContext should be detached. Likely a protected page.
+  BOOL _forceDetachPageContext;
+
   // The callback to execute once all async work is complete, whichs
   // relinquishes ownership of the PageContext proto to the callback's handler.
-  base::OnceCallback<void(
-      std::unique_ptr<optimization_guide::proto::PageContext>)>
+  base::OnceCallback<void(PageContextWrapperCallbackResponse)>
       _completion_callback;
 
   // Unique pointer to the PageContext proto.
   std::unique_ptr<optimization_guide::proto::PageContext> _page_context;
 }
 
-- (instancetype)
-      initWithWebState:(web::WebState*)webState
-    completionCallback:
-        (base::OnceCallback<
-            void(std::unique_ptr<optimization_guide::proto::PageContext>)>)
-            completionCallback {
+- (instancetype)initWithWebState:(web::WebState*)webState
+              completionCallback:
+                  (base::OnceCallback<void(PageContextWrapperCallbackResponse)>)
+                      completionCallback {
   self = [super init];
   if (self) {
     _asyncTasksToComplete = 0;
@@ -329,7 +351,10 @@
   base::Token nonce = base::Token::CreateRandom();
   std::u16string nonceString = base::UTF8ToUTF16(nonce.ToString());
   std::u16string script = base::ReplaceStringPlaceholders(
-      kInnerTextTreeJavaScript, nonceString, nullptr);
+      kInnerTextTreeJavaScript,
+      base::span<const std::u16string>(
+          {ios::provider::GetPageContextShouldDetachScript(), nonceString}),
+      nullptr);
 
   // Execute the JavaScript on the main WebFrame first and pass in the callback
   // (which executes the barrier when run)
@@ -358,7 +383,24 @@
 // Relinquish ownership to the callback handler.
 - (void)asyncWorkCompletedForPageContext {
   [self stopTextHighlighting];
-  std::move(_completion_callback).Run(std::move(_page_context));
+
+  PageContextWrapperCallbackResponse response;
+
+  // Construct the response, either with the expected value or an error.
+  if (_forceDetachPageContext) {
+    response = base::unexpected(PageContextWrapperError::kForceDetachError);
+  } else if (_shouldGetInnerText &&
+             !_page_context->has_annotated_page_content()) {
+    response = base::unexpected(PageContextWrapperError::kAPCError);
+  } else if (_shouldGetSnapshot && !_page_context->has_tab_screenshot()) {
+    response = base::unexpected(PageContextWrapperError::kScreenshotError);
+  } else if (_shouldGetFullPagePDF && !_page_context->has_pdf_data()) {
+    response = base::unexpected(PageContextWrapperError::kPDFDataError);
+  } else {
+    response = base::ok(std::move(_page_context));
+  }
+
+  std::move(_completion_callback).Run(std::move(response));
 }
 
 // Returns YES if the image is nil and forcing the update of missing snapshots
@@ -392,6 +434,10 @@
     return;
   }
 
+  if (_forceDetachPageContext) {
+    return;
+  }
+
   NSData* imageData = UIImagePNGRepresentation(image);
   if (!imageData) {
     DLOG(WARNING) << "Failed to convert the screenshot to PNG.";
@@ -410,6 +456,10 @@
     return;
   }
 
+  if (_forceDetachPageContext) {
+    return;
+  }
+
   NSString* base64String = [PDFData base64EncodedStringWithOptions:0];
   _page_context->set_pdf_data(base::SysNSStringToUTF8(base64String));
 }
@@ -429,6 +479,20 @@
     return;
   }
 
+  if (_forceDetachPageContext) {
+    return;
+  }
+
+  // Check if PageContext should be force detached.
+  // TODO(crbug.com/423681226): Force detaching PageContext shouldn't depend on
+  // fetching innerText/APC, it should always be enabled.
+  std::optional<bool> shouldDetachPageContext =
+      value->GetDict().FindBool(kShouldDetachPageContext);
+  if (shouldDetachPageContext.has_value() && shouldDetachPageContext.value()) {
+    _forceDetachPageContext = YES;
+    return;
+  }
+
   if (isMainFrame) {
     [self populateMainFrameSubtreeWithValue:value origin:securityOrigin];
   }
diff --git a/ios/chrome/browser/intelligence/proto_wrappers/tab_organization_request_wrapper.mm b/ios/chrome/browser/intelligence/proto_wrappers/tab_organization_request_wrapper.mm
index 88ac344..c30124e5 100644
--- a/ios/chrome/browser/intelligence/proto_wrappers/tab_organization_request_wrapper.mm
+++ b/ios/chrome/browser/intelligence/proto_wrappers/tab_organization_request_wrapper.mm
@@ -96,11 +96,13 @@
     PageContextWrapper* pageContextWrapper = [[PageContextWrapper alloc]
           initWithWebState:webState
         completionCallback:base::BindOnce(^(
-                               std::unique_ptr<
-                                   optimization_guide::proto::PageContext>
-                                   page_context) {
-          [weakSelf asyncWorkCompleteForPageContext:std::move(page_context)
-                                      associatedTab:tab];
+                               PageContextWrapperCallbackResponse response) {
+          // TODO(crbug.com/425736226): Handle PageContextWrapper errors.
+          if (response.has_value()) {
+            [weakSelf
+                asyncWorkCompleteForPageContext:std::move(response.value())
+                                  associatedTab:tab];
+          }
           barrier.Run();
         })];
 
diff --git a/ios/chrome/browser/location_bar/ui_bundled/BUILD.gn b/ios/chrome/browser/location_bar/ui_bundled/BUILD.gn
index 4a3b4871..20cb442 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/location_bar/ui_bundled/BUILD.gn
@@ -68,6 +68,7 @@
     "//ios/chrome/browser/omnibox/coordinator",
     "//ios/chrome/browser/omnibox/coordinator/popup",
     "//ios/chrome/browser/omnibox/model",
+    "//ios/chrome/browser/omnibox/model:placeholder_service",
     "//ios/chrome/browser/omnibox/model:ui_bundled_interface",
     "//ios/chrome/browser/omnibox/model/omnibox_position",
     "//ios/chrome/browser/omnibox/public",
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_consumer.h b/ios/chrome/browser/location_bar/ui_bundled/location_bar_consumer.h
index ccb44016..8215be4 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_consumer.h
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_consumer.h
@@ -28,6 +28,10 @@
 // Sets the search provider name that's used in the placeholder text in the
 // search box.
 - (void)setPlaceholderText:(NSString*)searchProviderName;
+
+// Sets the default search engine image to use as placeholder when the
+// placeholder is set to kDefaultSearchEngineIcon.
+- (void)setPlaceholderDefaultSearchEngineIcon:(UIImage*)icon;
 @end
 
 #endif  // IOS_CHROME_BROWSER_LOCATION_BAR_UI_BUNDLED_LOCATION_BAR_CONSUMER_H_
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
index ff5c702f4..0c3b4eef 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
@@ -13,6 +13,7 @@
 #import "components/omnibox/browser/omnibox_edit_model.h"
 #import "components/omnibox/browser/omnibox_text_util.h"
 #import "components/omnibox/browser/omnibox_view.h"
+#import "components/omnibox/common/omnibox_features.h"
 #import "components/open_from_clipboard/clipboard_recent_content.h"
 #import "components/prefs/pref_service.h"
 #import "components/profile_metrics/browser_profile_type.h"
@@ -53,6 +54,8 @@
 #import "ios/chrome/browser/omnibox/model/chrome_omnibox_client_ios.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_position/omnibox_position_browser_agent.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_position/omnibox_state_provider.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service_factory.h"
 #import "ios/chrome/browser/omnibox/ui/omnibox_focus_delegate.h"
 #import "ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.h"
 #import "ios/chrome/browser/overlays/model/public/overlay_presenter.h"
@@ -277,6 +280,11 @@
       ios::TemplateURLServiceFactory::GetForProfile(self.profile);
   self.mediator.consumer = self.viewController;
   self.mediator.webStateList = self.webStateList;
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    PlaceholderService* placeholderService =
+        ios::PlaceholderServiceFactory::GetForProfile(self.profile);
+    self.mediator.placeholderService = placeholderService;
+  }
 
   self.steadyViewMediator = [[LocationBarSteadyViewMediator alloc]
       initWithLocationBarModel:[self locationBarModel]];
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.h b/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.h
index 51015a83..b83a814a 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.h
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.h
@@ -8,6 +8,7 @@
 #import <UIKit/UIKit.h>
 
 @protocol LocationBarConsumer;
+class PlaceholderService;
 class TemplateURLService;
 class WebStateList;
 
@@ -24,6 +25,9 @@
 // search engine supports search-by-image.
 @property(nonatomic, assign) TemplateURLService* templateURLService;
 
+/// The placeholder used by this mediator to extract placeholder text and image.
+@property(nonatomic, assign) PlaceholderService* placeholderService;
+
 // The consumer for this object. This can change during the lifetime of this
 // object and may be nil.
 @property(nonatomic, weak) id<LocationBarConsumer> consumer;
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.mm
index 5a305b55..38efae0 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_mediator.mm
@@ -7,10 +7,13 @@
 #import "base/memory/ptr_util.h"
 #import "components/google/core/common/google_util.h"
 #import "components/lens/lens_url_utils.h"
+#import "components/omnibox/common/omnibox_features.h"
 #import "ios/chrome/browser/intelligence/features/features.h"
 #import "ios/chrome/browser/lens_overlay/coordinator/lens_overlay_availability.h"
 #import "ios/chrome/browser/location_bar/ui_bundled/location_bar_consumer.h"
 #import "ios/chrome/browser/ntp/model/new_tab_page_util.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service_observer_bridge.h"
 #import "ios/chrome/browser/omnibox/public/omnibox_util.h"
 #import "ios/chrome/browser/search_engines/model/search_engine_observer_bridge.h"
 #import "ios/chrome/browser/search_engines/model/search_engines_util.h"
@@ -26,7 +29,16 @@
 #import "ios/web/public/web_state.h"
 #import "skia/ext/skia_utils_ios.h"
 
-@interface LocationBarMediator () <SearchEngineObserving, WebStateListObserving>
+namespace {
+
+// The point size of the entry point's symbol.
+const CGFloat kIconPointSize = 16.0;
+
+}  // namespace
+
+@interface LocationBarMediator () <SearchEngineObserving,
+                                   WebStateListObserving,
+                                   PlaceholderServiceObserving>
 
 // Whether the current default search engine supports search by image.
 @property(nonatomic, assign) BOOL searchEngineSupportsSearchByImage;
@@ -39,6 +51,7 @@
 @implementation LocationBarMediator {
   std::unique_ptr<SearchEngineObserverBridge> _searchEngineObserver;
   std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
+  std::unique_ptr<PlaceholderServiceObserverBridge> _placeholderServiceObserver;
   BOOL _isIncognito;
 }
 
@@ -60,6 +73,9 @@
   }
   _webStateListObserver = nullptr;
   _searchEngineObserver = nullptr;
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    self.placeholderService = nullptr;
+  }
 }
 
 - (void)dealloc {
@@ -106,6 +122,20 @@
   }
 }
 
+- (void)setPlaceholderService:(PlaceholderService*)placeholderService {
+  CHECK(base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate));
+  _placeholderService = placeholderService;
+
+  if (!placeholderService) {
+    _placeholderServiceObserver.reset();
+    return;
+  }
+
+  _placeholderServiceObserver =
+      std::make_unique<PlaceholderServiceObserverBridge>(self,
+                                                         placeholderService);
+}
+
 - (void)setSearchEngineSupportsSearchByImage:
     (BOOL)searchEngineSupportsSearchByImage {
   BOOL supportChanged =
@@ -152,6 +182,20 @@
   }
 }
 
+#pragma mark - PlaceholderServiceObserving
+
+- (void)placeholderImageUpdated {
+  CHECK(base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate));
+
+  __weak __typeof(self) weakSelf = self;
+  if (self.placeholderService) {
+    self.placeholderService->FetchDefaultSearchEngineIcon(
+        kIconPointSize, base::BindRepeating(^(UIImage* image) {
+          [weakSelf.consumer setPlaceholderDefaultSearchEngineIcon:image];
+        }));
+  }
+}
+
 #pragma mark - Private
 
 - (bool)isLensOverlayAvailable {
@@ -168,6 +212,17 @@
 
 /// Updates the placeholder.
 - (void)updatePlaceholderType {
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate) &&
+      [self isCurrentPageNTP]) {
+    [self.consumer setPlaceholderType:LocationBarPlaceholderType::
+                                          kDefaultSearchEngineIcon];
+    return;
+  } else {
+    [self.consumer setPlaceholderType:LocationBarPlaceholderType::kNone];
+    // No early return here; allow Lens Overlay to override the placeholder if
+    // necessary.
+  }
+
   if (IsPageActionMenuEnabled()) {
     [self.consumer
         setPlaceholderType:LocationBarPlaceholderType::kPageActionMenu];
@@ -209,4 +264,16 @@
   return !IsURLNewTabPage(visibleURL) && !lens::IsLensMWebResult(visibleURL);
 }
 
+- (BOOL)isCurrentPageNTP {
+  GURL visibleURL = GURL();
+  if (_webStateList) {
+    web::WebState* webState = _webStateList->GetActiveWebState();
+    if (webState) {
+      visibleURL = webState->GetVisibleURL();
+    }
+  }
+
+  return IsURLNewTabPage(visibleURL);
+}
+
 @end
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_placeholder_type.h b/ios/chrome/browser/location_bar/ui_bundled/location_bar_placeholder_type.h
index 6aea5f3..c9e8744 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_placeholder_type.h
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_placeholder_type.h
@@ -13,6 +13,8 @@
   kLensOverlay,
   // Page action menu entry point.
   kPageActionMenu,
+  // Default search engine icon (on NTP).
+  kDefaultSearchEngineIcon,
 };
 
 #endif  // IOS_CHROME_BROWSER_LOCATION_BAR_UI_BUNDLED_LOCATION_BAR_PLACEHOLDER_TYPE_H_
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm
index 5989d39..05f03fa6 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm
@@ -144,6 +144,9 @@
 
   // The location bar button to access the page action menu.
   PageActionMenuEntrypointView* _pageActionMenuEntrypointView;
+
+  // The placeholder view that holds the DSE icon.
+  UIImageView* _defaultSearchEngineIconView;
 }
 
 #pragma mark - public
@@ -305,6 +308,15 @@
     [self registerForTraitChanges:@[ UITraitHorizontalSizeClass.class ]
                        withAction:@selector(sizeClassDidChange)];
   }
+
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    _defaultSearchEngineIconView = [[UIImageView alloc] init];
+    _defaultSearchEngineIconView.translatesAutoresizingMaskIntoConstraints = NO;
+    _defaultSearchEngineIconView.contentMode = UIViewContentModeCenter;
+    AddSizeConstraints(
+        _defaultSearchEngineIconView,
+        CGSizeMake(kOmniboxLeadingImageSize + 12.0f, kOmniboxLeadingImageSize));
+  }
 }
 
 - (void)viewWillDisappear:(BOOL)animated {
@@ -375,6 +387,10 @@
   }
 }
 
+- (void)setPlaceholderDefaultSearchEngineIcon:(UIImage*)icon {
+  _defaultSearchEngineIconView.image = icon;
+}
+
 #pragma mark - LocationBarSteadyViewConsumer
 
 - (void)updateLocationText:(NSString*)string clipTail:(BOOL)clipTail {
@@ -1035,6 +1051,9 @@
       self.locationBarSteadyView.placeholderView =
           _pageActionMenuEntrypointView;
       break;
+    case LocationBarPlaceholderType::kDefaultSearchEngineIcon:
+      self.locationBarSteadyView.placeholderView = _defaultSearchEngineIconView;
+      break;
   }
 }
 
diff --git a/ios/chrome/browser/metrics/model/ios_family_link_user_metrics_provider.mm b/ios/chrome/browser/metrics/model/ios_family_link_user_metrics_provider.mm
index bc0dd6e..2d29b64 100644
--- a/ios/chrome/browser/metrics/model/ios_family_link_user_metrics_provider.mm
+++ b/ios/chrome/browser/metrics/model/ios_family_link_user_metrics_provider.mm
@@ -24,12 +24,10 @@
   std::vector<supervised_user::FamilyLinkUserLogRecord> records;
   for (ProfileIOS* profile :
        GetApplicationContext()->GetProfileManager()->GetLoadedProfiles()) {
-    supervised_user::SupervisedUserService* service =
-        SupervisedUserServiceFactory::GetForProfile(profile);
     records.push_back(supervised_user::FamilyLinkUserLogRecord::Create(
         IdentityManagerFactory::GetForProfile(profile), *profile->GetPrefs(),
         *ios::HostContentSettingsMapFactory::GetForProfile(profile),
-        service ? service->GetURLFilter() : nullptr));
+        SupervisedUserServiceFactory::GetForProfile(profile)));
   }
   return supervised_user::EmitLogRecordHistograms(records);
 }
diff --git a/ios/chrome/browser/ntp/ui_bundled/BUILD.gn b/ios/chrome/browser/ntp/ui_bundled/BUILD.gn
index 42c5af73..66738a3f 100644
--- a/ios/chrome/browser/ntp/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/ntp/ui_bundled/BUILD.gn
@@ -100,6 +100,7 @@
     "//components/feature_engagement/public",
     "//components/feed/core/v2/public:common",
     "//components/feed/core/v2/public/ios:feed_ios_public",
+    "//components/omnibox/common",
     "//components/policy:policy_code_generate",
     "//components/pref_registry",
     "//components/prefs",
@@ -139,6 +140,7 @@
     "//ios/chrome/browser/ntp/shared/metrics:home_metrics",
     "//ios/chrome/browser/ntp/ui_bundled/feed_top_section",
     "//ios/chrome/browser/ntp/ui_bundled/incognito",
+    "//ios/chrome/browser/omnibox/model:placeholder_service",
     "//ios/chrome/browser/overscroll_actions/ui_bundled",
     "//ios/chrome/browser/search_engines/model:template_url_service_factory",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
@@ -245,6 +247,7 @@
     "//ios/chrome/browser/ntp/shared/metrics:home_metrics",
     "//ios/chrome/browser/ntp/ui_bundled/resources",
     "//ios/chrome/browser/ntp/ui_bundled/resources:animation_files",
+    "//ios/chrome/browser/omnibox/model:placeholder_service",
     "//ios/chrome/browser/omnibox/public",
     "//ios/chrome/browser/omnibox/public:features",
     "//ios/chrome/browser/omnibox/ui:omnibox_internal",
diff --git a/ios/chrome/browser/ntp/ui_bundled/DEPS b/ios/chrome/browser/ntp/ui_bundled/DEPS
index f3f118b6..1f81215 100644
--- a/ios/chrome/browser/ntp/ui_bundled/DEPS
+++ b/ios/chrome/browser/ntp/ui_bundled/DEPS
@@ -16,6 +16,7 @@
   "+ios/chrome/browser/omnibox/ui",
   "+ios/chrome/browser/omnibox/coordinator",
   "+ios/chrome/browser/omnibox/public",
+  "+ios/chrome/browser/omnibox/model",
   "+ios/chrome/browser/lens/ui_bundled",
   "+ios/chrome/browser/toolbar/ui_bundled/public",
   "+ios/chrome/browser/sharing/ui_bundled",
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_coordinator.mm b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_coordinator.mm
index 2c73e36..81f7e3f3 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_coordinator.mm
@@ -18,6 +18,7 @@
 #import "components/feed/core/v2/public/common_enums.h"
 #import "components/feed/core/v2/public/ios/pref_names.h"
 #import "components/feed/feed_feature_list.h"
+#import "components/omnibox/common/omnibox_features.h"
 #import "components/policy/policy_constants.h"
 #import "components/pref_registry/pref_registry_syncable.h"
 #import "components/prefs/pref_service.h"
@@ -85,6 +86,8 @@
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.h"
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.h"
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_view_controller.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service_factory.h"
 #import "ios/chrome/browser/overscroll_actions/ui_bundled/overscroll_actions_controller.h"
 #import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
 #import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h"
@@ -755,6 +758,11 @@
   NTPMediator.NTPContentDelegate = self;
   NTPMediator.headerConsumer = self.headerViewController;
   NTPMediator.consumer = self.NTPViewController;
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    PlaceholderService* placeholderService =
+        ios::PlaceholderServiceFactory::GetForProfile(self.profile);
+    NTPMediator.placeholderService = placeholderService;
+  }
   [NTPMediator setUp];
 }
 
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h
index 55bf3085..8c820f9 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h
@@ -29,6 +29,9 @@
 // Sets the default search engine name for display.
 - (void)setDefaultSearchEngineName:(NSString*)dseName;
 
+// Sets the default search engine icon for display.
+- (void)setDefaultSearchEngineImage:(UIImage*)image;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_NTP_UI_BUNDLED_NEW_TAB_PAGE_HEADER_CONSUMER_H_
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.h b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.h
index 6800fcde..a95c225 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.h
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.h
@@ -96,6 +96,9 @@
 // Adds views necessary to customize the NTP search box.
 - (void)addViewsToSearchField:(UIView*)searchField;
 
+// Configures the current default search engine logo.
+- (void)setDefaultSearchEngineLogo:(UIImage*)logo;
+
 // Highlights the fake omnibox.
 - (void)setFakeboxHighlighted:(BOOL)highlighted;
 
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.mm b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.mm
index e054f2c..a4a250ae 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.mm
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view.mm
@@ -68,8 +68,14 @@
 const CGFloat kEndButtonOmniboxTrailingSpace = 7.0;
 
 // The constants for the constraints the leading-edge aligned UI elements.
-const CGFloat kHintLabelFakeboxLeadingSpace = 26.0;
+const CGFloat kHintLabelFakeboxLeadingSpace = 28.0;
+const CGFloat kHintLabelFakeboxLeadingSpaceWithIcon = 49.0;
+
 const CGFloat kHintLabelOmniboxLeadingSpace = 20.0;
+const CGFloat kHintLabelOmniboxLeadingSpaceWithIcon = 39.0;
+
+const CGFloat kFakeboxImageLeadingSpace = 22.0;
+const CGFloat kFakeboxImageSize = 16.0;
 
 // The amount to inset the Fakebox from the rest of the modules on Home, when
 // Large Fakebox is enabled.
@@ -253,6 +259,8 @@
   UIView* _customizationNewFeatureBadge;
   // A view to contain all the buttons on the trailing side of the fakebox.
   UIStackView* _buttonStack;
+  // Default search engine logo view.
+  UIImageView* _logoView;
 
   // Constraints to update the `toolbarView`'s postion according to the
   // `tabGroupIndicatorView`'s visibility.
@@ -377,7 +385,7 @@
 
   self.hintLabelLeadingConstraint = [self.searchHintLabel.leadingAnchor
       constraintEqualToAnchor:self.fakeLocationBar.leadingAnchor
-                     constant:kHintLabelFakeboxLeadingSpace];
+                     constant:self.hintLabelFakeboxLeadingSpace];
   [NSLayoutConstraint activateConstraints:@[
     self.hintLabelLeadingConstraint,
     [self.searchHintLabel.heightAnchor
@@ -483,6 +491,34 @@
         constraintEqualToAnchor:self.fakeLocationBar.centerYAnchor],
     self.hintLabelTrailingConstraint,
   ]];
+
+  [self addSearchEngineLogoIfNeededToSearchField:searchField];
+}
+
+- (void)addSearchEngineLogoIfNeededToSearchField:(UIView*)searchField {
+  if (!base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    return;
+  }
+
+  UIImageView* logoView = [[UIImageView alloc] init];
+  [searchField addSubview:logoView];
+
+  logoView.translatesAutoresizingMaskIntoConstraints = NO;
+  AddSquareConstraints(logoView, kFakeboxImageSize);
+
+  [NSLayoutConstraint activateConstraints:@[
+    [logoView.leadingAnchor constraintEqualToAnchor:searchField.leadingAnchor
+                                           constant:kFakeboxImageLeadingSpace],
+    [logoView.centerYAnchor constraintEqualToAnchor:searchField.centerYAnchor
+                                           constant:-2.0],
+
+  ]];
+
+  _logoView = logoView;
+}
+
+- (void)setDefaultSearchEngineLogo:(UIImage*)logo {
+  _logoView.image = logo;
 }
 
 - (void)updateButtonsForUserInterfaceStyle:(UIUserInterfaceStyle)style {
@@ -607,7 +643,7 @@
 
     // Reset the view horizontal constraints.
     self.hintLabelLeadingConstraint.constant =
-        kHintLabelFakeboxLeadingSpace + hintLabelScalingExtraOffset;
+        self.hintLabelFakeboxLeadingSpace + hintLabelScalingExtraOffset;
 
     self.separator.alpha = 0;
 
@@ -657,9 +693,9 @@
   _buttonStack.directionalLayoutMargins =
       NSDirectionalEdgeInsetsMake(0, 0, 0, endButtonInset);
   self.hintLabelLeadingConstraint.constant =
-      hintLabelScalingExtraOffset + Interpolate(kHintLabelFakeboxLeadingSpace,
-                                                kHintLabelOmniboxLeadingSpace,
-                                                percent);
+      hintLabelScalingExtraOffset +
+      Interpolate(self.hintLabelFakeboxLeadingSpace,
+                  self.hintLabelOmniboxLeadingSpace, percent);
 
   // Fade N badge treatment when scrolled.
   if (_useNewBadgeForLensButton && !_lensButtonWithNewBadgeTapped &&
@@ -1085,4 +1121,22 @@
           NTPMIAEntrypointVariation::kOmniboxContainedEnlargedFakebox);
 }
 
+#pragma mark - helpers
+
+- (CGFloat)hintLabelFakeboxLeadingSpace {
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    return kHintLabelFakeboxLeadingSpaceWithIcon;
+  } else {
+    return kHintLabelFakeboxLeadingSpace;
+  }
+}
+
+- (CGFloat)hintLabelOmniboxLeadingSpace {
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    return kHintLabelOmniboxLeadingSpaceWithIcon;
+  } else {
+    return kHintLabelOmniboxLeadingSpace;
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm
index 1fd4a58d..75376e3b 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm
@@ -883,6 +883,11 @@
   self.headerView.placeholderText = self.placeholderText;
 }
 
+- (void)setDefaultSearchEngineImage:(UIImage*)image {
+  CHECK(base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate));
+  [self.headerView setDefaultSearchEngineLogo:image];
+}
+
 - (void)updateADPBadgeWithErrorFound:(BOOL)hasAccountError
                                 name:(NSString*)name
                                email:(NSString*)email {
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.h b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.h
index 288a6e17..f66d54a 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.h
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.h
@@ -38,6 +38,7 @@
 @protocol NewTabPageContentDelegate;
 @protocol NewTabPageHeaderConsumer;
 @class NewTabPageState;
+class PlaceholderService;
 class PrefService;
 class TemplateURLService;
 class UrlLoadingBrowserAgent;
@@ -84,6 +85,8 @@
 // Observer for feed visibility changes.
 @property(nonatomic, weak) id<DiscoverFeedVisibilityObserver>
     feedVisibilityObserver;
+// Placeholder service, for placeholder text and image.
+@property(nonatomic, assign) PlaceholderService* placeholderService;
 // Delegate for controlling the current feed.
 @property(nonatomic, weak) id<FeedControlDelegate> feedControlDelegate;
 // Delegate for actions relating to the NTP content.
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm
index 225633e..28444ae 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm
@@ -12,6 +12,7 @@
 #import "base/metrics/user_metrics_action.h"
 #import "components/image_fetcher/core/image_fetcher.h"
 #import "components/image_fetcher/core/image_fetcher_service.h"
+#import "components/omnibox/common/omnibox_features.h"
 #import "components/prefs/ios/pref_observer_bridge.h"
 #import "components/prefs/pref_change_registrar.h"
 #import "components/regional_capabilities/regional_capabilities_service.h"
@@ -41,6 +42,8 @@
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_constants.h"
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h"
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_view_controller.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service.h"
+#import "ios/chrome/browser/omnibox/model/placeholder_service_observer_bridge.h"
 #import "ios/chrome/browser/policy/model/policy_util.h"
 #import "ios/chrome/browser/search_engines/model/search_engine_observer_bridge.h"
 #import "ios/chrome/browser/shared/model/prefs/pref_names.h"
@@ -63,9 +66,17 @@
 #import "ui/base/l10n/l10n_util.h"
 #import "url/gurl.h"
 
+namespace {
+
+// The point size of the entry point's symbol.
+const CGFloat kIconPointSize = 18.0;
+
+}  // namespace
+
 @interface NewTabPageMediator () <BrowserViewVisibilityObserving,
                                   HomeBackgroundCustomizationServiceObserving,
                                   IdentityManagerObserverBridgeDelegate,
+                                  PlaceholderServiceObserving,
                                   PrefObserverDelegate,
                                   SearchEngineObserving,
                                   SyncObserverModelBridge>
@@ -121,6 +132,7 @@
   std::unique_ptr<SyncObserverBridge> _syncObserver;
   raw_ptr<signin::IdentityManager> _identityManager;
   id<SystemIdentity> _signedInIdentity;
+  std::unique_ptr<PlaceholderServiceObserverBridge> _placeholderServiceObserver;
 }
 
 // Synthesized from NewTabPageMutator.
@@ -241,6 +253,9 @@
   _backgroundCustomizationServiceObserverBridge = nullptr;
   _backgroundCustomizationService = nullptr;
   _imageFetcherService = nullptr;
+  if (base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
+    self.placeholderService = nullptr;
+  }
 }
 
 - (void)saveNTPStateForWebState:(web::WebState*)webState {
@@ -270,6 +285,21 @@
   }
 }
 
+- (void)setPlaceholderService:(PlaceholderService*)placeholderService {
+  CHECK(base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate));
+
+  _placeholderService = placeholderService;
+
+  if (!placeholderService) {
+    _placeholderServiceObserver.reset();
+    return;
+  }
+
+  _placeholderServiceObserver =
+      std::make_unique<PlaceholderServiceObserverBridge>(self,
+                                                         placeholderService);
+}
+
 #pragma mark - BrowserViewVisibilityObserving
 
 - (void)browserViewDidChangeToVisibilityState:
@@ -322,6 +352,27 @@
   [self updateAccountErrorBadge];
 }
 
+#pragma mark - PlaceholderServiceObserving
+
+- (void)placeholderImageUpdated {
+  // Show Default Search Engine favicon.
+  // Remember what is the Default Search Engine provider that the icon is
+  // for, in case the user changes Default Search Engine while this is being
+  // loaded.
+  __weak __typeof(self) weakSelf = self;
+  if (self.placeholderService) {
+    self.placeholderService->FetchDefaultSearchEngineIcon(
+        kIconPointSize, base::BindRepeating(^(UIImage* image) {
+          [weakSelf.headerConsumer setDefaultSearchEngineImage:image];
+        }));
+  }
+}
+
+- (void)placeholderServiceShuttingDown:(PlaceholderService*)service {
+  // Removes observation.
+  self.placeholderService = nil;
+}
+
 #pragma mark - PrefObserverDelegate
 
 - (void)onPreferenceChanged:(const std::string&)preferenceName {
diff --git a/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm b/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm
index 5f27515d..6daec22 100644
--- a/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm
+++ b/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm
@@ -31,7 +31,6 @@
 #import "ios/chrome/browser/omnibox/model/omnibox_popup_view_ios.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_text_controller.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_text_model.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
 #import "ios/chrome/browser/omnibox/model/placeholder_service.h"
 #import "ios/chrome/browser/omnibox/model/placeholder_service_factory.h"
 #import "ios/chrome/browser/omnibox/public/omnibox_util.h"
@@ -95,7 +94,6 @@
 
   // OmniboxCoordinator temporarely owns these class until they are removed
   // after the refactoring crbug.com/390409559.
-  std::unique_ptr<OmniboxViewIOS> _omniboxView;
   std::unique_ptr<OmniboxControllerIOS> _omniboxController;
   std::unique_ptr<OmniboxEditModelIOS> _omniboxEditModel;
   std::unique_ptr<OmniboxTextModel> _omniboxTextModel;
@@ -184,11 +182,8 @@
   _omniboxTextModel = std::make_unique<OmniboxTextModel>(_client.get());
   OmniboxTextFieldIOS* textField = viewController.textField;
   _omniboxController = std::make_unique<OmniboxControllerIOS>(_client.get());
-  _omniboxView = std::make_unique<OmniboxViewIOS>(textField);
   _omniboxEditModel = std::make_unique<OmniboxEditModelIOS>(
-      _omniboxController.get(), _omniboxView.get(), _omniboxTextModel.get());
-  _omniboxView->SetOmniboxEditModel(_omniboxEditModel.get());
-  _omniboxView->SetOmniboxController(_omniboxController.get());
+      _omniboxController.get(), _omniboxTextModel.get());
 
   self.pasteDelegate = [[OmniboxTextFieldPasteDelegate alloc] init];
   [textField setPasteDelegate:self.pasteDelegate];
@@ -216,7 +211,6 @@
 
   _omniboxTextController = [[OmniboxTextController alloc]
       initWithOmniboxController:_omniboxController.get()
-                 omniboxViewIOS:_omniboxView.get()
                omniboxEditModel:_omniboxEditModel.get()
                omniboxTextModel:_omniboxTextModel.get()
                   inLensOverlay:_isLensOverlay];
@@ -232,7 +226,6 @@
       _omniboxAutocompleteController);
 
   mediator.omniboxTextController = _omniboxTextController;
-  _omniboxView->SetOmniboxTextController(_omniboxTextController);
 
   self.zeroSuggestPrefetchHelper = [[ZeroSuggestPrefetchHelper alloc]
       initWithWebStateList:browser->GetWebStateList()];
@@ -273,7 +266,6 @@
   self.popupCoordinator = nil;
 
   _omniboxEditModel.reset();
-  _omniboxView.reset();
   _omniboxController.reset();
   _omniboxTextModel.reset();
   _client.reset();
diff --git a/ios/chrome/browser/omnibox/model/BUILD.gn b/ios/chrome/browser/omnibox/model/BUILD.gn
index 98350864..b6fa6d15 100644
--- a/ios/chrome/browser/omnibox/model/BUILD.gn
+++ b/ios/chrome/browser/omnibox/model/BUILD.gn
@@ -85,8 +85,6 @@
     "omnibox_text_controller_delegate.h",
     "omnibox_text_model.h",
     "omnibox_text_model.mm",
-    "omnibox_view_ios.h",
-    "omnibox_view_ios.mm",
     "pedal_section_extractor.h",
     "pedal_section_extractor.mm",
     "pedal_suggestion_wrapper.h",
@@ -192,8 +190,6 @@
     "test_omnibox_edit_model_ios.mm",
     "test_omnibox_popup_view_ios.h",
     "test_omnibox_popup_view_ios.mm",
-    "test_omnibox_view_ios.h",
-    "test_omnibox_view_ios.mm",
   ]
 
   deps = [
diff --git a/ios/chrome/browser/omnibox/model/omnibox_autocomplete_controller_unittest.mm b/ios/chrome/browser/omnibox/model/omnibox_autocomplete_controller_unittest.mm
index 76d2e414..2ca92bf 100644
--- a/ios/chrome/browser/omnibox/model/omnibox_autocomplete_controller_unittest.mm
+++ b/ios/chrome/browser/omnibox/model/omnibox_autocomplete_controller_unittest.mm
@@ -76,9 +76,8 @@
 class MockOmniboxEditModel : public OmniboxEditModelIOS {
  public:
   MockOmniboxEditModel(OmniboxControllerIOS* controller,
-                       OmniboxViewIOS* view,
                        OmniboxTextModel* text_model)
-      : OmniboxEditModelIOS(controller, view, text_model),
+      : OmniboxEditModelIOS(controller, text_model),
         last_opened_selection(OmniboxPopupSelection(UINT_MAX)) {}
   MockOmniboxEditModel(const MockOmniboxEditModel&) = delete;
   MockOmniboxEditModel& operator=(const MockOmniboxEditModel&) = delete;
@@ -124,7 +123,7 @@
         std::make_unique<OmniboxTextModel>(omnibox_client_.get());
 
     omnibox_edit_model_ = std::make_unique<MockOmniboxEditModel>(
-        omnibox_controller_.get(), nullptr, omnibox_text_model_.get());
+        omnibox_controller_.get(), omnibox_text_model_.get());
 
     controller_delegate_ =
         OCMProtocolMock(@protocol(OmniboxAutocompleteControllerDelegate));
diff --git a/ios/chrome/browser/omnibox/model/omnibox_controller_ios.mm b/ios/chrome/browser/omnibox/model/omnibox_controller_ios.mm
index daba58f5..95e8e37 100644
--- a/ios/chrome/browser/omnibox/model/omnibox_controller_ios.mm
+++ b/ios/chrome/browser/omnibox/model/omnibox_controller_ios.mm
@@ -22,7 +22,6 @@
 #import "components/omnibox/common/omnibox_feature_configs.h"
 #import "components/search_engines/template_url_starter_pack_data.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
 #import "ui/gfx/geometry/rect.h"
 
 OmniboxControllerIOS::OmniboxControllerIOS(
diff --git a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h
index 8cca345..fe20326 100644
--- a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h
+++ b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h
@@ -24,7 +24,6 @@
 #import "components/omnibox/browser/omnibox_popup_selection.h"
 #import "components/omnibox/common/omnibox_focus_state.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_text_model.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
 #import "third_party/metrics_proto/omnibox_event.pb.h"
 #import "ui/base/window_open_disposition.h"
 #import "url/gurl.h"
@@ -37,7 +36,6 @@
 class OmniboxEditModelIOS {
  public:
   OmniboxEditModelIOS(OmniboxControllerIOS* controller,
-                      OmniboxViewIOS* view,
                       OmniboxTextModel* text_model);
   virtual ~OmniboxEditModelIOS();
   OmniboxEditModelIOS(const OmniboxEditModelIOS&) = delete;
@@ -94,10 +92,6 @@
     return text_model_->user_input_in_progress;
   }
 
-  // Sets the state of user_input_in_progress_, and notifies the observer if
-  // that state has changed.
-  void SetInputInProgress(bool in_progress);
-
   // Resets the permanent display texts `url_for_editing_` to those provided by
   // the controller. Returns true if the display text shave changed and the
   // change should be immediately user-visible, because either the user is not
@@ -278,9 +272,6 @@
   // Owns this.
   raw_ptr<OmniboxControllerIOS> controller_;
 
-  // Owns `OmniboxControllerIOS` which owns this.
-  raw_ptr<OmniboxViewIOS> view_;
-
   // The omnibox text model containing the text state.
   raw_ptr<OmniboxTextModel> text_model_;
 
diff --git a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm
index 037e48f..c0a412e 100644
--- a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm
+++ b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm
@@ -70,7 +70,6 @@
 #import "ios/chrome/browser/omnibox/model/omnibox_controller_ios.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_popup_view_ios.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_text_controller.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
 #import "net/cookies/cookie_util.h"
 #import "third_party/icu/source/common/unicode/ubidi.h"
 #import "third_party/metrics_proto/omnibox_event.pb.h"
@@ -82,9 +81,8 @@
 using metrics::OmniboxEventProto;
 
 OmniboxEditModelIOS::OmniboxEditModelIOS(OmniboxControllerIOS* controller,
-                                         OmniboxViewIOS* view,
                                          OmniboxTextModel* text_model)
-    : controller_(controller), view_(view), text_model_(text_model) {}
+    : controller_(controller), text_model_(text_model) {}
 
 OmniboxEditModelIOS::~OmniboxEditModelIOS() = default;
 
@@ -140,7 +138,7 @@
 }
 
 void OmniboxEditModelIOS::SetUserText(const std::u16string& text) {
-  SetInputInProgress(true);
+  [text_controller_ setInputInProgress:YES];
   text_model_->UpdateUserText(text);
   GetInfoForCurrentText(&current_match_, nullptr);
   text_model_->paste_state = OmniboxPasteState::kNone;
@@ -180,17 +178,8 @@
       controller_->client(), url_from_text, write_url);
 }
 
-void OmniboxEditModelIOS::SetInputInProgress(bool in_progress) {
-  if (text_model_->SetInputInProgressNoNotify(in_progress)) {
-    if (text_model_->user_input_in_progress) {
-      autocomplete_controller()->ResetSession();
-    }
-    [text_controller_ notifyClientOnUserInputInProgressChange:in_progress];
-  }
-}
-
 void OmniboxEditModelIOS::Revert() {
-  SetInputInProgress(false);
+  [text_controller_ setInputInProgress:NO];
   text_model_->input.Clear();
   text_model_->paste_state = OmniboxPasteState::kNone;
   text_model_->UpdateUserText(std::u16string());
@@ -203,10 +192,14 @@
   // it. `SetCaretPos()` doesn't scroll the text, so doing that first wouldn't
   // accomplish anything.
   std::u16string current_permanent_url = GetPermanentDisplayText();
-  if (view_) {
-    view_->SetWindowTextAndCaretPos(current_permanent_url, 0, false, true);
-    view_->SetCaretPos(std::min(current_permanent_url.length(), start));
-  }
+
+  [text_controller_ setWindowText:current_permanent_url
+                         caretPos:0
+                startAutocomplete:false
+                notifyTextChanged:true];
+  [text_controller_
+      setCaretPos:std::min(current_permanent_url.length(), start)];
+
   controller_->client()->OnRevert();
 }
 
@@ -240,9 +233,7 @@
 
 void OmniboxEditModelIOS::ClearAdditionalText() {
   TRACE_EVENT0("omnibox", "OmniboxEditModelIOS::ClearAdditionalText");
-  if (view_) {
-    view_->SetAdditionalText(std::u16string());
-  }
+  [text_controller_ setAdditionalText:std::u16string()];
 }
 
 void OmniboxEditModelIOS::OnSetFocus() {
@@ -277,11 +268,11 @@
                                         ? text_model_->user_text
                                         : text_model_->input.text();
 
-  if (view_) {
-    view_->OnInlineAutocompleteTextMaybeChanged(
-        user_text, text_model_->inline_autocompletion);
-    view_->SetAdditionalText(additional_text);
-  }
+  [text_controller_
+      updateAutocompleteIfTextChanged:user_text
+                       autocompletion:text_model_->inline_autocompletion];
+  [text_controller_ setAdditionalText:additional_text];
+
   // We need to invoke OnChanged in case the destination url changed (as could
   // happen when control is toggled).
   OnChanged();
@@ -296,9 +287,7 @@
     return false;
   }
 
-  if (view_) {
-    view_->UpdatePopup();
-  }
+  [text_controller_ startAutocompleteAfterEdit];
 
   return true;
 }
@@ -607,7 +596,7 @@
     action->Execute(context);
   }
 
-  if (disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB && view_) {
+  if (disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB) {
     base::AutoReset<bool> tmp(&text_model_->in_revert, true);
     [text_controller_ revertAll];  // Revert the box to its unedited state.
   }
@@ -654,10 +643,5 @@
 }
 
 std::u16string OmniboxEditModelIOS::GetText() const {
-  // Once the model owns primary text, the check for `view_` won't be needed.
-  if (view_) {
-    return view_->GetText();
-  } else {
-    NOTREACHED();
-  }
+  return [text_controller_ displayedText];
 }
diff --git a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios_unittest.mm b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios_unittest.mm
index e3eafd1..e8a28ba 100644
--- a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios_unittest.mm
+++ b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios_unittest.mm
@@ -33,10 +33,9 @@
 #import "components/url_formatter/url_fixer.h"
 #import "extensions/buildflags/buildflags.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_controller_ios.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
+#import "ios/chrome/browser/omnibox/model/omnibox_text_controller.h"
 #import "ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.h"
 #import "ios/chrome/browser/omnibox/model/test_omnibox_popup_view_ios.h"
-#import "ios/chrome/browser/omnibox/model/test_omnibox_view_ios.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
 #import "testing/platform_test.h"
@@ -83,6 +82,39 @@
 
 }  // namespace
 
+// Mocking the text controller to not rely on the textfield view.
+@interface TestOmniboxTextController : OmniboxTextController
+@end
+
+@implementation TestOmniboxTextController {
+  std::u16string text_;
+}
+
+- (std::u16string)displayedText {
+  return text_;
+}
+
+- (void)setWindowText:(const std::u16string&)text
+             caretPos:(size_t)caretPos
+    startAutocomplete:(BOOL)startAutocomplete
+    notifyTextChanged:(BOOL)notifyTextChanged {
+  [super setWindowText:text
+               caretPos:caretPos
+      startAutocomplete:startAutocomplete
+      notifyTextChanged:notifyTextChanged];
+  text_ = text;
+}
+
+- (void)updateAutocompleteIfTextChanged:(const std::u16string&)userText
+                         autocompletion:
+                             (const std::u16string&)inlineAutocomplete {
+  [super updateAutocompleteIfTextChanged:userText
+                          autocompletion:inlineAutocomplete];
+  text_ = userText + inlineAutocomplete;
+}
+
+@end
+
 class OmniboxEditModelIOSTest : public PlatformTest {
  public:
   OmniboxEditModelIOSTest() {
@@ -90,18 +122,19 @@
 
     omnibox_controller_ =
         std::make_unique<OmniboxControllerIOS>(omnibox_client_.get());
-    view_ = std::make_unique<TestOmniboxViewIOS>();
     omnibox_text_model_ =
         std::make_unique<OmniboxTextModel>(omnibox_client_.get());
     omnibox_edit_model_ = std::make_unique<TestOmniboxEditModelIOS>(
-        omnibox_controller_.get(), view_.get(), /*pref_service=*/nullptr,
+        omnibox_controller_.get(), /*pref_service=*/nullptr,
         omnibox_text_model_.get());
-
-    view_->SetOmniboxEditModel(omnibox_edit_model_.get());
-    view_->SetOmniboxController(omnibox_controller_.get());
+    omnibox_text_controller_ = [[TestOmniboxTextController alloc]
+        initWithOmniboxController:omnibox_controller_.get()
+                 omniboxEditModel:omnibox_edit_model_.get()
+                 omniboxTextModel:omnibox_text_model_.get()
+                    inLensOverlay:NO];
+    omnibox_edit_model_->set_text_controller(omnibox_text_controller_);
   }
 
-  TestOmniboxViewIOS* view() { return view_.get(); }
   TestLocationBarModel* location_bar_model() {
     return omnibox_client_->location_bar_model();
   }
@@ -110,8 +143,8 @@
 
  protected:
   base::test::TaskEnvironment task_environment_;
+  TestOmniboxTextController* omnibox_text_controller_;
   std::unique_ptr<TestOmniboxClient> omnibox_client_;
-  std::unique_ptr<TestOmniboxViewIOS> view_;
   std::unique_ptr<OmniboxControllerIOS> omnibox_controller_;
   std::unique_ptr<OmniboxTextModel> omnibox_text_model_;
   std::unique_ptr<TestOmniboxEditModelIOS> omnibox_edit_model_;
@@ -119,30 +152,30 @@
 
 TEST_F(OmniboxEditModelIOSTest, DISABLED_InlineAutocompleteText) {
   // Test if the model updates the inline autocomplete text in the view.
-  EXPECT_EQ(std::u16string(), view()->inline_autocompletion());
+  EXPECT_EQ(std::u16string(), omnibox_text_model_->inline_autocompletion);
   model()->SetUserText(u"he");
   model()->OnPopupDataChanged(u"llo", std::u16string(), {});
-  EXPECT_EQ(u"hello", view()->GetText());
-  EXPECT_EQ(u"llo", view()->inline_autocompletion());
+  EXPECT_EQ(u"hello", [omnibox_text_controller_ displayedText]);
+  EXPECT_EQ(u"llo", omnibox_text_model_->inline_autocompletion);
 
   std::u16string text_before = u"he";
   std::u16string text_after = u"hel";
   OmniboxStateChanges state_changes{&text_before, &text_after, 3,    3,
                                     false,        true,        false};
   model()->OnAfterPossibleChange(state_changes);
-  EXPECT_EQ(std::u16string(), view()->inline_autocompletion());
+  EXPECT_EQ(std::u16string(), omnibox_text_model_->inline_autocompletion);
   model()->OnPopupDataChanged(u"lo", std::u16string(), {});
-  EXPECT_EQ(u"hello", view()->GetText());
-  EXPECT_EQ(u"lo", view()->inline_autocompletion());
+  EXPECT_EQ(u"hello", [omnibox_text_controller_ displayedText]);
+  EXPECT_EQ(u"lo", omnibox_text_model_->inline_autocompletion);
 
   model()->Revert();
-  EXPECT_EQ(std::u16string(), view()->GetText());
-  EXPECT_EQ(std::u16string(), view()->inline_autocompletion());
+  EXPECT_EQ(std::u16string(), [omnibox_text_controller_ displayedText]);
+  EXPECT_EQ(std::u16string(), omnibox_text_model_->inline_autocompletion);
 
   model()->SetUserText(u"he");
   model()->OnPopupDataChanged(u"llo", std::u16string(), {});
-  EXPECT_EQ(u"hello", view()->GetText());
-  EXPECT_EQ(u"llo", view()->inline_autocompletion());
+  EXPECT_EQ(u"hello", [omnibox_text_controller_ displayedText]);
+  EXPECT_EQ(u"llo", omnibox_text_model_->inline_autocompletion);
 }
 
 // This verifies the fix for a bug where calling OpenMatch() with a valid
@@ -190,7 +223,8 @@
     model()->ResetDisplayTexts();
     model()->Revert();
 
-    EXPECT_EQ(u"http://www.example.com/", view()->GetText());
+    EXPECT_EQ(u"http://www.example.com/",
+              [omnibox_text_controller_ displayedText]);
 
     AutocompleteMatch match = model()->CurrentMatch(nullptr);
     EXPECT_EQ(AutocompleteMatchType::URL_WHAT_YOU_TYPED, match.type);
@@ -206,7 +240,8 @@
     model()->ResetDisplayTexts();
     model()->Revert();
 
-    EXPECT_EQ(u"https://www.google.com/", view()->GetText());
+    EXPECT_EQ(u"https://www.google.com/",
+              [omnibox_text_controller_ displayedText]);
 
     AutocompleteMatch match = model()->CurrentMatch(nullptr);
     EXPECT_EQ(AutocompleteMatchType::URL_WHAT_YOU_TYPED, match.type);
@@ -229,10 +264,12 @@
   // iOS OmniboxEditModel always provides the full URL as the OmniboxView
   // permanent display text.
   EXPECT_EQ(u"https://www.example.com/", model()->GetPermanentDisplayText());
-  EXPECT_EQ(u"https://www.example.com/", view()->GetText());
+  EXPECT_EQ(u"https://www.example.com/",
+            [omnibox_text_controller_ displayedText]);
   EXPECT_FALSE(model()->user_input_in_progress());
 
-  EXPECT_EQ(u"https://www.example.com/", view()->GetText());
+  EXPECT_EQ(u"https://www.example.com/",
+            [omnibox_text_controller_ displayedText]);
   EXPECT_TRUE(model()->CurrentTextIsURL());
 }
 
diff --git a/ios/chrome/browser/omnibox/model/omnibox_text_controller.h b/ios/chrome/browser/omnibox/model/omnibox_text_controller.h
index 0b0a33d..8edd530 100644
--- a/ios/chrome/browser/omnibox/model/omnibox_text_controller.h
+++ b/ios/chrome/browser/omnibox/model/omnibox_text_controller.h
@@ -18,7 +18,6 @@
 @protocol OmniboxFocusDelegate;
 @protocol OmniboxTextControllerDelegate;
 @class OmniboxTextFieldIOS;
-class OmniboxViewIOS;
 
 /// Controller of the omnibox text.
 @interface OmniboxTextController : NSObject
@@ -42,7 +41,6 @@
 /// Temporary initializer, used during the refactoring. crbug.com/390409559
 - (instancetype)initWithOmniboxController:
                     (OmniboxControllerIOS*)omniboxController
-                           omniboxViewIOS:(OmniboxViewIOS*)omniboxViewIOS
                          omniboxEditModel:(OmniboxEditModelIOS*)omniboxEditModel
                          omniboxTextModel:(OmniboxTextModel*)omniboxTextModel
                             inLensOverlay:(BOOL)inLensOverlay
@@ -77,6 +75,12 @@
 /// showing, popup closed, no user input in progress).
 - (void)revertAll;
 
+/// Returns the current text field displayed text.
+- (std::u16string)displayedText;
+
+/// Updates the text model input_in_progress state.
+- (void)setInputInProgress:(BOOL)inProgress;
+
 #pragma mark - Autocomplete event
 
 /// Sets the additional text.
diff --git a/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm b/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm
index ccf1fbbe..cf4e128 100644
--- a/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm
+++ b/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm
@@ -20,7 +20,6 @@
 #import "ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_text_controller_delegate.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_text_model.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
 #import "ios/chrome/browser/omnibox/public/omnibox_metrics_helper.h"
 #import "ios/chrome/browser/omnibox/ui/omnibox_focus_delegate.h"
 #import "ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.h"
@@ -45,8 +44,6 @@
 @implementation OmniboxTextController {
   /// Controller of the omnibox.
   raw_ptr<OmniboxControllerIOS> _omniboxController;
-  /// Controller of the omnibox view.
-  raw_ptr<OmniboxViewIOS> _omniboxViewIOS;
   /// Omnibox edit model. Should only be used for text interactions.
   raw_ptr<OmniboxEditModelIOS> _omniboxEditModel;
   /// Whether the popup was scrolled during this omnibox interaction.
@@ -67,7 +64,6 @@
 
 - (instancetype)initWithOmniboxController:
                     (OmniboxControllerIOS*)omniboxController
-                           omniboxViewIOS:(OmniboxViewIOS*)omniboxViewIOS
                          omniboxEditModel:(OmniboxEditModelIOS*)omniboxEditModel
                          omniboxTextModel:(OmniboxTextModel*)omniboxTextModel
                             inLensOverlay:(BOOL)inLensOverlay {
@@ -75,7 +71,6 @@
   if (self) {
     _omniboxController = omniboxController;
     _omniboxEditModel = omniboxEditModel;
-    _omniboxViewIOS = omniboxViewIOS;
     _omniboxTextModel = omniboxTextModel;
     _inLensOverlay = inLensOverlay;
     _currentSelection = NSMakeRange(0, 0);
@@ -87,7 +82,6 @@
 - (void)disconnect {
   _omniboxController = nullptr;
   _omniboxEditModel = nullptr;
-  _omniboxViewIOS = nullptr;
 }
 
 - (void)updateAppearance {
@@ -227,6 +221,23 @@
   }
 }
 
+- (std::u16string)displayedText {
+  return base::SysNSStringToUTF16([self.textField displayedText]);
+}
+
+- (void)setInputInProgress:(BOOL)inProgress {
+  if (!_omniboxTextModel) {
+    return;
+  }
+
+  if (_omniboxTextModel->SetInputInProgressNoNotify(inProgress)) {
+    if (_omniboxTextModel->user_input_in_progress) {
+      _omniboxController->autocomplete_controller()->ResetSession();
+    }
+    [self notifyClientOnUserInputInProgressChange:inProgress];
+  }
+}
+
 #pragma mark - Autocomplete events
 
 - (void)setAdditionalText:(const std::u16string&)text {
@@ -284,9 +295,7 @@
     [textField clearAutocompleteText];
     [textField exitPreEditState];
     [textField setText:@""];
-    if (_omniboxViewIOS) {
-      [self textDidChangeWithUserEvent:YES];
-    }
+    [self textDidChangeWithUserEvent:YES];
   }
   // Calling textDidChangeWithUserEvent can trigger a scroll event, which
   // removes focus from the omnibox.
@@ -580,9 +589,7 @@
       // set to the empty string by `shouldChangeCharactersInRange` so when
       // OnAfterPossibleChange checks if the text has changed it does not see
       // any difference so it never sets the input-in-progress flag.
-      if (_omniboxEditModel) {
-        _omniboxEditModel->SetInputInProgress(YES);
-      }
+      [self setInputInProgress:YES];
     }
   }
 }
@@ -613,12 +620,17 @@
 
 - (void)refineWithText:(const std::u16string&)text {
   OmniboxTextFieldIOS* textField = self.textField;
-  if (!_omniboxViewIOS) {
-    return;
-  }
   // Exit preedit state and append the match. Refocus if necessary.
   [textField exitPreEditState];
-  _omniboxViewIOS->SetUserText(text);
+  if (_omniboxEditModel) {
+    _omniboxEditModel->SetUserText(text);
+  }
+
+  [self setWindowText:text
+               caretPos:text.length()
+      startAutocomplete:true
+      notifyTextChanged:true];
+
   [self onBeforePossibleChange];
   // Calling setText: does not trigger UIControlEventEditingChanged, so
   // trigger that manually.
@@ -675,12 +687,9 @@
 /// Updates the autocomplete popup and other state after the text has been
 /// changed by the user.
 - (void)startAutocompleteAfterEdit {
-  if (_omniboxEditModel) {
-    _omniboxEditModel->SetInputInProgress(true);
-  }
+  [self setInputInProgress:YES];
 
-  if (!_omniboxEditModel || !_omniboxEditModel->has_focus() ||
-      !_omniboxViewIOS) {
+  if (!_omniboxEditModel || !_omniboxEditModel->has_focus()) {
     return;
   }
 
diff --git a/ios/chrome/browser/omnibox/model/omnibox_view_ios.h b/ios/chrome/browser/omnibox/model/omnibox_view_ios.h
deleted file mode 100644
index b208678..0000000
--- a/ios/chrome/browser/omnibox/model/omnibox_view_ios.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_OMNIBOX_MODEL_OMNIBOX_VIEW_IOS_H_
-#define IOS_CHROME_BROWSER_OMNIBOX_MODEL_OMNIBOX_VIEW_IOS_H_
-
-#import <UIKit/UIKit.h>
-
-#import <memory>
-#import <optional>
-
-#import "base/memory/raw_ptr.h"
-#import "base/memory/weak_ptr.h"
-#import "components/omnibox/browser/location_bar_model.h"
-
-class OmniboxControllerIOS;
-class OmniboxEditModelIOS;
-@class OmniboxTextController;
-@class OmniboxTextFieldIOS;
-
-// Wraps a UITextField and interfaces with the rest of the autocomplete system.
-class OmniboxViewIOS {
- public:
-  // Retains `field`.
-  OmniboxViewIOS(OmniboxTextFieldIOS* field);
-  OmniboxViewIOS(const OmniboxViewIOS&) = delete;
-  OmniboxViewIOS& operator=(const OmniboxViewIOS&) = delete;
-  virtual ~OmniboxViewIOS();
-
-  void SetOmniboxEditModel(OmniboxEditModelIOS* edit_model);
-
-  void SetOmniboxController(OmniboxControllerIOS* omnibox_controller);
-
-  void SetOmniboxTextController(OmniboxTextController* controller) {
-    omnibox_text_controller_ = controller;
-  }
-
-  // Returns the current text of the edit control, which could be the
-  // "temporary" text set by the popup, the "permanent" text set by the
-  // browser, or just whatever the user has currently typed.
-  virtual std::u16string GetText() const;
-
-  // The user text is the text the user has manually keyed in. When present,
-  // this is shown in preference to the permanent text; hitting escape will
-  // revert to the permanent text.
-  void SetUserText(const std::u16string& text);
-  virtual void SetUserText(const std::u16string& text, bool update_popup);
-
-  // Sets the window text and the caret position. `notify_text_changed` is true
-  // if the model should be notified of the change. Clears the additional text.
-  virtual void SetWindowTextAndCaretPos(const std::u16string& text,
-                                        size_t caret_pos,
-                                        bool update_popup,
-                                        bool notify_text_changed);
-
-  // Sets the caret position. Removes any selection. Clamps the requested caret
-  // position to the length of the current text.
-  virtual void SetCaretPos(size_t caret_pos);
-
-  // Updates the autocomplete popup and other state after the text has been
-  // changed by the user.
-  virtual void UpdatePopup();
-
-  // Called when the inline autocomplete text in the model may have changed.
-  // `user_text` is the portion of omnibox text the user typed.
-  // `inline`_autocompletion` is the autocompleted part.
-  virtual void OnInlineAutocompleteTextMaybeChanged(
-      const std::u16string& user_text,
-      const std::u16string& inline_autocompletion);
-
-  // Sets the omnibox adjacent additional text label in the location bar view.
-  virtual void SetAdditionalText(const std::u16string& text);
-
-  // Called when autocomplete text is accepted. (e.g. tap on autocomplete text,
-  // tap on left/right arrow key).
-  void OnAcceptAutocomplete();
-
- private:
-  friend class TestOmniboxViewIOS;
-
-  base::WeakPtr<OmniboxControllerIOS> controller_;
-  OmniboxTextFieldIOS* field_;
-
-  /// Controller that will replace OmniboxViewIOS at the end of the refactoring
-  /// crbug.com/390409559.
-  __weak OmniboxTextController* omnibox_text_controller_;
-
-  base::WeakPtr<OmniboxEditModelIOS> model_;
-
-  // Used to cancel clipboard callbacks if this is deallocated;
-  base::WeakPtrFactory<OmniboxViewIOS> weak_ptr_factory_{this};
-};
-
-#endif  // IOS_CHROME_BROWSER_OMNIBOX_MODEL_OMNIBOX_VIEW_IOS_H_
diff --git a/ios/chrome/browser/omnibox/model/omnibox_view_ios.mm b/ios/chrome/browser/omnibox/model/omnibox_view_ios.mm
deleted file mode 100644
index 032cfd0c2..0000000
--- a/ios/chrome/browser/omnibox/model/omnibox_view_ios.mm
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
-
-#import <CoreText/CoreText.h>
-#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
-
-#import <string>
-
-#import "base/command_line.h"
-#import "base/ios/device_util.h"
-#import "base/ios/ios_util.h"
-#import "base/metrics/user_metrics.h"
-#import "base/metrics/user_metrics_action.h"
-#import "base/strings/string_util.h"
-#import "base/strings/sys_string_conversions.h"
-#import "components/omnibox/browser/autocomplete_input.h"
-#import "components/omnibox/browser/clipboard_provider.h"
-#import "components/omnibox/browser/location_bar_model.h"
-#import "components/omnibox/browser/omnibox_text_util.h"
-#import "components/omnibox/common/omnibox_focus_state.h"
-#import "components/open_from_clipboard/clipboard_recent_content.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_scheme_classifier_impl.h"
-#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_controller_ios.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h"
-#import "ios/chrome/browser/omnibox/model/omnibox_text_controller.h"
-#import "ios/chrome/browser/omnibox/public/omnibox_metrics_helper.h"
-#import "ios/chrome/browser/omnibox/public/omnibox_ui_features.h"
-#import "ios/chrome/browser/omnibox/public/omnibox_util.h"
-#import "ios/chrome/browser/omnibox/ui/omnibox_focus_delegate.h"
-#import "ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.h"
-#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
-#import "ios/chrome/browser/shared/public/commands/omnibox_commands.h"
-#import "ios/chrome/browser/shared/public/commands/toolbar_commands.h"
-#import "ios/chrome/browser/shared/public/features/features.h"
-#import "ios/chrome/browser/shared/ui/util/pasteboard_util.h"
-#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
-#import "ios/chrome/grit/ios_strings.h"
-#import "ios/chrome/grit/ios_theme_resources.h"
-#import "ios/web/public/navigation/referrer.h"
-#import "net/base/apple/url_conversions.h"
-#import "ui/base/device_form_factor.h"
-#import "ui/base/page_transition_types.h"
-#import "ui/base/resource/resource_bundle.h"
-#import "ui/base/window_open_disposition.h"
-#import "ui/gfx/image/image.h"
-
-using base::UserMetricsAction;
-
-#pragma mark - Public
-
-OmniboxViewIOS::OmniboxViewIOS(OmniboxTextFieldIOS* field) : field_(field) {}
-
-OmniboxViewIOS::~OmniboxViewIOS() = default;
-
-void OmniboxViewIOS::SetOmniboxEditModel(OmniboxEditModelIOS* edit_model) {
-  model_ = edit_model->AsWeakPtr();
-}
-
-void OmniboxViewIOS::SetOmniboxController(
-    OmniboxControllerIOS* omnibox_controller) {
-  controller_ = omnibox_controller->AsWeakPtr();
-}
-
-std::u16string OmniboxViewIOS::GetText() const {
-  return base::SysNSStringToUTF16([field_ displayedText]);
-}
-
-void OmniboxViewIOS::SetUserText(const std::u16string& text) {
-  SetUserText(text, true);
-}
-
-void OmniboxViewIOS::SetUserText(const std::u16string& text,
-                                 bool update_popup) {
-  if (model_) {
-    model_->SetUserText(text);
-  }
-  SetWindowTextAndCaretPos(text, text.length(), update_popup, true);
-}
-
-void OmniboxViewIOS::SetWindowTextAndCaretPos(const std::u16string& text,
-                                              size_t caret_pos,
-                                              bool update_popup,
-                                              bool notify_text_changed) {
-  [omnibox_text_controller_ setWindowText:text
-                                 caretPos:caret_pos
-                        startAutocomplete:update_popup
-                        notifyTextChanged:notify_text_changed];
-}
-
-void OmniboxViewIOS::SetCaretPos(size_t caret_pos) {
-  [omnibox_text_controller_ setCaretPos:caret_pos];
-}
-
-void OmniboxViewIOS::UpdatePopup() {
-  [omnibox_text_controller_ startAutocompleteAfterEdit];
-}
-
-void OmniboxViewIOS::OnInlineAutocompleteTextMaybeChanged(
-    const std::u16string& user_text,
-    const std::u16string& inline_autocompletion) {
-  [omnibox_text_controller_
-      updateAutocompleteIfTextChanged:user_text
-                       autocompletion:inline_autocompletion];
-}
-
-void OmniboxViewIOS::SetAdditionalText(const std::u16string& text) {
-  [omnibox_text_controller_ setAdditionalText:text];
-}
-
-void OmniboxViewIOS::OnAcceptAutocomplete() {
-  [omnibox_text_controller_ onAcceptAutocomplete];
-}
diff --git a/ios/chrome/browser/omnibox/model/placeholder_service.h b/ios/chrome/browser/omnibox/model/placeholder_service.h
index e1eb7bf..7280d1b 100644
--- a/ios/chrome/browser/omnibox/model/placeholder_service.h
+++ b/ios/chrome/browser/omnibox/model/placeholder_service.h
@@ -29,7 +29,8 @@
   // Relevant for both normal and search-only text.
   virtual void OnPlaceholderTextChanged() = 0;
 
-  // Notification that the search engine icon might have changed.
+  // Notification that the search engine icon might have changed. This is called
+  // when an icon is fetched even if it's not the right size icon.
   virtual void OnPlaceholderImageChanged() {}
 
   // Notification that the placeholder service is shutting down. Observers that
@@ -71,6 +72,12 @@
   // default search engine changes during the fetch.
   void FetchDefaultSearchEngineIcon(CGFloat icon_point_size,
                                     PlaceholderImageCallback callback);
+
+  // Returns the icon for the current default search engine at the given
+  // `icon_point_size`. If the icon is unavailable, it will be fetched and
+  // `OnPlaceholderImageChanged` will be called once it becomes available.
+  UIImage* GetDefaultSearchEngineIcon(CGFloat icon_point_size);
+
   NSString* GetCurrentPlaceholderText();
   NSString* GetCurrentSearchOnlyPlaceholderText();
 
diff --git a/ios/chrome/browser/omnibox/model/placeholder_service.mm b/ios/chrome/browser/omnibox/model/placeholder_service.mm
index 08c60705..d1406fe 100644
--- a/ios/chrome/browser/omnibox/model/placeholder_service.mm
+++ b/ios/chrome/browser/omnibox/model/placeholder_service.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/omnibox/model/placeholder_service.h"
 
+#import "base/functional/callback_helpers.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/omnibox/common/omnibox_features.h"
 #import "components/search_engines/template_url.h"
@@ -80,6 +81,31 @@
   PerformIconFetch(default_provider, icon_point_size);
 }
 
+UIImage* PlaceholderService::GetDefaultSearchEngineIcon(
+    CGFloat icon_point_size) {
+  // Return the cached image if there is one.
+  UIImage* cached_icon = [icon_cache_ objectForKey:@(icon_point_size)];
+  if (cached_icon) {
+    return cached_icon;
+  }
+
+  // Return the placeholder icon if there is no default search provider.
+  UIImage* placeholder_icon =
+      DefaultSymbolWithPointSize(kSearchSymbol, icon_point_size);
+  const TemplateURL* default_provider =
+      template_url_service_ ? template_url_service_->GetDefaultSearchProvider()
+                            : nullptr;
+  if (!default_provider) {
+    return placeholder_icon;
+  }
+  // Fetch the icon after return.
+  base::ScopedClosureRunner run_after_return =
+      base::ScopedClosureRunner(base::BindOnce(
+          &PlaceholderService::FetchDefaultSearchEngineIcon,
+          base::Unretained(this), icon_point_size, base::DoNothing()));
+  return placeholder_icon;
+}
+
 NSString* PlaceholderService::GetCurrentPlaceholderText() {
   if (!base::FeatureList::IsEnabled(omnibox::kOmniboxMobileParityUpdate)) {
     return l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT);
@@ -167,6 +193,10 @@
       ![icon_cache_ objectForKey:@(icon_point_size)]) {
     [icon_cache_ setObject:icon forKey:@(icon_point_size)];
 
+    for (auto& observer : model_observers_) {
+      observer.OnPlaceholderImageChanged();
+    }
+
     if (icon_callbacks_.contains(icon_point_size)) {
       std::vector<PlaceholderImageCallback> callbacks =
           std::move(icon_callbacks_[icon_point_size]);
diff --git a/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.h b/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.h
index 1456026..183f1914 100644
--- a/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.h
+++ b/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.h
@@ -14,7 +14,6 @@
 class TestOmniboxEditModelIOS : public OmniboxEditModelIOS {
  public:
   TestOmniboxEditModelIOS(OmniboxControllerIOS* omnibox_controller,
-                          OmniboxViewIOS* view,
                           PrefService* pref_service,
                           OmniboxTextModel* text_model);
   ~TestOmniboxEditModelIOS() override;
diff --git a/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.mm b/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.mm
index 558e5e7..836e4d0 100644
--- a/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.mm
+++ b/ios/chrome/browser/omnibox/model/test_omnibox_edit_model_ios.mm
@@ -11,10 +11,9 @@
 
 TestOmniboxEditModelIOS::TestOmniboxEditModelIOS(
     OmniboxControllerIOS* omnibox_controller,
-    OmniboxViewIOS* view,
     PrefService* pref_service,
     OmniboxTextModel* text_model)
-    : OmniboxEditModelIOS(omnibox_controller, view, text_model),
+    : OmniboxEditModelIOS(omnibox_controller, text_model),
       popup_is_open_(false),
       pref_service_(pref_service) {}
 
diff --git a/ios/chrome/browser/omnibox/model/test_omnibox_view_ios.h b/ios/chrome/browser/omnibox/model/test_omnibox_view_ios.h
deleted file mode 100644
index f58a787..0000000
--- a/ios/chrome/browser/omnibox/model/test_omnibox_view_ios.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2025 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_OMNIBOX_MODEL_TEST_OMNIBOX_VIEW_IOS_H_
-#define IOS_CHROME_BROWSER_OMNIBOX_MODEL_TEST_OMNIBOX_VIEW_IOS_H_
-
-#import <stddef.h>
-
-#import <string>
-
-#import "ios/chrome/browser/omnibox/model/omnibox_view_ios.h"
-#import "ui/gfx/range/range.h"
-
-// Fake implementation of OmniboxViewIOS for use in tests.
-class TestOmniboxViewIOS : public OmniboxViewIOS {
- public:
-  explicit TestOmniboxViewIOS() : OmniboxViewIOS(nil) {}
-
-  TestOmniboxViewIOS(const TestOmniboxViewIOS&) = delete;
-  TestOmniboxViewIOS& operator=(const TestOmniboxViewIOS&) = delete;
-
-  const std::u16string& inline_autocompletion() const {
-    return inline_autocompletion_;
-  }
-
-
-  // OmniboxViewIOS:
-  std::u16string GetText() const override;
-  void SetWindowTextAndCaretPos(const std::u16string& text,
-                                size_t caret_pos,
-                                bool update_popup,
-                                bool notify_text_changed) override;
-  void SetCaretPos(size_t caret_pos) override {}
-  void SetAdditionalText(const std::u16string& text) override {}
-  void UpdatePopup() override {}
-  void OnInlineAutocompleteTextMaybeChanged(
-      const std::u16string& user_text,
-      const std::u16string& inline_autocompletion) override;
-
- private:
-  std::u16string text_;
-  std::u16string inline_autocompletion_;
-  gfx::Range selection_;
-};
-
-#endif  // IOS_CHROME_BROWSER_OMNIBOX_MODEL_TEST_OMNIBOX_VIEW_IOS_H_
diff --git a/ios/chrome/browser/omnibox/model/test_omnibox_view_ios.mm b/ios/chrome/browser/omnibox/model/test_omnibox_view_ios.mm
deleted file mode 100644
index 6b9106bd..0000000
--- a/ios/chrome/browser/omnibox/model/test_omnibox_view_ios.mm
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2025 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/omnibox/model/test_omnibox_view_ios.h"
-
-#import <algorithm>
-
-#import "base/strings/utf_string_conversions.h"
-#import "components/omnibox/browser/test_omnibox_client.h"
-#import "ui/gfx/native_widget_types.h"
-
-std::u16string TestOmniboxViewIOS::GetText() const {
-  return text_;
-}
-
-void TestOmniboxViewIOS::SetWindowTextAndCaretPos(const std::u16string& text,
-                                                  size_t caret_pos,
-                                                  bool update_popup,
-                                                  bool notify_text_changed) {
-  text_ = text;
-  selection_ = gfx::Range(caret_pos);
-}
-
-void TestOmniboxViewIOS::OnInlineAutocompleteTextMaybeChanged(
-    const std::u16string& user_text,
-    const std::u16string& inline_autocompletion) {
-  std::u16string display_text = user_text + inline_autocompletion;
-  const bool text_changed = text_ != display_text;
-  text_ = display_text;
-  inline_autocompletion_ = inline_autocompletion;
-
-  // Just like the Views control, only change the selection if the text has
-  // actually changed.
-  if (text_changed) {
-    selection_ = gfx::Range(text_.size(), inline_autocompletion.size());
-  }
-}
diff --git a/ios/chrome/browser/passwords/model/ios_chrome_password_manager_client.mm b/ios/chrome/browser/passwords/model/ios_chrome_password_manager_client.mm
index 338bb04f..ea1e35c8 100644
--- a/ios/chrome/browser/passwords/model/ios_chrome_password_manager_client.mm
+++ b/ios/chrome/browser/passwords/model/ios_chrome_password_manager_client.mm
@@ -10,6 +10,7 @@
 #import "base/feature_list.h"
 #import "base/functional/bind.h"
 #import "base/functional/callback.h"
+#import "base/notimplemented.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/strings/utf_string_conversions.h"
 #import "base/types/optional_util.h"
diff --git a/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.mm b/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.mm
index de6254f..7582da16 100644
--- a/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.mm
+++ b/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.mm
@@ -7,6 +7,7 @@
 #import "base/check.h"
 #import "base/command_line.h"
 #import "base/functional/bind.h"
+#import "base/notimplemented.h"
 #import "base/notreached.h"
 #import "components/omnibox/browser/omnibox_event_global_tracker.h"
 #import "components/omnibox/browser/omnibox_log.h"
diff --git a/ios/chrome/browser/scanner/ui_bundled/scanner_view_controller.mm b/ios/chrome/browser/scanner/ui_bundled/scanner_view_controller.mm
index 3fe3a2f..2628356 100644
--- a/ios/chrome/browser/scanner/ui_bundled/scanner_view_controller.mm
+++ b/ios/chrome/browser/scanner/ui_bundled/scanner_view_controller.mm
@@ -9,6 +9,7 @@
 #import "base/logging.h"
 #import "base/metrics/user_metrics.h"
 #import "base/metrics/user_metrics_action.h"
+#import "base/notimplemented.h"
 #import "ios/chrome/browser/scanner/ui_bundled/scanner_alerts.h"
 #import "ios/chrome/browser/scanner/ui_bundled/scanner_presenting.h"
 #import "ios/chrome/browser/scanner/ui_bundled/scanner_transitioning_delegate.h"
diff --git a/ios/chrome/browser/send_tab_to_self/model/send_tab_to_self_browser_agent.mm b/ios/chrome/browser/send_tab_to_self/model/send_tab_to_self_browser_agent.mm
index d3f545b..eba8c0e 100644
--- a/ios/chrome/browser/send_tab_to_self/model/send_tab_to_self_browser_agent.mm
+++ b/ios/chrome/browser/send_tab_to_self/model/send_tab_to_self_browser_agent.mm
@@ -11,7 +11,7 @@
 #import <vector>
 
 #import "base/check.h"
-#import "base/notreached.h"
+#import "base/notimplemented.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/strings/utf_string_conversions.h"
 #import "components/infobars/core/infobar.h"
diff --git a/ios/chrome/browser/web/model/chrome_web_client.mm b/ios/chrome/browser/web/model/chrome_web_client.mm
index 9c2bdb6..cc88d2c6 100644
--- a/ios/chrome/browser/web/model/chrome_web_client.mm
+++ b/ios/chrome/browser/web/model/chrome_web_client.mm
@@ -261,7 +261,7 @@
   ProfileIOS* profile =
       ProfileIOS::FromBrowserState(web_state->GetBrowserState());
   std::string error_page_content =
-      supervised_user::SupervisedUserInterstitial::GetHTMLContents(
+      supervised_user::SupervisedUserInterstitial::GetHTMLContentsWithApprovals(
           SupervisedUserServiceFactory::GetForProfile(profile),
           profile->GetPrefs(), error_info->filtering_behavior_reason(),
           container->IsRemoteApprovalPendingForUrl(url),
diff --git a/ios/chrome/browser/web/model/web_state_delegate_browser_agent.mm b/ios/chrome/browser/web/model/web_state_delegate_browser_agent.mm
index 5d871fd..773eff9 100644
--- a/ios/chrome/browser/web/model/web_state_delegate_browser_agent.mm
+++ b/ios/chrome/browser/web/model/web_state_delegate_browser_agent.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/web/model/web_state_delegate_browser_agent.h"
 
+#import "base/notimplemented.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/content_settings/core/browser/host_content_settings_map.h"
 #import "components/content_settings/core/common/content_settings.h"
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 9d1a92ef..45439b4 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -18,7 +18,7 @@
 #import "base/functional/bind.h"
 #import "base/location.h"
 #import "base/memory/weak_ptr.h"
-#import "base/notreached.h"
+#import "base/notimplemented.h"
 #import "base/observer_list.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/task/sequenced_task_runner.h"
diff --git a/ios/web/content/navigation/content_navigation_manager.mm b/ios/web/content/navigation/content_navigation_manager.mm
index 21ccea0..53606ce 100644
--- a/ios/web/content/navigation/content_navigation_manager.mm
+++ b/ios/web/content/navigation/content_navigation_manager.mm
@@ -9,6 +9,7 @@
 #import <sstream>
 
 #import "base/apple/foundation_util.h"
+#import "base/notimplemented.h"
 #import "base/strings/sys_string_conversions.h"
 #import "content/public/browser/navigation_controller.h"
 #import "content/public/browser/navigation_entry.h"
diff --git a/ios/web/public/test/fakes/fake_cookie_store.cc b/ios/web/public/test/fakes/fake_cookie_store.cc
index 5a94b33..63942444 100644
--- a/ios/web/public/test/fakes/fake_cookie_store.cc
+++ b/ios/web/public/test/fakes/fake_cookie_store.cc
@@ -6,6 +6,7 @@
 
 #include <optional>
 
+#include "base/notimplemented.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
 
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller.mm b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
index b895b8a..89033ab 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_controller.mm
+++ b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
@@ -9,7 +9,7 @@
 
 #import "base/apple/foundation_util.h"
 #import "base/functional/callback.h"
-#import "base/notreached.h"
+#import "base/notimplemented.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/values.h"
 #import "components/autofill/core/browser/form_structure.h"
diff --git a/ios/web_view/internal/passwords/web_view_password_manager_client.mm b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
index 7b4396ea6..5906ef22 100644
--- a/ios/web_view/internal/passwords/web_view_password_manager_client.mm
+++ b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
@@ -8,6 +8,7 @@
 #import <utility>
 
 #import "base/functional/callback.h"
+#import "base/notimplemented.h"
 #import "components/autofill/core/browser/logging/log_manager.h"
 #import "components/autofill/core/browser/logging/log_router.h"
 #import "components/keyed_service/core/service_access_type.h"
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.mm b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
index 39669a6..793611c 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.mm
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
@@ -4,6 +4,7 @@
 
 #import "ios/web_view/internal/signin/ios_web_view_signin_client.h"
 
+#import "base/notimplemented.h"
 #import "components/signin/ios/browser/wait_for_network_callback_helper_ios.h"
 #import "components/signin/public/identity_manager/primary_account_change_event.h"
 #import "components/version_info/channel.h"
diff --git a/ios_internal b/ios_internal
index ca30afb..60004bd 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit ca30afba1f3ceed05b486665b6cbaf3dfd7afd99
+Subproject commit 60004bd65ffb1bcc3552545311cc10870ea99e4c
diff --git a/ipc/ipc_channel_nacl.cc b/ipc/ipc_channel_nacl.cc
index b4af28e..e7b6bd6 100644
--- a/ipc/ipc_channel_nacl.cc
+++ b/ipc/ipc_channel_nacl.cc
@@ -16,6 +16,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_pump_for_io.h"
+#include "base/notimplemented.h"
 #include "base/synchronization/lock.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/simple_thread.h"
diff --git a/ipc/ipc_test_sink.cc b/ipc/ipc_test_sink.cc
index db3d111..05b15b48 100644
--- a/ipc/ipc_test_sink.cc
+++ b/ipc/ipc_test_sink.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_message.h"
diff --git a/media/audio/apple/audio_input.cc b/media/audio/apple/audio_input.cc
index 0c70667..80e507a 100644
--- a/media/audio/apple/audio_input.cc
+++ b/media/audio/apple/audio_input.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "media/base/audio_sample_types.h"
diff --git a/media/audio/clockless_audio_sink.cc b/media/audio/clockless_audio_sink.cc
index 564465e..a27aee9d 100644
--- a/media/audio/clockless_audio_sink.cc
+++ b/media/audio/clockless_audio_sink.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/media/audio/fuchsia/audio_input_stream_fuchsia.cc b/media/audio/fuchsia/audio_input_stream_fuchsia.cc
index d55e86b..9c2ea4d 100644
--- a/media/audio/fuchsia/audio_input_stream_fuchsia.cc
+++ b/media/audio/fuchsia/audio_input_stream_fuchsia.cc
@@ -16,6 +16,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/fuchsia/process_context.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "media/audio/audio_device_description.h"
 #include "media/audio/fuchsia/audio_manager_fuchsia.h"
 #include "media/base/audio_sample_types.h"
diff --git a/media/audio/ios/audio_manager_ios.cc b/media/audio/ios/audio_manager_ios.cc
index 81e58d8..2d94db9 100644
--- a/media/audio/ios/audio_manager_ios.cc
+++ b/media/audio/ios/audio_manager_ios.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/notimplemented.h"
 #include "media/audio/apple/audio_input.h"
 #include "media/audio/apple/audio_low_latency_input.h"
 #include "media/audio/apple/audio_manager_apple.h"
diff --git a/media/base/fake_audio_renderer_sink.cc b/media/base/fake_audio_renderer_sink.cc
index 6ec9f352..5df1aa4d 100644
--- a/media/base/fake_audio_renderer_sink.cc
+++ b/media/base/fake_audio_renderer_sink.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "media/base/audio_glitch_info.h"
 
diff --git a/media/base/stream_parser.cc b/media/base/stream_parser.cc
index c4874452..3a5a779 100644
--- a/media/base/stream_parser.cc
+++ b/media/base/stream_parser.cc
@@ -4,6 +4,7 @@
 
 #include "media/base/stream_parser.h"
 
+#include "base/notimplemented.h"
 #include "media/base/stream_parser_buffer.h"
 
 namespace media {
diff --git a/media/capture/video/create_video_capture_device_factory.cc b/media/capture/video/create_video_capture_device_factory.cc
index 74789fcf..e8f93600 100644
--- a/media/capture/video/create_video_capture_device_factory.cc
+++ b/media/capture/video/create_video_capture_device_factory.cc
@@ -5,6 +5,7 @@
 #include "media/capture/video/create_video_capture_device_factory.h"
 
 #include "base/command_line.h"
+#include "base/notimplemented.h"
 #include "base/system/sys_info.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/media/capture/video/linux/fake_v4l2_impl.cc b/media/capture/video/linux/fake_v4l2_impl.cc
index 75451de..68338df 100644
--- a/media/capture/video/linux/fake_v4l2_impl.cc
+++ b/media/capture/video/linux/fake_v4l2_impl.cc
@@ -24,6 +24,7 @@
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
diff --git a/media/capture/video/linux/v4l2_capture_delegate.cc b/media/capture/video/linux/v4l2_capture_delegate.cc
index 360b7cc..d8b8c5bb 100644
--- a/media/capture/video/linux/v4l2_capture_delegate.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate.cc
@@ -24,6 +24,7 @@
 #include "base/memory/raw_ptr_exclusion.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
diff --git a/media/capture/video/linux/video_capture_device_factory_v4l2.cc b/media/capture/video/linux/video_capture_device_factory_v4l2.cc
index 8b1e6d1f..ef6b134 100644
--- a/media/capture/video/linux/video_capture_device_factory_v4l2.cc
+++ b/media/capture/video/linux/video_capture_device_factory_v4l2.cc
@@ -20,6 +20,7 @@
 #include "base/containers/contains.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
+#include "base/notimplemented.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/media/capture/video/linux/video_capture_device_webrtc.cc b/media/capture/video/linux/video_capture_device_webrtc.cc
index 60fa3c68..46f7a3b 100644
--- a/media/capture/video/linux/video_capture_device_webrtc.cc
+++ b/media/capture/video/linux/video_capture_device_webrtc.cc
@@ -4,9 +4,9 @@
 
 #include "media/capture/video/linux/video_capture_device_webrtc.h"
 
+#include "base/notimplemented.h"
 #include "media/capture/mojom/image_capture_types.h"
 #include "media/capture/video/linux/video_capture_device_factory_webrtc.h"
-
 #include "third_party/webrtc/modules/video_capture/video_capture_factory.h"
 #include "third_party/webrtc/modules/video_capture/video_capture_impl.h"
 
diff --git a/media/cast/encoding/external_video_encoder.cc b/media/cast/encoding/external_video_encoder.cc
index 9a358d0..9d37ce5 100644
--- a/media/cast/encoding/external_video_encoder.cc
+++ b/media/cast/encoding/external_video_encoder.cc
@@ -25,6 +25,7 @@
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/bind_post_task.h"
diff --git a/media/cdm/win/media_foundation_cdm.cc b/media/cdm/win/media_foundation_cdm.cc
index b338174..dbc7738 100644
--- a/media/cdm/win/media_foundation_cdm.cc
+++ b/media/cdm/win/media_foundation_cdm.cc
@@ -18,6 +18,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/not_fatal_until.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/media/cdm/win/test/media_foundation_clear_key_cdm.cc b/media/cdm/win/test/media_foundation_clear_key_cdm.cc
index 4e3247f..238831d7 100644
--- a/media/cdm/win/test/media_foundation_clear_key_cdm.cc
+++ b/media/cdm/win/test/media_foundation_clear_key_cdm.cc
@@ -11,7 +11,7 @@
 #include <wrl/client.h>
 #include <wrl/implements.h>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "media/base/win/mf_feature_checks.h"
 #include "media/base/win/mf_helpers.h"
 #include "media/cdm/clear_key_cdm_common.h"
diff --git a/media/cdm/win/test/media_foundation_clear_key_input_trust_authority.cc b/media/cdm/win/test/media_foundation_clear_key_input_trust_authority.cc
index e1ab24a..e2def36b 100644
--- a/media/cdm/win/test/media_foundation_clear_key_input_trust_authority.cc
+++ b/media/cdm/win/test/media_foundation_clear_key_input_trust_authority.cc
@@ -17,7 +17,7 @@
 
 #include <memory>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "media/base/win/mf_helpers.h"
 #include "media/cdm/win/test/media_foundation_clear_key_activate.h"
 #include "media/cdm/win/test/media_foundation_clear_key_decryptor.h"
diff --git a/media/formats/dts/dts_util.cc b/media/formats/dts/dts_util.cc
index febf8f1..17fe17bf 100644
--- a/media/formats/dts/dts_util.cc
+++ b/media/formats/dts/dts_util.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/bit_reader.h"
 #include "media/formats/dts/dts_stream_parser.h"
diff --git a/media/fuchsia/video/fuchsia_video_encode_accelerator.cc b/media/fuchsia/video/fuchsia_video_encode_accelerator.cc
index c6823a7e..7fbda2d 100644
--- a/media/fuchsia/video/fuchsia_video_encode_accelerator.cc
+++ b/media/fuchsia/video/fuchsia_video_encode_accelerator.cc
@@ -35,6 +35,7 @@
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/sequence_checker.h"
 #include "base/strings/stringprintf.h"
diff --git a/media/gpu/android/ndk_video_encode_accelerator.cc b/media/gpu/android/ndk_video_encode_accelerator.cc
index 8fcb39c..57eb4ee4 100644
--- a/media/gpu/android/ndk_video_encode_accelerator.cc
+++ b/media/gpu/android/ndk_video_encode_accelerator.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
 #include "media/base/android/media_codec_util.h"
diff --git a/media/gpu/chromeos/image_processor_backend.cc b/media/gpu/chromeos/image_processor_backend.cc
index 79359cf8..44ce6af4 100644
--- a/media/gpu/chromeos/image_processor_backend.cc
+++ b/media/gpu/chromeos/image_processor_backend.cc
@@ -9,6 +9,7 @@
 #include <sstream>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/task_traits.h"
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
index 93c5b7a..546a682 100644
--- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -21,6 +21,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
diff --git a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
index 490d87e5..84bd9c4f 100644
--- a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
@@ -21,6 +21,7 @@
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc
index e7ef8e8..630e78fa 100644
--- a/media/gpu/v4l2/v4l2_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder.cc
@@ -20,6 +20,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/trace_event/trace_event.h"
diff --git a/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc b/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc
index 974b927..53e1e99 100644
--- a/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc
+++ b/media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc
@@ -18,6 +18,7 @@
 #include "base/bits.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "build/build_config.h"
 #include "media/base/media_switches.h"
diff --git a/media/gpu/vaapi/test/fake_libva_driver/fake_context.cc b/media/gpu/vaapi/test/fake_libva_driver/fake_context.cc
index b98f5011..e2939662 100644
--- a/media/gpu/vaapi/test/fake_libva_driver/fake_context.cc
+++ b/media/gpu/vaapi/test/fake_libva_driver/fake_context.cc
@@ -5,7 +5,7 @@
 #include "media/gpu/vaapi/test/fake_libva_driver/fake_context.h"
 
 #include "base/environment.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "media/gpu/vaapi/test/fake_libva_driver/av1_decoder_delegate.h"
 #include "media/gpu/vaapi/test/fake_libva_driver/fake_buffer.h"
 #include "media/gpu/vaapi/test/fake_libva_driver/fake_config.h"
diff --git a/media/gpu/vaapi/test/fake_libva_driver/fake_surface.cc b/media/gpu/vaapi/test/fake_libva_driver/fake_surface.cc
index 4843fe6c..1b80806e2 100644
--- a/media/gpu/vaapi/test/fake_libva_driver/fake_surface.cc
+++ b/media/gpu/vaapi/test/fake_libva_driver/fake_surface.cc
@@ -18,7 +18,7 @@
 #include "base/check_op.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 
 namespace media::internal {
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index cac6d20..00a3d834 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -41,6 +41,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/posix/eintr_wrapper.h"
diff --git a/media/gpu/vp8_decoder.cc b/media/gpu/vp8_decoder.cc
index 9136dea..2316ddc2 100644
--- a/media/gpu/vp8_decoder.cc
+++ b/media/gpu/vp8_decoder.cc
@@ -5,7 +5,7 @@
 #include "media/gpu/vp8_decoder.h"
 
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "media/base/limits.h"
 #include "ui/gfx/hdr_metadata.h"
 
diff --git a/media/mojo/clients/mojo_codec_factory.cc b/media/mojo/clients/mojo_codec_factory.cc
index 7a9e149..0938131 100644
--- a/media/mojo/clients/mojo_codec_factory.cc
+++ b/media/mojo/clients/mojo_codec_factory.cc
@@ -9,7 +9,7 @@
 
 #include "base/functional/callback_forward.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
 #include "media/base/decoder.h"
diff --git a/media/mojo/services/gpu_mojo_media_client.cc b/media/mojo/services/gpu_mojo_media_client.cc
index e4f95056..d3cfa688 100644
--- a/media/mojo/services/gpu_mojo_media_client.cc
+++ b/media/mojo/services/gpu_mojo_media_client.cc
@@ -11,6 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/media/remoting/receiver.cc b/media/remoting/receiver.cc
index 2469839..8e3ed2f 100644
--- a/media/remoting/receiver.cc
+++ b/media/remoting/receiver.cc
@@ -8,6 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index 1b31578..80a0db92 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -27,6 +27,7 @@
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/memory_dump_manager.h"
diff --git a/media/video/video_encode_accelerator.cc b/media/video/video_encode_accelerator.cc
index af1d5a2d..421c275 100644
--- a/media/video/video_encode_accelerator.cc
+++ b/media/video/video_encode_accelerator.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 38473b4..3e22ee5 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2154,6 +2154,8 @@
     "test/embedded_test_server/http1_connection.h",
     "test/embedded_test_server/http2_connection.cc",
     "test/embedded_test_server/http2_connection.h",
+    "test/embedded_test_server/http_connect_proxy_handler.cc",
+    "test/embedded_test_server/http_connect_proxy_handler.h",
     "test/embedded_test_server/http_connection.cc",
     "test/embedded_test_server/http_connection.h",
     "test/embedded_test_server/http_request.cc",
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 5683a5ca5..d8be8ad 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -47,6 +47,7 @@
 #include "net/test/cert_test_util.h"
 #include "net/test/embedded_test_server/default_handlers.h"
 #include "net/test/embedded_test_server/embedded_test_server_connection_listener.h"
+#include "net/test/embedded_test_server/http_connect_proxy_handler.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/embedded_test_server/request_handler_util.h"
@@ -715,6 +716,7 @@
   shutdown_closures_.Notify();
   listen_socket_.reset();
   connections_.clear();
+  http_connect_proxy_handler_.reset();
 }
 
 HttpConnection* EmbeddedTestServer::GetConnectionForSocket(
@@ -747,6 +749,17 @@
     }
   }
 
+  if (http_connect_proxy_handler_) {
+    bool request_handled =
+        http_connect_proxy_handler_->HandleProxyRequest(*connection, *request);
+    // If the proxy handler took over the request, it took ownership of the
+    // underlying socket, so only need to delete the socket.
+    if (request_handled) {
+      connections_.erase(socket);
+      return;
+    }
+  }
+
   for (const auto& upgrade_request_handler : upgrade_request_handlers_) {
     auto upgrade_response = upgrade_request_handler.Run(*request, connection);
     if (upgrade_response.has_value()) {
@@ -977,6 +990,16 @@
   auth_handler_ = callback;
 }
 
+void EmbeddedTestServer::EnableConnectProxy(
+    uint16_t dest_port,
+    std::optional<HostPortPair> expected_dest) {
+  CHECK(!StartedAcceptingConnection());
+  CHECK(!http_connect_proxy_handler_);
+
+  http_connect_proxy_handler_ = std::make_unique<HttpConnectProxyHandler>(
+      dest_port, std::move(expected_dest));
+}
+
 void EmbeddedTestServer::RegisterUpgradeRequestHandler(
     const HandleUpgradeRequestCallback& callback) {
   CHECK_NE(protocol_, HttpConnection::Protocol::kHttp2)
diff --git a/net/test/embedded_test_server/embedded_test_server.h b/net/test/embedded_test_server/embedded_test_server.h
index 0952f2c..f2e4577 100644
--- a/net/test/embedded_test_server/embedded_test_server.h
+++ b/net/test/embedded_test_server/embedded_test_server.h
@@ -49,6 +49,7 @@
 
 class EmbeddedTestServerConnectionListener;
 class HttpConnection;
+class HttpConnectProxyHandler;
 class HttpResponse;
 class HttpResponseDelegate;
 struct HttpRequest;
@@ -450,6 +451,11 @@
   // Checks if the server has started listening for incoming connections.
   bool Started() const { return listen_socket_.get() != nullptr; }
 
+  // Checks if the server has started running the message loop.
+  bool StartedAcceptingConnection() const {
+    return io_thread_.get() != nullptr;
+  }
+
   static base::FilePath GetRootCertPemPath();
 
   HostPortPair host_port_pair() const {
@@ -559,6 +565,17 @@
   //    handling.
   void RegisterAuthHandler(const HandleRequestCallback& callback);
 
+  // Makes the server act as an HTTP/HTTPS CONNECT proxy. Must be invoked before
+  // the server is fully started. Only supports HTTP/1.x. All CONNECT requests
+  // go to `dest_port` on localhost, regardless of what destination is actually
+  // provided. `expected_dest`, if provided, is the expected destination of all
+  // requests. CONNECT requests to other destinations will then result in test
+  // failures.
+  //
+  // Must be called before the EmbeddedTestServer starts accepting connections.
+  void EnableConnectProxy(uint16_t dest_port,
+                          std::optional<HostPortPair> expected_dest);
+
   // Adds a handler callback to process WebSocket upgrade requests.
   // |callback| will be invoked on the server's IO thread when a request
   // attempts to upgrade to a WebSocket connection. Note that:
@@ -703,6 +720,11 @@
   // immediately without reaching other handlers.
   HandleRequestCallback auth_handler_;
 
+  // Optional handle to make the test server work as an HTTP/1 proxy. Created on
+  // main thread, but destroyed on `io_thread_`, as it may own sockets for
+  // tunnels.
+  std::unique_ptr<HttpConnectProxyHandler> http_connect_proxy_handler_;
+
   // Vector of registered and default request handlers and monitors.
   std::vector<HandleUpgradeRequestCallback> upgrade_request_handlers_;
   std::vector<HandleRequestCallback> request_handlers_;
diff --git a/net/test/embedded_test_server/embedded_test_server_unittest.cc b/net/test/embedded_test_server/embedded_test_server_unittest.cc
index 68bd0f5..6e5c7d3 100644
--- a/net/test/embedded_test_server/embedded_test_server_unittest.cc
+++ b/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -25,11 +25,16 @@
 #include "base/types/expected.h"
 #include "build/build_config.h"
 #include "net/base/elements_upload_data_stream.h"
+#include "net/base/proxy_chain.h"
+#include "net/base/proxy_server.h"
 #include "net/base/test_completion_callback.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/log/net_log_source.h"
+#include "net/proxy_resolution/configured_proxy_resolution_service.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_config_service_fixed.h"
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/stream_socket.h"
 #include "net/test/embedded_test_server/embedded_test_server_connection_listener.h"
@@ -121,13 +126,27 @@
 struct EmbeddedTestServerConfig {
   EmbeddedTestServer::Type type;
   HttpConnection::Protocol protocol;
+  std::optional<EmbeddedTestServer::Type> proxy_type;
 };
 
 std::vector<EmbeddedTestServerConfig> EmbeddedTestServerConfigs() {
   return {
-      {EmbeddedTestServer::TYPE_HTTP, HttpConnection::Protocol::kHttp1},
-      {EmbeddedTestServer::TYPE_HTTPS, HttpConnection::Protocol::kHttp1},
-      {EmbeddedTestServer::TYPE_HTTPS, HttpConnection::Protocol::kHttp2},
+      {EmbeddedTestServer::TYPE_HTTP, HttpConnection::Protocol::kHttp1,
+       /*proxy_type=*/std::nullopt},
+      {EmbeddedTestServer::TYPE_HTTPS, HttpConnection::Protocol::kHttp1,
+       /*proxy_type=*/std::nullopt},
+      {EmbeddedTestServer::TYPE_HTTPS, HttpConnection::Protocol::kHttp2,
+       /*proxy_type=*/std::nullopt},
+
+      // Proxy is HTTP/1.x CONNECT only, so can't be used with HTTP and proxy
+      // itself can't use HTTP/2. Testing all combinations of proxy server and
+      // destination server protocol seems not useful, so test HTTP/1.x server
+      // with HTTP proxy, and HTTP/2 server with HTTPS proxy, but each
+      // non-HTTP destination server type should work with the other proxy type.
+      {EmbeddedTestServer::TYPE_HTTPS, HttpConnection::Protocol::kHttp1,
+       /*proxy_type=*/EmbeddedTestServer::TYPE_HTTP},
+      {EmbeddedTestServer::TYPE_HTTPS, HttpConnection::Protocol::kHttp2,
+       /*proxy_type=*/EmbeddedTestServer::TYPE_HTTPS},
   };
 }
 
@@ -135,19 +154,67 @@
     : public testing::TestWithParam<EmbeddedTestServerConfig>,
       public WithTaskEnvironment {
  public:
-  EmbeddedTestServerTest()
-      : context_(CreateTestURLRequestContextBuilder()->Build()) {}
-
-  void SetUp() override {
+  EmbeddedTestServerTest() {
     server_ = std::make_unique<EmbeddedTestServer>(GetParam().type,
                                                    GetParam().protocol);
     server_->AddDefaultHandlers();
     server_->SetConnectionListener(&connection_listener_);
   }
 
-  void TearDown() override {
-    if (server_->Started())
-      ASSERT_TRUE(server_->ShutdownAndWaitUntilComplete());
+  ~EmbeddedTestServerTest() override {
+    if (server_->Started()) {
+      EXPECT_TRUE(server_->ShutdownAndWaitUntilComplete());
+    }
+    if (proxy_server_ && proxy_server_->Started()) {
+      EXPECT_TRUE(proxy_server_->ShutdownAndWaitUntilComplete());
+    }
+  }
+
+  // Helper to start `server_`, `proxy_server_` (if needed), and populate
+  // `context_`. This is need because the proxy server needs the server to be
+  // started, but starting the server (or even just creating the listen socket)
+  // prevents modifying the server in certain ways, so some individual tests
+  // have to configure the server before any of this can happen.
+  //
+  // `disable_proxy_destination_restrictions` remove the destination
+  // restrictions on the connect proxy, which normally restrict connections to
+  // be only to `server_->host_port_pair()`.
+  testing::AssertionResult StartServerAndSetUpContext(
+      bool disable_proxy_destination_restrictions = false) {
+    if (!server_->Start()) {
+      return testing::AssertionFailure() << "Failed to start server.";
+    }
+
+    auto builder = CreateTestURLRequestContextBuilder();
+    if (GetParam().proxy_type) {
+      proxy_server_ =
+          std::make_unique<EmbeddedTestServer>(*GetParam().proxy_type);
+      proxy_server_->EnableConnectProxy(
+          server_->port(),
+          disable_proxy_destination_restrictions
+              ? std::nullopt
+              : std::optional(/*expected_dest=*/server_->host_port_pair()));
+      if (!proxy_server_->Start()) {
+        return testing::AssertionFailure() << "Failed to start proxy.";
+      }
+
+      // Set up the URLRequestContext to use the proxy server.
+      ProxyConfig proxy_config;
+      proxy_config.proxy_rules().ParseFromString(
+          proxy_server_->GetOrigin().Serialize());
+      // Need this to avoid default bypass rules to not use proxy for localhost.
+      proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
+      ProxyConfigWithAnnotation annotated_config(proxy_config,
+                                                 TRAFFIC_ANNOTATION_FOR_TESTS);
+      builder->set_proxy_resolution_service(
+          ConfiguredProxyResolutionService::CreateWithoutProxyResolver(
+              std::make_unique<ProxyConfigServiceFixed>(
+                  std::move(annotated_config)),
+              /*net_log=*/nullptr));
+    }
+
+    context_ = builder->Build();
+    return testing::AssertionSuccess();
   }
 
   // Handles |request| sent to |path| and returns the response per |content|,
@@ -171,17 +238,30 @@
     return nullptr;
   }
 
+  // The ProxyChain requests are expected to use.
+  ProxyChain ExpectedProxyChain() const {
+    if (GetParam().proxy_type) {
+      return ProxyChain(GetParam().proxy_type == EmbeddedTestServer::TYPE_HTTP
+                            ? ProxyServer::SCHEME_HTTP
+                            : ProxyServer::SCHEME_HTTPS,
+                        proxy_server_->host_port_pair());
+    } else {
+      return ProxyChain::Direct();
+    }
+  }
+
  protected:
   std::string request_relative_url_;
   GURL request_absolute_url_;
   std::unique_ptr<URLRequestContext> context_;
   TestConnectionListener connection_listener_;
   std::unique_ptr<EmbeddedTestServer> server_;
+  std::unique_ptr<EmbeddedTestServer> proxy_server_;
   base::OnceClosure quit_run_loop_;
 };
 
 TEST_P(EmbeddedTestServerTest, GetBaseURL) {
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
   if (GetParam().type == EmbeddedTestServer::TYPE_HTTPS) {
     EXPECT_EQ(base::StringPrintf("https://127.0.0.1:%u/", server_->port()),
               server_->base_url().spec());
@@ -192,7 +272,7 @@
 }
 
 TEST_P(EmbeddedTestServerTest, GetURL) {
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
   if (GetParam().type == EmbeddedTestServer::TYPE_HTTPS) {
     EXPECT_EQ(base::StringPrintf("https://127.0.0.1:%u/path?query=foo",
                                  server_->port()),
@@ -205,7 +285,7 @@
 }
 
 TEST_P(EmbeddedTestServerTest, GetURLWithHostname) {
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
   if (GetParam().type == EmbeddedTestServer::TYPE_HTTPS) {
     EXPECT_EQ(base::StringPrintf("https://foo.com:%d/path?query=foo",
                                  server_->port()),
@@ -221,7 +301,7 @@
   server_->RegisterRequestHandler(base::BindRepeating(
       &EmbeddedTestServerTest::HandleRequest, base::Unretained(this), "/test",
       "<b>Worked!</b>", "text/html", HTTP_OK));
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(
@@ -237,6 +317,7 @@
   EXPECT_EQ("<b>Worked!</b>", delegate.data_received());
   EXPECT_EQ(request->response_headers()->GetNormalizedHeader("Content-Type"),
             "text/html");
+  EXPECT_EQ(request->proxy_chain(), ExpectedProxyChain());
 
   EXPECT_EQ("/test?q=foo", request_relative_url_);
   EXPECT_EQ(server_->GetURL("/test?q=foo"), request_absolute_url_);
@@ -247,7 +328,7 @@
   ASSERT_TRUE(base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &src_dir));
   server_->ServeFilesFromDirectory(
       src_dir.AppendASCII("net").AppendASCII("data"));
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(
@@ -263,6 +344,7 @@
   EXPECT_EQ("<p>Hello World!</p>", delegate.data_received());
   EXPECT_EQ(request->response_headers()->GetNormalizedHeader("Content-Type"),
             "text/html");
+  EXPECT_EQ(request->proxy_chain(), ExpectedProxyChain());
 }
 
 TEST_P(EmbeddedTestServerTest, MockHeadersWithoutCRLF) {
@@ -275,7 +357,7 @@
   server_->ServeFilesFromDirectory(
       src_dir.AppendASCII("net").AppendASCII("data").AppendASCII(
           "embedded_test_server"));
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(context_->CreateRequest(
@@ -291,10 +373,11 @@
   EXPECT_EQ("<p>Hello World!</p>", delegate.data_received());
   EXPECT_EQ(request->response_headers()->GetNormalizedHeader("Content-Type"),
             "text/html");
+  EXPECT_EQ(request->proxy_chain(), ExpectedProxyChain());
 }
 
 TEST_P(EmbeddedTestServerTest, DefaultNotFoundResponse) {
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(context_->CreateRequest(
@@ -307,10 +390,11 @@
   EXPECT_EQ(net::OK, delegate.request_status());
   ASSERT_TRUE(request->response_headers());
   EXPECT_EQ(HTTP_NOT_FOUND, request->response_headers()->response_code());
+  EXPECT_EQ(request->proxy_chain(), ExpectedProxyChain());
 }
 
 TEST_P(EmbeddedTestServerTest, ConnectionListenerAccept) {
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   net::AddressList address_list;
   EXPECT_TRUE(server_->GetAddressList(&address_list));
@@ -329,7 +413,7 @@
 }
 
 TEST_P(EmbeddedTestServerTest, ConnectionListenerRead) {
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(context_->CreateRequest(
@@ -345,8 +429,9 @@
 
 TEST_P(EmbeddedTestServerTest,
        UpgradeRequestHandlerEvalContinuesOnKNotHandled) {
-  if (GetParam().protocol == HttpConnection::Protocol::kHttp2) {
-    GTEST_SKIP() << "This test is not supported on HTTP/2";
+  if (GetParam().protocol == HttpConnection::Protocol::kHttp2 ||
+      GetParam().proxy_type) {
+    GTEST_SKIP() << "This test is not supported on HTTP/2 or with proxies";
   }
 
   const std::string websocket_upgrade_path = "/websocket_upgrade_path";
@@ -374,6 +459,10 @@
   auto server_handle = server_->StartAndReturnHandle();
   ASSERT_TRUE(server_handle);
 
+  // Have to manually create the context, since proxy setup code isn't
+  // compatible with EmbeddedTestServer::StartAndReturnHandle()
+  context_ = CreateTestURLRequestContextBuilder()->Build();
+
   GURL a_different_url = server_->GetURL("/a_different_path");
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(
@@ -387,9 +476,35 @@
   EXPECT_TRUE(second_handler_called.IsSet());
 }
 
+// Tests the case of a connection failure after the destination server has been
+// shut down. Primarily intended to test the CONNECT proxy case.
+TEST_P(EmbeddedTestServerTest, ConnectionFailure) {
+  ASSERT_TRUE(StartServerAndSetUpContext());
+
+  TestDelegate delegate;
+  std::unique_ptr<URLRequest> request(
+      context_->CreateRequest(server_->GetURL("/"), DEFAULT_PRIORITY, &delegate,
+                              TRAFFIC_ANNOTATION_FOR_TESTS));
+
+  // A recently closed socket should be blocked from reuse for some time, so the
+  // closed socket should not be reopened by some other app in the small windows
+  // before this test tries to connect to it.
+  EXPECT_TRUE(server_->ShutdownAndWaitUntilComplete());
+
+  request->Start();
+  delegate.RunUntilComplete();
+
+  if (GetParam().proxy_type) {
+    EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, delegate.request_status());
+  } else {
+    EXPECT_EQ(ERR_CONNECTION_REFUSED, delegate.request_status());
+  }
+}
+
 TEST_P(EmbeddedTestServerTest, UpgradeRequestHandlerTransfersSocket) {
-  if (GetParam().protocol == HttpConnection::Protocol::kHttp2) {
-    GTEST_SKIP() << "This test is not supported on HTTP/2";
+  if (GetParam().protocol == HttpConnection::Protocol::kHttp2 ||
+      GetParam().proxy_type) {
+    GTEST_SKIP() << "This test is not supported on HTTP/2 or with proxies";
   }
 
   const std::string websocket_upgrade_path = "/websocket_upgrade_path";
@@ -410,6 +525,10 @@
   auto server_handle = server_->StartAndReturnHandle();
   ASSERT_TRUE(server_handle);
 
+  // Have to manually create the context, since proxy setup code isn't
+  // compatible with EmbeddedTestServer::StartAndReturnHandle()
+  context_ = CreateTestURLRequestContextBuilder()->Build();
+
   GURL websocket_upgrade_url = server_->GetURL(websocket_upgrade_path);
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(
@@ -422,8 +541,9 @@
 }
 
 TEST_P(EmbeddedTestServerTest, UpgradeRequestHandlerEvalStopsOnErrorResponse) {
-  if (GetParam().protocol == HttpConnection::Protocol::kHttp2) {
-    GTEST_SKIP() << "This test is not supported on HTTP/2";
+  if (GetParam().protocol == HttpConnection::Protocol::kHttp2 ||
+      GetParam().proxy_type) {
+    GTEST_SKIP() << "This test is not supported on HTTP/2 or with proxies";
   }
 
   const std::string websocket_upgrade_path = "/websocket_upgrade_path";
@@ -454,6 +574,10 @@
   auto server_handle = server_->StartAndReturnHandle();
   ASSERT_TRUE(server_handle);
 
+  // Have to manually create the context, since proxy setup code isn't
+  // compatible with EmbeddedTestServer::StartAndReturnHandle()
+  context_ = CreateTestURLRequestContextBuilder()->Build();
+
   GURL websocket_upgrade_url = server_->GetURL(websocket_upgrade_path);
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request(
@@ -484,7 +608,7 @@
   if (GetParam().protocol == HttpConnection::Protocol::kHttp2)
     return;
 
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate;
   // Need to send a Keep-Alive response header since the EmbeddedTestServer only
@@ -516,7 +640,7 @@
   server_->RegisterRequestHandler(base::BindRepeating(
       &EmbeddedTestServerTest::HandleRequest, base::Unretained(this), "/test3",
       "No chocolates", "text/plain", HTTP_NOT_FOUND));
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate1;
   std::unique_ptr<URLRequest> request1(
@@ -642,7 +766,7 @@
   server_->RegisterRequestHandler(
       base::BindRepeating(&HandlePrefixedRequest, "/infinite",
                           base::BindRepeating(&HandleInfiniteRequest)));
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   std::unique_ptr<URLRequest> request =
       context_->CreateRequest(server_->GetURL("/infinite"), DEFAULT_PRIORITY,
@@ -692,7 +816,7 @@
   server_->SetAlpsAcceptCH("", "foo");
   server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
 
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   TestDelegate delegate;
   std::unique_ptr<URLRequest> request_a(context_->CreateRequest(
@@ -715,7 +839,8 @@
   server_->SetAlpsAcceptCH("c.b.test", "c");
   server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
 
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext(
+      /*disable_proxy_destination_restrictions=*/true));
 
   {
     TestDelegate delegate;
@@ -766,7 +891,7 @@
       }));
 
   server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
-  ASSERT_TRUE(server_->Start());
+  ASSERT_TRUE(StartServerAndSetUpContext());
 
   auto reader = std::make_unique<UploadBytesElementReader>(
       base::as_byte_span(large_post_body));
diff --git a/net/test/embedded_test_server/http1_connection.cc b/net/test/embedded_test_server/http1_connection.cc
index 2355c7f..d7361f19 100644
--- a/net/test/embedded_test_server/http1_connection.cc
+++ b/net/test/embedded_test_server/http1_connection.cc
@@ -25,7 +25,8 @@
     std::unique_ptr<StreamSocket> socket,
     EmbeddedTestServerConnectionListener* connection_listener,
     EmbeddedTestServer* server_delegate)
-    : socket_(std::move(socket)),
+    : HttpConnection(Protocol::kHttp1),
+      socket_(std::move(socket)),
       connection_listener_(connection_listener),
       server_delegate_(server_delegate),
       read_buf_(base::MakeRefCounted<IOBufferWithSize>(4096)) {}
diff --git a/net/test/embedded_test_server/http2_connection.cc b/net/test/embedded_test_server/http2_connection.cc
index 60824471..eba9897 100644
--- a/net/test/embedded_test_server/http2_connection.cc
+++ b/net/test/embedded_test_server/http2_connection.cc
@@ -191,7 +191,8 @@
     std::unique_ptr<StreamSocket> socket,
     EmbeddedTestServerConnectionListener* connection_listener,
     EmbeddedTestServer* embedded_test_server)
-    : socket_(std::move(socket)),
+    : HttpConnection(Protocol::kHttp2),
+      socket_(std::move(socket)),
       connection_listener_(connection_listener),
       embedded_test_server_(embedded_test_server),
       read_buf_(base::MakeRefCounted<IOBufferWithSize>(4096)) {
diff --git a/net/test/embedded_test_server/http_connect_proxy_handler.cc b/net/test/embedded_test_server/http_connect_proxy_handler.cc
new file mode 100644
index 0000000..1568c44
--- /dev/null
+++ b/net/test/embedded_test_server/http_connect_proxy_handler.cc
@@ -0,0 +1,269 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/test/embedded_test_server/http_connect_proxy_handler.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+#include <set>
+
+#include "base/check_op.h"
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/functional/bind.h"
+#include "base/location.h"
+#include "base/memory/raw_ptr.h"
+#include "base/strings/strcat.h"
+#include "base/task/sequenced_task_runner.h"
+#include "net/base/address_list.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_status_code.h"
+#include "net/log/net_log_source.h"
+#include "net/socket/stream_socket.h"
+#include "net/socket/tcp_client_socket.h"
+#include "net/test/embedded_test_server/http_connection.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/origin.h"
+
+namespace net::test_server {
+
+class HttpConnectProxyHandler::ConnectTunnel {
+ public:
+  static constexpr size_t kCapacity = 32 * 1024;
+  using DeleteCallback = base::OnceCallback<void(ConnectTunnel*)>;
+
+  ConnectTunnel(HttpConnectProxyHandler* http_proxy_handler,
+                std::unique_ptr<StreamSocket> socket)
+      : http_proxy_handler_(http_proxy_handler), socket_(std::move(socket)) {}
+
+  ~ConnectTunnel() = default;
+
+  // Tries to establish a connection to localhost on `dest_port`, and on
+  // success, tells the client socket a tunnel was successfully established, and
+  // starts tunnelling data between the connections.
+  void Start(uint16_t dest_port) {
+    dest_socket_ = std::make_unique<TCPClientSocket>(
+        AddressList::CreateFromIPAddress(IPAddress::IPv4Localhost(), dest_port),
+        /*socket_performance_watcher=*/nullptr,
+        /*network_quality_estimator=*/nullptr, /*net_log=*/nullptr,
+        NetLogSource());
+
+    int result = dest_socket_->Connect(base::BindOnce(
+        &ConnectTunnel::OnConnectComplete, base::Unretained(this)));
+    if (result != ERR_IO_PENDING) {
+      OnConnectComplete(result);
+    }
+  }
+
+ private:
+  void OnConnectComplete(int result) {
+    // If unable to connect, write a bad gateway error to `socket_` before
+    // deleting `this`.
+    if (result != OK) {
+      DVLOG(1) << "Failed to establish tunnel connection.";
+
+      BasicHttpResponse response;
+      response.set_code(HttpStatusCode::HTTP_BAD_GATEWAY);
+      response.set_reason("Bad Gateway");
+      std::string response_string = response.ToResponseString();
+
+      scoped_refptr<GrowableIOBuffer> buffer =
+          base::MakeRefCounted<GrowableIOBuffer>();
+      buffer->SetCapacity(response_string.size());
+      buffer->span().copy_prefix_from(base::as_byte_span(response_string));
+      DoWrite(/*src=*/nullptr, /*dest=*/socket_.get(), std::move(buffer),
+              response_string.size());
+      return;
+    }
+
+    // Write HTTP headers to client socket to indicate the connect succeeded,
+    // and then start tunnelling.
+    BasicHttpResponse response;
+    response.set_reason("Connection established");
+    StartTunneling(/*src=*/dest_socket_.get(), /*dest=*/socket_.get(),
+                   response.ToResponseString());
+    // Start tunneling from client socket to destination immediately, no need to
+    // write anything else.
+    StartTunneling(/*src=*/socket_.get(), /*dest=*/dest_socket_.get());
+  }
+
+  // Starts reading from `src` and writing that data to `dest`. If
+  // `initial_data` is provided, writes that `dest` before writing to `src`.
+  // Since a CONNECT proxy passes data in both directions, this needs to be
+  // called twice, flipping `src` and `dest` between calls, to fully set up the
+  // tunnelling.
+  void StartTunneling(StreamSocket* src,
+                      StreamSocket* dest,
+                      std::string initial_data = {}) {
+    scoped_refptr<GrowableIOBuffer> buffer =
+        base::MakeRefCounted<GrowableIOBuffer>();
+    buffer->SetCapacity(std::max(kCapacity, initial_data.size()));
+    if (!initial_data.empty()) {
+      // Start with a write, if `initial_data` is provided.
+      buffer->span().copy_prefix_from(base::as_byte_span(initial_data));
+      DoWrite(src, dest, std::move(buffer), initial_data.size());
+      return;
+    }
+
+    DoRead(src, dest, std::move(buffer));
+  }
+
+  // Try to read data from `src`. Once data is read, write it all to `dest`, and
+  // then repeat the process, until an error is encountered. Uses
+  // GrowableIOBuffer because it can track an offset that indicates how much
+  // data has been written. DrainableIOBuffer can do the same, but requires a
+  // nested IOBuffer, so is a little more complicated to us.
+  void DoRead(StreamSocket* src,
+              StreamSocket* dest,
+              scoped_refptr<GrowableIOBuffer> buffer) {
+    int result =
+        src->Read(buffer.get(), buffer->size(),
+                  base::BindOnce(&ConnectTunnel::OnReadComplete,
+                                 base::Unretained(this), src, dest, buffer));
+    if (result == ERR_IO_PENDING) {
+      return;
+    }
+    OnReadComplete(src, dest, std::move(buffer), result);
+  }
+
+  // Called when a read from `src` completes. On error, tears down the socket.
+  // Otherwise, starts writing the data to `dest`, and will start reading from
+  // `src` again, once all data is written.
+  void OnReadComplete(StreamSocket* src,
+                      StreamSocket* dest,
+                      scoped_refptr<GrowableIOBuffer> buffer,
+                      int result) {
+    CHECK_NE(result, ERR_IO_PENDING);
+
+    if (result <= 0) {
+      // On error / close, close both sockets - this behavior is good enough,
+      // since the client side (Chrome's network stack) only closes the write
+      // pipe when it's done reading, and since this code doesn't read from the
+      // destination pipe (likely to another EmbeddedTestServer) while there's
+      // data in the buffer to write to the client pipe, all data will be
+      // written before the EmbeddedTestServer closing the pipe will be
+      // observed.
+      http_proxy_handler_->DeleteTunnel(this);
+      return;
+    }
+
+    DoWrite(src, dest, std::move(buffer), result);
+  }
+
+  // Writes `remaining_bytes` from `buffer` to `dest`. Once all data has been
+  // written, will start reading from `src` again. If `src` is nullptr, writes
+  // data to `dest`, and destroys the `ConnectTunnel` once everything has been
+  // written.
+  void DoWrite(StreamSocket* src,
+               StreamSocket* dest,
+               scoped_refptr<GrowableIOBuffer> buffer,
+               int remaining_bytes) {
+    CHECK_GE(remaining_bytes, 0);
+    int result = dest->Write(
+        buffer.get(), remaining_bytes,
+        base::BindOnce(&ConnectTunnel::OnWriteComplete, base::Unretained(this),
+                       src, dest, buffer, remaining_bytes),
+        TRAFFIC_ANNOTATION_FOR_TESTS);
+    if (result == ERR_IO_PENDING) {
+      return;
+    }
+    OnWriteComplete(src, dest, std::move(buffer), remaining_bytes, result);
+  }
+
+  // Called once data has been written to `dest` or there was a write error. On
+  // error, tears down `this`. Otherwise, keeps writing until all data has been
+  // written, and then starts reading from `src` again.
+  void OnWriteComplete(StreamSocket* src,
+                       StreamSocket* dest,
+                       scoped_refptr<GrowableIOBuffer> buffer,
+                       int remaining_bytes,
+                       int result) {
+    CHECK_NE(result, ERR_IO_PENDING);
+
+    if (result < 0) {
+      // See OnReadComplete() for explanation on why this is ok to do.
+      http_proxy_handler_->DeleteTunnel(this);
+      return;
+    }
+
+    CHECK_LE(result, remaining_bytes);
+    buffer->DidConsume(result);
+    remaining_bytes -= result;
+    if (remaining_bytes > 0) {
+      DoWrite(src, dest, std::move(buffer), remaining_bytes);
+      return;
+    }
+
+    // `src` will be nullptr when writing a connect error. In that case, once
+    // everything has been written, delete `this` to close `socket_`.
+    if (!src) {
+      http_proxy_handler_->DeleteTunnel(this);
+      return;
+    }
+
+    buffer->set_offset(0);
+    DoRead(src, dest, std::move(buffer));
+  }
+
+  raw_ptr<HttpConnectProxyHandler> http_proxy_handler_;
+
+  // The socket to the client (Chrome's network stack).
+  std::unique_ptr<StreamSocket> socket_;
+
+  // The socket to the server (typically another EmbeddedTestServer instance).
+  std::unique_ptr<TCPClientSocket> dest_socket_;
+};
+
+HttpConnectProxyHandler::HttpConnectProxyHandler(
+    const uint16_t dest_port,
+    std::optional<HostPortPair> expected_dest)
+    : dest_port_(dest_port), expected_dest_(expected_dest) {}
+
+HttpConnectProxyHandler::~HttpConnectProxyHandler() = default;
+
+bool HttpConnectProxyHandler::HandleProxyRequest(HttpConnection& connection,
+                                                 const HttpRequest& request) {
+  // This class only support HTTP/1.x.
+  CHECK_EQ(connection.protocol(), HttpConnection::Protocol::kHttp1);
+
+  if (request.method != METHOD_CONNECT) {
+    return false;
+  }
+
+  // For CONNECT requests, `relative_url` is actually a host and port.
+  HostPortPair dest = HostPortPair::FromString(request.relative_url);
+  std::unique_ptr<BasicHttpResponse> error_response;
+
+  if (dest.IsEmpty()) {
+    ADD_FAILURE() << "Invalid CONNECT destination: " << request.relative_url;
+    // Returning true on error will result in the socket being closed.
+    return true;
+  }
+  if (expected_dest_ && *expected_dest_ != dest) {
+    ADD_FAILURE() << "Unexpected CONNECT destination: " << dest.ToString();
+    // Returning true on error will result in the socket being closed.
+    return true;
+  }
+
+  auto tunnel = std::make_unique<ConnectTunnel>(this, connection.TakeSocket());
+  auto tunnel_it = connect_tunnels_.insert(std::move(tunnel)).first;
+  (*tunnel_it)->Start(dest_port_);
+
+  return true;
+}
+
+void HttpConnectProxyHandler::DeleteTunnel(ConnectTunnel* tunnel) {
+  auto tunnel_it = connect_tunnels_.find(tunnel);
+  CHECK(tunnel_it != connect_tunnels_.end());
+  connect_tunnels_.erase(tunnel_it);
+}
+
+}  // namespace net::test_server
diff --git a/net/test/embedded_test_server/http_connect_proxy_handler.h b/net/test/embedded_test_server/http_connect_proxy_handler.h
new file mode 100644
index 0000000..536f0c4
--- /dev/null
+++ b/net/test/embedded_test_server/http_connect_proxy_handler.h
@@ -0,0 +1,59 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TEST_EMBEDDED_TEST_SERVER_HTTP_CONNECT_PROXY_HANDLER_H_
+#define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_CONNECT_PROXY_HANDLER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+#include <set>
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "net/base/host_port_pair.h"
+
+namespace net::test_server {
+
+class HttpConnection;
+struct HttpRequest;
+
+// Helper for use by the EmbeddedTestServer to act as an HTTP proxy. Only
+// supports HTTP/1.x CONNECT requests.
+class HttpConnectProxyHandler {
+ public:
+  // Regardless of the requested destination, all requests are proxied to
+  // `dest_port` on 127.0.0.1. If provided, connections to destinations other
+  // than `expected_dest` result in test expectation failures.
+  HttpConnectProxyHandler(uint16_t dest_port,
+                          std::optional<HostPortPair> expected_dest);
+  ~HttpConnectProxyHandler();
+
+  // If `request` is not a CONNECT request, returns false. Otherwise, takes
+  // ownership of the socket owned by `connection`, validates the destination,
+  // connects to the real destination location, writes an HTTP success message
+  // to the original socket, and starts tunnelling data between the two sockets.
+  //
+  // Logs on connection failures, but does not fail the test.
+  //
+  // Only supports CONNECT requests.  Non-CONNECT requests can be simulated
+  // without a proxy, if needed.
+  bool HandleProxyRequest(HttpConnection& connection,
+                          const HttpRequest& request);
+
+ private:
+  class ConnectTunnel;
+
+  void DeleteTunnel(ConnectTunnel* tunnel);
+
+  const uint16_t dest_port_;
+  const std::optional<HostPortPair> expected_dest_;
+
+  std::set<std::unique_ptr<ConnectTunnel>, base::UniquePtrComparator>
+      connect_tunnels_;
+};
+
+}  // namespace net::test_server
+
+#endif  // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_CONNECT_PROXY_HANDLER_H_
diff --git a/net/test/embedded_test_server/http_connection.cc b/net/test/embedded_test_server/http_connection.cc
index 07c31cd5..09f2337 100644
--- a/net/test/embedded_test_server/http_connection.cc
+++ b/net/test/embedded_test_server/http_connection.cc
@@ -10,6 +10,8 @@
 
 namespace net::test_server {
 
+HttpConnection::HttpConnection(Protocol protocol) : protocol_(protocol) {}
+
 std::unique_ptr<HttpConnection> HttpConnection::Create(
     std::unique_ptr<StreamSocket> socket,
     EmbeddedTestServerConnectionListener* listener,
diff --git a/net/test/embedded_test_server/http_connection.h b/net/test/embedded_test_server/http_connection.h
index c324330..de4fbc9 100644
--- a/net/test/embedded_test_server/http_connection.h
+++ b/net/test/embedded_test_server/http_connection.h
@@ -28,7 +28,7 @@
  public:
   enum class Protocol { kHttp1, kHttp2 };
 
-  HttpConnection() = default;
+  explicit HttpConnection(Protocol protocol);
   virtual ~HttpConnection() = default;
   HttpConnection(HttpConnection&) = delete;
   virtual HttpConnection& operator=(HttpConnection&) = delete;
@@ -40,6 +40,8 @@
       EmbeddedTestServer* server,
       Protocol protocol);
 
+  Protocol protocol() const { return protocol_; }
+
   // Notify that the socket is ready to receive data (which may not be
   // immediately, due to SSL handshake). May call the delegate's HandleRequest()
   // or CloseConnection() methods, and may call them asynchronously.
@@ -50,6 +52,9 @@
 
   virtual StreamSocket* Socket() = 0;
   virtual base::WeakPtr<HttpConnection> GetWeakPtr() = 0;
+
+ private:
+  Protocol protocol_;
 };
 
 }  // namespace test_server
diff --git a/net/test/embedded_test_server/register_basic_auth_handler.cc b/net/test/embedded_test_server/register_basic_auth_handler.cc
index 523a73e..00bd70b 100644
--- a/net/test/embedded_test_server/register_basic_auth_handler.cc
+++ b/net/test/embedded_test_server/register_basic_auth_handler.cc
@@ -4,6 +4,8 @@
 
 #include "net/test/embedded_test_server/register_basic_auth_handler.h"
 
+#include <ios>
+
 #include "base/base64.h"
 #include "base/logging.h"
 #include "base/strings/strcat.h"
@@ -17,12 +19,26 @@
 
 namespace {
 
+// Constructs an expected authorization header value (e.g., "Basic
+// dXNlcm5hbWU6cGFzc3dvcmQ="). Works with both "WWW-Authenticate" and
+// "Proxy-Authenticate" request lines.
+std::string CreateExpectedBasicAuthHeader(std::string_view username,
+                                          std::string_view password) {
+  const std::string credentials = base::StrCat({username, ":", password});
+  const std::string encoded_credentials = base::Base64Encode(credentials);
+  return base::StrCat({"Basic ", encoded_credentials});
+}
+
 // Creates a 401 Unauthorized error response with the required WWW-Authenticate
 // header.
-std::unique_ptr<HttpResponse> CreateUnauthorizedResponse() {
+std::unique_ptr<HttpResponse> CreateUnauthorizedResponse(bool is_proxy_auth) {
   auto response = std::make_unique<BasicHttpResponse>();
-  response->set_code(HttpStatusCode::HTTP_UNAUTHORIZED);
-  response->AddCustomHeader("WWW-Authenticate", "Basic realm=\"TestServer\"");
+  response->set_code(is_proxy_auth
+                         ? HttpStatusCode::HTTP_PROXY_AUTHENTICATION_REQUIRED
+                         : HttpStatusCode::HTTP_UNAUTHORIZED);
+  response->AddCustomHeader(
+      is_proxy_auth ? "Proxy-Authenticate" : "WWW-Authenticate",
+      "Basic realm=\"TestServer\"");
   response->set_content("Unauthorized");
   response->set_content_type("text/plain");
   return response;
@@ -31,16 +47,19 @@
 // Callback to handle BasicAuth validation.
 std::unique_ptr<HttpResponse> HandleBasicAuth(
     const std::string& expected_auth_header,
+    bool is_proxy_auth,
     const HttpRequest& request) {
-  auto auth_header = request.headers.find("Authorization");
+  auto auth_header = request.headers.find(is_proxy_auth ? "Proxy-Authorization"
+                                                        : "Authorization");
 
   if (auth_header == request.headers.end() ||
       auth_header->second != expected_auth_header) {
-    DVLOG(1) << "Authorization failed or header missing.";
-    return CreateUnauthorizedResponse();
+    DVLOG(1) << "Authorization failed or header missing. For Proxy: "
+             << std::boolalpha << is_proxy_auth;
+    return CreateUnauthorizedResponse(is_proxy_auth);
   }
 
-  DVLOG(3) << "Authorization successful.";
+  DVLOG(3) << "Authorization successful. For Proxy: " << is_proxy_auth;
   return nullptr;
 }
 
@@ -49,16 +68,19 @@
 void RegisterBasicAuthHandler(EmbeddedTestServer& server,
                               std::string_view username,
                               std::string_view password) {
-  // Construct the expected authorization header value (e.g., "Basic
-  // dXNlcm5hbWU6cGFzc3dvcmQ=")
-  const std::string credentials = base::StrCat({username, ":", password});
-  const std::string encoded_credentials = base::Base64Encode(credentials);
-  const std::string expected_auth_header =
-      base::StrCat({"Basic ", encoded_credentials});
-
   // Register the BasicAuth handler with the server.
-  server.RegisterAuthHandler(
-      base::BindRepeating(&HandleBasicAuth, expected_auth_header));
+  server.RegisterAuthHandler(base::BindRepeating(
+      &HandleBasicAuth, CreateExpectedBasicAuthHeader(username, password),
+      /*is_proxy_auth=*/false));
+}
+
+void RegisterProxyBasicAuthHandler(EmbeddedTestServer& server,
+                                   std::string_view username,
+                                   std::string_view password) {
+  // Register the BasicAuth handler with the server.
+  server.RegisterAuthHandler(base::BindRepeating(
+      &HandleBasicAuth, CreateExpectedBasicAuthHeader(username, password),
+      /*is_proxy_auth=*/true));
 }
 
 GURL GetURLWithUser(const EmbeddedTestServer& server,
diff --git a/net/test/embedded_test_server/register_basic_auth_handler.h b/net/test/embedded_test_server/register_basic_auth_handler.h
index 31baf16..74284cf 100644
--- a/net/test/embedded_test_server/register_basic_auth_handler.h
+++ b/net/test/embedded_test_server/register_basic_auth_handler.h
@@ -18,6 +18,13 @@
                               std::string_view username,
                               std::string_view password);
 
+// Registers a BasicAuth handler with a username and password that mimics proxy
+// auth. Will overwrite any other auth handler (including non-proxy auth
+// handlers).
+void RegisterProxyBasicAuthHandler(EmbeddedTestServer& server,
+                                   std::string_view username,
+                                   std::string_view password);
+
 // Helper to generate a URL with username for Basic Authentication.
 GURL GetURLWithUser(const EmbeddedTestServer& server,
                     std::string_view path,
diff --git a/net/websockets/websocket_end_to_end_test.cc b/net/websockets/websocket_end_to_end_test.cc
index 66a04c23..0993fb2 100644
--- a/net/websockets/websocket_end_to_end_test.cc
+++ b/net/websockets/websocket_end_to_end_test.cc
@@ -69,6 +69,7 @@
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/embedded_test_server/install_default_websocket_handlers.h"
+#include "net/test/embedded_test_server/register_basic_auth_handler.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/test/ssl_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -508,27 +509,20 @@
   CloseWebSocketSuccessfully();
 }
 
-// These test are not compatible with RemoteTestServer because RemoteTestServer
-// doesn't support TYPE_BASIC_AUTH_PROXY.
-// TODO(ricea): Make these tests work. See crbug.com/441711.
-constexpr bool kHasBasicAuthProxy =
-    !(BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA));
-
 // Test for issue crbug.com/433695 "Unencrypted WebSocket connection via
 // authenticated proxy times out".
 TEST_F(WebSocketEndToEndTest, HttpsProxyUnauthedFails) {
-  if (!kHasBasicAuthProxy) {
-    GTEST_SKIP() << "Test not supported on this platform";
-  }
-
-  SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
-                                 base::FilePath());
+  EmbeddedTestServer proxy_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
   SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
                               GetWebSocketTestDataDirectory());
-  ASSERT_TRUE(proxy_server.StartInBackground());
   ASSERT_TRUE(ws_server.StartInBackground());
-  ASSERT_TRUE(proxy_server.BlockUntilStarted());
   ASSERT_TRUE(ws_server.BlockUntilStarted());
+
+  proxy_server.EnableConnectProxy(ws_server.host_port_pair().port(),
+                                  /*expected_dest=*/ws_server.host_port_pair());
+  RegisterProxyBasicAuthHandler(proxy_server, "user", "pass");
+  ASSERT_TRUE(proxy_server.Start());
+
   ProxyConfig proxy_config;
   proxy_config.proxy_rules().ParseFromString(
       "https=" + proxy_server.host_port_pair().ToString());
@@ -548,18 +542,18 @@
 }
 
 TEST_F(WebSocketEndToEndTest, HttpsWssProxyUnauthedFails) {
-  if (!kHasBasicAuthProxy) {
-    GTEST_SKIP() << "Test not supported on this platform";
-  }
-
-  SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
-                                 base::FilePath());
+  EmbeddedTestServer proxy_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
   SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS,
                                GetWebSocketTestDataDirectory());
-  ASSERT_TRUE(proxy_server.StartInBackground());
   ASSERT_TRUE(wss_server.StartInBackground());
-  ASSERT_TRUE(proxy_server.BlockUntilStarted());
   ASSERT_TRUE(wss_server.BlockUntilStarted());
+
+  proxy_server.EnableConnectProxy(
+      wss_server.host_port_pair().port(),
+      /*expected_dest=*/wss_server.host_port_pair());
+  RegisterProxyBasicAuthHandler(proxy_server, "user", "pass");
+  ASSERT_TRUE(proxy_server.Start());
+
   ProxyConfig proxy_config;
   proxy_config.proxy_rules().ParseFromString(
       "https=" + proxy_server.host_port_pair().ToString());
@@ -580,22 +574,20 @@
 // Regression test for crbug.com/426736 "WebSocket connections not using
 // configured system HTTPS Proxy".
 TEST_F(WebSocketEndToEndTest, HttpsProxyUsed) {
-  if (!kHasBasicAuthProxy) {
-    GTEST_SKIP() << "Test not supported on this platform";
-  }
-
-  SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
-                                 base::FilePath());
+  EmbeddedTestServer proxy_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
   SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
                               GetWebSocketTestDataDirectory());
-  ASSERT_TRUE(proxy_server.StartInBackground());
   ASSERT_TRUE(ws_server.StartInBackground());
-  ASSERT_TRUE(proxy_server.BlockUntilStarted());
   ASSERT_TRUE(ws_server.BlockUntilStarted());
+
+  proxy_server.EnableConnectProxy(ws_server.host_port_pair().port(),
+                                  /*expected_dest=*/ws_server.host_port_pair());
+
+  ASSERT_TRUE(proxy_server.Start());
+
   ProxyConfig proxy_config;
   proxy_config.proxy_rules().ParseFromString(
-      "https=" + proxy_server.host_port_pair().ToString() + ";" +
-      "http=" + proxy_server.host_port_pair().ToString());
+      "https=" + proxy_server.host_port_pair().ToString());
   // TODO(crbug.com/40600992): Don't rely on proxying localhost.
   proxy_config.proxy_rules().bypass_rules.AddRulesToSubtractImplicit();
 
@@ -646,19 +638,24 @@
   }
 
   EmbeddedTestServer proxy_pac_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
-  SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_PROXY,
-                                 base::FilePath());
+  EmbeddedTestServer proxy_server(net::EmbeddedTestServer::Type::TYPE_HTTP);
   SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS,
                               GetWebSocketTestDataDirectory());
   proxy_pac_server.RegisterRequestHandler(base::BindRepeating(ProxyPacHandler));
-  proxy_server.set_redirect_connect_to_localhost(true);
 
   ASSERT_TRUE(proxy_pac_server.Start());
-  ASSERT_TRUE(proxy_server.StartInBackground());
   ASSERT_TRUE(ws_server.StartInBackground());
-  ASSERT_TRUE(proxy_server.BlockUntilStarted());
   ASSERT_TRUE(ws_server.BlockUntilStarted());
 
+  // Use a name other than localhost, since localhost implicitly bypasses the
+  // use of proxy.pac.
+  HostPortPair fake_ws_host_port_pair("stealth-localhost",
+                                      ws_server.host_port_pair().port());
+
+  proxy_server.EnableConnectProxy(ws_server.host_port_pair().port(),
+                                  /*expected_dest=*/fake_ws_host_port_pair);
+  ASSERT_TRUE(proxy_server.Start());
+
   ProxyConfig proxy_config =
       ProxyConfig::CreateFromCustomPacURL(proxy_pac_server.GetURL(base::StrCat(
           {"/proxy.pac?proxy=", proxy_server.host_port_pair().ToString()})));
@@ -674,11 +671,6 @@
       std::move(proxy_resolution_service));
   InitialiseContext();
 
-  // Use a name other than localhost, since localhost implicitly bypasses the
-  // use of proxy.pac.
-  HostPortPair fake_ws_host_port_pair("stealth-localhost",
-                                      ws_server.host_port_pair().port());
-
   GURL ws_url(base::StrCat(
       {"ws://", fake_ws_host_port_pair.ToString(), "/", kEchoServer}));
   EXPECT_TRUE(ConnectAndWait(ws_url));
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index ad9032b62..485c7d0 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -30,6 +30,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/ppapi/nacl_irt/ppapi_dispatcher.cc b/ppapi/nacl_irt/ppapi_dispatcher.cc
index 0e3958b..0f399b9 100644
--- a/ppapi/nacl_irt/ppapi_dispatcher.cc
+++ b/ppapi/nacl_irt/ppapi_dispatcher.cc
@@ -15,6 +15,7 @@
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/ppapi/proxy/ppb_testing_proxy.cc b/ppapi/proxy/ppb_testing_proxy.cc
index e09f10d..32da620 100644
--- a/ppapi/proxy/ppb_testing_proxy.cc
+++ b/ppapi/proxy/ppb_testing_proxy.cc
@@ -11,6 +11,7 @@
 
 #include <stddef.h>
 
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "ppapi/c/private/ppb_testing_private.h"
 #include "ppapi/proxy/enter_proxy.h"
diff --git a/ppapi/proxy/ppp_class_proxy.cc b/ppapi/proxy/ppp_class_proxy.cc
index 829ae576..5a0922a4 100644
--- a/ppapi/proxy/ppp_class_proxy.cc
+++ b/ppapi/proxy/ppp_class_proxy.cc
@@ -4,6 +4,7 @@
 
 #include "ppapi/proxy/ppp_class_proxy.h"
 
+#include "base/notimplemented.h"
 #include "ppapi/c/dev/ppb_var_deprecated.h"
 #include "ppapi/c/dev/ppp_class_deprecated.h"
 #include "ppapi/c/pp_var.h"
diff --git a/ppapi/proxy/tcp_socket_resource_base.cc b/ppapi/proxy/tcp_socket_resource_base.cc
index c7b44da..e56abc5 100644
--- a/ppapi/proxy/tcp_socket_resource_base.cc
+++ b/ppapi/proxy/tcp_socket_resource_base.cc
@@ -10,6 +10,7 @@
 #include "base/check.h"
 #include "base/check_op.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_errors.h"
diff --git a/ppapi/shared_impl/ppb_image_data_shared.cc b/ppapi/shared_impl/ppb_image_data_shared.cc
index 0a214c13..24c5dc43 100644
--- a/ppapi/shared_impl/ppb_image_data_shared.cc
+++ b/ppapi/shared_impl/ppb_image_data_shared.cc
@@ -4,7 +4,7 @@
 
 #include "ppapi/shared_impl/ppb_image_data_shared.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "components/nacl/common/buildflags.h"
 
diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc
index c7003b4..9e84f45 100644
--- a/printing/printing_context_win.cc
+++ b/printing/printing_context_win.cc
@@ -15,6 +15,7 @@
 #include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/memory/free_deleter.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/current_thread.h"
diff --git a/printing/test_printing_context.cc b/printing/test_printing_context.cc
index 65ae78c..502a7d1 100644
--- a/printing/test_printing_context.cc
+++ b/printing/test_printing_context.cc
@@ -9,7 +9,7 @@
 
 #include "base/check.h"
 #include "base/containers/flat_map.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "printing/backend/print_backend.h"
diff --git a/remoting/base/fake_oauth_token_getter.cc b/remoting/base/fake_oauth_token_getter.cc
index 2ec851d7..ed17b47 100644
--- a/remoting/base/fake_oauth_token_getter.cc
+++ b/remoting/base/fake_oauth_token_getter.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 
 namespace remoting {
diff --git a/remoting/base/passthrough_oauth_token_getter.cc b/remoting/base/passthrough_oauth_token_getter.cc
index 36b00e1..bf00594c 100644
--- a/remoting/base/passthrough_oauth_token_getter.cc
+++ b/remoting/base/passthrough_oauth_token_getter.cc
@@ -5,6 +5,7 @@
 #include "remoting/base/passthrough_oauth_token_getter.h"
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 
 namespace remoting {
diff --git a/remoting/base/protobuf_http_stream_request.cc b/remoting/base/protobuf_http_stream_request.cc
index 04ebba1..b903ee3 100644
--- a/remoting/base/protobuf_http_stream_request.cc
+++ b/remoting/base/protobuf_http_stream_request.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "remoting/base/http_status.h"
 #include "remoting/base/protobuf_http_client.h"
diff --git a/remoting/client/common/remoting_client.cc b/remoting/client/common/remoting_client.cc
index bde4b31..2dc64652 100644
--- a/remoting/client/common/remoting_client.cc
+++ b/remoting/client/common/remoting_client.cc
@@ -14,6 +14,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "components/webrtc/thread_wrapper.h"
diff --git a/remoting/codec/audio_decoder.cc b/remoting/codec/audio_decoder.cc
index 6dd25360..e5d77600 100644
--- a/remoting/codec/audio_decoder.cc
+++ b/remoting/codec/audio_decoder.cc
@@ -5,7 +5,7 @@
 #include "remoting/codec/audio_decoder.h"
 
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "remoting/codec/audio_decoder_opus.h"
 #include "remoting/protocol/session_config.h"
 
diff --git a/remoting/codec/video_decoder_verbatim.cc b/remoting/codec/video_decoder_verbatim.cc
index b85cfed..9b566ea3 100644
--- a/remoting/codec/video_decoder_verbatim.cc
+++ b/remoting/codec/video_decoder_verbatim.cc
@@ -9,7 +9,7 @@
 
 #include "base/containers/span.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "remoting/base/util.h"
 #include "remoting/proto/video.pb.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
diff --git a/remoting/host/active_display_monitor.cc b/remoting/host/active_display_monitor.cc
index da0aabd5..ced1cc3 100644
--- a/remoting/host/active_display_monitor.cc
+++ b/remoting/host/active_display_monitor.cc
@@ -5,7 +5,7 @@
 #include "remoting/host/active_display_monitor.h"
 
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 
 namespace remoting {
diff --git a/remoting/host/audio_capturer_chromeos.cc b/remoting/host/audio_capturer_chromeos.cc
index 9b9b970..af573eef 100644
--- a/remoting/host/audio_capturer_chromeos.cc
+++ b/remoting/host/audio_capturer_chromeos.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/notreached.h"
 #include "remoting/host/audio_capturer.h"
 
+#include "base/notimplemented.h"
+
 namespace remoting {
 
 bool AudioCapturer::IsSupported() {
diff --git a/remoting/host/base/process_util.cc b/remoting/host/base/process_util.cc
index f157018..9e906c8 100644
--- a/remoting/host/base/process_util.cc
+++ b/remoting/host/base/process_util.cc
@@ -15,7 +15,7 @@
 
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
diff --git a/remoting/host/base/username.cc b/remoting/host/base/username.cc
index 74ec593..ea4f4cb0 100644
--- a/remoting/host/base/username.cc
+++ b/remoting/host/base/username.cc
@@ -7,7 +7,7 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_POSIX)
diff --git a/remoting/host/chromoting_host_services_client.cc b/remoting/host/chromoting_host_services_client.cc
index 956fc11..4ce2156e 100644
--- a/remoting/host/chromoting_host_services_client.cc
+++ b/remoting/host/chromoting_host_services_client.cc
@@ -110,6 +110,11 @@
   return session_services_remote_.get();
 }
 
+void ChromotingHostServicesClient::set_disconnect_handler(
+    base::OnceClosure disconnect_handler) {
+  disconnect_handler_ = std::move(disconnect_handler);
+}
+
 bool ChromotingHostServicesClient::EnsureConnection() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -155,6 +160,10 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   remote_.reset();
+
+  if (disconnect_handler_) {
+    std::move(disconnect_handler_).Run();
+  }
 }
 
 void ChromotingHostServicesClient::OnSessionDisconnected() {
@@ -162,8 +171,8 @@
 
   session_services_remote_.reset();
 
-  if (on_session_disconnected_callback_for_testing_) {
-    std::move(on_session_disconnected_callback_for_testing_).Run();
+  if (disconnect_handler_) {
+    std::move(disconnect_handler_).Run();
   }
 }
 
diff --git a/remoting/host/chromoting_host_services_client.h b/remoting/host/chromoting_host_services_client.h
index 519b626..c6ebcc0 100644
--- a/remoting/host/chromoting_host_services_client.h
+++ b/remoting/host/chromoting_host_services_client.h
@@ -49,6 +49,8 @@
   // receivers/remotes/message pipes sent will be closed.
   mojom::ChromotingSessionServices* GetSessionServices() const override;
 
+  void set_disconnect_handler(base::OnceClosure disconnect_handler) override;
+
  private:
   friend class ChromotingHostServicesClientTest;
 
@@ -77,7 +79,7 @@
   mojo::Remote<mojom::ChromotingSessionServices> session_services_remote_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
-  base::OnceClosure on_session_disconnected_callback_for_testing_;
+  base::OnceClosure disconnect_handler_;
 };
 
 }  // namespace remoting
diff --git a/remoting/host/chromoting_host_services_client_unittest.cc b/remoting/host/chromoting_host_services_client_unittest.cc
index 56c5613..bcbeea5 100644
--- a/remoting/host/chromoting_host_services_client_unittest.cc
+++ b/remoting/host/chromoting_host_services_client_unittest.cc
@@ -41,7 +41,6 @@
  protected:
   void SetChromeRemoteDesktopSessionEnvVar(bool is_crd_session);
   void WaitForSessionServicesBound();
-  void SetRemoteDisconnectCallback(base::OnceClosure callback);
 
   base::test::TaskEnvironment task_environment_;
   raw_ptr<base::Environment, DanglingUntriaged> environment_;
@@ -98,11 +97,6 @@
   session_services_bound_run_loop_ = std::make_unique<base::RunLoop>();
 }
 
-void ChromotingHostServicesClientTest::SetRemoteDisconnectCallback(
-    base::OnceClosure callback) {
-  client_->on_session_disconnected_callback_for_testing_ = std::move(callback);
-}
-
 mojo::PendingRemote<mojom::ChromotingHostServices>
 ChromotingHostServicesClientTest::ConnectToServer() {
   if (!is_server_started_) {
@@ -143,13 +137,25 @@
 }
 
 TEST_F(ChromotingHostServicesClientTest,
-       ServerClosesReceiverAndClientReconnects) {
+       ServerClosesSessionHostReceiver_DisconnectHandlerCalled) {
   ASSERT_NE(client_->GetSessionServices(), nullptr);
   WaitForSessionServicesBound();
   ASSERT_EQ(session_services_receivers_.size(), 1u);
 
   base::RunLoop remote_disconnect_run_loop;
-  SetRemoteDisconnectCallback(remote_disconnect_run_loop.QuitClosure());
+  client_->set_disconnect_handler(remote_disconnect_run_loop.QuitClosure());
+  host_services_receivers_.Clear();
+  remote_disconnect_run_loop.Run();
+}
+
+TEST_F(ChromotingHostServicesClientTest,
+       ServerClosesSessionServicesReceiverAndClientReconnects) {
+  ASSERT_NE(client_->GetSessionServices(), nullptr);
+  WaitForSessionServicesBound();
+  ASSERT_EQ(session_services_receivers_.size(), 1u);
+
+  base::RunLoop remote_disconnect_run_loop;
+  client_->set_disconnect_handler(remote_disconnect_run_loop.QuitClosure());
   session_services_receivers_.clear();
   remote_disconnect_run_loop.Run();
 
diff --git a/remoting/host/chromoting_host_services_provider.h b/remoting/host/chromoting_host_services_provider.h
index d3cddee0..b35f197 100644
--- a/remoting/host/chromoting_host_services_provider.h
+++ b/remoting/host/chromoting_host_services_provider.h
@@ -5,6 +5,8 @@
 #ifndef REMOTING_HOST_CHROMOTING_HOST_SERVICES_PROVIDER_H_
 #define REMOTING_HOST_CHROMOTING_HOST_SERVICES_PROVIDER_H_
 
+#include "base/functional/callback_forward.h"
+
 namespace remoting {
 
 namespace mojom {
@@ -18,8 +20,19 @@
 
   // Gets the ChromotingHostServices. Returns nullptr if the interface cannot be
   // provided at the moment.
+  // Always null-check before using it, as nullptr will be returned if the
+  // connection could not be established.
+  // Note that when the session is not remoted, you will still get a callable
+  // interface, but all outgoing IPCs will be silently dropped, and any pending
+  // receivers/remotes/message pipes sent will be closed. In this case, if you
+  // have set the disconnect handler, it will be called soon after this function
+  // is called.
   virtual mojom::ChromotingSessionServices* GetSessionServices() const = 0;
 
+  // Sets a disconnect handler, which will be run when the receiver of
+  // ChromotingSessionServices disconnects, or the IPC channel disconnects.
+  virtual void set_disconnect_handler(base::OnceClosure disconnect_handler) = 0;
+
  protected:
   ChromotingHostServicesProvider() = default;
 };
diff --git a/remoting/host/desktop_resizer_mac.cc b/remoting/host/desktop_resizer_mac.cc
index ca02b14b..539d346 100644
--- a/remoting/host/desktop_resizer_mac.cc
+++ b/remoting/host/desktop_resizer_mac.cc
@@ -11,7 +11,7 @@
 #include "base/apple/scoped_cftyperef.h"
 #include "base/mac/mac_util.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "remoting/base/logging.h"
 
 namespace {
diff --git a/remoting/host/desktop_resizer_win.cc b/remoting/host/desktop_resizer_win.cc
index b0c39412..db4f5723 100644
--- a/remoting/host/desktop_resizer_win.cc
+++ b/remoting/host/desktop_resizer_win.cc
@@ -12,7 +12,7 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace {
 // TODO(jamiewalch): Use the correct DPI for the mode: http://crbug.com/172405.
diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h
index a2e5637..a9aa336f 100644
--- a/remoting/host/host_mock_objects.h
+++ b/remoting/host/host_mock_objects.h
@@ -381,6 +381,10 @@
               GetSessionServices,
               (),
               (const, override));
+  MOCK_METHOD(void,
+              set_disconnect_handler,
+              (base::OnceClosure disconnect_handler),
+              (override));
 };
 
 }  // namespace remoting
diff --git a/remoting/host/input_injector_chromeos.cc b/remoting/host/input_injector_chromeos.cc
index 2f91bdbe..d4499b1 100644
--- a/remoting/host/input_injector_chromeos.cc
+++ b/remoting/host/input_injector_chromeos.cc
@@ -15,6 +15,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/i18n/icu_string_conversions.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/remoting/host/input_injector_mac.cc b/remoting/host/input_injector_mac.cc
index 38f18ec..66ec467 100644
--- a/remoting/host/input_injector_mac.cc
+++ b/remoting/host/input_injector_mac.cc
@@ -21,6 +21,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/remoting/host/input_monitor/local_keyboard_input_monitor_linux.cc b/remoting/host/input_monitor/local_keyboard_input_monitor_linux.cc
index c0f404d..acb113119 100644
--- a/remoting/host/input_monitor/local_keyboard_input_monitor_linux.cc
+++ b/remoting/host/input_monitor/local_keyboard_input_monitor_linux.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 
 namespace remoting {
diff --git a/remoting/host/ipc_screen_controls.cc b/remoting/host/ipc_screen_controls.cc
index 0a822e8..e086dac 100644
--- a/remoting/host/ipc_screen_controls.cc
+++ b/remoting/host/ipc_screen_controls.cc
@@ -4,7 +4,7 @@
 
 #include "remoting/host/ipc_screen_controls.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "remoting/host/desktop_session_proxy.h"
 
 namespace remoting {
diff --git a/remoting/host/ipc_video_frame_capturer.cc b/remoting/host/ipc_video_frame_capturer.cc
index 41e03b6d..bb20131 100644
--- a/remoting/host/ipc_video_frame_capturer.cc
+++ b/remoting/host/ipc_video_frame_capturer.cc
@@ -5,7 +5,7 @@
 #include "remoting/host/ipc_video_frame_capturer.h"
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "remoting/host/desktop_session_proxy.h"
 #include "remoting/host/video_memory_utils.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
diff --git a/remoting/host/linux/input_injector_x11.cc b/remoting/host/linux/input_injector_x11.cc
index e10a5b9..6ab2371b 100644
--- a/remoting/host/linux/input_injector_x11.cc
+++ b/remoting/host/linux/input_injector_x11.cc
@@ -16,6 +16,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/remoting/host/policy_watcher.cc b/remoting/host/policy_watcher.cc
index acff1f68..a00def8 100644
--- a/remoting/host/policy_watcher.cc
+++ b/remoting/host/policy_watcher.cc
@@ -16,6 +16,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/values.h"
 #include "build/branding_buildflags.h"
diff --git a/remoting/host/remote_open_url/remote_open_url_client.cc b/remoting/host/remote_open_url/remote_open_url_client.cc
index ed0178fc..23179d5 100644
--- a/remoting/host/remote_open_url/remote_open_url_client.cc
+++ b/remoting/host/remote_open_url/remote_open_url_client.cc
@@ -106,6 +106,16 @@
     return;
   }
 
+  auto disconnect_handler = base::BindRepeating(
+      &RemoteOpenUrlClient::OnIpcDisconnected, base::Unretained(this));
+  // There is a bug in Mojo, such that if the host rejects binding of session
+  // services, there is a chance that binding of RemoteUrlOpener appears to be
+  // successful and the disconnect handler of `remote_` is never called, so
+  // `remote_` will remain invalid forever.
+  // The disconnect handler of session services is still called, so we set a
+  // disconnect handler on it.
+  // See https://crbug.com/425759818#comment8 for more context.
+  api_provider_->set_disconnect_handler(disconnect_handler);
   auto* api = api_provider_->GetSessionServices();
   if (!api) {
     HOST_LOG << "Can't make IPC connection. The host is probably not running.";
@@ -113,8 +123,7 @@
     return;
   }
   api->BindRemoteUrlOpener(remote_.BindNewPipeAndPassReceiver());
-  remote_.set_disconnect_handler(base::BindOnce(
-      &RemoteOpenUrlClient::OnIpcDisconnected, base::Unretained(this)));
+  remote_.set_disconnect_handler(disconnect_handler);
   timeout_timer_.Start(FROM_HERE, request_timeout_, this,
                        &RemoteOpenUrlClient::OnRequestTimeout);
   remote_->OpenUrl(url_, base::BindOnce(&RemoteOpenUrlClient::OnOpenUrlResponse,
diff --git a/remoting/host/remote_open_url/remote_open_url_client_delegate_win.cc b/remoting/host/remote_open_url/remote_open_url_client_delegate_win.cc
index bde8b2f..a4493138 100644
--- a/remoting/host/remote_open_url/remote_open_url_client_delegate_win.cc
+++ b/remoting/host/remote_open_url/remote_open_url_client_delegate_win.cc
@@ -9,7 +9,7 @@
 #include <ios>
 #include <string>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/process/launch.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/remoting/host/remote_open_url/remote_open_url_client_unittest.cc b/remoting/host/remote_open_url/remote_open_url_client_unittest.cc
index 204cc39..f323583 100644
--- a/remoting/host/remote_open_url/remote_open_url_client_unittest.cc
+++ b/remoting/host/remote_open_url/remote_open_url_client_unittest.cc
@@ -31,6 +31,7 @@
 namespace {
 
 using testing::_;
+using testing::AnyNumber;
 using testing::Return;
 
 // The IPC channel doesn't work if we use a mock clock, so we just reduce the
@@ -97,6 +98,7 @@
 RemoteOpenUrlClientTest::~RemoteOpenUrlClientTest() = default;
 
 void RemoteOpenUrlClientTest::BindMockRemoteUrlOpener() {
+  EXPECT_CALL(*api_provider_, set_disconnect_handler(_)).Times(AnyNumber());
   EXPECT_CALL(*api_provider_, GetSessionServices())
       .WillRepeatedly(Return(&mock_api_));
   EXPECT_CALL(mock_api_, BindRemoteUrlOpener(_))
@@ -132,6 +134,7 @@
 
 TEST_F(RemoteOpenUrlClientTest,
        OpenWhenHostServicesApiIsNotProvided_FallsBack) {
+  EXPECT_CALL(*api_provider_, set_disconnect_handler(_));
   EXPECT_CALL(*api_provider_, GetSessionServices()).WillOnce(Return(nullptr));
   EXPECT_CALL(*delegate_, OpenUrlOnFallbackBrowser(GURL("http://google.com/")))
       .Times(1);
diff --git a/remoting/host/remote_open_url/url_forwarder_configurator.cc b/remoting/host/remote_open_url/url_forwarder_configurator.cc
index be06596..21a3ea40 100644
--- a/remoting/host/remote_open_url/url_forwarder_configurator.cc
+++ b/remoting/host/remote_open_url/url_forwarder_configurator.cc
@@ -4,6 +4,7 @@
 
 #include "remoting/host/remote_open_url/url_forwarder_configurator.h"
 
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 
 namespace remoting {
diff --git a/remoting/host/resizing_host_observer_unittest.cc b/remoting/host/resizing_host_observer_unittest.cc
index 08b7adc3..00461828 100644
--- a/remoting/host/resizing_host_observer_unittest.cc
+++ b/remoting/host/resizing_host_observer_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/simple_test_tick_clock.h"
diff --git a/remoting/host/security_key/security_key_ipc_client.cc b/remoting/host/security_key/security_key_ipc_client.cc
index 1b666313..b6be801 100644
--- a/remoting/host/security_key/security_key_ipc_client.cc
+++ b/remoting/host/security_key/security_key_ipc_client.cc
@@ -130,10 +130,19 @@
     OnChannelError();
     return;
   }
+  auto disconnect_handler = base::BindRepeating(
+      &SecurityKeyIpcClient::OnChannelError, base::Unretained(this));
+  // There is a bug in Mojo, such that if the host rejects binding of session
+  // services, there is a chance that binding of SecurityKeyForwarder appears to
+  // be successful and the disconnect handler of `remote_` is never called, so
+  // `remote_` will remain invalid forever.
+  // The disconnect handler of session services is still called, so we set a
+  // disconnect handler on it.
+  // See https://crbug.com/425759818#comment8 for more context.
+  service_provider_->set_disconnect_handler(disconnect_handler);
   service_provider_->GetSessionServices()->BindSecurityKeyForwarder(
       security_key_forwarder_.BindNewPipeAndPassReceiver());
-  security_key_forwarder_.set_disconnect_handler(base::BindOnce(
-      &SecurityKeyIpcClient::OnChannelError, base::Unretained(this)));
+  security_key_forwarder_.set_disconnect_handler(disconnect_handler);
   // This is to determine if the peer binding is successful. If the connection
   // is disconnected before OnQueryVersionResult() is called, it means the
   // server has rejected the binding request.
diff --git a/remoting/host/security_key/security_key_ipc_client_unittest.cc b/remoting/host/security_key/security_key_ipc_client_unittest.cc
index a647457..ce7b5d3a 100644
--- a/remoting/host/security_key/security_key_ipc_client_unittest.cc
+++ b/remoting/host/security_key/security_key_ipc_client_unittest.cc
@@ -26,6 +26,7 @@
 const int kLargeMessageSizeBytes = 256 * 1024;
 
 using testing::_;
+using testing::AnyNumber;
 using testing::Return;
 }  // namespace
 
@@ -148,6 +149,7 @@
 }
 
 void SecurityKeyIpcClientTest::EstablishConnection(bool expect_error) {
+  EXPECT_CALL(*api_provider_, set_disconnect_handler(_)).Times(AnyNumber());
   EXPECT_CALL(*api_provider_, GetSessionServices())
       .WillRepeatedly(Return(&mock_api_));
 
@@ -283,6 +285,7 @@
 }
 
 TEST_F(SecurityKeyIpcClientTest, NonExistentIpcServerChannel) {
+  EXPECT_CALL(*api_provider_, set_disconnect_handler(_)).Times(AnyNumber());
   EXPECT_CALL(*api_provider_, GetSessionServices())
       .WillRepeatedly(Return(nullptr));
 
diff --git a/remoting/host/usage_stats_consent_linux.cc b/remoting/host/usage_stats_consent_linux.cc
index fe6a7b1..0a86d44 100644
--- a/remoting/host/usage_stats_consent_linux.cc
+++ b/remoting/host/usage_stats_consent_linux.cc
@@ -11,7 +11,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 #include "remoting/base/file_path_util_linux.h"
 #include "remoting/base/is_google_email.h"
diff --git a/remoting/host/usage_stats_consent_mac.cc b/remoting/host/usage_stats_consent_mac.cc
index db5d93ba..ac62dbb 100644
--- a/remoting/host/usage_stats_consent_mac.cc
+++ b/remoting/host/usage_stats_consent_mac.cc
@@ -10,7 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/values.h"
 #include "remoting/host/config_file_watcher.h"
 #include "remoting/host/host_config.h"
diff --git a/remoting/host/webauthn/remote_webauthn_caller_security_utils.cc b/remoting/host/webauthn/remote_webauthn_caller_security_utils.cc
index 4fb6214..dac24cc 100644
--- a/remoting/host/webauthn/remote_webauthn_caller_security_utils.cc
+++ b/remoting/host/webauthn/remote_webauthn_caller_security_utils.cc
@@ -8,7 +8,7 @@
 
 #include "base/environment.h"
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/process/process_handle.h"
 #include "base/strings/cstring_view.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/remoting/host/webauthn/remote_webauthn_extension_notifier.cc b/remoting/host/webauthn/remote_webauthn_extension_notifier.cc
index 2f46d94..82305ea 100644
--- a/remoting/host/webauthn/remote_webauthn_extension_notifier.cc
+++ b/remoting/host/webauthn/remote_webauthn_extension_notifier.cc
@@ -19,7 +19,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/no_destructor.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/sequence_checker.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc b/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc
index 5f0fc47..ff79fe8b 100644
--- a/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc
+++ b/remoting/host/webauthn/remote_webauthn_native_messaging_host.cc
@@ -424,14 +424,23 @@
     return true;
   }
 
+  auto disconnect_handler =
+      base::BindRepeating(&RemoteWebAuthnNativeMessagingHost::OnIpcDisconnected,
+                          base::Unretained(this));
+  // There is a bug in Mojo, such that if the host rejects binding of session
+  // services, there is a chance that binding of WebAuthnProxy appears to be
+  // successful and the disconnect handler of `remote_` is never called, so
+  // `remote_` will remain invalid forever.
+  // The disconnect handler of session services is still called, so we set a
+  // disconnect handler on it.
+  // See https://crbug.com/425759818#comment8 for more context.
+  host_service_api_client_->set_disconnect_handler(disconnect_handler);
   auto* api = host_service_api_client_->GetSessionServices();
   if (!api) {
     return false;
   }
   api->BindWebAuthnProxy(remote_.BindNewPipeAndPassReceiver());
-  remote_.set_disconnect_handler(
-      base::BindOnce(&RemoteWebAuthnNativeMessagingHost::OnIpcDisconnected,
-                     base::Unretained(this)));
+  remote_.set_disconnect_handler(disconnect_handler);
   return true;
 }
 
diff --git a/remoting/host/webauthn/remote_webauthn_native_messaging_host_unittest.cc b/remoting/host/webauthn/remote_webauthn_native_messaging_host_unittest.cc
index 87e51f5..de64df8 100644
--- a/remoting/host/webauthn/remote_webauthn_native_messaging_host_unittest.cc
+++ b/remoting/host/webauthn/remote_webauthn_native_messaging_host_unittest.cc
@@ -181,6 +181,7 @@
 testing::Expectation
 RemoteWebAuthnNativeMessagingHostTest::ExpectGetSessionServices(
     bool should_return_valid_services) {
+  EXPECT_CALL(*api_provider_, set_disconnect_handler(_));
   return EXPECT_CALL(*api_provider_, GetSessionServices())
       .WillOnce(Return(should_return_valid_services ? &api_ : nullptr));
 }
diff --git a/remoting/protocol/chromium_socket_factory.cc b/remoting/protocol/chromium_socket_factory.cc
index 71da8835..99b92b8 100644
--- a/remoting/protocol/chromium_socket_factory.cc
+++ b/remoting/protocol/chromium_socket_factory.cc
@@ -18,6 +18,7 @@
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/rand_util.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
diff --git a/remoting/protocol/fake_connection_to_client.cc b/remoting/protocol/fake_connection_to_client.cc
index 0c4e090..34061f1 100644
--- a/remoting/protocol/fake_connection_to_client.cc
+++ b/remoting/protocol/fake_connection_to_client.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "remoting/codec/video_encoder.h"
 #include "remoting/protocol/audio_source.h"
 #include "remoting/protocol/audio_stream.h"
diff --git a/remoting/protocol/fake_desktop_capturer.cc b/remoting/protocol/fake_desktop_capturer.cc
index 3cad95b..1fd15d5f 100644
--- a/remoting/protocol/fake_desktop_capturer.cc
+++ b/remoting/protocol/fake_desktop_capturer.cc
@@ -15,7 +15,7 @@
 
 #include "base/check.h"
 #include "base/functional/bind.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
diff --git a/remoting/protocol/ice_config_fetcher_corp.cc b/remoting/protocol/ice_config_fetcher_corp.cc
index 320ddaf..881c3f4 100644
--- a/remoting/protocol/ice_config_fetcher_corp.cc
+++ b/remoting/protocol/ice_config_fetcher_corp.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "base/memory/scoped_refptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace remoting::protocol {
diff --git a/remoting/protocol/no_op_webrtc_frame_scheduler.cc b/remoting/protocol/no_op_webrtc_frame_scheduler.cc
index 80a49360..86194725 100644
--- a/remoting/protocol/no_op_webrtc_frame_scheduler.cc
+++ b/remoting/protocol/no_op_webrtc_frame_scheduler.cc
@@ -4,7 +4,7 @@
 
 #include "remoting/protocol/no_op_webrtc_frame_scheduler.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace remoting::protocol {
 
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator.cc b/remoting/protocol/ssl_hmac_channel_authenticator.cc
index 0182fbd..e22d6f8 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator.cc
+++ b/remoting/protocol/ssl_hmac_channel_authenticator.cc
@@ -11,6 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "crypto/secure_util.h"
 #include "net/base/host_port_pair.h"
diff --git a/remoting/protocol/stream_packet_socket.cc b/remoting/protocol/stream_packet_socket.cc
index 3e3803c..8832f91 100644
--- a/remoting/protocol/stream_packet_socket.cc
+++ b/remoting/protocol/stream_packet_socket.cc
@@ -5,6 +5,7 @@
 #include "remoting/protocol/stream_packet_socket.h"
 
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "components/webrtc/net_address_utils.h"
 #include "net/base/address_list.h"
 #include "net/base/io_buffer.h"
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc
index 79f3afa..5e1a838 100644
--- a/remoting/protocol/webrtc_transport.cc
+++ b/remoting/protocol/webrtc_transport.cc
@@ -17,6 +17,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ref.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/remoting/protocol/webrtc_video_encoder_wrapper.cc b/remoting/protocol/webrtc_video_encoder_wrapper.cc
index 4ecf3cc..b2086ec 100644
--- a/remoting/protocol/webrtc_video_encoder_wrapper.cc
+++ b/remoting/protocol/webrtc_video_encoder_wrapper.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/remoting/protocol/webrtc_video_frame_adapter.cc b/remoting/protocol/webrtc_video_frame_adapter.cc
index fc48564..3f6afaab 100644
--- a/remoting/protocol/webrtc_video_frame_adapter.cc
+++ b/remoting/protocol/webrtc_video_frame_adapter.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "third_party/webrtc/rtc_base/ref_counted_object.h"
 
 namespace remoting::protocol {
diff --git a/remoting/signaling/fake_signal_strategy.cc b/remoting/signaling/fake_signal_strategy.cc
index 96830d3..aac5f3d 100644
--- a/remoting/signaling/fake_signal_strategy.cc
+++ b/remoting/signaling/fake_signal_strategy.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "remoting/signaling/signaling_id_util.h"
diff --git a/remoting/test/fake_socket_factory.cc b/remoting/test/fake_socket_factory.cc
index 081c727..d40be61 100644
--- a/remoting/test/fake_socket_factory.cc
+++ b/remoting/test/fake_socket_factory.cc
@@ -21,6 +21,7 @@
 #include "base/functional/callback.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "net/base/io_buffer.h"
diff --git a/remoting/test/fake_test_token_storage.cc b/remoting/test/fake_test_token_storage.cc
index d3c77db..4a78030 100644
--- a/remoting/test/fake_test_token_storage.cc
+++ b/remoting/test/fake_test_token_storage.cc
@@ -4,7 +4,7 @@
 
 #include "remoting/test/fake_test_token_storage.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace {
 const char kRefreshTokenValue[] = "1/lkjalseLKJlsiJgr45jbv";
diff --git a/rlz/chromeos/lib/rlz_value_store_chromeos.cc b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
index fa5b4b7..0fb349b8 100644
--- a/rlz/chromeos/lib/rlz_value_store_chromeos.cc
+++ b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
@@ -19,6 +19,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/rlz/mac/lib/rlz_value_store_mac.mm b/rlz/mac/lib/rlz_value_store_mac.mm
index 2f33fefd..f32e533 100644
--- a/rlz/mac/lib/rlz_value_store_mac.mm
+++ b/rlz/mac/lib/rlz_value_store_mac.mm
@@ -12,7 +12,7 @@
 #include "base/check.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "rlz/lib/assert.h"
 #include "rlz/lib/lib_values.h"
diff --git a/services/accessibility/features/devtools/os_devtools_agent.cc b/services/accessibility/features/devtools/os_devtools_agent.cc
index cad8e4f1..148cd4f3 100644
--- a/services/accessibility/features/devtools/os_devtools_agent.cc
+++ b/services/accessibility/features/devtools/os_devtools_agent.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/notimplemented.h"
 #include "services/accessibility/features/devtools/debug_command_queue.h"
 #include "services/accessibility/features/devtools/os_devtools_session.h"
 #include "services/accessibility/features/v8_manager.h"
diff --git a/services/accessibility/features/devtools/os_devtools_session.cc b/services/accessibility/features/devtools/os_devtools_session.cc
index 577e527..10c75ba 100644
--- a/services/accessibility/features/devtools/os_devtools_session.cc
+++ b/services/accessibility/features/devtools/os_devtools_session.cc
@@ -13,6 +13,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
diff --git a/services/audio/test/audio_system_to_service_adapter_test.cc b/services/audio/test/audio_system_to_service_adapter_test.cc
index ad6aabf..acfe4fa 100644
--- a/services/audio/test/audio_system_to_service_adapter_test.cc
+++ b/services/audio/test/audio_system_to_service_adapter_test.cc
@@ -5,6 +5,7 @@
 #include "services/audio/public/cpp/audio_system_to_service_adapter.h"
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
diff --git a/services/device/battery/battery_status_manager_default.cc b/services/device/battery/battery_status_manager_default.cc
index 32c9a11..4133862 100644
--- a/services/device/battery/battery_status_manager_default.cc
+++ b/services/device/battery/battery_status_manager_default.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/device/battery/battery_status_manager.h"
-
 #include <memory>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
+#include "services/device/battery/battery_status_manager.h"
 
 namespace device {
 
diff --git a/services/device/generic_sensor/platform_sensor_reader_win.cc b/services/device/generic_sensor/platform_sensor_reader_win.cc
index 1343660c..5bb52f7f 100644
--- a/services/device/generic_sensor/platform_sensor_reader_win.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_win.cc
@@ -20,6 +20,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/numerics/angle_conversions.h"
 #include "base/numerics/math_constants.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.cc b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
index f2ae986..0e4bf8a 100644
--- a/services/device/generic_sensor/platform_sensor_reader_winrt.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
@@ -6,6 +6,7 @@
 
 #include <cmath>
 
+#include "base/notimplemented.h"
 #include "base/numerics/angle_conversions.h"
 #include "base/numerics/math_constants.h"
 #include "base/time/time.h"
diff --git a/services/device/hid/hid_service_fuchsia.cc b/services/device/hid/hid_service_fuchsia.cc
index 83a47bf..50e7ac9 100644
--- a/services/device/hid/hid_service_fuchsia.cc
+++ b/services/device/hid/hid_service_fuchsia.cc
@@ -4,7 +4,7 @@
 
 #include "services/device/hid/hid_service_fuchsia.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "services/device/hid/hid_connection.h"
 
 namespace device {
diff --git a/services/device/public/cpp/test/fake_sensor_and_provider.cc b/services/device/public/cpp/test/fake_sensor_and_provider.cc
index 0090c25..f9c5b74 100644
--- a/services/device/public/cpp/test/fake_sensor_and_provider.cc
+++ b/services/device/public/cpp/test/fake_sensor_and_provider.cc
@@ -8,7 +8,7 @@
 #include <memory>
 #include <utility>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer.h"
diff --git a/services/device/public/cpp/test/test_wake_lock_provider.cc b/services/device/public/cpp/test/test_wake_lock_provider.cc
index 38b05c93..48b15576d 100644
--- a/services/device/public/cpp/test/test_wake_lock_provider.cc
+++ b/services/device/public/cpp/test/test_wake_lock_provider.cc
@@ -10,7 +10,7 @@
 #include "base/check_op.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
 
diff --git a/services/device/public/mojom/nfc.mojom b/services/device/public/mojom/nfc.mojom
index ec1f475..8d4cacd 100644
--- a/services/device/public/mojom/nfc.mojom
+++ b/services/device/public/mojom/nfc.mojom
@@ -183,12 +183,6 @@
   // available.
   OnWatch(array<uint32> watch_ids, string? serial_number, NDEFMessage message);
 
-  // Same as above but takes a raw message which is unparsed. Since we do
-  // not want to parse untrusted data in the browser we leave it for the
-  // renderer to parse.
-  [EnableIf=is_ios_iphoneos]
-  OnWatch(array<uint32> watch_ids, NDEFRawMessage message);
-
   // Sends |error| to all readers that are trying to read some data from the nfc
   // tag coming nearby.
   OnError(NDEFError error);
@@ -202,7 +196,6 @@
 interface RawNFCClient {
   // Sends |message| to those readers that have registered |watch_ids| via
   // NFC.Watch(), i.e. |message| matches their filtering criteria.
-  [EnableIf=is_ios_iphoneos]
   OnWatch(array<uint32> watch_ids, NDEFRawMessage message);
 
   // Sends |error| to all readers that are trying to read some data from the nfc
diff --git a/services/device/serial/serial_io_handler_win.cc b/services/device/serial/serial_io_handler_win.cc
index 52e71303..8c953161 100644
--- a/services/device/serial/serial_io_handler_win.cc
+++ b/services/device/serial/serial_io_handler_win.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/sequence_checker.h"
 #include "base/task/current_thread.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/services/device/usb/fake_usb_device_handle.cc b/services/device/usb/fake_usb_device_handle.cc
index ad77af8..12fdb68b 100644
--- a/services/device/usb/fake_usb_device_handle.cc
+++ b/services/device/usb/fake_usb_device_handle.cc
@@ -9,7 +9,7 @@
 
 #include "base/functional/callback.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "services/device/usb/usb_device.h"
 
 namespace device {
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc
index 3fd8540..a4da55a1 100644
--- a/services/media_session/audio_focus_manager.cc
+++ b/services/media_session/audio_focus_manager.cc
@@ -10,6 +10,7 @@
 
 #include "base/containers/adapters.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/power_monitor/power_observer.h"
 #include "base/unguessable_token.h"
diff --git a/services/network/data_pipe_element_reader_unittest.cc b/services/network/data_pipe_element_reader_unittest.cc
index e9045fa..9aacd78 100644
--- a/services/network/data_pipe_element_reader_unittest.cc
+++ b/services/network/data_pipe_element_reader_unittest.cc
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "base/memory/ref_counted.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/task_environment.h"
diff --git a/services/network/p2p/socket_test_utils.cc b/services/network/p2p/socket_test_utils.cc
index ce80dcc6..cee57d1d 100644
--- a/services/network/p2p/socket_test_utils.cc
+++ b/services/network/p2p/socket_test_utils.cc
@@ -12,6 +12,7 @@
 #include "base/check.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/byte_conversions.h"
 #include "base/numerics/safe_conversions.h"
diff --git a/services/network/p2p/socket_udp_unittest.cc b/services/network/p2p/socket_udp_unittest.cc
index e09298b..5c1eed0d 100644
--- a/services/network/p2p/socket_udp_unittest.cc
+++ b/services/network/p2p/socket_udp_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/containers/circular_deque.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/run_loop.h"
diff --git a/services/network/proxy_resolving_client_socket.cc b/services/network/proxy_resolving_client_socket.cc
index 652acfe..b40a102 100644
--- a/services/network/proxy_resolving_client_socket.cc
+++ b/services/network/proxy_resolving_client_socket.cc
@@ -15,6 +15,7 @@
 #include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_address.h"
diff --git a/services/network/test/test_restricted_udp_socket.cc b/services/network/test/test_restricted_udp_socket.cc
index c4b089d..c22d065 100644
--- a/services/network/test/test_restricted_udp_socket.cc
+++ b/services/network/test/test_restricted_udp_socket.cc
@@ -4,7 +4,7 @@
 
 #include "services/network/test/test_restricted_udp_socket.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
diff --git a/services/network/test/test_udp_socket.cc b/services/network/test/test_udp_socket.cc
index 2da20da..0748184 100644
--- a/services/network/test/test_udp_socket.cc
+++ b/services/network/test/test_udp_socket.cc
@@ -4,7 +4,7 @@
 
 #include "services/network/test/test_udp_socket.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace network {
 
diff --git a/services/network/web_bundle/web_bundle_url_loader_factory.cc b/services/network/web_bundle/web_bundle_url_loader_factory.cc
index 005a853..6d7f1064 100644
--- a/services/network/web_bundle/web_bundle_url_loader_factory.cc
+++ b/services/network/web_bundle/web_bundle_url_loader_factory.cc
@@ -9,6 +9,7 @@
 
 #include "base/functional/callback.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/services/preferences/public/cpp/tracked/pref_names.cc b/services/preferences/public/cpp/tracked/pref_names.cc
index e9b44250..395e8a30 100644
--- a/services/preferences/public/cpp/tracked/pref_names.cc
+++ b/services/preferences/public/cpp/tracked/pref_names.cc
@@ -10,4 +10,7 @@
 // a preference was reset.
 const char kPreferenceResetTime[] = "prefs.preference_reset_time";
 
+// Pref that can be set to trigger a write of the preference file to disk. It
+// stores a string representation of the time of the last scheduled flush.
+const char kScheduleToFlushToDisk[] = "schedule_to_flush_to_disk";
 }  // namespace user_prefs
diff --git a/services/preferences/public/cpp/tracked/pref_names.h b/services/preferences/public/cpp/tracked/pref_names.h
index f6289716..21f24bd 100644
--- a/services/preferences/public/cpp/tracked/pref_names.h
+++ b/services/preferences/public/cpp/tracked/pref_names.h
@@ -9,6 +9,7 @@
 
 extern const char kPreferenceResetTime[];
 
+extern const char kScheduleToFlushToDisk[];
 }  // namespace user_prefs
 
 #endif  // SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_PREF_NAMES_H_
diff --git a/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc b/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc
index 4d678c0..f83d7ac6 100644
--- a/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc
+++ b/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc
@@ -21,7 +21,29 @@
 const char kTrackedPrefHistogramWantedReset[] =
     "Settings.TrackedPreferenceWantedReset";
 const char kTrackedPrefHistogramReset[] = "Settings.TrackedPreferenceReset";
+const char kTrackedPrefHistogramResetViaHmacFallback[] =
+    "Settings.TrackedPreferenceResetViaHmacFallback";
+const char kTrackedPrefHistogramResetEncrypted[] =
+    "Settings.TrackedPreferenceResetEncrypted";
 const char kTrackedPrefRegistryValidationSuffix[] = "FromRegistry";
 
+const char kTrackedPrefHistogramWantedResetViaHmacFallback[] =
+    "Settings.TrackedPreferenceWantedResetViaHmacFallback";
+const char kTrackedPrefHistogramWantedResetEncrypted[] =
+    "Settings.TrackedPreferenceWantedResetEncrypted";
+
+const char kTrackedPrefHistogramUnchangedEncrypted[] =
+    "Settings.TrackedPreferenceUnchangedEncrypted";
+const char kTrackedPrefHistogramClearedEncrypted[] =
+    "Settings.TrackedPreferenceClearedEncrypted";
+const char kTrackedPrefHistogramChangedEncrypted[] =
+    "Settings.TrackedPreferenceChangedEncrypted";
+
+const char kTrackedPrefHistogramUnchangedViaHmacFallback[] =
+    "Settings.TrackedPreferenceUnchangedViaHmacFallback";
+const char kTrackedPrefHistogramClearedViaHmacFallback[] =
+    "Settings.TrackedPreferenceClearedViaHmacFallback";
+const char kTrackedPrefHistogramChangedViaHmacFallback[] =
+    "Settings.TrackedPreferenceChangedViaHmacFallback";
 }  // namespace tracked
 }  // namespace user_prefs
diff --git a/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h b/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h
index d440398..3800e21c 100644
--- a/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h
+++ b/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h
@@ -16,7 +16,19 @@
 extern const char kTrackedPrefHistogramNullInitialized[];
 extern const char kTrackedPrefHistogramWantedReset[];
 extern const char kTrackedPrefHistogramReset[];
+extern const char kTrackedPrefHistogramResetViaHmacFallback[];
+extern const char kTrackedPrefHistogramResetEncrypted[];
 extern const char kTrackedPrefRegistryValidationSuffix[];
+extern const char kTrackedPrefHistogramWantedResetViaHmacFallback[];
+extern const char kTrackedPrefHistogramWantedResetEncrypted[];
+// Histograms for encrypted hash validation.
+extern const char kTrackedPrefHistogramUnchangedEncrypted[];
+extern const char kTrackedPrefHistogramClearedEncrypted[];
+extern const char kTrackedPrefHistogramChangedEncrypted[];
+// Histograms for HMAC validation fallback.
+extern const char kTrackedPrefHistogramUnchangedViaHmacFallback[];
+extern const char kTrackedPrefHistogramClearedViaHmacFallback[];
+extern const char kTrackedPrefHistogramChangedViaHmacFallback[];
 
 }  // namespace tracked
 }  // namespace user_prefs
diff --git a/services/preferences/public/mojom/tracked_preference_validation_delegate.mojom b/services/preferences/public/mojom/tracked_preference_validation_delegate.mojom
index c4ce51a2..1de5f9c 100644
--- a/services/preferences/public/mojom/tracked_preference_validation_delegate.mojom
+++ b/services/preferences/public/mojom/tracked_preference_validation_delegate.mojom
@@ -27,6 +27,27 @@
     TRUSTED_NULL_VALUE,
     // This transaction's store type is not supported.
     UNSUPPORTED,
+    // ---- Encrypted Hash Path States ----
+    // These are used when the encryptor is available and an encrypted hash is
+    // present.
+    // The preference value corresponds to its stored and valid ENCRYPTED HASH.
+    UNCHANGED_ENCRYPTED,
+    // The preference value has been changed, and its stored ENCRYPTED HASH is
+    // invalid or fails to decrypt.
+    CHANGED_ENCRYPTED,
+    // The preference has been cleared, but a stored ENCRYPTED HASH was found.
+    CLEARED_ENCRYPTED,
+
+    // ---- Encrypted Fallback PathStates ----
+    // These are used when the encryptor is available, but NO encrypted hash is
+    // present, so validation falls back to the legacy MAC.
+    // The preference value corresponds to its stored legacy MAC, signaling
+    // that an encrypted hash should be generated.
+    UNCHANGED_VIA_HMAC_FALLBACK,
+    // The preference value has been changed, and its legacy MAC is invalid.
+    CHANGED_VIA_HMAC_FALLBACK,
+    // The preference has been cleared since the last legacy MAC was stored.
+    CLEARED_VIA_HMAC_FALLBACK
   };
 
   // Notifies observes of the result (|value_state|) of checking the atomic
diff --git a/services/preferences/tracked/BUILD.gn b/services/preferences/tracked/BUILD.gn
index 2040481..7188263 100644
--- a/services/preferences/tracked/BUILD.gn
+++ b/services/preferences/tracked/BUILD.gn
@@ -56,11 +56,14 @@
   ]
 
   deps = [
+    ":features",
     "//base",
     "//build:branding_buildflags",
+    "//components/os_crypt/async/browser",
     "//components/os_crypt/async/common",
     "//components/pref_registry",
     "//components/prefs",
+    "//components/safe_browsing/core/common:features",
     "//crypto",
   ]
 
@@ -91,8 +94,23 @@
     "//components/os_crypt/async/browser:test_support",
     "//components/os_crypt/async/common",
     "//components/prefs:test_support",
+    "//components/safe_browsing/core/common:features",
+    "//components/sync_preferences:test_support",
     "//crypto:crypto",
     "//services/preferences/public/cpp/tracked:test_support",
     "//testing/gtest",
   ]
+
+  public_deps = [ ":features" ]
+}
+
+source_set("features") {
+  sources = [
+    "features.cc",
+    "features.h",
+  ]
+
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+
+  deps = [ "//base" ]
 }
diff --git a/services/preferences/tracked/DEPS b/services/preferences/tracked/DEPS
index 2620c26d..65b7be04 100644
--- a/services/preferences/tracked/DEPS
+++ b/services/preferences/tracked/DEPS
@@ -3,5 +3,6 @@
   "+crypto/hmac.h",
   '+components/os_crypt/async/browser',
   '+components/os_crypt/async/common',
+  '+components/safe_browsing/core/common',
   '+crypto',
 ]
diff --git a/services/preferences/tracked/features.cc b/services/preferences/tracked/features.cc
new file mode 100644
index 0000000..0ea3f8c
--- /dev/null
+++ b/services/preferences/tracked/features.cc
@@ -0,0 +1,15 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "services/preferences/tracked/features.h"
+
+#include "base/feature_list.h"
+
+namespace tracked {
+
+// Enables hashing of encrypted pref values for integrity checks.
+BASE_FEATURE(kEncryptedPrefHashing,
+             "EncryptedPrefHashing",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace tracked
diff --git a/services/preferences/tracked/features.h b/services/preferences/tracked/features.h
new file mode 100644
index 0000000..c93b388
--- /dev/null
+++ b/services/preferences/tracked/features.h
@@ -0,0 +1,17 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_PREFERENCES_TRACKED_FEATURES_H_
+#define SERVICES_PREFERENCES_TRACKED_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace tracked {
+
+// Enabled encrypted hashing for prefs.
+BASE_DECLARE_FEATURE(kEncryptedPrefHashing);
+
+}  // namespace tracked
+
+#endif  // SERVICES_PREFERENCES_TRACKED_FEATURES_H_
diff --git a/services/preferences/tracked/interceptable_pref_filter.cc b/services/preferences/tracked/interceptable_pref_filter.cc
index b9dc1de..7d4a311 100644
--- a/services/preferences/tracked/interceptable_pref_filter.cc
+++ b/services/preferences/tracked/interceptable_pref_filter.cc
@@ -7,9 +7,11 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/task/deferred_sequenced_task_runner.h"
+#include "base/task/sequenced_task_runner.h"
 
 InterceptablePrefFilter::InterceptablePrefFilter() {}
-InterceptablePrefFilter::~InterceptablePrefFilter() {}
+InterceptablePrefFilter::~InterceptablePrefFilter() = default;
 
 void InterceptablePrefFilter::FilterOnLoad(
     PostFilterOnLoadCallback post_filter_on_load_callback,
diff --git a/services/preferences/tracked/interceptable_pref_filter.h b/services/preferences/tracked/interceptable_pref_filter.h
index 069b8cc..204852c 100644
--- a/services/preferences/tracked/interceptable_pref_filter.h
+++ b/services/preferences/tracked/interceptable_pref_filter.h
@@ -7,7 +7,9 @@
 
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "base/task/deferred_sequenced_task_runner.h"
 #include "base/values.h"
+#include "components/os_crypt/async/common/encryptor.h"
 #include "components/prefs/pref_filter.h"
 
 // A partial implementation of a PrefFilter whose FilterOnLoad call may be
@@ -45,6 +47,8 @@
 
   void OnStoreDeletionFromDisk() override;
 
+  virtual void OnEncryptorReceived(os_crypt_async::Encryptor encryptor) = 0;
+
  private:
   // Does any extra filtering required by the implementation of this
   // InterceptablePrefFilter and hands back the |pref_store_contents| to the
diff --git a/services/preferences/tracked/interceptable_pref_filter_unittest.cc b/services/preferences/tracked/interceptable_pref_filter_unittest.cc
index 38bd960..bb24128fc 100644
--- a/services/preferences/tracked/interceptable_pref_filter_unittest.cc
+++ b/services/preferences/tracked/interceptable_pref_filter_unittest.cc
@@ -9,7 +9,9 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/weak_ptr.h"
+#include "base/test/task_environment.h"
 #include "base/values.h"
+#include "components/os_crypt/async/common/encryptor.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -33,6 +35,7 @@
   }
 
   void SetPrefService(PrefService* pref_service) override {}
+  void OnEncryptorReceived(os_crypt_async::Encryptor encryptor) override {}
 
   base::WeakPtr<InterceptablePrefFilter> AsWeakPtr() override {
     return weak_ptr_factory_.GetWeakPtr();
@@ -54,6 +57,7 @@
 }
 
 TEST(InterceptablePrefFilterTest, CallbackDeletes) {
+  base::test::TaskEnvironment task_environment;
   auto filter = std::make_unique<TestInterceptablePrefFilter>();
   filter->InterceptNextFilterOnLoad(base::BindOnce(&NoOpIntercept));
   filter->FilterOnLoad(base::BindOnce(&DeleteFilter, &filter),
diff --git a/services/preferences/tracked/pref_hash_filter.cc b/services/preferences/tracked/pref_hash_filter.cc
index d1c1c4e..37ecedc 100644
--- a/services/preferences/tracked/pref_hash_filter.cc
+++ b/services/preferences/tracked/pref_hash_filter.cc
@@ -10,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/check_is_test.h"
 #include "base/check_op.h"
 #include "base/functional/bind.h"
 #include "base/memory/weak_ptr.h"
@@ -21,11 +22,13 @@
 #include "base/values.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "components/os_crypt/async/browser/os_crypt_async.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/pref_store.h"
 #include "services/preferences/public/cpp/tracked/pref_names.h"
 #include "services/preferences/tracked/dictionary_hash_store_contents.h"
+#include "services/preferences/tracked/features.h"
 #include "services/preferences/tracked/pref_hash_store_transaction.h"
 #include "services/preferences/tracked/tracked_atomic_preference.h"
 #include "services/preferences/tracked/tracked_split_preference.h"
@@ -84,7 +87,8 @@
     scoped_refptr<base::RefCountedData<
         mojo::Remote<prefs::mojom::TrackedPreferenceValidationDelegate>>>
         delegate,
-    size_t reporting_ids_count)
+    size_t reporting_ids_count,
+    os_crypt_async::OSCryptAsync* os_crypt)
     : pref_hash_store_(std::move(pref_hash_store)),
       external_validation_hash_store_pair_(
           external_validation_hash_store_pair.first
@@ -92,7 +96,12 @@
                     std::move(external_validation_hash_store_pair))
               : std::nullopt),
       reset_on_load_observer_(std::move(reset_on_load_observer)),
-      delegate_(std::move(delegate)) {
+      delegate_(std::move(delegate)),
+      deferred_task_runner_(
+          base::MakeRefCounted<base::DeferredSequencedTaskRunner>(
+              base::SequencedTaskRunner::GetCurrentDefault())),
+      encrypted_hashing_enabled_(
+          base::FeatureList::IsEnabled(tracked::kEncryptedPrefHashing)) {
   DCHECK(pref_hash_store_);
   DCHECK_GE(reporting_ids_count, tracked_preferences.size());
   // Verify that, if |external_validation_hash_store_pair_| is present, both its
@@ -101,6 +110,11 @@
          (external_validation_hash_store_pair_->first &&
           external_validation_hash_store_pair_->second));
 
+  if (encrypted_hashing_enabled_ && os_crypt) {
+    os_crypt->GetInstance(
+        base::BindOnce(&InterceptablePrefFilter::OnEncryptorReceived,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
   prefs::mojom::TrackedPreferenceValidationDelegate* delegate_ptr =
       (delegate_ ? delegate_->data.get() : nullptr);
   for (size_t i = 0; i < tracked_preferences.size(); ++i) {
@@ -138,8 +152,9 @@
 
 void PrefHashFilter::SetPrefService(PrefService* pref_service) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // This should only be set once, shortly after construction.
-  DCHECK(!pref_service_);
+  if (pref_service_) {
+    CHECK_IS_TEST();
+  }
   pref_service_ = pref_service;
 }
 
@@ -150,6 +165,11 @@
   registry->RegisterStringPref(
       user_prefs::kPreferenceResetTime,
       base::NumberToString(base::Time().ToInternalValue()));
+  // Register the preference to trigger a flush to disk.
+  // It's a string preference to store a timestamp.
+  registry->RegisterStringPref(
+      user_prefs::kScheduleToFlushToDisk,
+      base::NumberToString(base::Time().ToInternalValue()));
 }
 
 // static
@@ -174,6 +194,7 @@
 }
 
 void PrefHashFilter::Initialize(base::Value::Dict& pref_store_contents) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DictionaryHashStoreContents dictionary_contents(pref_store_contents);
   std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
       pref_hash_store_->BeginTransaction(&dictionary_contents));
@@ -182,6 +203,9 @@
     const TrackedPreference* initialized_preference = it->second.get();
     const base::Value* value =
         pref_store_contents.FindByDottedPath(initialized_path);
+    // Initialize calls the 2-arg compatibility overload of
+    // TrackedPreference::OnNewValue. Because at this point, the encryptor is
+    // highly likely not ready yet.
     initialized_preference->OnNewValue(value, hash_store_transaction.get());
   }
 }
@@ -194,39 +218,64 @@
     changed_paths_.insert(std::make_pair(path, it->second.get()));
 }
 
+void PrefHashFilter::OnEncryptorReceived(os_crypt_async::Encryptor encryptor) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK(encrypted_hashing_enabled_ && deferred_task_runner_);
+  encryptor_.emplace(std::move(encryptor));
+  deferred_task_runner_->Start();
+}
+
 // Updates the stored hashes for |changed_paths_| before serializing data to
 // disk. This is required as storing the hash everytime a pref's value changes
 // is too expensive (see perf regression @ http://crbug.com/331273).
 PrefFilter::OnWriteCallbackPair PrefHashFilter::FilterSerializeData(
     base::Value::Dict& pref_store_contents) {
-  // Generate the callback pair before clearing |changed_paths_|.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   PrefFilter::OnWriteCallbackPair callback_pair =
       GetOnWriteSynchronousCallbacks(pref_store_contents);
 
   if (!changed_paths_.empty()) {
-    {
-      DictionaryHashStoreContents dictionary_contents(pref_store_contents);
-      std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
-          pref_hash_store_->BeginTransaction(&dictionary_contents));
+    const os_crypt_async::Encryptor* current_encryptor_ptr =
+        encryptor_.has_value() ? &encryptor_.value() : nullptr;
 
-      std::unique_ptr<PrefHashStoreTransaction>
-          external_validation_hash_store_transaction;
-      if (external_validation_hash_store_pair_) {
-        external_validation_hash_store_transaction =
-            external_validation_hash_store_pair_->first->BeginTransaction(
-                external_validation_hash_store_pair_->second.get());
-      }
+    DictionaryHashStoreContents dictionary_contents(pref_store_contents);
+    std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
+        pref_hash_store_->BeginTransaction(&dictionary_contents,
+                                           current_encryptor_ptr));
 
-      for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
-           it != changed_paths_.end(); ++it) {
-        const std::string& changed_path = it->first;
-        const TrackedPreference* changed_preference = it->second;
-        const base::Value* value =
-            pref_store_contents.FindByDottedPath(changed_path);
-        changed_preference->OnNewValue(value, hash_store_transaction.get());
-      }
-      changed_paths_.clear();
+    std::unique_ptr<PrefHashStoreTransaction>
+        external_validation_hash_store_transaction;
+    if (external_validation_hash_store_pair_) {
+      external_validation_hash_store_transaction =
+          external_validation_hash_store_pair_->first->BeginTransaction(
+              external_validation_hash_store_pair_->second.get(),
+              current_encryptor_ptr);
     }
+
+    auto process_paths = [&](const auto& paths_container) {
+      for (const auto& [path, preference] : paths_container) {
+        const base::Value* value = pref_store_contents.FindByDottedPath(path);
+        preference->OnNewValue(value, hash_store_transaction.get(),
+                               current_encryptor_ptr);
+      }
+    };
+    // If the encryptor is available, we must re-hash all tracked preferences to
+    // ensure they have an encrypted hash. This is the fallback step for
+    // profiles that were created before this feature was enabled.
+    if (current_encryptor_ptr) {
+      process_paths(tracked_paths_);
+    } else {
+      // If the feature is disabled/encryptor is not available, clear any
+      // existing encrypted hashes.
+      for (const auto& tracked_path : tracked_paths_) {
+        hash_store_transaction->ClearEncryptedHash(tracked_path.first);
+      }
+      // If the encryptor isn't available, fall back to the old behavior of only
+      // processing paths that have changed.
+      process_paths(changed_paths_);
+    }
+
+    changed_paths_.clear();
   }
 
   return callback_pair;
@@ -247,7 +296,11 @@
     PostFilterOnLoadCallback post_filter_on_load_callback,
     base::Value::Dict pref_store_contents,
     bool prefs_altered) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bool did_reset = false;
+
+  // Perform the initial synchronous validation pass (without the encryptor).
+  // This validates the super MAC and all individual preference MACs.
   {
     DictionaryHashStoreContents dictionary_contents(pref_store_contents);
     std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
@@ -287,10 +340,81 @@
   }
   reset_on_load_observer_.reset();
 
+  // If encrypted hashing is on, post a deferred task to re-validate with the
+  // encryptor once it's available. Pass a clone of the pref store contents
+  // so the task operates on the exact state at load time.
+  if (encrypted_hashing_enabled_ && !did_reset) {
+    deferred_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&PrefHashFilter::DeferredEncryptorRevalidation,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       pref_store_contents.Clone()));
+  } else {
+    // If the feature is disabled, and we have a test callback, run it now
+    // as no deferred task will be posted.
+    if (on_deferred_revalidation_complete_for_testing_) {
+      std::move(on_deferred_revalidation_complete_for_testing_).Run();
+    }
+  }
+
+  // Immediately call the callback with the original pref_store_contents to
+  // allow startup to proceed without waiting for the encryptor.
   std::move(post_filter_on_load_callback)
       .Run(std::move(pref_store_contents), prefs_altered);
 }
 
+void PrefHashFilter::DeferredEncryptorRevalidation(
+    base::Value::Dict pref_store_contents_at_load) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK(encryptor_.has_value());
+  const os_crypt_async::Encryptor* encryptor = &encryptor_.value();
+
+  // The transaction operates on our cloned dictionary from load time.
+  DictionaryHashStoreContents dictionary_contents(pref_store_contents_at_load);
+  std::unique_ptr<PrefHashStoreTransaction> transaction(
+      pref_hash_store_->BeginTransaction(&dictionary_contents, encryptor));
+
+  // Schedule a write to disk by updating a tracked preference. This is done to
+  // ensure the newly computed encrypted hashes are flushed to the pref store.
+  // This value will be replaced by another reset time stamp if there are any
+  // reset prefs.
+  std::string_view pref_to_write(user_prefs::kScheduleToFlushToDisk);
+
+  // First pass: Validate and reset any tampered preferences.
+  for (const auto& [path, preference] : tracked_paths_) {
+    if (!pref_service_->FindPreference(path)) {
+      continue;
+    }
+
+    const base::Value* value_at_load =
+        pref_store_contents_at_load.FindByDottedPath(path);
+    const base::Value* current_value = pref_service_->GetUserPrefValue(path);
+
+    // Compare the current value from pref service and the value from the copy
+    // of the loaded store. If the pref has been modified, we skip the
+    // encryption hash check.
+    if (current_value && (!value_at_load || *current_value != *value_at_load)) {
+      continue;
+    }
+
+    if (preference->EnforceAndReport(pref_store_contents_at_load,
+                                     transaction.get(),
+                                     nullptr /* external_tx */, encryptor)) {
+      // The preference was invalid. Reset the *live* preference. This action
+      // will mark the PrefService as dirty and automatically schedule a new
+      // write operation, during which new encrypted hashes will be generated.
+      pref_service_->ClearPref(path);
+      pref_to_write = user_prefs::kPreferenceResetTime;
+    }
+  }
+
+  pref_service_->SetString(
+      pref_to_write, base::NumberToString(base::Time::Now().ToInternalValue()));
+  if (on_deferred_revalidation_complete_for_testing_) {
+    std::move(on_deferred_revalidation_complete_for_testing_).Run();
+  }
+}
+
 base::WeakPtr<InterceptablePrefFilter> PrefHashFilter::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
@@ -341,6 +465,7 @@
 
 PrefFilter::OnWriteCallbackPair PrefHashFilter::GetOnWriteSynchronousCallbacks(
     base::Value::Dict& pref_store_contents) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (changed_paths_.empty() || !external_validation_hash_store_pair_) {
     return std::make_pair(base::OnceClosure(),
                           base::OnceCallback<void(bool success)>());
@@ -395,6 +520,12 @@
                      std::move(changed_paths_macs)));
 }
 
+void PrefHashFilter::SetOnDeferredRevalidationCompleteForTesting(
+    base::OnceClosure callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  on_deferred_revalidation_complete_for_testing_ = std::move(callback);
+}
+
 // static
 void PrefHashFilter::SetDeprecatedPrefsForTesting(
     const std::vector<const char*>& deprecated_prefs) {
diff --git a/services/preferences/tracked/pref_hash_filter.h b/services/preferences/tracked/pref_hash_filter.h
index ff7dcbd..0e6a80e 100644
--- a/services/preferences/tracked/pref_hash_filter.h
+++ b/services/preferences/tracked/pref_hash_filter.h
@@ -21,6 +21,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/task/deferred_sequenced_task_runner.h"
 #include "base/values.h"
 #include "components/prefs/transparent_unordered_string_map.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -53,6 +54,11 @@
   using StoreContentsPair = std::pair<std::unique_ptr<PrefHashStore>,
                                       std::unique_ptr<HashStoreContents>>;
 
+  // A map from changed paths to their corresponding TrackedPreferences (which
+  // aren't owned by this map).
+  using ChangedPathsMap =
+      std::map<std::string, raw_ptr<const TrackedPreference, CtnExperimental>>;
+
   // Constructs a PrefHashFilter tracking the specified |tracked_preferences|
   // using |pref_hash_store| to check/store hashes. An optional |delegate| is
   // notified of the status of each preference as it is checked.
@@ -62,6 +68,10 @@
   // than |tracked_preferences.size()|).
   // |external_validation_hash_store_pair_| will be used (if non-null) to
   // perform extra validations without triggering resets.
+  // |os_crypt| provides an asynchronous interface to OS-level encryption for
+  // storing an additional encrypted hash if kEncryptedPrefHashing is enabled.
+  // The encryptor could be null on start-up but it will be retrieved
+  // asynchronously.
   PrefHashFilter(
       std::unique_ptr<PrefHashStore> pref_hash_store,
       StoreContentsPair external_validation_hash_store_pair_,
@@ -72,7 +82,8 @@
       scoped_refptr<base::RefCountedData<
           mojo::Remote<prefs::mojom::TrackedPreferenceValidationDelegate>>>
           delegate,
-      size_t reporting_ids_count);
+      size_t reporting_ids_count,
+      os_crypt_async::OSCryptAsync* os_crypt);
 
   PrefHashFilter(const PrefHashFilter&) = delete;
   PrefHashFilter& operator=(const PrefHashFilter&) = delete;
@@ -105,6 +116,10 @@
   static void SetDeprecatedPrefsForTesting(
       const std::vector<const char*>& deprecated_prefs);
 
+  // Sets a callback to be run for testing purposes when deferred revalidation
+  // is complete.
+  void SetOnDeferredRevalidationCompleteForTesting(base::OnceClosure callback);
+
   // Sets the PrefService that owns this filter. This must be called after
   // construction and before any deferred tasks can run that might need it.
   void SetPrefService(PrefService* pref_service) override;
@@ -137,6 +152,13 @@
       std::unique_ptr<base::Value::Dict> changed_paths_and_macs,
       bool write_success);
 
+  void OnEncryptorReceived(os_crypt_async::Encryptor encryptor) override;
+
+  // Performs the deferred work of re-validating preferences after the
+  // encryptor has been fetched. This is posted from FinalizeFilterOnLoad.
+  void DeferredEncryptorRevalidation(
+      base::Value::Dict pref_store_contents_at_load);
+
   // Callback to be invoked only once (and subsequently reset) on the next
   // FilterOnLoad event. It will be allowed to modify the |prefs| handed to
   // FilterOnLoad before handing them back to this PrefHashFilter.
@@ -147,11 +169,6 @@
   using TrackedPreferencesMap =
       TransparentUnorderedStringMap<std::unique_ptr<TrackedPreference>>;
 
-  // A map from changed paths to their corresponding TrackedPreferences (which
-  // aren't owned by this map).
-  using ChangedPathsMap =
-      std::map<std::string, raw_ptr<const TrackedPreference, CtnExperimental>>;
-
   std::unique_ptr<PrefHashStore> pref_hash_store_;
 
   // A store and contents on which to perform extra validations without
@@ -171,12 +188,24 @@
   // FilterSerializeData.
   ChangedPathsMap changed_paths_;
 
+  // A deferred task runner to defer and start the async encryptor related
+  // validation task.
+  scoped_refptr<base::DeferredSequencedTaskRunner> deferred_task_runner_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   // A raw pointer to the PrefService that owns this filter. This is safe
   // because the PrefService is guaranteed to outlive this filter.
   raw_ptr<PrefService> pref_service_ = nullptr;
 
+  const bool encrypted_hashing_enabled_;
+  std::optional<os_crypt_async::Encryptor> encryptor_
+      GUARDED_BY_CONTEXT(sequence_checker_);
+
+  // A callback to be run for testing purposes when deferred revalidation is
+  // complete.
+  base::OnceClosure on_deferred_revalidation_complete_for_testing_;
+
   base::WeakPtrFactory<PrefHashFilter> weak_ptr_factory_{this};
 };
 
diff --git a/services/preferences/tracked/pref_hash_filter_unittest.cc b/services/preferences/tracked/pref_hash_filter_unittest.cc
index 3fbc1a1a..9047368 100644
--- a/services/preferences/tracked/pref_hash_filter_unittest.cc
+++ b/services/preferences/tracked/pref_hash_filter_unittest.cc
@@ -22,14 +22,22 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
+#include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/values.h"
+#include "components/os_crypt/async/browser/test_utils.h"
+#include "components/os_crypt/async/common/encryptor.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/prefs/testing_pref_store.h"
+#include "components/safe_browsing/core/common/features.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "services/preferences/public/cpp/tracked/configuration.h"
 #include "services/preferences/public/cpp/tracked/mock_validation_delegate.h"
 #include "services/preferences/public/cpp/tracked/pref_names.h"
+#include "services/preferences/tracked/features.h"
 #include "services/preferences/tracked/hash_store_contents.h"
 #include "services/preferences/tracked/pref_hash_store.h"
 #include "services/preferences/tracked/pref_hash_store_transaction.h"
@@ -54,6 +62,7 @@
 const char kReportOnlyPref[] = "report_only";
 const char kReportOnlySplitPref[] = "report_only_split_pref";
 const char kSplitPref[] = "split_pref";
+const char kScheduleToFlushToDisk[] = "schedule_to_flush_to_disk";
 
 const prefs::TrackedPreferenceMetadata kTestTrackedPrefs[] = {
     {0, kAtomicPref, EnforcementLevel::ENFORCE_ON_LOAD,
@@ -83,6 +92,7 @@
   MockPrefHashStore()
       : stamp_super_mac_result_(false),
         is_super_mac_valid_result_(false),
+        store_encrypted_hash_called_(false),
         transactions_performed_(0),
         transaction_active_(false) {}
 
@@ -108,6 +118,10 @@
     stamp_super_mac_result_ = result;
   }
 
+  bool StoreEncryptedHashCalled() const { return store_encrypted_hash_called_; }
+
+  void ClearTestState() { checked_values_.clear(); }
+
   // Sets the value that will be returned from
   // PrefHashStoreTransaction::IsSuperMACValid().
   void set_is_super_mac_valid_result(bool result) {
@@ -121,7 +135,7 @@
   size_t checked_paths_count() const { return checked_values_.size(); }
 
   // Returns the number of paths stored.
-  size_t stored_paths_count() const { return stored_values_.size(); }
+  size_t stored_paths_count() const { return owned_stored_values_.size(); }
 
   // Returns the pointer value and strategy that was passed to
   // |CheckHash/CheckSplitHash| for |path|. The returned pointer could since
@@ -139,10 +153,10 @@
   // |path|. The returned pointer could since have been freed and is thus not
   // safe to dereference.
   ValuePtrStrategyPair stored_value(const std::string& path) const {
-    std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
-        stored_values_.find(path);
-    if (value != stored_values_.end())
-      return value->second;
+    auto it = owned_stored_values_.find(path);
+    if (it != owned_stored_values_.end()) {
+      return std::make_pair(it->second.first.get(), it->second.second);
+    }
     return std::make_pair(reinterpret_cast<void*>(0xBAD),
                           static_cast<PrefTrackingStrategy>(-1));
   }
@@ -169,6 +183,8 @@
       const base::Value::Dict* split_values,
       const os_crypt_async::Encryptor* encryptor_ptr) override;
 
+  void SetTransactionCompletionCallback(base::OnceClosure callback);
+
  private:
   // A MockPrefHashStoreTransaction is handed to the caller on
   // MockPrefHashStore::BeginTransaction(). It then stores state in its
@@ -186,6 +202,11 @@
     ~MockPrefHashStoreTransaction() override {
       outer_->transaction_active_ = false;
       ++outer_->transactions_performed_;
+      if (outer_->completion_callback_) {
+        // Post a task to avoid potential re-entrancy issues.
+        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+            FROM_HERE, std::move(outer_->completion_callback_));
+      }
     }
 
     // PrefHashStoreTransaction implementation.
@@ -203,10 +224,13 @@
     bool HasHash(const std::string& path) const override;
     void ImportHash(const std::string& path, const base::Value* hash) override;
     void ClearHash(const std::string& path) override;
+    void ClearEncryptedHash(const std::string& path) override;
     bool IsSuperMACValid() const override;
     bool StampSuperMac() override;
     void StoreEncryptedHash(const std::string& path,
                             const base::Value* value) override {
+      outer_->store_encrypted_hash_called_ = true;
+
       // Record this like a normal store operation in this simple mock.
       // Pass the base value pointer directly.
       outer_->RecordStoreHash(path, value, PrefTrackingStrategy::ATOMIC);
@@ -216,6 +240,7 @@
     }
     void StoreSplitEncryptedHash(const std::string& path,
                                  const base::Value::Dict* value) override {
+      outer_->store_encrypted_hash_called_ = true;
       // Record this like a normal store operation in this simple mock.
       // Pass the base value pointer directly.
       outer_->RecordStoreHash(path, value, PrefTrackingStrategy::SPLIT);
@@ -251,9 +276,14 @@
 
   bool stamp_super_mac_result_;
   bool is_super_mac_valid_result_;
+  bool store_encrypted_hash_called_;
+  base::OnceClosure completion_callback_;
 
   std::map<std::string, ValuePtrStrategyPair> checked_values_;
   std::map<std::string, ValuePtrStrategyPair> stored_values_;
+  std::map<std::string,
+           std::pair<std::unique_ptr<base::Value>, PrefTrackingStrategy>>
+      owned_stored_values_;
 
   // Number of transactions that were performed via this MockPrefHashStore.
   size_t transactions_performed_;
@@ -355,16 +385,25 @@
 }
 
 void MockPrefHashStore::RecordStoreHash(const std::string& path,
-                                        const void* new_value,
+                                        const void* new_value_ptr,
                                         PrefTrackingStrategy strategy) {
-  EXPECT_TRUE(
-      stored_values_
-          .insert(std::make_pair(path, std::make_pair(new_value, strategy)))
-          .second);
+  const base::Value* value_to_store =
+      static_cast<const base::Value*>(new_value_ptr);
+  std::unique_ptr<base::Value> owned_copy;
+
+  if (value_to_store) {
+    owned_copy = std::make_unique<base::Value>(
+        value_to_store->Clone());  // Store a CLONE
+  }
+
+  // Store the unique_ptr (which might be null if new_value_ptr was null)
+  // and the strategy. For simplicity, assuming overwrite is fine or paths are
+  // unique per transaction.
+  owned_stored_values_[path] = std::make_pair(std::move(owned_copy), strategy);
 }
 
 void MockPrefHashStore::ClearStoreHash(const std::string& path) {
-  stored_values_.erase(path);
+  owned_stored_values_.erase(path);
 }
 
 std::string_view
@@ -427,6 +466,13 @@
   outer_->ClearStoreHash(path);
 }
 
+void MockPrefHashStore::MockPrefHashStoreTransaction::ClearEncryptedHash(
+    const std::string& encrypted_path) {
+  // Allow this to be called by PrefHashFilter's deprecated tracked prefs
+  // cleanup tasks.
+  outer_->ClearStoreHash(encrypted_path);
+}
+
 bool MockPrefHashStore::MockPrefHashStoreTransaction::IsSuperMACValid() const {
   return outer_->is_super_mac_valid_result_;
 }
@@ -435,6 +481,11 @@
   return outer_->stamp_super_mac_result_;
 }
 
+void MockPrefHashStore::SetTransactionCompletionCallback(
+    base::OnceClosure callback) {
+  completion_callback_ = std::move(callback);
+}
+
 std::vector<prefs::mojom::TrackedPreferenceMetadataPtr> GetConfiguration(
     EnforcementLevel max_enforcement_level) {
   auto configuration = prefs::ConstructTrackedConfiguration(kTestTrackedPrefs);
@@ -635,21 +686,65 @@
   PrefHashFilterTest& operator=(const PrefHashFilterTest&) = delete;
 
   void SetUp() override {
+    // By default, initialize with a synchronous OSCrypt instance for existing
+    // tests.
+    InitializeSyncOSCrypt();
     Reset();
   }
 
- protected:
-  // Reset the PrefHashFilter instance.
+  // Resets to the default state (feature off).
   void Reset() {
-    // Construct a PrefHashFilter and MockPrefHashStore for the test.
-    InitializePrefHashFilter(GetConfiguration(GetParam()));
+    ResetImpl(false /* enable_encrypted_hashing_feature */,
+              test_os_crypt_async_.get());
+  }
+
+  // The main reset implementation, allowing tests to control the feature flag
+  // and the OSCrypt instance.
+  void ResetImpl(bool enable_encrypted_hashing_feature,
+                 os_crypt_async::OSCryptAsync* os_crypt_instance_to_use) {
+    feature_list_.Reset();  // Clear previous ScopedFeatureList state
+    if (enable_encrypted_hashing_feature) {
+      feature_list_.InitAndEnableFeature(tracked::kEncryptedPrefHashing);
+    } else {
+      feature_list_.InitAndDisableFeature(tracked::kEncryptedPrefHashing);
+    }
+    InitializePrefHashFilter(GetConfiguration(GetParam()),
+                             os_crypt_instance_to_use);
+  }
+
+  // Stores |prefs| back in |pref_store_contents| and ensure
+  // |expected_schedule_write| matches the reported |schedule_write|.
+  void GetPrefsBack(bool expected_schedule_write,
+                    base::Value::Dict prefs,
+                    bool schedule_write) {
+    pref_store_contents_ = std::move(prefs);
+    EXPECT_EQ(expected_schedule_write, schedule_write);
+  }
+
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  std::unique_ptr<os_crypt_async::OSCryptAsync> test_os_crypt_async_;
+
+ protected:
+  // Initializes a TestOSCryptAsync instance that will provide its encryptor
+  // asynchronously.
+  void InitializeAsyncOSCrypt() {
+    test_os_crypt_async_ = os_crypt_async::GetTestOSCryptAsyncForTesting(
+        false /* is_sync_default */);
+  }
+
+  // Initializes a TestOSCryptAsync instance that provides its encryptor
+  // synchronously upon request.
+  void InitializeSyncOSCrypt() {
+    test_os_crypt_async_ = os_crypt_async::GetTestOSCryptAsyncForTesting(
+        true /* is_sync_default */);
   }
 
   // Initializes |pref_hash_filter_| with a PrefHashFilter that uses a
   // MockPrefHashStore. The raw pointer to the MockPrefHashStore (owned by the
   // PrefHashFilter) is stored in |mock_pref_hash_store_|.
   void InitializePrefHashFilter(
-      std::vector<prefs::mojom::TrackedPreferenceMetadataPtr> configuration) {
+      std::vector<prefs::mojom::TrackedPreferenceMetadataPtr> configuration,
+      os_crypt_async::OSCryptAsync* os_crypt) {
     std::unique_ptr<MockPrefHashStore> temp_mock_pref_hash_store(
         new MockPrefHashStore);
     std::unique_ptr<MockPrefHashStore>
@@ -662,6 +757,10 @@
         temp_mock_external_validation_pref_hash_store.get();
     mock_external_validation_hash_store_contents_ =
         temp_mock_external_validation_hash_store_contents.get();
+
+    validation_delegate_receiver_.reset();
+    reset_on_load_observer_receivers_.Clear();
+
     mojo::PendingRemote<prefs::mojom::ResetOnLoadObserver>
         reset_on_load_observer;
     reset_on_load_observer_receivers_.Add(
@@ -679,8 +778,8 @@
             std::move(temp_mock_external_validation_pref_hash_store),
             std::move(temp_mock_external_validation_hash_store_contents)),
         std::move(configuration), std::move(reset_on_load_observer),
-        std::move(validation_delegate_remote_ref),
-        std::size(kTestTrackedPrefs));
+        std::move(validation_delegate_remote_ref), std::size(kTestTrackedPrefs),
+        os_crypt);
   }
 
   // Verifies whether a reset was reported by the PrefHashFiler. Also verifies
@@ -696,14 +795,11 @@
   // handed off, but should be given back to us synchronously through
   // GetPrefsBack() as there is no FilterOnLoadInterceptor installed on
   // |pref_hash_filter_|.
-  void DoFilterOnLoad(bool expect_prefs_modifications) {
+  void DoFilterOnLoad(bool expected_final_prefs_altered) {
     pref_hash_filter_->FilterOnLoad(
         base::BindOnce(&PrefHashFilterTest::GetPrefsBack,
-                       base::Unretained(this), expect_prefs_modifications),
+                       base::Unretained(this), expected_final_prefs_altered),
         std::move(pref_store_contents_));
-    // `mock_pref_hash_store_` is updated over an in-process mojo interface,
-    // flush pending tasks to make sure everything is up to date after this
-    // call.
     task_environment_.RunUntilIdle();
   }
 
@@ -717,15 +813,6 @@
   std::unique_ptr<PrefHashFilter> pref_hash_filter_;
 
  private:
-  // Stores |prefs| back in |pref_store_contents| and ensure
-  // |expected_schedule_write| matches the reported |schedule_write|.
-  void GetPrefsBack(bool expected_schedule_write,
-                    base::Value::Dict prefs,
-                    bool schedule_write) {
-    pref_store_contents_ = std::move(prefs);
-    EXPECT_EQ(expected_schedule_write, schedule_write);
-  }
-
   void OnResetOnLoad() override {
     // As-is |reset_recorded_| is only designed to remember a single reset, make
     // sure none was previously recorded.
@@ -733,7 +820,7 @@
     reset_recorded_ = true;
   }
 
-  base::test::SingleThreadTaskEnvironment task_environment_;
+  base::test::ScopedFeatureList feature_list_;
   MockValidationDelegate mock_validation_delegate_;
   mojo::Receiver<prefs::mojom::TrackedPreferenceValidationDelegate>
       validation_delegate_receiver_;
@@ -775,18 +862,28 @@
 
 TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) {
   base::Value::Dict root_dict;
-  base::Value* string_value = root_dict.Set(kAtomicPref, "string value");
+  std::string expected_string_content = "string value";
+  root_dict.Set(kAtomicPref, expected_string_content);
 
   // No path should be stored on FilterUpdate.
   pref_hash_filter_->FilterUpdate(kAtomicPref);
   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
 
   // One path should be stored on FilterSerializeData.
+  base::RunLoop run_loop;
+  mock_pref_hash_store_->SetTransactionCompletionCallback(
+      run_loop.QuitClosure());
   pref_hash_filter_->FilterSerializeData(root_dict);
+  run_loop.Run();  // Ensure any posted tasks are run
   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
   MockPrefHashStore::ValuePtrStrategyPair stored_value =
       mock_pref_hash_store_->stored_value(kAtomicPref);
-  ASSERT_EQ(string_value, stored_value.first);
+  // Compare value content, not pointer
+  ASSERT_TRUE(stored_value.first);
+  const base::Value* actual_stored_value =
+      static_cast<const base::Value*>(stored_value.first);
+  ASSERT_TRUE(actual_stored_value->is_string());
+  EXPECT_EQ(expected_string_content, actual_stored_value->GetString());
   ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value.second);
 
   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
@@ -816,22 +913,31 @@
 
 TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
   base::Value::Dict root_dict;
-  base::Value::Dict& dict_value =
-      root_dict.Set(kSplitPref, base::Value::Dict())->GetDict();
-  dict_value.Set("a", "foo");
-  dict_value.Set("b", 1234);
-
+  // Store expected content
+  base::Value::Dict expected_dict_content;
+  expected_dict_content.Set("a", "foo");
+  expected_dict_content.Set("b", 1234);
+  root_dict.Set(kSplitPref, expected_dict_content.Clone());
   // No path should be stored on FilterUpdate.
   pref_hash_filter_->FilterUpdate(kSplitPref);
   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
 
   // One path should be stored on FilterSerializeData.
+  base::RunLoop run_loop;
+  mock_pref_hash_store_->SetTransactionCompletionCallback(
+      run_loop.QuitClosure());
   pref_hash_filter_->FilterSerializeData(root_dict);
+  run_loop.Run();
   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
-  MockPrefHashStore::ValuePtrStrategyPair stored_value =
+  MockPrefHashStore::ValuePtrStrategyPair stored_value_info =
       mock_pref_hash_store_->stored_value(kSplitPref);
-  ASSERT_EQ(&dict_value, stored_value.first);
-  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value.second);
+  ASSERT_TRUE(stored_value_info.first);
+  const base::Value* actual_stored_value =
+      static_cast<const base::Value*>(stored_value_info.first);
+  ASSERT_TRUE(actual_stored_value->is_dict());
+  // Compare dictionary contents directly.
+  EXPECT_EQ(expected_dict_content, actual_stored_value->GetDict());
+  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value_info.second);
 
   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
   VerifyRecordedReset(false);
@@ -877,42 +983,60 @@
 
 TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
   base::Value::Dict root_dict;
-  base::Value* int_value1 = root_dict.Set(kAtomicPref, 1);
+  int expected_atomic_val = 1;
+  int expected_atomic3_val = 5;
+  base::Value::Dict expected_split_dict_content;
+  expected_split_dict_content.Set("a", true);
+
+  root_dict.Set(kAtomicPref, expected_atomic_val);
   root_dict.Set(kAtomicPref2, 2);
   root_dict.Set(kAtomicPref3, 3);
   root_dict.Set("untracked", 4);
-  base::Value* dict_value = root_dict.Set(kSplitPref, base::Value::Dict());
-  dict_value->GetDict().Set("a", true);
-
+  root_dict.Set(kSplitPref, expected_split_dict_content.Clone());
   // Only update kAtomicPref, kAtomicPref3, and kSplitPref.
   pref_hash_filter_->FilterUpdate(kAtomicPref);
   pref_hash_filter_->FilterUpdate(kAtomicPref3);
   pref_hash_filter_->FilterUpdate(kSplitPref);
-  ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+  root_dict.Set(kAtomicPref3, expected_atomic3_val);
 
-  // Update kAtomicPref3 again, nothing should be stored still.
-  base::Value* int_value5 = root_dict.Set(kAtomicPref3, 5);
-  ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-
-  // On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref
-  // should get a new hash.
+  base::RunLoop run_loop;
+  mock_pref_hash_store_->SetTransactionCompletionCallback(
+      run_loop.QuitClosure());
   pref_hash_filter_->FilterSerializeData(root_dict);
+  run_loop.Run();
+
   ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count());
-  MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 =
-      mock_pref_hash_store_->stored_value(kAtomicPref);
-  ASSERT_EQ(int_value1, stored_value_atomic1.first);
-  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic1.second);
   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
 
-  MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 =
-      mock_pref_hash_store_->stored_value(kAtomicPref3);
-  ASSERT_EQ(int_value5, stored_value_atomic3.first);
-  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic3.second);
+  // Verify kAtomicPref
+  MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1_info =
+      mock_pref_hash_store_->stored_value(kAtomicPref);
+  ASSERT_TRUE(stored_value_atomic1_info.first);
+  const base::Value* actual_atomic1 =
+      static_cast<const base::Value*>(stored_value_atomic1_info.first);
+  ASSERT_TRUE(actual_atomic1->is_int());
+  EXPECT_EQ(expected_atomic_val, actual_atomic1->GetInt());
+  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic1_info.second);
 
-  MockPrefHashStore::ValuePtrStrategyPair stored_value_split =
+  // Verify kAtomicPref3
+  MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3_info =
+      mock_pref_hash_store_->stored_value(kAtomicPref3);
+  ASSERT_TRUE(stored_value_atomic3_info.first);
+  const base::Value* actual_atomic3 =
+      static_cast<const base::Value*>(stored_value_atomic3_info.first);
+  ASSERT_TRUE(actual_atomic3->is_int());
+  EXPECT_EQ(expected_atomic3_val, actual_atomic3->GetInt());
+  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic3_info.second);
+
+  // Verify kSplitPref
+  MockPrefHashStore::ValuePtrStrategyPair stored_value_split_info =
       mock_pref_hash_store_->stored_value(kSplitPref);
-  ASSERT_EQ(dict_value, stored_value_split.first);
-  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value_split.second);
+  ASSERT_TRUE(stored_value_split_info.first);
+  const base::Value* actual_split =
+      static_cast<const base::Value*>(stored_value_split_info.first);
+  ASSERT_TRUE(actual_split->is_dict());
+  EXPECT_EQ(expected_split_dict_content, actual_split->GetDict());
+  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value_split_info.second);
 }
 
 TEST_P(PrefHashFilterTest, UnknownNullValue) {
@@ -959,17 +1083,13 @@
 }
 
 TEST_P(PrefHashFilterTest, InitialValueUnknown) {
-  base::Value* string_value =
-      pref_store_contents_.Set(kAtomicPref, "string value");
+  std::string expected_atomic_string_content = "string value";
+  base::Value::Dict expected_split_dict_content;
+  expected_split_dict_content.Set("a", "foo");
+  expected_split_dict_content.Set("b", 1234);
 
-  base::Value* value =
-      pref_store_contents_.Set(kSplitPref, base::Value::Dict());
-  ASSERT_TRUE(value->is_dict());
-
-  base::Value::Dict& dict_value = value->GetDict();
-
-  dict_value.Set("a", "foo");
-  dict_value.Set("b", 1234);
+  pref_store_contents_.Set(kAtomicPref, expected_atomic_string_content);
+  pref_store_contents_.Set(kSplitPref, expected_split_dict_content.Clone());
 
   ASSERT_TRUE(pref_store_contents_.contains(kAtomicPref));
   ASSERT_TRUE(pref_store_contents_.contains(kSplitPref));
@@ -985,7 +1105,6 @@
   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
 
-  // Delegate saw all prefs, two of which had the expected value_state.
   ASSERT_EQ(std::size(kTestTrackedPrefs),
             mock_validation_delegate_record_->recorded_validations_count());
   ASSERT_EQ(2u, mock_validation_delegate_record_->CountValidationsOfState(
@@ -994,50 +1113,57 @@
             mock_validation_delegate_record_->CountValidationsOfState(
                 ValueState::UNCHANGED));
 
-  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value_info =
       mock_pref_hash_store_->stored_value(kAtomicPref);
-  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value_info =
       mock_pref_hash_store_->stored_value(kSplitPref);
-  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
-  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value_info.second);
+  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value_info.second);
   if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) {
-    // Ensure the prefs were cleared and the hashes for nullptr were restored if
-    // the current enforcement level denies seeding.
     ASSERT_FALSE(pref_store_contents_.contains(kAtomicPref));
-    ASSERT_FALSE(stored_atomic_value.first);
-
+    ASSERT_FALSE(stored_atomic_value_info.first);
     ASSERT_FALSE(pref_store_contents_.contains(kSplitPref));
-    ASSERT_FALSE(stored_split_value.first);
-
+    ASSERT_FALSE(stored_split_value_info.first);
     VerifyRecordedReset(true);
-  } else {
-    // Otherwise the values should have remained intact and the hashes should
-    // have been updated to match them.
+  } else {  // NO_ENFORCEMENT
     const base::Value* atomic_value_in_store =
         pref_store_contents_.Find(kAtomicPref);
     ASSERT_TRUE(atomic_value_in_store);
-    ASSERT_EQ(string_value, atomic_value_in_store);
-    ASSERT_EQ(string_value, stored_atomic_value.first);
+    ASSERT_TRUE(atomic_value_in_store->is_string());
+    EXPECT_EQ(expected_atomic_string_content,
+              atomic_value_in_store->GetString());
+
+    ASSERT_TRUE(stored_atomic_value_info.first);
+    const base::Value* actual_stored_atomic =
+        static_cast<const base::Value*>(stored_atomic_value_info.first);
+    ASSERT_TRUE(actual_stored_atomic->is_string());
+    EXPECT_EQ(expected_atomic_string_content,
+              actual_stored_atomic->GetString());
 
     const base::Value* split_value_in_store =
         pref_store_contents_.Find(kSplitPref);
     ASSERT_TRUE(split_value_in_store);
-    ASSERT_EQ(value, split_value_in_store);
-    ASSERT_EQ(value, stored_split_value.first);
+    ASSERT_TRUE(split_value_in_store->is_dict());
+    EXPECT_EQ(expected_split_dict_content, split_value_in_store->GetDict());
+
+    ASSERT_TRUE(stored_split_value_info.first);
+    const base::Value* actual_stored_split =
+        static_cast<const base::Value*>(stored_split_value_info.first);
+    ASSERT_TRUE(actual_stored_split->is_dict());
+    EXPECT_EQ(expected_split_dict_content, actual_stored_split->GetDict());
 
     VerifyRecordedReset(false);
   }
 }
 
 TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
-  base::Value* string_value = pref_store_contents_.Set(kAtomicPref, "test");
+  std::string expected_atomic_string_content = "test";
+  base::Value::Dict expected_split_dict_content;
+  expected_split_dict_content.Set("a", "foo");
+  expected_split_dict_content.Set("b", 1234);
 
-  auto* value = pref_store_contents_.Set(kSplitPref, base::Value::Dict());
-  ASSERT_TRUE(value->is_dict());
-
-  auto& dict_value = value->GetDict();
-  dict_value.Set("a", "foo");
-  dict_value.Set("b", 1234);
+  pref_store_contents_.Set(kAtomicPref, expected_atomic_string_content);
+  pref_store_contents_.Set(kSplitPref, expected_split_dict_content.Clone());
 
   ASSERT_TRUE(pref_store_contents_.contains(kAtomicPref));
   ASSERT_TRUE(pref_store_contents_.contains(kSplitPref));
@@ -1065,34 +1191,48 @@
   const base::Value* atomic_value_in_store =
       pref_store_contents_.Find(kAtomicPref);
   ASSERT_TRUE(atomic_value_in_store);
-  ASSERT_EQ(string_value, atomic_value_in_store);
-  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+  ASSERT_TRUE(atomic_value_in_store->is_string());
+  EXPECT_EQ(expected_atomic_string_content, atomic_value_in_store->GetString());
+
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value_info =
       mock_pref_hash_store_->stored_value(kAtomicPref);
-  ASSERT_EQ(string_value, stored_atomic_value.first);
-  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
+  ASSERT_TRUE(stored_atomic_value_info.first);
+  const base::Value* actual_stored_atomic =
+      static_cast<const base::Value*>(stored_atomic_value_info.first);
+  ASSERT_TRUE(actual_stored_atomic->is_string());
+  EXPECT_EQ(expected_atomic_string_content, actual_stored_atomic->GetString());
+  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value_info.second);
 
   const base::Value* split_value_in_store =
       pref_store_contents_.Find(kSplitPref);
   ASSERT_TRUE(split_value_in_store);
-  ASSERT_EQ(value, split_value_in_store);
-  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+  ASSERT_TRUE(split_value_in_store->is_dict());
+  EXPECT_EQ(expected_split_dict_content, split_value_in_store->GetDict());
+
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value_info =
       mock_pref_hash_store_->stored_value(kSplitPref);
-  ASSERT_EQ(value, stored_split_value.first);
-  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+  ASSERT_TRUE(stored_split_value_info.first);
+  const base::Value* actual_stored_split =
+      static_cast<const base::Value*>(stored_split_value_info.first);
+  ASSERT_TRUE(actual_stored_split->is_dict());
+  EXPECT_EQ(expected_split_dict_content, actual_stored_split->GetDict());
+  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value_info.second);
 }
 
 TEST_P(PrefHashFilterTest, InitialValueChanged) {
-  base::Value* int_value = pref_store_contents_.Set(kAtomicPref, 1234);
+  int expected_atomic_int_content = 1234;
+  base::Value::Dict initial_split_dict_content;
+  initial_split_dict_content.Set("a", "foo");
+  initial_split_dict_content.Set("b", 1234);
+  initial_split_dict_content.Set("c", 56);
+  initial_split_dict_content.Set("d", false);
 
-  base::Value* value =
-      pref_store_contents_.Set(kSplitPref, base::Value::Dict());
-  ASSERT_TRUE(value->is_dict());
+  base::Value::Dict expected_final_split_dict_content;
+  expected_final_split_dict_content.Set("b", 1234);
+  expected_final_split_dict_content.Set("d", false);
 
-  base::Value::Dict& dict_value = value->GetDict();
-  dict_value.Set("a", "foo");
-  dict_value.Set("b", 1234);
-  dict_value.Set("c", 56);
-  dict_value.Set("d", false);
+  pref_store_contents_.Set(kAtomicPref, expected_atomic_int_content);
+  pref_store_contents_.Set(kSplitPref, initial_split_dict_content.Clone());
 
   ASSERT_TRUE(pref_store_contents_.contains(kAtomicPref));
   ASSERT_TRUE(pref_store_contents_.contains(kSplitPref));
@@ -1111,50 +1251,61 @@
   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
 
-  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value_info =
       mock_pref_hash_store_->stored_value(kAtomicPref);
-  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value_info =
       mock_pref_hash_store_->stored_value(kSplitPref);
-  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
-  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+  ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value_info.second);
+  ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value_info.second);
   if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) {
     // Ensure the atomic pref was cleared and the hash for nullptr was restored
     // if the current enforcement level prevents changes.
     ASSERT_FALSE(pref_store_contents_.contains(kAtomicPref));
-    ASSERT_FALSE(stored_atomic_value.first);
+    ASSERT_FALSE(stored_atomic_value_info.first);
 
     // The split pref on the other hand should only have been stripped of its
     // invalid keys.
     const base::Value* split_value_in_store =
         pref_store_contents_.Find(kSplitPref);
     ASSERT_TRUE(split_value_in_store);
-    ASSERT_EQ(2U, dict_value.size());
-    ASSERT_FALSE(dict_value.contains("a"));
-    ASSERT_TRUE(dict_value.contains("b"));
-    ASSERT_FALSE(dict_value.contains("c"));
-    ASSERT_TRUE(dict_value.contains("d"));
-    ASSERT_EQ(value, stored_split_value.first);
+    ASSERT_TRUE(split_value_in_store->is_dict());
+    EXPECT_EQ(expected_final_split_dict_content,
+              split_value_in_store->GetDict());
+
+    ASSERT_TRUE(stored_split_value_info.first);
+    const base::Value* actual_stored_split =
+        static_cast<const base::Value*>(stored_split_value_info.first);
+    ASSERT_TRUE(actual_stored_split->is_dict());
+    EXPECT_EQ(expected_final_split_dict_content,
+              actual_stored_split->GetDict());
 
     VerifyRecordedReset(true);
-  } else {
+  } else {  // NO_ENFORCEMENT
     // Otherwise the value should have remained intact and the hash should have
     // been updated to match it.
     const base::Value* atomic_value_in_store =
         pref_store_contents_.Find(kAtomicPref);
     ASSERT_TRUE(atomic_value_in_store);
-    ASSERT_EQ(int_value, atomic_value_in_store);
-    ASSERT_EQ(int_value, stored_atomic_value.first);
+    ASSERT_TRUE(atomic_value_in_store->is_int());
+    EXPECT_EQ(expected_atomic_int_content, atomic_value_in_store->GetInt());
+
+    ASSERT_TRUE(stored_atomic_value_info.first);
+    const base::Value* actual_stored_atomic =
+        static_cast<const base::Value*>(stored_atomic_value_info.first);
+    ASSERT_TRUE(actual_stored_atomic->is_int());
+    EXPECT_EQ(expected_atomic_int_content, actual_stored_atomic->GetInt());
 
     const base::Value* split_value_in_store =
         pref_store_contents_.Find(kSplitPref);
     ASSERT_TRUE(split_value_in_store);
-    ASSERT_EQ(value, split_value_in_store);
-    ASSERT_EQ(4U, dict_value.size());
-    ASSERT_TRUE(dict_value.contains("a"));
-    ASSERT_TRUE(dict_value.contains("b"));
-    ASSERT_TRUE(dict_value.contains("c"));
-    ASSERT_TRUE(dict_value.contains("d"));
-    ASSERT_EQ(value, stored_split_value.first);
+    ASSERT_TRUE(split_value_in_store->is_dict());
+    EXPECT_EQ(initial_split_dict_content, split_value_in_store->GetDict());
+
+    ASSERT_TRUE(stored_split_value_info.first);
+    const base::Value* actual_stored_split =
+        static_cast<const base::Value*>(stored_split_value_info.first);
+    ASSERT_TRUE(actual_stored_split->is_dict());
+    EXPECT_EQ(initial_split_dict_content, actual_stored_split->GetDict());
 
     VerifyRecordedReset(false);
   }
@@ -1196,18 +1347,17 @@
 }
 
 TEST_P(PrefHashFilterTest, DontResetReportOnly) {
-  base::Value* int_value1 = pref_store_contents_.Set(kAtomicPref, 1);
-  base::Value* int_value2 = pref_store_contents_.Set(kAtomicPref2, 2);
-  base::Value* report_only_val = pref_store_contents_.Set(kReportOnlyPref, 3);
-  base::Value* report_only_split_val =
-      pref_store_contents_.Set(kReportOnlySplitPref, base::Value::Dict());
-  ASSERT_TRUE(report_only_split_val->is_dict());
-  report_only_split_val->GetDict().Set("a", 1234);
+  int expected_atomic_val = 1;
+  int expected_atomic2_val = 2;
+  int expected_report_only_val = 3;
+  base::Value::Dict expected_report_only_split_val_content;
+  expected_report_only_split_val_content.Set("a", 1234);
 
-  ASSERT_TRUE(pref_store_contents_.contains(kAtomicPref));
-  ASSERT_TRUE(pref_store_contents_.contains(kAtomicPref2));
-  ASSERT_TRUE(pref_store_contents_.contains(kReportOnlyPref));
-  ASSERT_TRUE(pref_store_contents_.contains(kReportOnlySplitPref));
+  pref_store_contents_.Set(kAtomicPref, expected_atomic_val);
+  pref_store_contents_.Set(kAtomicPref2, expected_atomic2_val);
+  pref_store_contents_.Set(kReportOnlyPref, expected_report_only_val);
+  pref_store_contents_.Set(kReportOnlySplitPref,
+                           expected_report_only_split_val_content.Clone());
 
   mock_pref_hash_store_->SetCheckResult(kAtomicPref, ValueState::CHANGED);
   mock_pref_hash_store_->SetCheckResult(kAtomicPref2, ValueState::CHANGED);
@@ -1236,12 +1386,25 @@
   // be reset.
   ASSERT_TRUE(pref_store_contents_.contains(kReportOnlyPref));
   ASSERT_TRUE(pref_store_contents_.contains(kReportOnlySplitPref));
-  ASSERT_EQ(report_only_val,
-            mock_pref_hash_store_->stored_value(kReportOnlyPref).first);
-  ASSERT_EQ(report_only_split_val,
-            mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first);
 
-  // All other prefs should have been reset if the enforcement level allows it.
+  // Compare content for report-only prefs
+  MockPrefHashStore::ValuePtrStrategyPair stored_report_only_info =
+      mock_pref_hash_store_->stored_value(kReportOnlyPref);
+  ASSERT_TRUE(stored_report_only_info.first);
+  const base::Value* actual_stored_report_only =
+      static_cast<const base::Value*>(stored_report_only_info.first);
+  ASSERT_TRUE(actual_stored_report_only->is_int());
+  EXPECT_EQ(expected_report_only_val, actual_stored_report_only->GetInt());
+
+  MockPrefHashStore::ValuePtrStrategyPair stored_report_only_split_info =
+      mock_pref_hash_store_->stored_value(kReportOnlySplitPref);
+  ASSERT_TRUE(stored_report_only_split_info.first);
+  const base::Value* actual_stored_report_only_split =
+      static_cast<const base::Value*>(stored_report_only_split_info.first);
+  ASSERT_TRUE(actual_stored_report_only_split->is_dict());
+  EXPECT_EQ(expected_report_only_split_val_content,
+            actual_stored_report_only_split->GetDict());
+
   if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) {
     ASSERT_FALSE(pref_store_contents_.contains(kAtomicPref));
     ASSERT_FALSE(pref_store_contents_.contains(kAtomicPref2));
@@ -1249,18 +1412,31 @@
     ASSERT_FALSE(mock_pref_hash_store_->stored_value(kAtomicPref2).first);
 
     VerifyRecordedReset(true);
-  } else {
-    const base::Value* value_in_store = pref_store_contents_.Find(kAtomicPref);
-    const base::Value* value_in_store2 =
+  } else {  // NO_ENFORCEMENT
+    // Compare content for enforced prefs if not reset
+    const base::Value* atomic_val_in_store =
+        pref_store_contents_.Find(kAtomicPref);
+    ASSERT_TRUE(atomic_val_in_store && atomic_val_in_store->is_int());
+    EXPECT_EQ(expected_atomic_val, atomic_val_in_store->GetInt());
+    MockPrefHashStore::ValuePtrStrategyPair stored_atomic_info =
+        mock_pref_hash_store_->stored_value(kAtomicPref);
+    ASSERT_TRUE(stored_atomic_info.first);
+    const base::Value* actual_stored_atomic =
+        static_cast<const base::Value*>(stored_atomic_info.first);
+    ASSERT_TRUE(actual_stored_atomic->is_int());
+    EXPECT_EQ(expected_atomic_val, actual_stored_atomic->GetInt());
+
+    const base::Value* atomic2_val_in_store =
         pref_store_contents_.Find(kAtomicPref2);
-    ASSERT_TRUE(value_in_store);
-    ASSERT_TRUE(value_in_store2);
-    ASSERT_EQ(int_value1, value_in_store);
-    ASSERT_EQ(int_value1,
-              mock_pref_hash_store_->stored_value(kAtomicPref).first);
-    ASSERT_EQ(int_value2, value_in_store2);
-    ASSERT_EQ(int_value2,
-              mock_pref_hash_store_->stored_value(kAtomicPref2).first);
+    ASSERT_TRUE(atomic2_val_in_store && atomic2_val_in_store->is_int());
+    EXPECT_EQ(expected_atomic2_val, atomic2_val_in_store->GetInt());
+    MockPrefHashStore::ValuePtrStrategyPair stored_atomic2_info =
+        mock_pref_hash_store_->stored_value(kAtomicPref2);
+    ASSERT_TRUE(stored_atomic2_info.first);
+    const base::Value* actual_stored_atomic2 =
+        static_cast<const base::Value*>(stored_atomic2_info.first);
+    ASSERT_TRUE(actual_stored_atomic2->is_int());
+    EXPECT_EQ(expected_atomic2_val, actual_stored_atomic2->GetInt());
 
     VerifyRecordedReset(false);
   }
@@ -1415,3 +1591,147 @@
                          PrefHashFilterTest,
                          testing::Values(EnforcementLevel::NO_ENFORCEMENT,
                                          EnforcementLevel::ENFORCE_ON_LOAD));
+
+// A test fixture for the PrefHashFilter that specifically handles testing the
+// new encrypted hashing and deferred validation logic.
+class PrefHashFilterEncryptedTest : public PrefHashFilterTest {
+ public:
+  // Helper function to handle the deferred revalidation callback.
+  void OnDeferredRevalidationComplete(bool* callback_ran_flag,
+                                      base::OnceClosure quit_closure) {
+    *callback_ran_flag = true;
+    std::move(quit_closure).Run();
+  }
+
+ protected:
+  void SetUp() override {
+    // This fixture manually controls its setup, so the base SetUp is not
+    // needed.
+  }
+
+  void TearDown() override {
+    // Ensure the dependency is always broken after each test.
+    if (pref_hash_filter_) {
+      pref_hash_filter_->SetPrefService(nullptr);
+    }
+    PrefHashFilterTest::TearDown();
+  }
+
+  // A mock PrefService that allows us to observe calls to ClearPref.
+  class MockPrefService : public TestingPrefServiceSimple {
+   public:
+    MockPrefService() = default;
+    ~MockPrefService() override = default;
+
+    void ClearPref(const std::string& path) { cleared_prefs_.insert(path); }
+    bool WasCleared(const std::string& path) const {
+      return cleared_prefs_.count(path);
+    }
+
+   private:
+    std::set<std::string> cleared_prefs_;
+  };
+  std::unique_ptr<MockPrefService> mock_pref_service_;
+};
+
+TEST_P(PrefHashFilterEncryptedTest, FallbackPathInFilterSerializeData) {
+  InitializeSyncOSCrypt();
+  ResetImpl(true, test_os_crypt_async_.get());
+  pref_hash_filter_->FilterUpdate(kAtomicPref);
+  base::Value::Dict root_dict;
+  root_dict.Set(kAtomicPref, "value");
+  base::RunLoop run_loop;
+  mock_pref_hash_store_->SetTransactionCompletionCallback(
+      run_loop.QuitClosure());
+  pref_hash_filter_->FilterSerializeData(root_dict);
+  run_loop.Run();
+  EXPECT_TRUE(mock_pref_hash_store_->StoreEncryptedHashCalled());
+  EXPECT_EQ(std::size(kTestTrackedPrefs),
+            mock_pref_hash_store_->stored_paths_count());
+}
+
+TEST_P(PrefHashFilterEncryptedTest, PostsDeferredTaskOnlyWhenFeatureEnabled) {
+  InitializeAsyncOSCrypt();
+  mock_pref_service_ = std::make_unique<MockPrefService>();
+  // Also register the reset pref as a matter of good practice.
+  mock_pref_service_->registry()->RegisterStringPref(kScheduleToFlushToDisk,
+                                                     "0");
+
+  bool callback_ran = false;
+  auto set_callback = [&](base::RunLoop& run_loop) {
+    pref_hash_filter_->SetOnDeferredRevalidationCompleteForTesting(
+        base::BindLambdaForTesting([&]() {
+          callback_ran = true;
+          run_loop.Quit();
+        }));
+  };
+
+  // 1. Test with feature DISABLED.
+  {
+    callback_ran = false;
+    base::RunLoop completion_run_loop;
+    ResetImpl(false, test_os_crypt_async_.get());
+    pref_hash_filter_->SetPrefService(mock_pref_service_.get());
+    set_callback(completion_run_loop);
+
+    DoFilterOnLoad(false);
+    completion_run_loop.Run();
+    EXPECT_TRUE(callback_ran);
+  }
+
+  // 2. Test with feature ENABLED.
+  {
+    callback_ran = false;
+    base::RunLoop revalidation_loop;
+    ResetImpl(true, test_os_crypt_async_.get());
+    pref_hash_filter_->SetPrefService(mock_pref_service_.get());
+    set_callback(revalidation_loop);
+
+    pref_hash_filter_->FilterOnLoad(
+        base::BindOnce(&PrefHashFilterTest::GetPrefsBack,
+                       base::Unretained(this), false /* expected_altered */),
+        pref_store_contents_.Clone());
+
+    EXPECT_FALSE(callback_ran);
+    revalidation_loop.Run();
+    EXPECT_TRUE(callback_ran);
+  }
+}
+
+TEST_P(PrefHashFilterEncryptedTest, DeferredRevalidationSkipsIfValueChanged) {
+  InitializeAsyncOSCrypt();
+  ResetImpl(true, test_os_crypt_async_.get());
+
+  mock_pref_service_ = std::make_unique<MockPrefService>();
+  mock_pref_service_->registry()->RegisterStringPref(kAtomicPref, "");
+  mock_pref_service_->registry()->RegisterStringPref(kScheduleToFlushToDisk,
+                                                     "0");
+  pref_hash_filter_->SetPrefService(mock_pref_service_.get());
+
+  pref_store_contents_.Set(kAtomicPref, "value_at_load");
+  mock_pref_hash_store_->SetCheckResult(kAtomicPref, ValueState::UNCHANGED);
+
+  pref_hash_filter_->FilterOnLoad(
+      base::BindOnce(&PrefHashFilterTest::GetPrefsBack, base::Unretained(this),
+                     false),
+      std::move(pref_store_contents_));
+
+  mock_pref_service_->SetString(kAtomicPref, "value_changed_in_browser");
+
+  // Wait for the deferred revalidation to complete.
+  base::RunLoop revalidation_run_loop;
+  bool was_validation_performed = false;
+
+  pref_hash_filter_->SetOnDeferredRevalidationCompleteForTesting(base::BindOnce(
+      &PrefHashFilterEncryptedTest::OnDeferredRevalidationComplete,
+      base::Unretained(this), &was_validation_performed,
+      revalidation_run_loop.QuitClosure()));
+  mock_pref_hash_store_->ClearTestState();
+  revalidation_run_loop.Run();
+
+  EXPECT_FALSE(mock_pref_service_->WasCleared(kAtomicPref));
+}
+INSTANTIATE_TEST_SUITE_P(PrefHashFilterTestInstance,
+                         PrefHashFilterEncryptedTest,
+                         testing::Values(EnforcementLevel::NO_ENFORCEMENT,
+                                         EnforcementLevel::ENFORCE_ON_LOAD));
diff --git a/services/preferences/tracked/pref_hash_store_impl.cc b/services/preferences/tracked/pref_hash_store_impl.cc
index 75c8254a..0c4b9c7 100644
--- a/services/preferences/tracked/pref_hash_store_impl.cc
+++ b/services/preferences/tracked/pref_hash_store_impl.cc
@@ -101,7 +101,7 @@
                                const base::Value::Dict* split_value) override;
 
   // Clears only the Encrypted Hash for the path.
-  void ClearEncryptedHash(const std::string& path);
+  void ClearEncryptedHash(const std::string& path) override;
 
   // Gets the stored split encrypted hashes if they exist. Returns false
   // otherwise.
@@ -313,40 +313,41 @@
     const base::Value* value,
     const std::optional<std::string>& stored_encrypted_hash,
     const std::optional<std::string>& stored_mac) const {
-  // -- Priority 1: Check encrypted hash --
-  if (stored_encrypted_hash.has_value()) {
     if (encryptor_) {
-      ValidationResult encrypted_validation_result =
-          outer_->pref_hash_calculator_.ValidateEncrypted(
-              path, value, *stored_encrypted_hash, encryptor_);
-
-      if (encrypted_validation_result == ValidationResult::VALID_ENCRYPTED) {
-        return ValueState::UNCHANGED;
-      } else {
-        // Encrypted hash is invalid or decryption failed. Do NOT fall back.
+      // Priority 1: Check encrypted hash.
+      if (stored_encrypted_hash.has_value()) {
+        ValidationResult result =
+            outer_->pref_hash_calculator_.ValidateEncrypted(
+                path, value, *stored_encrypted_hash, encryptor_);
+        if (result == ValidationResult::VALID_ENCRYPTED) {
+          return ValueState::UNCHANGED_ENCRYPTED;
+        }
+        return value ? ValueState::CHANGED_ENCRYPTED
+                     : ValueState::CLEARED_ENCRYPTED;
+      }
+      // Priority 2: Fallback to legacy MAC for healing.
+      if (stored_mac.has_value()) {
+        ValidationResult result =
+            outer_->pref_hash_calculator_.Validate(path, value, *stored_mac);
+        if (result == ValidationResult::VALID) {
+          return ValueState::UNCHANGED_VIA_HMAC_FALLBACK;
+        }
+        return value ? ValueState::CHANGED_VIA_HMAC_FALLBACK
+                     : ValueState::CLEARED_VIA_HMAC_FALLBACK;
+      }
+    } else {
+      // ---- Encryptor is NOT available: Legacy path ----
+      if (stored_mac.has_value()) {
+        ValidationResult mac_validation_result =
+            outer_->pref_hash_calculator_.Validate(path, value, *stored_mac);
+        if (mac_validation_result == ValidationResult::VALID) {
+          // If we fell through from encrypted (which was unusable), a valid MAC
+          // still means the value is UNCHANGED.
+          return ValueState::UNCHANGED;
+        }
         return value ? ValueState::CHANGED : ValueState::CLEARED;
       }
     }
-  }
-
-  // --- Priority 2: Check legacy HMAC ---
-  if (stored_mac.has_value()) {
-    ValidationResult mac_validation_result =
-        outer_->pref_hash_calculator_.Validate(path, value, *stored_mac);
-    switch (mac_validation_result) {
-      case ValidationResult::VALID:
-        // If we fell through from encrypted (which was unusable), a valid MAC
-        // still means the value is UNCHANGED.
-        return ValueState::UNCHANGED;
-      case ValidationResult::INVALID:
-        // If encrypted was present but unvalidatable, OR if only MAC was
-        // present and invalid
-        return value ? ValueState::CHANGED : ValueState::CLEARED;
-      default:
-        NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
-                     << mac_validation_result;
-    }
-  }
 
   // --- No Usable Hashes Found ---
   // Arrive here if:
@@ -435,82 +436,98 @@
 
   const bool is_initial_value_empty =
       (!initial_split_value || initial_split_value->empty());
-
-  bool try_mac_fallback = false;
   bool only_unusable_encrypted_present = false;
 
-  // --- Priority 1: Check split encrypted hashes ---
-  if (has_encrypted_hashes) {
     if (encryptor_) {
-      if (is_initial_value_empty) {
-        return ValueState::CLEARED;
-      }
-      bool any_invalid = false;
-      std::map<std::string, std::string> current_encrypted =
-          split_encrypted_hashes;
-      std::string keyed_path_base = path + ".";
-      if (initial_split_value) {
-        for (const auto item : *initial_split_value) {
-          std::string keyed_path = keyed_path_base + item.first;
-          auto it = current_encrypted.find(item.first);
-          if (it == current_encrypted.end() ||
-              outer_->pref_hash_calculator_.ValidateEncrypted(
-                  keyed_path, &item.second, it->second, encryptor_) !=
-                  ValidationResult::VALID_ENCRYPTED) {
-            invalid_keys->push_back(item.first);
-            any_invalid = true;
-          }
-          if (it != current_encrypted.end()) {
-            current_encrypted.erase(it);
+      // --- Encryptor is available ---
+      if (has_encrypted_hashes) {
+        // --- Priority 1: Check split encrypted hashes ---
+        std::map<std::string, std::string> current_encrypted =
+            split_encrypted_hashes;
+        if (initial_split_value) {
+          for (const auto item : *initial_split_value) {
+            const std::string keyed_path = path + "." + item.first;
+            auto it = current_encrypted.find(item.first);
+            if (it == current_encrypted.end() ||
+                outer_->pref_hash_calculator_.ValidateEncrypted(
+                    keyed_path, &item.second, it->second, encryptor_) !=
+                    ValidationResult::VALID_ENCRYPTED) {
+              invalid_keys->push_back(item.first);
+            }
+            if (it != current_encrypted.end()) {
+              current_encrypted.erase(it);
+            }
           }
         }
-      }
-      for (const auto& pair : current_encrypted) {
-        invalid_keys->push_back(pair.first);
-        any_invalid = true;
-      }
-      return any_invalid ? ValueState::CHANGED : ValueState::UNCHANGED;
-    } else {
-      try_mac_fallback = true;
-      if (!has_mac_hashes) {
-        only_unusable_encrypted_present = true;
-      }
-    }
-  }
+        for (const auto& pair : current_encrypted) {
+          invalid_keys->push_back(pair.first);
+        }
 
-  // --- Priority 2: Check legacy split HMACs ---
-  // Proceed if no encrypted hashes were found OR if fallback was indicated
-  if (has_mac_hashes && (!has_encrypted_hashes || try_mac_fallback)) {
-    if (is_initial_value_empty) {
-      return ValueState::CLEARED;
-    }
-    bool any_invalid = false;
-    std::map<std::string, std::string> current_macs = split_macs;
-    std::string keyed_path_base = path + ".";
-    if (initial_split_value) {
-      for (const auto item : *initial_split_value) {
-        std::string keyed_path = keyed_path_base + item.first;
-        auto it = current_macs.find(item.first);
-        if (it == current_macs.end()) {
-          invalid_keys->push_back(item.first);
-          any_invalid = true;
-        } else {
-          ValidationResult result = outer_->pref_hash_calculator_.Validate(
-              keyed_path, &item.second, it->second);
-          if (result == ValidationResult::INVALID) {
-            invalid_keys->push_back(item.first);
-            any_invalid = true;
-          }
-          current_macs.erase(it);
+        if (invalid_keys->empty()) {
+          return ValueState::UNCHANGED_ENCRYPTED;
         }
+        return is_initial_value_empty ? ValueState::CLEARED_ENCRYPTED
+                                      : ValueState::CHANGED_ENCRYPTED;
+      }
+
+      // --- Priority 2: Fallback to legacy MACs for healing.
+      if (has_mac_hashes) {
+        std::map<std::string, std::string> current_macs = split_macs;
+        if (initial_split_value) {
+          for (const auto item : *initial_split_value) {
+            const std::string keyed_path = path + "." + item.first;
+            auto it = current_macs.find(item.first);
+            if (it == current_macs.end() ||
+                outer_->pref_hash_calculator_.Validate(keyed_path, &item.second,
+                                                       it->second) !=
+                    ValidationResult::VALID) {
+              invalid_keys->push_back(item.first);
+            }
+            if (it != current_macs.end()) {
+              current_macs.erase(it);
+            }
+          }
+        }
+        for (const auto& pair : current_macs) {
+          invalid_keys->push_back(pair.first);
+        }
+
+        if (invalid_keys->empty()) {
+          return ValueState::UNCHANGED_VIA_HMAC_FALLBACK;
+        }
+        return is_initial_value_empty ? ValueState::CLEARED_VIA_HMAC_FALLBACK
+                                      : ValueState::CHANGED_VIA_HMAC_FALLBACK;
+      }
+    } else {
+      // --- No encryptor, legacy-only path ---
+      if (has_mac_hashes) {
+        std::map<std::string, std::string> current_macs = split_macs;
+        if (initial_split_value) {
+          for (const auto item : *initial_split_value) {
+            const std::string keyed_path = path + "." + item.first;
+            auto it = current_macs.find(item.first);
+            if (it == current_macs.end() ||
+                outer_->pref_hash_calculator_.Validate(keyed_path, &item.second,
+                                                       it->second) !=
+                    ValidationResult::VALID) {
+              invalid_keys->push_back(item.first);
+            }
+            if (it != current_macs.end()) {
+              current_macs.erase(it);
+            }
+          }
+        }
+        for (const auto& pair : current_macs) {
+          invalid_keys->push_back(pair.first);
+        }
+
+        if (invalid_keys->empty()) {
+          return ValueState::UNCHANGED;
+        }
+        return is_initial_value_empty ? ValueState::CLEARED
+                                      : ValueState::CHANGED;
       }
     }
-    for (const auto& pair : current_macs) {
-      invalid_keys->push_back(pair.first);
-      any_invalid = true;
-    }
-    return any_invalid ? ValueState::CHANGED : ValueState::UNCHANGED;
-  }
 
   // --- No Usable Hashes Found ---
   // Arrive here if:
diff --git a/services/preferences/tracked/pref_hash_store_impl_unittest.cc b/services/preferences/tracked/pref_hash_store_impl_unittest.cc
index b7cf4a96..8fe1d39 100644
--- a/services/preferences/tracked/pref_hash_store_impl_unittest.cc
+++ b/services/preferences/tracked/pref_hash_store_impl_unittest.cc
@@ -390,10 +390,25 @@
     // Verify NULL or empty dicts are declared as having been cleared.
     EXPECT_EQ(ValueState::CLEARED,
               transaction->CheckSplitValue("path1", NULL, &invalid_keys));
-    EXPECT_TRUE(invalid_keys.empty());
+
+    // invalid_keys should contain the keys that were removed.
+    std::vector<std::string> expected_cleared_keys;
+    expected_cleared_keys.push_back("a");
+    expected_cleared_keys.push_back("unchanged.path.with.dots");
+    expected_cleared_keys.push_back("o");
+
+    // Sort both vectors for a stable comparison.
+    std::sort(expected_cleared_keys.begin(), expected_cleared_keys.end());
+    std::sort(invalid_keys.begin(), invalid_keys.end());
+    EXPECT_EQ(expected_cleared_keys, invalid_keys);
+    invalid_keys.clear();
+
     EXPECT_EQ(ValueState::CLEARED, transaction->CheckSplitValue(
                                        "path1", &empty_dict, &invalid_keys));
-    EXPECT_TRUE(invalid_keys.empty());
+    // The same keys should be reported as invalid/cleared for an empty dict.
+    std::sort(invalid_keys.begin(), invalid_keys.end());
+    EXPECT_EQ(expected_cleared_keys, invalid_keys);
+    invalid_keys.clear();
 
     // Verify changes are properly detected.
     EXPECT_EQ(ValueState::CHANGED, transaction->CheckSplitValue(
@@ -793,39 +808,47 @@
     // Scenario 1: Store both, check valid, check wrong, check null
     tx->StoreHash(path, &value);
     tx->StoreEncryptedHash(path, &value);
-    EXPECT_EQ(ValueState::UNCHANGED, tx->CheckValue(path, &value));
-    EXPECT_EQ(ValueState::CHANGED, tx->CheckValue(path, &wrong_value));
-    EXPECT_EQ(ValueState::CLEARED, tx->CheckValue(path, null_value_ptr));
+    EXPECT_EQ(ValueState::UNCHANGED_ENCRYPTED, tx->CheckValue(path, &value));
+    EXPECT_EQ(ValueState::CHANGED_ENCRYPTED,
+              tx->CheckValue(path, &wrong_value));
+    EXPECT_EQ(ValueState::CLEARED_ENCRYPTED,
+              tx->CheckValue(path, null_value_ptr));
 
     // Scenario 2: Store only MAC, check valid, check wrong, check null
     tx->ClearHash(path);
     tx->StoreHash(path, &value);
-    // Encrypted missing, fallback to MAC -> UNCHANGED
-    EXPECT_EQ(ValueState::UNCHANGED, tx->CheckValue(path, &value));
-    EXPECT_EQ(ValueState::CHANGED, tx->CheckValue(path, &wrong_value));
-    EXPECT_EQ(ValueState::CLEARED, tx->CheckValue(path, null_value_ptr));
+    // Encrypted missing, fallback to MAC
+    EXPECT_EQ(ValueState::UNCHANGED_VIA_HMAC_FALLBACK,
+              tx->CheckValue(path, &value));
+    EXPECT_EQ(ValueState::CHANGED_VIA_HMAC_FALLBACK,
+              tx->CheckValue(path, &wrong_value));
+    EXPECT_EQ(ValueState::CLEARED_VIA_HMAC_FALLBACK,
+              tx->CheckValue(path, null_value_ptr));
 
     // Scenario 3: Store only Encrypted, check valid, check wrong, check null
     tx->ClearHash(path);
     tx->StoreEncryptedHash(path, &value);
-    // MAC missing, Encrypted OK -> UNCHANGED
-    EXPECT_EQ(ValueState::UNCHANGED, tx->CheckValue(path, &value));
-    EXPECT_EQ(ValueState::CHANGED, tx->CheckValue(path, &wrong_value));
-    EXPECT_EQ(ValueState::CLEARED, tx->CheckValue(path, null_value_ptr));
+    // MAC missing, Encrypted OK
+    EXPECT_EQ(ValueState::UNCHANGED_ENCRYPTED, tx->CheckValue(path, &value));
+    EXPECT_EQ(ValueState::CHANGED_ENCRYPTED,
+              tx->CheckValue(path, &wrong_value));
+    EXPECT_EQ(ValueState::CLEARED_ENCRYPTED,
+              tx->CheckValue(path, null_value_ptr));
 
     // Scenario 4: Store invalid Encrypted, valid MAC -> CHANGED (Enc preferred)
     tx->ClearHash(path);
     tx->StoreHash(path, &value);
     // Manually seed bad data.
     dictionary_contents_.SetMac(GetEncKey(path), "Invalid Base64");
-    EXPECT_EQ(ValueState::CHANGED, tx->CheckValue(path, &value));
+    EXPECT_EQ(ValueState::CHANGED_ENCRYPTED, tx->CheckValue(path, &value));
 
     // Scenario 5: Store MAC for null, check null, check value.
     tx->ClearHash(path);
     tx->StoreHash(path, null_value_ptr);
     tx->StoreEncryptedHash(path, null_value_ptr);
-    EXPECT_EQ(ValueState::UNCHANGED, tx->CheckValue(path, null_value_ptr));
-    EXPECT_EQ(ValueState::CHANGED, tx->CheckValue(path, &value));
+    EXPECT_EQ(ValueState::UNCHANGED_ENCRYPTED,
+              tx->CheckValue(path, null_value_ptr));
+    EXPECT_EQ(ValueState::CHANGED_ENCRYPTED, tx->CheckValue(path, &value));
 
     // Scenario 6: No Hashes stored, SuperMAC invalid
     tx->ClearHash(path);
@@ -959,7 +982,7 @@
   s1_prefs_and_hashes.Set("key1", "value1");
   s1_prefs_and_hashes.Set("key2", "value2");
   run_scenario("E1_AllValid", &s1_prefs_and_hashes, s1_prefs_and_hashes,
-               ValueState::UNCHANGED, {});
+               ValueState::UNCHANGED_ENCRYPTED, {});
 
   // Scenario E2: Value Changed for One Key (Hash Invalid)
   base::Value::Dict s2_current_prefs;
@@ -969,7 +992,7 @@
   s2_original_hashes.Set("key1", "value1");
   s2_original_hashes.Set("key2", "value2");
   run_scenario("E2_OneValueChanged", &s2_current_prefs, s2_original_hashes,
-               ValueState::CHANGED, {"key1"});
+               ValueState::CHANGED_ENCRYPTED, {"key1"});
 
   // Scenario E3: Key Added in Value (Not in Stored Hashes)
   base::Value::Dict s3_current_prefs;
@@ -978,7 +1001,7 @@
   base::Value::Dict s3_original_hashes;
   s3_original_hashes.Set("key1", "value1");
   run_scenario("E3_KeyAddedInValue", &s3_current_prefs, s3_original_hashes,
-               ValueState::CHANGED, {"key2"});
+               ValueState::CHANGED_ENCRYPTED, {"key2"});
 
   // Scenario E4: Key Removed from Value (Present in Stored Hashes)
   base::Value::Dict s4_current_prefs;
@@ -987,7 +1010,7 @@
   s4_original_hashes.Set("key1", "value1");
   s4_original_hashes.Set("key2", "value2");
   run_scenario("E4_KeyRemovedFromValue", &s4_current_prefs, s4_original_hashes,
-               ValueState::CHANGED, {"key2"});
+               ValueState::CHANGED_ENCRYPTED, {"key2"});
 
   // Scenario E5: Multiple Invalidities (Value Change, Key Added, Key Removed)
   base::Value::Dict s5_current_prefs;
@@ -997,18 +1020,18 @@
   s5_original_hashes.Set("keyA", "valueA");
   s5_original_hashes.Set("keyB", "valueB");
   run_scenario("E5_MultipleInvalidities", &s5_current_prefs, s5_original_hashes,
-               ValueState::CHANGED, {"keyA", "keyB", "keyC"});
+               ValueState::CHANGED_ENCRYPTED, {"keyA", "keyB", "keyC"});
 
   // Scenario E6: Initial Value is Empty, Stored Encrypted Hashes Exist
   base::Value::Dict s6_original_hashes;
   s6_original_hashes.Set("key1", "value1");
   base::Value::Dict s6_empty_current_prefs;
   run_scenario("E6_EmptyValue_HashesExist", &s6_empty_current_prefs,
-               s6_original_hashes, ValueState::CLEARED, {});
+               s6_original_hashes, ValueState::CLEARED_ENCRYPTED, {"key1"});
 
   // Scenario E6b: Initial Value is Null, Stored Encrypted Hashes Exist
   run_scenario("E6b_NullValue_HashesExist", nullptr, s6_original_hashes,
-               ValueState::CLEARED, {});
+               ValueState::CLEARED_ENCRYPTED, {"key1"});
 
   // --- Scenario E7: Initial Value Exists, No Stored Encrypted Hashes (empty
   // map of seed hashes) ---
@@ -1049,7 +1072,7 @@
     // 4. Verify results
     // Expected: CHANGED, because current pref has keys, but stored hash dict is
     // empty.
-    EXPECT_EQ(ValueState::CHANGED, result_state);
+    EXPECT_EQ(ValueState::CHANGED_ENCRYPTED, result_state);
     std::vector<std::string> expected_bad_keys_s8 = {"keyA", "keyB"};
     std::sort(actual_invalid_keys.begin(), actual_invalid_keys.end());
     std::sort(expected_bad_keys_s8.begin(), expected_bad_keys_s8.end());
@@ -1105,7 +1128,7 @@
   {
     auto tx = BeginTransaction(true);
     std::vector<std::string> invalid_keys;
-    EXPECT_EQ(ValueState::UNCHANGED,
+    EXPECT_EQ(ValueState::UNCHANGED_ENCRYPTED,
               tx->CheckSplitValue(kBasePath, &input_dict4, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
   }
@@ -1150,7 +1173,7 @@
   {
     auto tx = BeginTransaction(true);
     std::vector<std::string> invalid_keys;
-    EXPECT_EQ(ValueState::UNCHANGED,
+    EXPECT_EQ(ValueState::UNCHANGED_ENCRYPTED,
               tx->CheckSplitValue(kBasePath, &input_dict5, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
   }
@@ -1209,7 +1232,7 @@
   ValueState state =
       tx->CheckSplitValue(kPath, &current_pref_dict, &invalid_keys);
 
-  EXPECT_EQ(ValueState::CHANGED, state);
+  EXPECT_EQ(ValueState::CHANGED_ENCRYPTED, state);
   ASSERT_EQ(1u, invalid_keys.size());
   EXPECT_EQ("keyB_in_store_only", invalid_keys[0]);
 }
diff --git a/services/preferences/tracked/pref_hash_store_transaction.h b/services/preferences/tracked/pref_hash_store_transaction.h
index 5be5172a..e61a4a3 100644
--- a/services/preferences/tracked/pref_hash_store_transaction.h
+++ b/services/preferences/tracked/pref_hash_store_transaction.h
@@ -72,6 +72,9 @@
   // Returns true if this results in a change to the store contents.
   virtual bool StampSuperMac() = 0;
 
+  // Removes the encrypted hash stored at |path|.
+  virtual void ClearEncryptedHash(const std::string& path) = 0;
+
   // Stores the OS-encrypted hash of the preference at |path| and |value|.
   // |value| may be NULL. Requires the encryptor to have been provided at
   // transaction start.
diff --git a/services/preferences/tracked/tracked_atomic_preference.cc b/services/preferences/tracked/tracked_atomic_preference.cc
index eb88478..6a16bfb 100644
--- a/services/preferences/tracked/tracked_atomic_preference.cc
+++ b/services/preferences/tracked/tracked_atomic_preference.cc
@@ -32,15 +32,26 @@
 
 void TrackedAtomicPreference::OnNewValue(
     const base::Value* value,
-    PrefHashStoreTransaction* transaction) const {
+    PrefHashStoreTransaction* transaction,
+    const os_crypt_async::Encryptor* encryptor) const {
   transaction->StoreHash(pref_path_, value);
+
+  if (encryptor) {
+    transaction->StoreEncryptedHash(pref_path_, value);
+  }
 }
 
 bool TrackedAtomicPreference::EnforceAndReport(
     base::Value::Dict& pref_store_contents,
     PrefHashStoreTransaction* transaction,
-    PrefHashStoreTransaction* external_validation_transaction) const {
+    PrefHashStoreTransaction* external_validation_transaction,
+    const os_crypt_async::Encryptor* encryptor) const {
   const base::Value* value = pref_store_contents.FindByDottedPath(pref_path_);
+  // TODO(zackhan@): Currently this function support dual-hash validation.
+  // Revisit and double check this function later on when the feature is fully
+  // rolled out and the hmac based validation is removed.
+  // transaction->CheckValue() (from CL1) is dual-hash aware and uses the
+  // encryptor with which `transaction` was initialized by PrefHashFilter.
   ValueState value_state = transaction->CheckValue(pref_path_, value);
   helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix());
 
@@ -63,16 +74,28 @@
   helper_.ReportAction(reset_action);
 
   bool was_reset = false;
-  if (reset_action == TrackedPreferenceHelper::DO_RESET) {
+  if (reset_action == TrackedPreferenceHelper::DO_RESET ||
+      reset_action == TrackedPreferenceHelper::DO_RESET_LEGACY ||
+      reset_action == TrackedPreferenceHelper::DO_RESET_ENCRYPTED) {
     pref_store_contents.RemoveByDottedPath(pref_path_);
     was_reset = true;
   }
 
-  if (value_state != ValueState::UNCHANGED) {
-    // Store the hash for the new value (whether it was reset or not).
+  // A hash needs to be stored if the state is anything other than the two
+  // ideal "unchanged" states. This includes writing an encrypted hash to a
+  // preference that was UNCHANGED_VIA_HMAC_FALLBACK.
+  if (value_state != ValueState::UNCHANGED &&
+      value_state != ValueState::UNCHANGED_ENCRYPTED) {
+    // Get the new value (which could be the default if a reset occurred).
     const base::Value* new_value =
         pref_store_contents.FindByDottedPath(pref_path_);
+
+    // Store the legacy MAC for backward compatibility.
     transaction->StoreHash(pref_path_, new_value);
+
+    if (encryptor) {
+      transaction->StoreEncryptedHash(pref_path_, new_value);
+    }
   }
 
   // Update MACs in the external store if there is one and there either was a
@@ -82,6 +105,10 @@
     const base::Value* new_value =
         pref_store_contents.FindByDottedPath(pref_path_);
     external_validation_transaction->StoreHash(pref_path_, new_value);
+    if (encryptor) {
+      external_validation_transaction->StoreEncryptedHash(
+          pref_path_, pref_store_contents.FindByDottedPath(pref_path_));
+    }
   }
 
   return was_reset;
diff --git a/services/preferences/tracked/tracked_atomic_preference.h b/services/preferences/tracked/tracked_atomic_preference.h
index ae8b634..d8e3495 100644
--- a/services/preferences/tracked/tracked_atomic_preference.h
+++ b/services/preferences/tracked/tracked_atomic_preference.h
@@ -11,6 +11,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/raw_ptr.h"
+#include "services/preferences/tracked/features.h"
 #include "services/preferences/tracked/pref_hash_filter.h"
 #include "services/preferences/tracked/tracked_preference.h"
 #include "services/preferences/tracked/tracked_preference_helper.h"
@@ -41,11 +42,14 @@
   // TrackedPreference implementation.
   TrackedPreferenceType GetType() const override;
   void OnNewValue(const base::Value* value,
-                  PrefHashStoreTransaction* transaction) const override;
+                  PrefHashStoreTransaction* transaction,
+                  const os_crypt_async::Encryptor* encryptor) const override;
+
   bool EnforceAndReport(
       base::Value::Dict& pref_store_contents,
       PrefHashStoreTransaction* transaction,
-      PrefHashStoreTransaction* external_validation_transaction) const override;
+      PrefHashStoreTransaction* external_validation_transaction,
+      const os_crypt_async::Encryptor* encryptor) const override;
 
  private:
   const std::string pref_path_;
diff --git a/services/preferences/tracked/tracked_persistent_pref_store_factory.cc b/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
index 3a8dc7c..3b1566b4 100644
--- a/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
+++ b/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
@@ -13,6 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
+#include "components/os_crypt/async/browser/os_crypt_async.h"
 #include "components/prefs/json_pref_store.h"
 #include "components/prefs/pref_filter.h"
 #include "components/prefs/pref_name_set.h"
@@ -67,7 +68,8 @@
 
 PersistentPrefStore* CreateTrackedPersistentPrefStore(
     prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
-    scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    os_crypt_async::OSCryptAsync* os_crypt) {
   std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
       unprotected_configuration;
   std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
@@ -118,13 +120,14 @@
                          GetExternalVerificationPrefHashStorePair(
                              *config, temp_scoped_dir_cleaner),
                          unprotected_configuration, mojo::NullRemote(),
-                         validation_delegate_ref, config->reporting_ids_count));
+                         validation_delegate_ref, config->reporting_ids_count,
+                         os_crypt));
   std::unique_ptr<PrefHashFilter> protected_pref_hash_filter(new PrefHashFilter(
       CreatePrefHashStore(*config, true),
       GetExternalVerificationPrefHashStorePair(*config,
                                                temp_scoped_dir_cleaner),
       protected_configuration, std::move(config->reset_on_load_observer),
-      validation_delegate_ref, config->reporting_ids_count));
+      validation_delegate_ref, config->reporting_ids_count, os_crypt));
 
   PrefHashFilter* raw_unprotected_pref_hash_filter =
       unprotected_pref_hash_filter.get();
@@ -158,11 +161,12 @@
 
 void InitializeMasterPrefsTracking(
     prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr configuration,
-    base::Value::Dict& master_prefs) {
+    base::Value::Dict& master_prefs,
+    os_crypt_async::OSCryptAsync* os_crypt) {
   PrefHashFilter(
       CreatePrefHashStore(*configuration, false),
       GetExternalVerificationPrefHashStorePair(*configuration, nullptr),
       configuration->tracking_configuration, mojo::NullRemote(), nullptr,
-      configuration->reporting_ids_count)
+      configuration->reporting_ids_count, os_crypt)
       .Initialize(master_prefs);
 }
diff --git a/services/preferences/tracked/tracked_persistent_pref_store_factory.h b/services/preferences/tracked/tracked_persistent_pref_store_factory.h
index 56314ef..911945d4 100644
--- a/services/preferences/tracked/tracked_persistent_pref_store_factory.h
+++ b/services/preferences/tracked/tracked_persistent_pref_store_factory.h
@@ -10,14 +10,19 @@
 #include "services/preferences/public/mojom/preferences.mojom.h"
 
 class PersistentPrefStore;
+namespace os_crypt_async {
+class OSCryptAsync;
+}
 
 PersistentPrefStore* CreateTrackedPersistentPrefStore(
     prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
-    scoped_refptr<base::SequencedTaskRunner> io_task_runner);
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    os_crypt_async::OSCryptAsync* os_crypt);
 
 // TODO(sammc): This should move somewhere more appropriate in the longer term.
 void InitializeMasterPrefsTracking(
     prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr configuration,
-    base::Value::Dict& master_prefs);
+    base::Value::Dict& master_prefs,
+    os_crypt_async::OSCryptAsync* os_crypt);
 
 #endif  // SERVICES_PREFERENCES_TRACKED_TRACKED_PERSISTENT_PREF_STORE_FACTORY_H_
diff --git a/services/preferences/tracked/tracked_preference.h b/services/preferences/tracked/tracked_preference.h
index 19b0454..7a48af89 100644
--- a/services/preferences/tracked/tracked_preference.h
+++ b/services/preferences/tracked/tracked_preference.h
@@ -8,6 +8,9 @@
 #include "base/values.h"
 
 class PrefHashStoreTransaction;
+namespace os_crypt_async {
+class Encryptor;
+}  // namespace os_crypt_async
 
 enum class TrackedPreferenceType { ATOMIC, SPLIT };
 
@@ -22,7 +25,8 @@
   // Notifies the underlying TrackedPreference about its new |value| which
   // can update hashes in the corresponding hash store via |transaction|.
   virtual void OnNewValue(const base::Value* value,
-                          PrefHashStoreTransaction* transaction) const = 0;
+                          PrefHashStoreTransaction* transaction,
+                          const os_crypt_async::Encryptor* encryptor) const = 0;
 
   // Verifies that the value of this TrackedPreference in |pref_store_contents|
   // is valid. Responds to verification failures according to
@@ -32,10 +36,32 @@
   // |external_validation_transaction|. This call assumes exclusive access to
   // |external_validation_transaction| and its associated state and as such
   // should only be called before any other subsystem is made aware of it.
+  // |encryptor| is an optional OS-level encryptor used for an additional
+  // encrypted hash if the kEncryptedPrefHashing feature is enabled.
   virtual bool EnforceAndReport(
       base::Value::Dict& pref_store_contents,
       PrefHashStoreTransaction* transaction,
-      PrefHashStoreTransaction* external_validation_transaction) const = 0;
+      PrefHashStoreTransaction* external_validation_transaction,
+      const os_crypt_async::Encryptor* encryptor) const = 0;
+
+  // Compatibility Overload
+  // This calls the primary virtual method OnNewValue above, passing nullptr for
+  // encryptor.
+  void OnNewValue(const base::Value* value,
+                  PrefHashStoreTransaction* transaction) const {
+    OnNewValue(value, transaction, nullptr /*encryptor*/);
+  }
+  // Compatibility Overload.
+  // This calls the primary virtual method EnforceAndReport above, passing
+  // nullptr for encryptor.
+  bool EnforceAndReport(
+      base::Value::Dict& pref_store_contents,
+      PrefHashStoreTransaction* transaction,
+      PrefHashStoreTransaction* external_validation_transaction) const {
+    return EnforceAndReport(pref_store_contents, transaction,
+                            external_validation_transaction,
+                            nullptr /*encryptor*/);
+  }
 };
 
 #endif  // SERVICES_PREFERENCES_TRACKED_TRACKED_PREFERENCE_H_
diff --git a/services/preferences/tracked/tracked_preference_helper.cc b/services/preferences/tracked/tracked_preference_helper.cc
index 6c9dbfa..71a36506 100644
--- a/services/preferences/tracked/tracked_preference_helper.cc
+++ b/services/preferences/tracked/tracked_preference_helper.cc
@@ -32,9 +32,13 @@
     ValueState value_state) const {
   switch (value_state) {
     case ValueState::UNCHANGED:
+    case ValueState::UNCHANGED_ENCRYPTED:
+    case ValueState::UNCHANGED_VIA_HMAC_FALLBACK:
       // Desired case, nothing to do.
       return DONT_RESET;
     case ValueState::CLEARED:
+    case ValueState::CLEARED_ENCRYPTED:
+    case ValueState::CLEARED_VIA_HMAC_FALLBACK:
       // Unfortunate case, but there is nothing we can do.
       return DONT_RESET;
     case ValueState::TRUSTED_NULL_VALUE:  // Falls through.
@@ -47,6 +51,10 @@
     case ValueState::UNTRUSTED_UNKNOWN_VALUE:  // Falls through.
     case ValueState::CHANGED:
       return enforce_ ? DO_RESET : WANTED_RESET;
+    case ValueState::CHANGED_ENCRYPTED:
+      return enforce_ ? DO_RESET_ENCRYPTED : WANTED_RESET_ENCRYPTED;
+    case ValueState::CHANGED_VIA_HMAC_FALLBACK:
+      return enforce_ ? DO_RESET_LEGACY : WANTED_RESET_LEGACY;
   }
   NOTREACHED() << "Unexpected ValueState: " << value_state;
 }
@@ -69,6 +77,30 @@
     case ValueState::CHANGED:
       histogram_name = user_prefs::tracked::kTrackedPrefHistogramChanged;
       break;
+    case ValueState::UNCHANGED_ENCRYPTED:
+      histogram_name =
+          user_prefs::tracked::kTrackedPrefHistogramUnchangedEncrypted;
+      break;
+    case ValueState::CLEARED_ENCRYPTED:
+      histogram_name =
+          user_prefs::tracked::kTrackedPrefHistogramClearedEncrypted;
+      break;
+    case ValueState::CHANGED_ENCRYPTED:
+      histogram_name =
+          user_prefs::tracked::kTrackedPrefHistogramChangedEncrypted;
+      break;
+    case ValueState::UNCHANGED_VIA_HMAC_FALLBACK:
+      histogram_name =
+          user_prefs::tracked::kTrackedPrefHistogramUnchangedViaHmacFallback;
+      break;
+    case ValueState::CLEARED_VIA_HMAC_FALLBACK:
+      histogram_name =
+          user_prefs::tracked::kTrackedPrefHistogramClearedViaHmacFallback;
+      break;
+    case ValueState::CHANGED_VIA_HMAC_FALLBACK:
+      histogram_name =
+          user_prefs::tracked::kTrackedPrefHistogramChangedViaHmacFallback;
+      break;
     case ValueState::UNTRUSTED_UNKNOWN_VALUE:
       histogram_name = user_prefs::tracked::kTrackedPrefHistogramInitialized;
       break;
@@ -109,10 +141,30 @@
           user_prefs::tracked::kTrackedPrefHistogramWantedReset, reporting_id_,
           reporting_ids_count_);
       break;
+    case WANTED_RESET_LEGACY:
+      UMA_HISTOGRAM_EXACT_LINEAR(
+          user_prefs::tracked::kTrackedPrefHistogramWantedResetViaHmacFallback,
+          reporting_id_, reporting_ids_count_);
+      break;
+    case WANTED_RESET_ENCRYPTED:
+      UMA_HISTOGRAM_EXACT_LINEAR(
+          user_prefs::tracked::kTrackedPrefHistogramWantedResetEncrypted,
+          reporting_id_, reporting_ids_count_);
+      break;
     case DO_RESET:
       UMA_HISTOGRAM_EXACT_LINEAR(
           user_prefs::tracked::kTrackedPrefHistogramReset, reporting_id_,
           reporting_ids_count_);
       break;
+    case DO_RESET_LEGACY:
+      UMA_HISTOGRAM_EXACT_LINEAR(
+          user_prefs::tracked::kTrackedPrefHistogramResetViaHmacFallback,
+          reporting_id_, reporting_ids_count_);
+      break;
+    case DO_RESET_ENCRYPTED:
+      UMA_HISTOGRAM_EXACT_LINEAR(
+          user_prefs::tracked::kTrackedPrefHistogramResetEncrypted,
+          reporting_id_, reporting_ids_count_);
+      break;
   }
 }
diff --git a/services/preferences/tracked/tracked_preference_helper.h b/services/preferences/tracked/tracked_preference_helper.h
index e8c4ff8..85149159 100644
--- a/services/preferences/tracked/tracked_preference_helper.h
+++ b/services/preferences/tracked/tracked_preference_helper.h
@@ -20,9 +20,18 @@
  public:
   enum ResetAction {
     DONT_RESET,
+    // Indicates that a pref should be reset to its default state
+    // using the 'legacy' or fallback resetting mechanism.
+    DO_RESET_LEGACY,
+    // Specifies that a pref, which is known to be encrypted, should be reset.
+    DO_RESET_ENCRYPTED,
     // WANTED_RESET is reported when DO_RESET would have been reported but the
     // current |enforcement_level| doesn't allow a reset for the detected state.
     WANTED_RESET,
+    // A reset was wanted through the encryption fallback verifiction.
+    WANTED_RESET_LEGACY,
+    // A reset was wanted through the encryption verification.
+    WANTED_RESET_ENCRYPTED,
     DO_RESET,
   };
 
diff --git a/services/preferences/tracked/tracked_preferences_migration_unittest.cc b/services/preferences/tracked/tracked_preferences_migration_unittest.cc
index 7b65cfe..05b852c 100644
--- a/services/preferences/tracked/tracked_preferences_migration_unittest.cc
+++ b/services/preferences/tracked/tracked_preferences_migration_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_split.h"
+#include "base/test/task_environment.h"
 #include "base/values.h"
 #include "components/prefs/pref_name_set.h"
 #include "components/prefs/testing_pref_service.h"
@@ -67,6 +68,8 @@
         .Run(std::move(pref_store_contents), prefs_altered);
   }
 
+  void OnEncryptorReceived(os_crypt_async::Encryptor encryptor) override {}
+
   base::WeakPtr<InterceptablePrefFilter> AsWeakPtr() override {
     return weak_ptr_factory_.GetWeakPtr();
   }
@@ -88,6 +91,9 @@
     MOCK_PROTECTED_PREF_STORE,
   };
 
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI};
+
   TrackedPreferencesMigrationTest()
       : unprotected_prefs_(new base::Value::Dict),
         protected_prefs_(new base::Value::Dict),
diff --git a/services/preferences/tracked/tracked_split_preference.cc b/services/preferences/tracked/tracked_split_preference.cc
index a8a6e0e..95927b0 100644
--- a/services/preferences/tracked/tracked_split_preference.cc
+++ b/services/preferences/tracked/tracked_split_preference.cc
@@ -36,18 +36,24 @@
 
 void TrackedSplitPreference::OnNewValue(
     const base::Value* value,
-    PrefHashStoreTransaction* transaction) const {
+    PrefHashStoreTransaction* transaction,
+    const os_crypt_async::Encryptor* encryptor) const {
   if (value && !value->is_dict()) {
     NOTREACHED();
   }
-
   transaction->StoreSplitHash(pref_path_, value ? &value->GetDict() : nullptr);
+
+  if (encryptor) {
+    transaction->StoreSplitEncryptedHash(pref_path_,
+                                         value ? &value->GetDict() : nullptr);
+  }
 }
 
 bool TrackedSplitPreference::EnforceAndReport(
     base::Value::Dict& pref_store_contents,
     PrefHashStoreTransaction* transaction,
-    PrefHashStoreTransaction* external_validation_transaction) const {
+    PrefHashStoreTransaction* external_validation_transaction,
+    const os_crypt_async::Encryptor* encryptor) const {
   bool was_reset = false;
   base::Value* value = pref_store_contents.FindByDottedPath(pref_path_);
   if (value && !value->is_dict()) {
@@ -62,6 +68,11 @@
   base::Value::Dict* dict_value = value ? &value->GetDict() : nullptr;
 
   std::vector<std::string> invalid_keys;
+  // TODO(zackhan@): Currently this function support dual-hash validation.
+  // Revisit and double check this function later on when the feature is fully
+  // rolled out and the hmac based validation is removed.
+  // transaction->CheckValue() (from CL1) is dual-hash aware and uses the
+  // encryptor with which `transaction` was initialized by PrefHashFilter.
   ValueState value_state =
       transaction->CheckSplitValue(pref_path_, dict_value, &invalid_keys);
 
@@ -87,8 +98,12 @@
       helper_.GetAction(value_state);
   helper_.ReportAction(reset_action);
 
-  if (reset_action == TrackedPreferenceHelper::DO_RESET) {
-    if (value_state == ValueState::CHANGED) {
+  if (reset_action == TrackedPreferenceHelper::DO_RESET ||
+      reset_action == TrackedPreferenceHelper::DO_RESET_LEGACY ||
+      reset_action == TrackedPreferenceHelper::DO_RESET_ENCRYPTED) {
+    if (value_state == ValueState::CHANGED ||
+        value_state == ValueState::CHANGED_VIA_HMAC_FALLBACK ||
+        value_state == ValueState::CHANGED_ENCRYPTED) {
       DCHECK(!invalid_keys.empty());
 
       for (std::vector<std::string>::const_iterator it = invalid_keys.begin();
@@ -101,10 +116,16 @@
     was_reset = true;
   }
 
-  if (value_state != ValueState::UNCHANGED) {
+  if (value_state != ValueState::UNCHANGED &&
+      value_state != ValueState::UNCHANGED_ENCRYPTED) {
     // Store the hash for the new value (whether it was reset or not).
     transaction->StoreSplitHash(
         pref_path_, pref_store_contents.FindDictByDottedPath(pref_path_));
+
+    if (encryptor) {
+      transaction->StoreSplitEncryptedHash(
+          pref_path_, pref_store_contents.FindDictByDottedPath(pref_path_));
+    }
   }
 
   // Update MACs in the external store if there is one and there either was a
@@ -113,6 +134,10 @@
       (was_reset || external_validation_value_state != ValueState::UNCHANGED)) {
     external_validation_transaction->StoreSplitHash(
         pref_path_, pref_store_contents.FindDictByDottedPath(pref_path_));
+    if (encryptor) {
+      external_validation_transaction->StoreSplitEncryptedHash(
+          pref_path_, pref_store_contents.FindDictByDottedPath(pref_path_));
+    }
   }
 
   return was_reset;
diff --git a/services/preferences/tracked/tracked_split_preference.h b/services/preferences/tracked/tracked_split_preference.h
index 131296a..75b3eee5d 100644
--- a/services/preferences/tracked/tracked_split_preference.h
+++ b/services/preferences/tracked/tracked_split_preference.h
@@ -11,6 +11,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/raw_ptr.h"
+#include "services/preferences/tracked/features.h"
 #include "services/preferences/tracked/pref_hash_filter.h"
 #include "services/preferences/tracked/tracked_preference.h"
 #include "services/preferences/tracked/tracked_preference_helper.h"
@@ -42,11 +43,13 @@
   // TrackedPreference implementation.
   TrackedPreferenceType GetType() const override;
   void OnNewValue(const base::Value* value,
-                  PrefHashStoreTransaction* transaction) const override;
+                  PrefHashStoreTransaction* transaction,
+                  const os_crypt_async::Encryptor* encryptor) const override;
   bool EnforceAndReport(
       base::Value::Dict& pref_store_contents,
       PrefHashStoreTransaction* transaction,
-      PrefHashStoreTransaction* external_validation_transaction) const override;
+      PrefHashStoreTransaction* external_validation_transaction,
+      const os_crypt_async::Encryptor* encryptor) const override;
 
  private:
   const std::string pref_path_;
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc
index adac7b8..967158e 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc
@@ -4,17 +4,19 @@
 
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
 
-#include "base/process/process.h"
-#include "base/process/process_handle.h"
-
 #include <lib/zx/job.h>
 #include <lib/zx/object.h>
 #include <lib/zx/process.h>
 #include <zircon/limits.h>
 #include <zircon/status.h>
 #include <zircon/syscalls.h>
+
 #include <vector>
 
+#include "base/notimplemented.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+
 namespace memory_instrumentation {
 
 // static
diff --git a/services/service_manager/public/cpp/standalone_connector_impl.cc b/services/service_manager/public/cpp/standalone_connector_impl.cc
index 2ca1b9d..5c3e55e 100644
--- a/services/service_manager/public/cpp/standalone_connector_impl.cc
+++ b/services/service_manager/public/cpp/standalone_connector_impl.cc
@@ -5,7 +5,7 @@
 #include "services/service_manager/public/cpp/standalone_connector_impl.h"
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace service_manager {
 
diff --git a/services/service_manager/service_process_launcher.cc b/services/service_manager/service_process_launcher.cc
index bb99780..6048425 100644
--- a/services/service_manager/service_process_launcher.cc
+++ b/services/service_manager/service_process_launcher.cc
@@ -15,6 +15,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
+#include "base/notimplemented.h"
 #include "base/path_service.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
diff --git a/services/video_capture/device_factory_impl.cc b/services/video_capture/device_factory_impl.cc
index 94c3a40..18d3be09 100644
--- a/services/video_capture/device_factory_impl.cc
+++ b/services/video_capture/device_factory_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #if BUILDFLAG(IS_CHROMEOS)
 #include "base/metrics/histogram_functions.h"
 #endif  // BUILDFLAG(IS_CHROMEOS)
diff --git a/services/viz/public/mojom/BUILD.gn b/services/viz/public/mojom/BUILD.gn
index 7cff71ed..2fb2ebe 100644
--- a/services/viz/public/mojom/BUILD.gn
+++ b/services/viz/public/mojom/BUILD.gn
@@ -703,6 +703,7 @@
       ]
       traits_headers = [ "//services/viz/public/cpp/compositing/shared_image_format_mojom_traits.h" ]
       traits_sources = [ "//services/viz/public/cpp/compositing/shared_image_format_mojom_traits.cc" ]
+      traits_public_deps = [ "//components/viz/common:shared_image_format" ]
     },
   ]
 
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index fd557c7..b53c76e 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -26,7 +26,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -71,7 +71,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -107,7 +107,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -143,7 +143,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -188,7 +188,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -225,7 +225,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -261,7 +261,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -298,7 +298,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
@@ -336,7 +336,7 @@
         },
         "swarming": {
           "dimensions": {
-            "device_os": "PQ3A.190801.002",
+            "device_os": "QQ1A.191205.008",
             "device_os_flavor": "google",
             "device_os_type": "userdebug",
             "device_type": "walleye",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 08116cda..c3ee308 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -696,7 +696,7 @@
         'os_type': 'android',
         'skip_merge_script': True,
         'mixins': [
-          'chromium_pixel_2_pie',
+          'chromium_pixel_2_q',
         ],
         'test_suites': {
           'gpu_telemetry_tests': 'gpu_telemetry_tests_v8',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 22f57c7..e79f1fd 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -9257,6 +9257,27 @@
             ]
         }
     ],
+    "EncryptedPrefHashing": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "EncryptedPrefHashing"
+                    ]
+                }
+            ]
+        }
+    ],
     "EndOfLifeIncentive": [
         {
             "platforms": [
@@ -20149,26 +20170,6 @@
             ]
         }
     ],
-    "RemoveCancelledScriptedIdleTasks": [
-        {
-            "platforms": [
-                "android_webview",
-                "android",
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "RemoveCancelledScriptedIdleTasks"
-                    ]
-                }
-            ]
-        }
-    ],
     "RemoveDataUrlInSvgUse": [
         {
             "platforms": [
@@ -26182,6 +26183,26 @@
             ]
         }
     ],
+    "WebGPUEnableRangeAnalysisForRobustness": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "WebGPUEnableRangeAnalysisForRobustness"
+                    ]
+                }
+            ]
+        }
+    ],
     "WebGPUSupportMetrics": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index 2f18b71..6495149 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 2f18b71d0e10a430beb1ec31560e6e2828ec096a
+Subproject commit 649514930e65cb7a9baa489092431010df5e8b4a
diff --git a/third_party/blink/DEPS b/third_party/blink/DEPS
index b748915..3bc48c4 100644
--- a/third_party/blink/DEPS
+++ b/third_party/blink/DEPS
@@ -11,6 +11,7 @@
     "+base/memory/raw_span.h",
     "+base/memory/raw_ptr_exclusion.h",
     "+base/memory/stack_allocated.h",
+    "+base/notimplemented.h",
     "+base/notreached.h",
     "+base/observer_list.h",
     "+base/trace_event",
diff --git a/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc b/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc
index 8cb00d6..66f4acb 100644
--- a/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc
+++ b/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
diff --git a/third_party/blink/common/loader/url_loader_throttle.cc b/third_party/blink/common/loader/url_loader_throttle.cc
index 5eed0c2..adeeba7a 100644
--- a/third_party/blink/common/loader/url_loader_throttle.cc
+++ b/third_party/blink/common/loader/url_loader_throttle.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/public/common/loader/url_loader_throttle.h"
 
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
diff --git a/third_party/blink/common/page_state/page_state_serialization.cc b/third_party/blink/common/page_state/page_state_serialization.cc
index 46f5b56..b8ec5b3 100644
--- a/third_party/blink/common/page_state/page_state_serialization.cc
+++ b/third_party/blink/common/page_state/page_state_serialization.cc
@@ -11,6 +11,7 @@
 #include "base/containers/span.h"
 #include "base/containers/to_vector.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/pickle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/third_party/blink/common/permissions/permission_utils.cc b/third_party/blink/common/permissions/permission_utils.cc
index 6886f57..4dd8b8d 100644
--- a/third_party/blink/common/permissions/permission_utils.cc
+++ b/third_party/blink/common/permissions/permission_utils.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/public/common/permissions/permission_utils.h"
 
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
 #include "third_party/blink/public/mojom/permissions/permission.mojom.h"
diff --git a/third_party/blink/renderer/core/exported/web_performance_metrics_for_reporting.cc b/third_party/blink/renderer/core/exported/web_performance_metrics_for_reporting.cc
index b2af8602..26e43757 100644
--- a/third_party/blink/renderer/core/exported/web_performance_metrics_for_reporting.cc
+++ b/third_party/blink/renderer/core/exported/web_performance_metrics_for_reporting.cc
@@ -147,8 +147,8 @@
 }
 
 double WebPerformanceMetricsForReporting::FirstContentfulPaint() const {
-  return base::Milliseconds(private_->timingForReporting()
-                                ->FirstContentfulPaintIgnoringSoftNavigations())
+  return base::Milliseconds(
+             private_->timingForReporting()->FirstContentfulPaint())
       .InSecondsF();
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 446fb972..1dddd52f8 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -39,6 +39,7 @@
 #include "base/check_deref.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc b/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
index 04769da..49ed8f6 100644
--- a/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
+++ b/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
@@ -72,7 +72,7 @@
 
   // Skip any measurement before the FCP.
   if (PaintTiming::From(*outermost_main_frame->GetDocument())
-          .FirstContentfulPaintIgnoringSoftNavigations()
+          .FirstContentfulPaint()
           .is_null()) {
     return;
   }
diff --git a/third_party/blink/renderer/core/frame/sticky_ad_detector.cc b/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
index e0547e3..8dd8e2c1 100644
--- a/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
+++ b/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
@@ -64,7 +64,7 @@
 
   // Skip any measurement before the FCP.
   if (PaintTiming::From(*outermost_main_frame->GetDocument())
-          .FirstContentfulPaintIgnoringSoftNavigations()
+          .FirstContentfulPaint()
           .is_null()) {
     return;
   }
diff --git a/third_party/blink/renderer/core/highlight/highlight.cc b/third_party/blink/renderer/core/highlight/highlight.cc
index 783e154..1baa323 100644
--- a/third_party/blink/renderer/core/highlight/highlight.cc
+++ b/third_party/blink/renderer/core/highlight/highlight.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/highlight/highlight.h"
 
+#include "base/notimplemented.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index 44ecc38..6854f0a6 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -7,6 +7,7 @@
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 91eac6e..07345df 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -38,6 +38,7 @@
 #include "base/location.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/clamped_math.h"
 #include "base/numerics/safe_conversions.h"
diff --git a/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc b/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
index 2f52ab38..e73deded 100644
--- a/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.cc
@@ -106,8 +106,8 @@
   client_->NotifyFetchFinishedSuccess(ModuleScriptCreationParams(
       /*source_url=*/url, /*base_url=*/url,
       ScriptSourceLocationType::kExternalFile, resolved_module_type.value(),
-      script_resource->SourceText(), script_resource->CacheHandler(),
-      response_referrer_policy,
+      script_resource->GetSourceTextOrWasmSource(resolved_module_type.value()),
+      script_resource->CacheHandler(), response_referrer_policy,
       script_resource->GetResponse().HttpHeaderField(http_names::kSourceMap),
       streamer, not_streamed_reason, import_phase_));
 }
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc b/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc
index a83711b..ca90954 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.cc
@@ -20,4 +20,12 @@
   }
 }
 
+std::variant<ParkableString, base::HeapArray<uint8_t>>
+ModuleScriptCreationParams::CopySource() const {
+  if (module_type_ == ResolvedModuleType::kWasm) {
+    return base::HeapArray<uint8_t>::CopiedFrom(GetWasmSource());
+  }
+  return GetSourceText();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h b/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
index 855f5a2..0d3b5a8b 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
@@ -35,7 +35,7 @@
 // ModuleScriptCreationParams constructor.
 enum class ResolvedModuleType { kJSON, kCSS, kJavaScript, kWasm };
 
-class ModuleScriptCreationParams {
+class CORE_EXPORT ModuleScriptCreationParams {
   DISALLOW_NEW();
 
  public:
@@ -44,7 +44,7 @@
       const KURL& base_url,
       ScriptSourceLocationType source_location_type,
       const ResolvedModuleType module_type,
-      const ParkableString& source_text,
+      std::variant<ParkableString, base::HeapArray<uint8_t>>&& source,
       CachedMetadataHandler* cache_handler,
       network::mojom::ReferrerPolicy response_referrer_policy,
       const String& source_map_url,
@@ -56,7 +56,7 @@
         base_url_(base_url),
         source_location_type_(source_location_type),
         module_type_(module_type),
-        source_text_(source_text),
+        source_(std::move(source)),
         cache_handler_(cache_handler),
         response_referrer_policy_(response_referrer_policy),
         source_map_url_(source_map_url),
@@ -91,7 +91,7 @@
     // ModuleScriptCreationParams is passed across threads.
     return ModuleScriptCreationParams(
         SourceURL(), BaseURL(), source_location_type_, module_type_,
-        source_text_, /*cache_handler=*/nullptr, response_referrer_policy_,
+        CopySource(), /*cache_handler=*/nullptr, response_referrer_policy_,
         source_map_url_, /*script_streamer=*/nullptr,
         ScriptStreamer::NotStreamingReason::kStreamingDisabled, import_phase_);
   }
@@ -104,7 +104,13 @@
   const String& SourceMapURL() const { return source_map_url_; }
 
   const ParkableString& GetSourceText() const {
-    return source_text_;
+    CHECK_NE(module_type_, ResolvedModuleType::kWasm);
+    return std::get<ParkableString>(source_);
+  }
+
+  const base::HeapArray<uint8_t>& GetWasmSource() const {
+    CHECK_EQ(module_type_, ResolvedModuleType::kWasm);
+    return std::get<base::HeapArray<uint8_t>>(source_);
   }
 
   ScriptSourceLocationType SourceLocationType() const {
@@ -137,13 +143,19 @@
   }
 
  private:
+  std::variant<ParkableString, base::HeapArray<uint8_t>> CopySource() const;
 
   const KURL source_url_;
   const KURL base_url_;
   const ScriptSourceLocationType source_location_type_;
   const ResolvedModuleType module_type_;
 
-  const ParkableString source_text_;
+  // For Wasm modules the wire bytes are passed directly to the compiler.
+  // Otherwise, decoded text is stored as ParkableString.
+  // Cannot be const to support the move constructor.
+  // TODO(https://crbug.com/42204365): Wrap this and the module type in a
+  // new class.
+  std::variant<ParkableString, base::HeapArray<uint8_t>> source_;
 
   // |cache_handler_| is cleared when crossing thread boundaries.
   Persistent<CachedMetadataHandler> cache_handler_;
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
index 2c0b288..aeeb9db 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
@@ -587,6 +587,29 @@
   EXPECT_TRUE(module_script->IsWasmModuleRecord());
 }
 
+TEST_F(ModuleScriptLoaderTest, TestNonUTF8EncodeableModule) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {blink::features::kJavaScriptSourcePhaseImports},
+      /*disabled_features =*/{});
+  InitializeForDocument();
+  TestModuleScriptLoaderClient* client =
+      MakeGarbageCollected<TestModuleScriptLoaderClient>();
+  TestFetchURL(ModuleScriptCustomFetchType::kNone, client,
+               "https://example.test/non_UTF8.wasm", "non_UTF8.wasm",
+               "application/wasm");
+
+  EXPECT_FALSE(client->WasNotifyFinished())
+      << "ModuleScriptLoader unexpectedly finished synchronously.";
+  platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
+
+  EXPECT_TRUE(
+      base::test::RunUntil([&]() { return client->WasNotifyFinished(); }));
+  ModuleScript* module_script = client->GetModuleScript();
+  EXPECT_TRUE(module_script);
+  EXPECT_TRUE(module_script->IsWasmModuleRecord());
+}
+
 TEST_F(ModuleScriptLoaderTest, FetchWasmURLWrongMimeType) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
diff --git a/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc b/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
index 068f147..fd38682 100644
--- a/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
@@ -119,15 +119,18 @@
     }
   }
 
-  NotifyClient(resource->Url(), resolved_module_type.value(),
-               script_resource->SourceText(), resource->GetResponse(),
-               script_resource->CacheHandler());
+  NotifyClient(
+      resource->Url(), resolved_module_type.value(),
+      script_resource->GetSourceTextOrWasmSource(resolved_module_type.value()),
+      resource->GetResponse(), script_resource->CacheHandler());
 }
 
+// TODO(https://crbug.com/42204365): Wrap `source` and  `module_type` in a
+// new class.
 void WorkerModuleScriptFetcher::NotifyClient(
     const KURL& request_url,
     ResolvedModuleType module_type,
-    const ParkableString& source_text,
+    std::variant<ParkableString, base::HeapArray<uint8_t>>&& source,
     const ResourceResponse& response,
     CachedMetadataHandler* cache_handler) {
   HeapVector<Member<ConsoleMessage>> error_messages;
@@ -200,7 +203,7 @@
   // https://html.spec.whatwg.org/multipage/webappapis.html#concept-script-base-url
   client_->NotifyFetchFinishedSuccess(ModuleScriptCreationParams(
       /*source_url=*/response_url, /*base_url=*/response_url,
-      ScriptSourceLocationType::kExternalFile, module_type, source_text,
+      ScriptSourceLocationType::kExternalFile, module_type, std::move(source),
       cache_handler, response_referrer_policy,
       response.HttpHeaderField(http_names::kSourceMap), nullptr,
       ScriptStreamer::NotStreamingReason::kStreamingDisabled, import_phase_));
diff --git a/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h b/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
index c93e6b0..ca38221 100644
--- a/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
+++ b/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h
@@ -51,11 +51,14 @@
   void NotifyFinished(Resource*) override;
   String DebugName() const override { return "WorkerModuleScriptFetcher"; }
 
-  void NotifyClient(const KURL& request_url,
-                    ResolvedModuleType module_type,
-                    const ParkableString& source_text,
-                    const ResourceResponse& response,
-                    CachedMetadataHandler* cache_handler);
+  // `base::HeapArray<uint8_t>` is stored when `module_type` is
+  // `ResolvedModuleType::kWasm`, and `ParkableString` otherwise.
+  void NotifyClient(
+      const KURL& request_url,
+      ResolvedModuleType module_type,
+      std::variant<ParkableString, base::HeapArray<uint8_t>>&& source,
+      const ResourceResponse& response,
+      CachedMetadataHandler* cache_handler);
 
   const Member<WorkerGlobalScope> global_scope_;
 
diff --git a/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc b/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
index aab30d8d..3c16e85 100644
--- a/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.cc
@@ -84,8 +84,9 @@
     params.emplace(
         /*source_url=*/url, /*base_url=*/url,
         ScriptSourceLocationType::kExternalFile, resolved_module_type.value(),
-        script_resource->SourceText(), script_resource->CacheHandler(),
-        response_referrer_policy,
+        script_resource->GetSourceTextOrWasmSource(
+            resolved_module_type.value()),
+        script_resource->CacheHandler(), response_referrer_policy,
         script_resource->GetResponse().HttpHeaderField(http_names::kSourceMap));
   }
 
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource.cc b/third_party/blink/renderer/core/loader/resource/script_resource.cc
index 1b2e529..d4431d3 100644
--- a/third_party/blink/renderer/core/loader/resource/script_resource.cc
+++ b/third_party/blink/renderer/core/loader/resource/script_resource.cc
@@ -42,6 +42,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_compile_hints_consumer.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_compile_hints_producer.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h"
 #include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
@@ -205,6 +206,8 @@
   TextResource::Trace(visitor);
 }
 
+// TODO(https://crbug.com/42204365): Investigate if we need special support for
+// Wasm resources.
 void ScriptResource::OnMemoryDump(WebMemoryDumpLevelOfDetail level_of_detail,
                                   WebProcessMemoryDump* memory_dump) const {
   Resource::OnMemoryDump(level_of_detail, memory_dump);
@@ -232,6 +235,27 @@
   return source_text_;
 }
 
+std::variant<ParkableString, base::HeapArray<uint8_t>>
+ScriptResource::GetSourceTextOrWasmSource(ResolvedModuleType module_type) {
+  if (module_type == ResolvedModuleType::kWasm) {
+    return GetWasmSource();
+  }
+  return SourceText();
+}
+
+base::HeapArray<uint8_t> ScriptResource::GetWasmSource() {
+  // Data is not cleared for Wasm resources.
+  // TODO(https://crbug.com/425682456): Currently this assumption doesn't hold.
+  CHECK(IsLoaded());
+  CHECK(base::FeatureList::IsEnabled(
+      blink::features::kJavaScriptSourcePhaseImports));
+  CHECK(MIMETypeRegistry::IsWasmMIMEType(GetResponse().HttpContentType()));
+  CHECK(Data());
+  auto data_array = base::HeapArray<uint8_t>::Uninit(Data()->size());
+  CHECK(Data()->GetBytes(data_array));
+  return data_array;
+}
+
 String ScriptResource::TextForInspector() const {
   // If the resource buffer exists, we can safely return the decoded text.
   if (ResourceBuffer()) {
@@ -248,6 +272,9 @@
   // ... or we either haven't started loading and haven't received data yet, or
   // we finished loading with an error/cancellation, and thus don't have data.
   // In both cases, we can treat the resource as empty.
+  //
+  // Also Wasm resources are not decoded, so we return an empty string.
+  // TODO(https://crbug.com/42204365): Investigate if we need inspector support.
   return "";
 }
 
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource.h b/third_party/blink/renderer/core/loader/resource/script_resource.h
index dbeebf2..a696d0c 100644
--- a/third_party/blink/renderer/core/loader/resource/script_resource.h
+++ b/third_party/blink/renderer/core/loader/resource/script_resource.h
@@ -47,20 +47,23 @@
 class KURL;
 class ResourceFetcher;
 
+enum class ResolvedModuleType;
+
 namespace v8_compile_hints {
 class V8CrowdsourcedCompileHintsConsumer;
 class V8CrowdsourcedCompileHintsProducer;
 }  // namespace v8_compile_hints
 
-// ScriptResource is a resource representing a JavaScript, either a classic or
-// module script. Based on discussions (crbug.com/1178198) ScriptResources are
-// shared between classic and module scripts.
+// ScriptResource is a resource representing a JavaScript classic
+// script or a (JS, CSS, JSON or Wasm) module script. Based on discussions
+// (crbug.com/1178198) ScriptResources are shared between classic and
+// module scripts.
 //
 // In addition to loading the script, a ScriptResource can optionally stream the
 // script to the JavaScript parser/compiler, using a ScriptStreamer. In this
 // case, clients of the ScriptResource will not receive the finished
 // notification until the streaming completes.
-// Note: ScriptStreamer is only used for "classic" scripts, i.e. not modules.
+// TODO(https://crbug.com/42204365): Support Wasm streaming.
 //
 // See also:
 // https://docs.google.com/document/d/143GOPl_XVgLPFfO-31b_MdBcnjklLEX2OIg_6eN6fQ4
@@ -114,8 +117,23 @@
 
   void SetSerializedCachedMetadata(mojo_base::BigBuffer data) override;
 
+  // Returns the decoded source text as a ParkableString.
+  //
+  // This shouldn't be used for Wasm resources.
   const ParkableString& SourceText();
 
+  // For module purposes.
+  // Returns the wire bytes for Wasm modules, or otherwise, the decoded text.
+  // See `ModuleScriptCreationParams::source_`.
+  //
+  // `module_type` should be the return value from
+  // `ModuleScriptFetcher::WasModuleLoadSuccessful(this,...)`.
+  // Particularly, if `module_type` is `kWasm`, then the Content Type of `this`
+  // should be a WASM MIME type (See the corresponding `CHECK()` in
+  // `GetWasmSource()`).
+  std::variant<ParkableString, base::HeapArray<uint8_t>>
+  GetSourceTextOrWasmSource(ResolvedModuleType module_type);
+
   // Get the resource's current text. This can return partial data, so should
   // not be used outside of the inspector.
   String TextForInspector() const;
@@ -277,6 +295,10 @@
     mojom::blink::ScriptType initial_request_script_type_;
   };
 
+  // For Wasm sources. Returns a flattened representation of the Data without
+  // clearing the buffer. The returned buffer is not stored within this class.
+  base::HeapArray<uint8_t> GetWasmSource();
+
   bool CanUseCacheValidator() const override;
 
   void DisableStreaming(ScriptStreamer::NotStreamingReason no_streamer_reason);
@@ -296,6 +318,7 @@
   void OnDataPipeReadable(MojoResult result,
                           const mojo::HandleSignalsState& state);
 
+  // Stores the source text. Should be used only for non-Wasm resources.
   ParkableString source_text_;
 
   // This isolate will be null if this ScriptResource is not created on the main
diff --git a/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector.cc b/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector.cc
index 64d99f3..01bbacd0 100644
--- a/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector.cc
+++ b/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector.cc
@@ -126,7 +126,7 @@
           paint_timing_
               ->FirstContentfulPaintRenderedButNotPresentedAsMonotonicTime();
       first_meaningful_paint_presentation =
-          paint_timing_->FirstContentfulPaintIgnoringSoftNavigations();
+          paint_timing_->FirstContentfulPaint();
       // It's possible that this timer fires between when the first contentful
       // paint is set and its presentation promise is fulfilled. If this
       // happens, defer until NotifyFirstContentfulPaint() is called.
diff --git a/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector_test.cc b/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector_test.cc
index 751f6ad..ed8d9b3 100644
--- a/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector_test.cc
+++ b/third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector_test.cc
@@ -224,7 +224,7 @@
   MarkFirstContentfulPaintAndClearPresentationPromise();
   SimulateNetworkStable();
   EXPECT_GE(GetPaintTiming().FirstMeaningfulPaint(),
-            GetPaintTiming().FirstContentfulPaintIgnoringSoftNavigations());
+            GetPaintTiming().FirstContentfulPaint());
 }
 
 TEST_F(FirstMeaningfulPaintDetectorTest,
@@ -297,7 +297,7 @@
   ClearFirstContentfulPaintPresentationPromise();
   EXPECT_GT(GetPaintTiming().FirstMeaningfulPaint(), base::TimeTicks());
   EXPECT_EQ(GetPaintTiming().FirstMeaningfulPaint(),
-            GetPaintTiming().FirstContentfulPaintIgnoringSoftNavigations());
+            GetPaintTiming().FirstContentfulPaint());
 }
 
 TEST_F(
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing.h b/third_party/blink/renderer/core/paint/timing/paint_timing.h
index cfbba501..d897049 100644
--- a/third_party/blink/renderer/core/paint/timing/paint_timing.h
+++ b/third_party/blink/renderer/core/paint/timing/paint_timing.h
@@ -120,10 +120,9 @@
   }
 
   // Returns the first time that 'contentful' content was painted in the current
-  // document after a hard navigation (and ignoring soft navigations). For
-  // instance, the first time that text or image content was painted after the
-  // user landed on the page.
-  base::TimeTicks FirstContentfulPaintIgnoringSoftNavigations() const {
+  // document after a hard navigation. For instance, the first time that text or
+  // image content was painted after the user landed on the page.
+  base::TimeTicks FirstContentfulPaint() const {
     return first_contentful_paint_presentation_;
   }
 
@@ -250,10 +249,8 @@
   DOMPaintTimingInfo ToDOMPaintTimingInfo(const PaintTimingInfo&) const;
 
   PaintDetails paint_details_;
-  // First paint timestamp that doesn't update after soft navigations, and only
-  // used for UKM reporting.
+  // Timestamps used for UKM reporting.
   base::TimeTicks first_paint_presentation_for_ukm_;
-  // FCP timestamp that does not update after soft navigations.
   base::TimeTicks first_contentful_paint_presentation_;
   base::TimeTicks first_meaningful_paint_presentation_;
   base::TimeTicks first_meaningful_paint_candidate_;
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 ebe0094..49ab2bea 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
@@ -317,9 +317,8 @@
     return;
   }
 
-  auto latest_lcp_details =
+  lcp_details_for_metrics_ =
       GetLargestContentfulPaintCalculator()->LatestLcpDetails();
-  lcp_details_for_metrics_ = latest_lcp_details;
 
   DidChangePerformanceTiming();
 }
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 dac5ba36..64a820f 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
@@ -103,10 +103,6 @@
       const {
     return lcp_details_for_metrics_;
   }
-  const LargestContentfulPaintDetails&
-  SoftNavigationLargestContentfulPaintDetailsForMetrics() const {
-    return soft_navigation_lcp_details_for_metrics_;
-  }
 
   const LargestContentfulPaintDetails& LatestLcpDetailsForTest();
 
@@ -153,8 +149,6 @@
 
   // The LCP details reported to metrics (UKM).
   LargestContentfulPaintDetails lcp_details_for_metrics_;
-  // The soft navigation LCP details reported to metrics (UKM).
-  LargestContentfulPaintDetails soft_navigation_lcp_details_for_metrics_;
 };
 
 // Largest Text Paint and Text Element Timing aggregate text nodes by these
diff --git a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h
index 58e90cad..31664fa 100644
--- a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.h
@@ -59,7 +59,7 @@
   gfx::RectF root_visual_rect_;
   std::unique_ptr<LCPRectInfo> lcp_rect_info_;
   // The time of the first paint after fully loaded.
-  base::TimeTicks paint_time = base::TimeTicks();
+  base::TimeTicks paint_time;
   DOMPaintTimingInfo paint_timing_info;
   bool is_needed_for_timing_ = false;
   WeakMember<SoftNavigationContext> soft_navigation_context_;
diff --git a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc
index da9cd19..f1fc52a5 100644
--- a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc
+++ b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller.cc
@@ -86,7 +86,7 @@
 
 BASE_FEATURE(kRemoveCancelledScriptedIdleTasks,
              "RemoveCancelledScriptedIdleTasks",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 IdleTask::~IdleTask() {
   CHECK(!delayed_task_handle_.IsValid());
diff --git a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc
index ed95664..08f7280 100644
--- a/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc
+++ b/third_party/blink/renderer/core/scheduler/scripted_idle_task_controller_test.cc
@@ -6,6 +6,7 @@
 
 #include <deque>
 
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/scoped_feature_list.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/third_party/blink/renderer/core/script/module_map_test.cc b/third_party/blink/renderer/core/script/module_map_test.cc
index babcb795..f687cd27 100644
--- a/third_party/blink/renderer/core/script/module_map_test.cc
+++ b/third_party/blink/renderer/core/script/module_map_test.cc
@@ -163,10 +163,9 @@
         : url_(url), client_(client), import_phase_(import_phase) {}
     void NotifyFetchFinished() {
       ResolvedModuleType resolved_module_type = ResolvedModuleTypeFromUrl();
-      String script_string = EmptyModuleString(resolved_module_type);
       client_->NotifyFetchFinishedSuccess(ModuleScriptCreationParams(
           url_, url_, ScriptSourceLocationType::kExternalFile,
-          resolved_module_type, ParkableString(script_string.ReleaseImpl()),
+          resolved_module_type, EmptyModuleSource(resolved_module_type),
           nullptr, network::mojom::ReferrerPolicy::kDefault,
           /*source_map_url=*/String(), nullptr,
           ScriptStreamer::NotStreamingReason::kStreamingDisabled,
@@ -184,13 +183,14 @@
       return ResolvedModuleType::kWasm;
     }
 
-    String EmptyModuleString(ResolvedModuleType module_type) {
+    std::variant<ParkableString, base::HeapArray<uint8_t>> EmptyModuleSource(
+        ResolvedModuleType module_type) {
       if (module_type == ResolvedModuleType::kJavaScript) {
-        return String("");
+        return ParkableString(g_empty_string.Impl());
       }
       CHECK_EQ(module_type, ResolvedModuleType::kWasm);
-      return String(base::span<const uint8_t, 8>(
-          WasmModuleScript::kEmptyWasmByteSequence));
+      return base::HeapArray<uint8_t>::CopiedFrom(
+          WasmModuleScript::kEmptyWasmByteSequence);
     }
 
     const KURL url_;
diff --git a/third_party/blink/renderer/core/script/wasm_module_script.cc b/third_party/blink/renderer/core/script/wasm_module_script.cc
index 28b21d7..e9f4a03 100644
--- a/third_party/blink/renderer/core/script/wasm_module_script.cc
+++ b/third_party/blink/renderer/core/script/wasm_module_script.cc
@@ -30,13 +30,9 @@
   // <spec step="1"> If scripting is disabled for settings's then set
   // bodyBytes to the byte sequence 0x00 0x61 0x73 0x6d 0x01 0x00 0x00 0x00.
   // </spec>
-  const uint8_t* source =
-      modulator->IsScriptingDisabled()
-          ? kEmptyWasmByteSequence
-          : base::as_bytes(params.GetSourceText().SpanChar()).data();
-
-  size_t source_length =
-      modulator->IsScriptingDisabled() ? 8 : params.GetSourceText().length();
+  base::span<const uint8_t> source = modulator->IsScriptingDisabled()
+                                         ? kEmptyWasmByteSequence
+                                         : params.GetWasmSource().as_span();
 
   // <spec step="2">Let script be a new module script that this algorithm will
   // subsequently initialize.</spec>
@@ -57,7 +53,7 @@
   v8::Local<v8::WasmModuleObject> result;
   bool success =
       v8::WasmModuleObject::Compile(
-          isolate, v8::MemorySpan<const uint8_t>(source, source_length))
+          isolate, v8::MemorySpan<const uint8_t>(source.data(), source.size()))
           .ToLocal(&result);
   // <spec step="8">If the previous step threw an error, then:</spec>
   WasmModuleScript* script = MakeGarbageCollected<WasmModuleScript>(
@@ -95,7 +91,8 @@
   v8::Local<v8::WasmModuleObject> result;
   bool success =
       v8::WasmModuleObject::Compile(
-          isolate, v8::MemorySpan<const uint8_t>(kEmptyWasmByteSequence, 8))
+          isolate, v8::MemorySpan<const uint8_t>(kEmptyWasmByteSequence.data(),
+                                                 kEmptyWasmByteSequence.size()))
           .ToLocal(&result);
   CHECK(success);
   return result;
diff --git a/third_party/blink/renderer/core/script/wasm_module_script.h b/third_party/blink/renderer/core/script/wasm_module_script.h
index 927d43f..d5ddfc62 100644
--- a/third_party/blink/renderer/core/script/wasm_module_script.h
+++ b/third_party/blink/renderer/core/script/wasm_module_script.h
@@ -56,8 +56,10 @@
 
   // This byte sequence corresponds to an empty WebAssembly module with only
   // the magic bytes and version number provided.
-  static constexpr const uint8_t kEmptyWasmByteSequence[8] = {
+  static constexpr uint8_t kEmptyWasmByteSequenceRaw[] = {
       0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00};
+  static constexpr base::span<const uint8_t, 8> kEmptyWasmByteSequence =
+      base::span<const uint8_t, 8>(kEmptyWasmByteSequenceRaw);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_aura_test.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_aura_test.cc
index 96bca277..17de0a6 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_aura_test.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_aura_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme_aura.h"
 
+#include "base/notimplemented.h"
 #include "third_party/blink/public/common/input/web_mouse_event.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_test_suite.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
diff --git a/third_party/blink/renderer/core/testing/data/core_test_bundle_data.filelist b/third_party/blink/renderer/core/testing/data/core_test_bundle_data.filelist
index bc0cbedc..392c534c 100644
--- a/third_party/blink/renderer/core/testing/data/core_test_bundle_data.filelist
+++ b/third_party/blink/renderer/core/testing/data/core_test_bundle_data.filelist
@@ -311,6 +311,7 @@
 testing/data/no_scale_for_you.html
 testing/data/no_viewport_tag.html
 testing/data/nodeimage.html
+testing/data/non_UTF8.wasm
 testing/data/non-scrollable.html
 testing/data/non_user_input_text_update.html
 testing/data/not_an_image.ico
diff --git a/third_party/blink/renderer/core/testing/data/non_UTF8.wasm b/third_party/blink/renderer/core/testing/data/non_UTF8.wasm
new file mode 100644
index 0000000..9a15244a
--- /dev/null
+++ b/third_party/blink/renderer/core/testing/data/non_UTF8.wasm
Binary files differ
diff --git a/third_party/blink/renderer/core/timing/performance_timing_for_reporting.cc b/third_party/blink/renderer/core/timing/performance_timing_for_reporting.cc
index 052d7eb..e0a9303 100644
--- a/third_party/blink/renderer/core/timing/performance_timing_for_reporting.cc
+++ b/third_party/blink/renderer/core/timing/performance_timing_for_reporting.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/paint/timing/paint_timing.h"
 #include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h"
 #include "third_party/blink/renderer/core/timing/performance.h"
+#include "third_party/blink/renderer/core/timing/soft_navigation_heuristics.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h"
 
 namespace blink {
@@ -178,15 +179,12 @@
   return MonotonicTimeToIntegerMilliseconds(timing->FirstImagePaint());
 }
 
-uint64_t
-PerformanceTimingForReporting::FirstContentfulPaintIgnoringSoftNavigations()
-    const {
+uint64_t PerformanceTimingForReporting::FirstContentfulPaint() const {
   const PaintTiming* timing = GetPaintTiming();
   if (!timing)
     return 0;
 
-  return MonotonicTimeToIntegerMilliseconds(
-      timing->FirstContentfulPaintIgnoringSoftNavigations());
+  return MonotonicTimeToIntegerMilliseconds(timing->FirstContentfulPaint());
 }
 
 base::TimeTicks PerformanceTimingForReporting::
@@ -205,7 +203,7 @@
   if (!timing)
     return base::TimeTicks();
 
-  return timing->FirstContentfulPaintIgnoringSoftNavigations();
+  return timing->FirstContentfulPaint();
 }
 
 uint64_t PerformanceTimingForReporting::FirstMeaningfulPaint() const {
@@ -240,13 +238,13 @@
 
 LargestContentfulPaintDetailsForReporting PerformanceTimingForReporting::
     SoftNavigationLargestContentfulPaintDetailsForMetrics() const {
-  PaintTimingDetector* paint_timing_detector = GetPaintTimingDetector();
-  if (!paint_timing_detector) {
+  SoftNavigationHeuristics* heuristics = GetSoftNavigationHeuristics();
+  if (!heuristics) {
     return {};
   }
 
-  auto timing = paint_timing_detector
-                    ->SoftNavigationLargestContentfulPaintDetailsForMetrics();
+  auto timing =
+      heuristics->SoftNavigationLargestContentfulPaintDetailsForMetrics();
 
   return PopulateLargestContentfulPaintDetailsForReporting(timing);
 }
@@ -499,6 +497,14 @@
   return &DomWindow()->GetFrame()->View()->GetPaintTimingDetector();
 }
 
+SoftNavigationHeuristics*
+PerformanceTimingForReporting::GetSoftNavigationHeuristics() const {
+  if (!DomWindow()) {
+    return nullptr;
+  }
+  return DomWindow()->GetSoftNavigationHeuristics();
+}
+
 std::optional<base::TimeDelta>
 PerformanceTimingForReporting::MonotonicTimeToPseudoWallTime(
     const std::optional<base::TimeTicks>& time) const {
diff --git a/third_party/blink/renderer/core/timing/performance_timing_for_reporting.h b/third_party/blink/renderer/core/timing/performance_timing_for_reporting.h
index 216f67e..aafeb7f6 100644
--- a/third_party/blink/renderer/core/timing/performance_timing_for_reporting.h
+++ b/third_party/blink/renderer/core/timing/performance_timing_for_reporting.h
@@ -25,6 +25,7 @@
 class InteractiveDetector;
 class PaintTiming;
 struct LargestContentfulPaintDetails;
+class SoftNavigationHeuristics;
 
 // This class is only used for non-web-exposed reporting purposes (e.g. UKM).
 class CORE_EXPORT PerformanceTimingForReporting final
@@ -76,7 +77,7 @@
 
   // The time of the first 'contentful' paint. A contentful paint is a paint
   // that includes content of some kind (for example, text or image content).
-  uint64_t FirstContentfulPaintIgnoringSoftNavigations() const;
+  uint64_t FirstContentfulPaint() const;
 
   // The first 'contentful' paint as full-resolution monotonic time. Intended to
   // be used for correlation with other events internal to blink.
@@ -181,6 +182,7 @@
   const DocumentParserTiming* GetDocumentParserTiming() const;
   const PaintTiming* GetPaintTiming() const;
   PaintTimingDetector* GetPaintTimingDetector() const;
+  SoftNavigationHeuristics* GetSoftNavigationHeuristics() const;
   DocumentLoader* GetDocumentLoader() const;
   DocumentLoadTiming* GetDocumentLoadTiming() const;
   InteractiveDetector* GetInteractiveDetector() const;
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_context.cc b/third_party/blink/renderer/core/timing/soft_navigation_context.cc
index ee171a7..c78186b 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_context.cc
+++ b/third_party/blink/renderer/core/timing/soft_navigation_context.cc
@@ -174,12 +174,6 @@
     return;
   }
   first_input_or_scroll_time_ = base::TimeTicks::Now();
-
-  // TODO(crbug.com/422958651): Same as with hard-LCP, although we have just
-  // scrolled/had input, we might still be waiting for presentation time
-  // feedback from paints that came before that scroll/input.  It seems
-  // perfectly reasonable to keep lcp_calculator_ around until those report.
-  lcp_calculator_ = nullptr;
 }
 
 // TODO(crbug.com/419386429): This gets called after each new presentation time
@@ -207,19 +201,47 @@
 // Soft-nav entry if we already have candidates to report.  Similar to above,
 // there are concerns with reporting Candidates after Paint but before
 // Presentation.
-void SoftNavigationContext::UpdateSoftLcpCandidate() {
-  // Check if we have already stopped measuring LCP (Input or Scroll)
-  if (!lcp_calculator_) {
-    return;
-  }
-  // Check if we are ready to start measuring LCP (After soft-nav entry).
-  if (!WasEmitted()) {
-    return;
-  }
+void SoftNavigationContext::UpdateWebExposedLargestContentfulPaintIfNeeded() {
   lcp_calculator_->UpdateWebExposedLargestContentfulPaintIfNeeded(
       largest_text_, largest_image_, true);
 }
 
+bool SoftNavigationContext::TryUpdateLcpCandidate() {
+  // After we are ready to start measuring LCP (was emitted soft-nav entry) and
+  // before we want to stop (input or scroll), we update LCP candidate.
+  if (!WasEmitted() || !first_input_or_scroll_time_.is_null()) {
+    return false;
+  }
+  // TODO(crbug.com/425398556): Consider updating `lcp_calculator_` to accept
+  // ImageRecord and TextRecord and to extract its own timings/sizes rather than
+  // passing them manually here-- similar to how
+  // `UpdateWebExposedLargestContentfulPaintIfNeeded` does it.
+  bool latest_lcp_details_for_ukm_changed = false;
+  // TODO(crbug.com/425989954): Guard on paint_time, because although this
+  // TryUpdateLcpCandidate gets called after presentation feedback, it might not
+  // be the right presentation time for this specific text/image record.
+  if (largest_text_ && !largest_text_->paint_time.is_null()) {
+    latest_lcp_details_for_ukm_changed =
+        latest_lcp_details_for_ukm_changed ||
+        lcp_calculator_->NotifyMetricsIfLargestTextPaintChanged(
+            largest_text_->paint_time, largest_text_->recorded_size);
+  }
+  if (largest_image_ && !largest_image_->paint_time.is_null()) {
+    latest_lcp_details_for_ukm_changed =
+        latest_lcp_details_for_ukm_changed ||
+        lcp_calculator_->NotifyMetricsIfLargestImagePaintChanged(
+            largest_image_->paint_time, largest_image_->recorded_size,
+            largest_image_, largest_image_->EntropyForLCP(),
+            largest_image_->RequestPriority());
+  }
+  return latest_lcp_details_for_ukm_changed;
+}
+
+const LargestContentfulPaintDetails&
+SoftNavigationContext::LatestLcpDetailsForUkm() {
+  return lcp_calculator_->LatestLcpDetails();
+}
+
 void SoftNavigationContext::WriteIntoTrace(
     perfetto::TracedValue context) const {
   perfetto::TracedDictionary dict = std::move(context).WriteDictionary();
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_context.h b/third_party/blink/renderer/core/timing/soft_navigation_context.h
index b671208..55b9d28 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_context.h
+++ b/third_party/blink/renderer/core/timing/soft_navigation_context.h
@@ -22,6 +22,7 @@
 class TextRecord;
 class ImageRecord;
 class LargestContentfulPaintCalculator;
+struct LargestContentfulPaintDetails;
 
 class CORE_EXPORT SoftNavigationContext
     : public GarbageCollected<SoftNavigationContext> {
@@ -72,7 +73,9 @@
   // Used to check if it is worthwhile to call `SatisfiesSoftNavPaintCriteria`.
   bool OnPaintFinished();
   void OnInputOrScroll();
-  void UpdateSoftLcpCandidate();
+  bool TryUpdateLcpCandidate();
+  void UpdateWebExposedLargestContentfulPaintIfNeeded();
+  const LargestContentfulPaintDetails& LatestLcpDetailsForUkm();
 
   bool SatisfiesSoftNavNonPaintCriteria() const;
   bool SatisfiesSoftNavPaintCriteria(uint64_t required_paint_area) const;
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
index 6c487d0..b6207f9 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -441,14 +441,37 @@
 }
 
 void SoftNavigationHeuristics::UpdateSoftLcpCandidate() {
+  // This is called from PaintTimingMixin on every paint timing update, without
+  // feature flag check. We shouldn't have a url context without the feature.
   if (!context_for_current_url_) {
     return;
   }
-  // Performance timeline won't allow emitting LCP entries without this flag,
-  // but we can save a lot of needless work by also just not even trying.
-  if (RuntimeEnabledFeatures::SoftNavigationHeuristicsEnabled(window_)) {
-    context_for_current_url_->UpdateSoftLcpCandidate();
+  CHECK(RuntimeEnabledFeatures::SoftNavigationDetectionEnabled(window_));
+
+  bool has_new_lcp_candidate =
+      context_for_current_url_->TryUpdateLcpCandidate();
+  if (!has_new_lcp_candidate) {
+    return;
   }
+
+  // Performance timeline won't allow emitting soft-LCP entries without this
+  // flag, but we can save some needless work by just not even trying to report.
+  if (RuntimeEnabledFeatures::SoftNavigationHeuristicsEnabled(window_)) {
+    context_for_current_url_->UpdateWebExposedLargestContentfulPaintIfNeeded();
+  }
+
+  soft_navigation_lcp_details_for_metrics_ =
+      context_for_current_url_->LatestLcpDetailsForUkm();
+
+  Document* document = window_->document();
+  if (!document) {
+    return;
+  }
+  DocumentLoader* loader = document->Loader();
+  if (!loader) {
+    return;
+  }
+  loader->DidChangePerformanceTiming();
 }
 
 void SoftNavigationHeuristics::ReportSoftNavigationToMetrics(
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
index f5f933b..79d4e96 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/paint/timing/lcp_objects.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h"
@@ -105,6 +106,11 @@
   void OnInputOrScroll();
   void UpdateSoftLcpCandidate();
 
+  const LargestContentfulPaintDetails&
+  SoftNavigationLargestContentfulPaintDetailsForMetrics() const {
+    return soft_navigation_lcp_details_for_metrics_;
+  }
+
   // Returns an `EventScope` suitable for navigation. Used for navigations not
   // yet associated with an event.
   EventScope CreateNavigationEventScope(ScriptState* script_state) {
@@ -180,6 +186,9 @@
   // which should happen before the tracker is destroyed, since its lifetime is
   // tied to the lifetime of the isolate/main thread.
   scheduler::TaskAttributionTracker* task_attribution_tracker_;
+
+  // The soft navigation LCP details reported to metrics (UKM).
+  LargestContentfulPaintDetails soft_navigation_lcp_details_for_metrics_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/credentialmanagement/authenticator_response.cc b/third_party/blink/renderer/modules/credentialmanagement/authenticator_response.cc
index 883ab44..89486964 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/authenticator_response.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/authenticator_response.cc
@@ -6,7 +6,7 @@
 
 #include <variant>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc b/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc
index d720d516..646b384 100644
--- a/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc
+++ b/third_party/blink/renderer/modules/mediasource/cross_thread_media_source_attachment.cc
@@ -6,6 +6,7 @@
 
 #include "base/feature_list.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/types/pass_key.h"
 #include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
diff --git a/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc b/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
index 83dc0c9..f5846e29 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h"
 
+#include "base/notimplemented.h"
+
 namespace blink {
 
 MediaSourceAttachmentSupplement::MediaSourceAttachmentSupplement() = default;
diff --git a/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc b/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc
index 4dcc36d..d0fda3c 100644
--- a/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc
+++ b/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc
@@ -15,6 +15,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/sequence_checker.h"
 #include "base/strings/to_string.h"
 #include "base/task/bind_post_task.h"
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
index 65b820e..9b0fe33 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/notimplemented.h"
 #include "services/webnn/public/mojom/webnn_device.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_transpose_options.h"
 #ifdef UNSAFE_BUFFERS_BUILD
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
index 8a11838..6a26055 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/containers/span.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -30,7 +31,9 @@
 
 static const char kFakeRecordId[] =
     "https://w3c.github.io/web-nfc/dummy-record-id";
+#if !BUILDFLAG(IS_IOS) || BUILDFLAG(IS_IOS_TVOS)
 static const char kFakeNfcTagSerialNumber[] = "c0:45:00:02";
+#endif
 
 MATCHER_P(MessageEquals, expected, "") {
   // Only check the first data array.
@@ -81,8 +84,21 @@
     if (!client_ || !tag_message_)
       return;
 
+#if BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS)
+    auto raw_message = device::mojom::blink::NDEFRawMessage::New();
+    WTF::Vector<uint8_t> record_data(
+        {0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10});
+    auto raw_record = device::mojom::blink::NDEFRawRecord::New(
+        WTF::Vector<uint8_t>(base::as_byte_span(kFakeRecordId)), record_data,
+        WTF::Vector<uint8_t>("mime"),
+        device::mojom::blink::NSRawTypeNameFormat::kMedia);
+    raw_message->data.push_back(std::move(raw_record));
+
+    client_->OnWatch(std::move(watchIDs_), std::move(raw_message));
+#else
     client_->OnWatch(std::move(watchIDs_), kFakeNfcTagSerialNumber,
                      tag_message_.Clone());
+#endif
   }
 
   void set_tag_message(device::mojom::blink::NDEFMessagePtr message) {
@@ -97,10 +113,17 @@
 
  private:
   // Override methods from device::mojom::blink::NFC.
+#if BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS)
+  void SetClient(
+      mojo::PendingRemote<device::mojom::blink::RawNFCClient> client) override {
+    client_.Bind(std::move(client));
+  }
+#else
   void SetClient(
       mojo::PendingRemote<device::mojom::blink::NFCClient> client) override {
     client_.Bind(std::move(client));
   }
+#endif
   void Push(device::mojom::blink::NDEFMessagePtr message,
             device::mojom::blink::NDEFWriteOptionsPtr options,
             PushCallback callback) override {
@@ -127,7 +150,11 @@
 
   device::mojom::blink::NDEFErrorPtr watch_error_;
   device::mojom::blink::NDEFMessagePtr tag_message_;
+#if BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS)
+  mojo::Remote<device::mojom::blink::RawNFCClient> client_;
+#else
   mojo::Remote<device::mojom::blink::NFCClient> client_;
+#endif
   WTF::Vector<uint32_t> watchIDs_;
   mojo::Receiver<device::mojom::blink::NFC> receiver_;
 };
@@ -186,8 +213,13 @@
 
   {
     base::RunLoop loop;
-    EXPECT_CALL(*reader, OnReading(String(kFakeNfcTagSerialNumber),
-                                   MessageEquals(record_data)))
+    EXPECT_CALL(*reader, OnReading(
+#if BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS)
+                             String(),
+#else
+                             String(kFakeNfcTagSerialNumber),
+#endif
+                             MessageEquals(record_data)))
         .WillOnce(Invoke([&](const String& serial_number,
                              const device::mojom::blink::NDEFMessage& message) {
           loop.Quit();
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc
index 370e0c1..5aec9e01 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc
@@ -6,6 +6,7 @@
 
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc b/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc
index 4bbc4744..e47b42e 100644
--- a/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.h"
+
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
-#include "third_party/blink/renderer/modules/peerconnection/fake_rtc_rtp_transceiver_impl.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_component_impl.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.cc b/third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.cc
index cf37d0a..f50f155 100644
--- a/third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc b/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
index 87f12ef2..2800caee 100644
--- a/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
@@ -13,7 +13,7 @@
 #include "base/check_op.h"
 #include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.h"
 #include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h"
 #include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc b/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc
index 26ec3f6..e3309f7 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_stats_report.cc
@@ -6,6 +6,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "third_party/blink/public/common/features.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 346be4ba..572a64c 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -14,6 +14,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/numerics/clamped_math.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index 9cb635a..2977910 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -10,6 +10,7 @@
 #include "base/containers/span.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/task/bind_post_task.h"
 #include "base/time/time.h"
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index b3e86cd..d01b1e2 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -34,6 +34,7 @@
 #include "base/feature_list.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/numerics/checked_math.h"
 #include "base/synchronization/lock.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_composition_layer.cc b/third_party/blink/renderer/modules/xr/xr_composition_layer.cc
index f69b821..96ae1db7 100644
--- a/third_party/blink/renderer/modules/xr/xr_composition_layer.cc
+++ b/third_party/blink/renderer/modules/xr/xr_composition_layer.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/xr/xr_composition_layer.h"
 
+#include "base/notimplemented.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_xr_layer_layout.h"
 #include "third_party/blink/renderer/modules/xr/xr_graphics_binding.h"
 #include "third_party/blink/renderer/modules/xr/xr_session.h"
diff --git a/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc b/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc
index e0e555dc..c61602f 100644
--- a/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc
+++ b/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/platform/blob/testing/fake_blob_registry.h"
 
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc
index 19569b0..0384f4c 100644
--- a/third_party/blink/renderer/platform/exported/platform.cc
+++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -32,6 +32,7 @@
 
 #include <memory>
 
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
index 2d96aea..e08e3c3 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/third_party/blink/renderer/platform/graphics/color.cc b/third_party/blink/renderer/platform/graphics/color.cc
index 41203b862..e3378d1 100644
--- a/third_party/blink/renderer/platform/graphics/color.cc
+++ b/third_party/blink/renderer/platform/graphics/color.cc
@@ -32,6 +32,7 @@
 #include <tuple>
 
 #include "base/check_op.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_view_util.h"
 #include "build/build_config.h"
diff --git a/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc b/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
index 2ac3820..0f28740 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
index 590ef0f..2e4df939 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -34,6 +34,7 @@
 #include <memory>
 #include <optional>
 
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/types/optional_ref.h"
 #include "components/subresource_filter/core/common/scoped_rule.h"
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
index 34cee8e..6210f66 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
@@ -13,6 +13,7 @@
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/third_party/blink/renderer/platform/media/web_audio_source_provider_impl.cc b/third_party/blink/renderer/platform/media/web_audio_source_provider_impl.cc
index 4352b65..f5e3a3fee 100644
--- a/third_party/blink/renderer/platform/media/web_audio_source_provider_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_audio_source_provider_impl.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/task/bind_post_task.h"
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
index 2008276..04f5612 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
@@ -11,6 +11,7 @@
 
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/to_string.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/third_party/blink/renderer/platform/p2p/filtering_network_manager_test.cc b/third_party/blink/renderer/platform/p2p/filtering_network_manager_test.cc
index e412ddfb..2a5a622 100644
--- a/third_party/blink/renderer/platform/p2p/filtering_network_manager_test.cc
+++ b/third_party/blink/renderer/platform/p2p/filtering_network_manager_test.cc
@@ -19,6 +19,7 @@
 #include "base/memory/raw_ptr_exclusion.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/test_simple_task_runner.h"
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 cb223d96..ccae910 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
@@ -15,6 +15,7 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/sequenced_task_runner.h"
diff --git a/third_party/blink/renderer/platform/scheduler/public/thread.h b/third_party/blink/renderer/platform/scheduler/public/thread.h
index 41fcaeb..c1b69f3 100644
--- a/third_party/blink/renderer/platform/scheduler/public/thread.h
+++ b/third_party/blink/renderer/platform/scheduler/public/thread.h
@@ -26,9 +26,11 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_THREAD_H_
 
 #include <stdint.h>
+
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/task/task_observer.h"
 #include "base/threading/thread.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
diff --git a/third_party/blink/renderer/platform/testing/url_loader_mock.cc b/third_party/blink/renderer/platform/testing/url_loader_mock.cc
index a8523ab0..58dd7b95 100644
--- a/third_party/blink/renderer/platform/testing/url_loader_mock.cc
+++ b/third_party/blink/renderer/platform/testing/url_loader_mock.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "net/cookies/site_for_cookies.h"
 #include "services/network/public/cpp/resource_request.h"
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
index 587349a..a962c59 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
+++ b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
@@ -76,6 +76,7 @@
 crbug.com/1209223 [ Linux ] external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-security-check-same-origin-domain.sub.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/426107053 virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-nn.html [ Timeout ]
 crbug.com/421504441 virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html [ Timeout ]
 crbug.com/416794747 external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html?3-4 [ Crash Pass ]
 crbug.com/415690774 external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html?5-6 [ Crash ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 0625383..42ebc7b8 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1772,6 +1772,7 @@
       "external/wpt/wasm/webapi/esm-integration/wasm-import-wasm-export.tentative.html",
       "external/wpt/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html",
       "external/wpt/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html",
+      "wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice.html",
       "wpt_internal/js/source-phase-imports/invalid-module-types-throw.html"
     ],
     "args": [
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 91a4705..c2f6b1e 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
@@ -7807,6 +7807,15 @@
      ],
      "element": {
       "manual": {
+       "drawing-paths-to-the-canvas": {
+        "fill-path-with-uninvertible-transform-crash.html": [
+         "9d032ddba9637c8bee07c8cb9c4ec618a1c5d701",
+         [
+          null,
+          {}
+         ]
+        ]
+       },
        "filters": {
         "svg-filter-crash.html": [
          "f64379c79241409ab55535596f4cbad894f45b42",
@@ -74926,6 +74935,19 @@
        {}
       ]
      ],
+     "anchor-position-multicol-colspan-003.html": [
+      "e985cebfb807f65d7413d81885f6d2be7234b2a9",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "anchor-position-non-anchored-fallback.html": [
       "26965fe8bf413ca199dae0a09940d46f0b29f62c",
       [
@@ -75904,6 +75926,84 @@
        {}
       ]
      ],
+     "transform-001.tentative.html": [
+      "62170211c2777c50ac3c4433c354ee83a34c326a",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "transform-002.tentative.html": [
+      "65e2942698e0cf370c69e07db7be1628b40f674e",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "transform-003.tentative.html": [
+      "b492fab584f9cd5d213aedb938d9498a6fc061b6",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "transform-004.tentative.html": [
+      "bdd1a804df7b09de8a5459eab8d1afe83fde8290",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "transform-005.tentative.html": [
+      "e6871ced8d21d8917e12ce13f2c9d84b369f21a3",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "transform-006.tentative.html": [
+      "22390d6d0f6c7270b19cf2253144a68389537d9f",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "vertical-aligned-table-cell.html": [
       "9b16621b7132fdf92856f65eaf7a8450c1fc7b63",
       [
@@ -130588,6 +130688,32 @@
        {}
       ]
      ],
+     "font-feature-settings-descriptor-02.html": [
+      "4be3aaa0d82db503807ee14cd048025f6bfa085a",
+      [
+       null,
+       [
+        [
+         "/css/css-fonts/font-feature-settings-descriptor-02-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "font-feature-settings-descriptor-binary.html": [
+      "a7c11bb8dec6296d5b96ea91f158ead900d24dc5",
+      [
+       null,
+       [
+        [
+         "/css/css-fonts/font-feature-settings-descriptor-binary-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "font-feature-settings-tibetan.html": [
       "45cde9acb5d2b4aba2ea53f7c0080551369f4abb",
       [
@@ -324877,7 +325003,7 @@
      []
     ],
     "get-host-info.sub.js": [
-     "9b8c2b5de63f282663cab92231fe1c35184e6f02",
+     "f680cd8b1999a317066de5ce3aab1c682b081bc5",
      []
     ],
     "get-host-info.sub.js.headers": [
@@ -338008,14 +338134,6 @@
        "box-shadow-spread-valid-expected.txt": [
         "b62502c787e8269f268a85abe12d709a4b0bfecd",
         []
-       ],
-       "corners-computed-expected.txt": [
-        "2ab97845bb5be924d484b04ad1ebc1e8bdd3f453",
-        []
-       ],
-       "corners-valid-expected.txt": [
-        "652f11b1cc259d576111c79eee9d3d458df95fe7",
-        []
        ]
       }
      }
@@ -345143,6 +345261,14 @@
       "4a1723e690882650361410bb8af55dab7cbb3b73",
       []
      ],
+     "font-feature-settings-descriptor-02-ref.html": [
+      "180a9cccbb2923e5d1cd2503d18d6c785dd062d4",
+      []
+     ],
+     "font-feature-settings-descriptor-binary-ref.html": [
+      "c5119f37bdeee39fb1ef17d3d13fb892e328ed3e",
+      []
+     ],
      "font-feature-settings-tibetan-ref.html": [
       "83bfe744596dbd9f435ed18ba65018215fff42ed",
       []
@@ -368574,14 +368700,6 @@
        "9d895a5e5b25c85cf04e9be3d659232b64ec2ae3",
        []
       ],
-      "letter-spacing-computed-expected.txt": [
-       "6c45f23b1c3b1904f2ea0d83a4742f26e6a49d03",
-       []
-      ],
-      "letter-spacing-valid-expected.txt": [
-       "9decd1a95edf2debf45fcb504fc7d39127a5ade7",
-       []
-      ],
       "text-align-all-valid-expected.txt": [
        "eed49d7a26f16f94b0320cd9ee431ffdf2d4fc01",
        []
@@ -373853,10 +373971,6 @@
         "07301e286d4573309d66c3ca4323f6d736c2ddb2",
         []
        ],
-       "letter-spacing-expected.txt": [
-        "5d4fa8be30384b0b2d3ca29cafa98871e8777136",
-        []
-       ],
        "list-style-type-expected.txt": [
         "a88dfe45f1e20e09391d0643e07dbf635169a996",
         []
@@ -375469,12 +375583,6 @@
       "2248d3702b0c0276dbb2dd1f1f2ae2712fa654c8",
       []
      ],
-     "animations": {
-      "calc-interpolation-expected.txt": [
-       "9bfa4f27e43e6663f54dc91992bce453f9233c8f",
-       []
-      ]
-     },
      "attr-all-types-expected.txt": [
       "668de5de5e1f881149822e1952b06a8d1761892f",
       []
@@ -375535,10 +375643,6 @@
       "cced79a004c0e7f1acdd55298a1221212bdfe94d",
       []
      ],
-     "calc-letter-spacing-expected.txt": [
-      "4446bc0ab25d5af5c1d71ad94371386bb5ceecf2",
-      []
-     ],
      "calc-linear-radial-conic-gradient-001-expected.txt": [
       "faed530112822a605af26c6b73ec2b8068b7be11",
       []
@@ -375651,12 +375755,24 @@
       "f28ffcb85852f3888516de47a5885ac5c1c48928",
       []
      ],
+     "container-progress-computed.tentative-expected.txt": [
+      "cc139b94b1be6fe64bf2dfcb41c8e7be6c156943",
+      []
+     ],
+     "container-progress-serialize.tentative-expected.txt": [
+      "ca2834815d3bd60d5c9a7938458c880b8796a623",
+      []
+     ],
      "ex-calc-expression-001-ref.html": [
       "888a51ea9b6ac04fb065ee5d84a18be8fe765aca",
       []
      ],
-     "hypot-pow-sqrt-serialize-expected.txt": [
-      "cdc2180e17ea741cee5baad0ade5a92e6e8b004e",
+     "media-progress-computed.tentative-expected.txt": [
+      "1bb9184699c32979579dc49892d0f7c5ca20a5dd",
+      []
+     ],
+     "media-progress-serialize.tentative-expected.txt": [
+      "5bd23a622e55045a4152c262d37afbef8125f00e",
       []
      ],
      "minmax-percentage-serialize-expected.txt": [
@@ -428769,7 +428885,7 @@
        []
       ],
       "utils.sub.js": [
-       "36e5144060132205b387d757c8b93e8498f8c51a",
+       "ceb5e3d06ffc0ca38506fb062868fe4872e497f1",
        []
       ]
      },
@@ -500833,6 +500949,13 @@
         {}
        ]
       ],
+      "corner-shape-invalid.html": [
+       "d65ef996ade2f5581c3657131b406adc758536f7",
+       [
+        null,
+        {}
+       ]
+      ],
       "corner-shape-outside-left.html": [
        "b38b7f3f27872e5bf8ad402aa6dabe981a9d5530",
        [
@@ -500854,8 +500977,22 @@
         {}
        ]
       ],
+      "corners-computed.html": [
+       "2449c8e5f3920f7d5f101f823e5704e3a773a5e0",
+       [
+        null,
+        {}
+       ]
+      ],
       "corners-invalid.html": [
-       "1a762a757250e050bd437f341a786d45a21cee71",
+       "7a1487aaabb563ea62d8416dc0f297ce53d3726e",
+       [
+        null,
+        {}
+       ]
+      ],
+      "corners-valid.html": [
+       "7a1396195c0556a14466ec1f75cd8a277b44a058",
        [
         null,
         {}
@@ -501157,27 +501294,6 @@
          null,
          {}
         ]
-       ],
-       "corner-shape-invalid.html": [
-        "d65ef996ade2f5581c3657131b406adc758536f7",
-        [
-         null,
-         {}
-        ]
-       ],
-       "corners-computed.html": [
-        "6605f9eeb0cccf9f5882278ac123470e546cd168",
-        [
-         null,
-         {}
-        ]
-       ],
-       "corners-valid.html": [
-        "5b1ae7afb3f9fd50e9d7474d6632ddf600749c92",
-        [
-         null,
-         {}
-        ]
        ]
       }
      }
@@ -503898,7 +504014,7 @@
        ]
       ],
       "query-evaluation-style.html": [
-       "585d5e7742b66f504a1e17e0b531b1802c41c509",
+       "84da9a4c9484114d84bc2dc306851e53344526c9",
        [
         null,
         {}
@@ -515331,27 +515447,6 @@
          {}
         ]
        ],
-       "masonry-auto-tracks-computed.html": [
-        "2581a35292f65cba7bd4d74cecad454ce349ce54",
-        [
-         null,
-         {}
-        ]
-       ],
-       "masonry-auto-tracks-invalid.html": [
-        "e23933ecd295866a9335511b2c85880164ceceda",
-        [
-         null,
-         {}
-        ]
-       ],
-       "masonry-auto-tracks-valid.html": [
-        "b0c1424fa726818763db3bde4a62993db3a5418b",
-        [
-         null,
-         {}
-        ]
-       ],
        "masonry-direction-computed.html": [
         "d94476540f59d254ba58c3c0513420a1e9afd608",
         [
@@ -515414,41 +515509,6 @@
          null,
          {}
         ]
-       ],
-       "masonry-template-tracks-invalid.html": [
-        "7fed500c28ebcf3a117eccc8faedad901527e347",
-        [
-         null,
-         {}
-        ]
-       ],
-       "masonry-template-tracks-valid.html": [
-        "45550cbb11295eb72d20c046287e81feeba7986e",
-        [
-         null,
-         {}
-        ]
-       ],
-       "masonry-track-computed.html": [
-        "771626ca94dd8d8afed8674c5fec9eeab108e16c",
-        [
-         null,
-         {}
-        ]
-       ],
-       "masonry-track-invalid.html": [
-        "ba03c8426cb48e61c097c451df3d2e87a01d7848",
-        [
-         null,
-         {}
-        ]
-       ],
-       "masonry-track-valid.html": [
-        "2625c2629e582829fc223007e908c77a3ec8cd68",
-        [
-         null,
-         {}
-        ]
        ]
       }
      }
@@ -533730,7 +533790,7 @@
       ]
      ],
      "if-conditionals.html": [
-      "bc25196e615139e43082c00d6bb066709754ad02",
+      "a299b267af5011f94160705cbd1fe0ec2cb58e51",
       [
        null,
        {}
@@ -533989,7 +534049,7 @@
       ]
      ],
      "progress-computed.html": [
-      "8eb4e2b6757e2559b76c6a641dca40f1df32e0b7",
+      "6d4e8365fb45c34c5c23a080faa92d1f4e67866b",
       [
        null,
        {}
@@ -534117,7 +534177,7 @@
       ]
      ],
      "sign-in-keyframes-with-relative-units.html": [
-      "ad7ffdfd77078d9361b5eff3e1d814315af297c4",
+      "2b5b73332ee048aa684b7f08c110c1f985a49b80",
       [
        null,
        {}
@@ -534229,6 +534289,13 @@
         {}
        ]
       ],
+      "sibling-index-keyframe-font-style-dynamic.html": [
+       "743bf099192bae37c965f1298e2e9a44954829b0",
+       [
+        null,
+        {}
+       ]
+      ],
       "sibling-index-keyframe-font-variation-settings-dynamic.html": [
        "d98a72a2fb219e08dac908eca790bae20fc9f234",
        [
@@ -534250,6 +534317,13 @@
         {}
        ]
       ],
+      "sibling-index-keyframe-palette-mix-dynamic.html": [
+       "aef994da26e8eb0819ca7a98374d60d5eedfd1e0",
+       [
+        null,
+        {}
+       ]
+      ],
       "sibling-index-keyframe-percent-dynamic.html": [
        "58d1e7990d3aa73d94aa857386c948e46d763f03",
        [
@@ -547442,6 +547516,13 @@
         {}
        ]
       ],
+      "child-style-preserve.html": [
+       "68bdec16037fbf2748919ebc295720e20b9aaa88",
+       [
+        null,
+        {}
+       ]
+      ],
       "continue-css-animation-left.html": [
        "8c7f73e3c933ce6f6a9749281707c62e0a090d7d",
        [
@@ -717874,7 +717955,7 @@
     ],
     "prefetch": {
      "anonymous-client.https.html": [
-      "902724cdb0e08e603d0d41566a2fe889646088f0",
+      "a371255eede7305cd1f07ec9517d1a0c26f5ed2b",
       [
        null,
        {}
@@ -717932,8 +718013,18 @@
        }
       ]
      ],
+     "cross-origin-cookies-anonymous-client-ip-duplicate.https.html": [
+      "4e793c9f04aaf55f9c59cceb567c829355ce6fff",
+      [
+       null,
+       {
+        "testdriver": true,
+        "timeout": "long"
+       }
+      ]
+     ],
      "cross-origin-cookies.https.html": [
-      "95c95197a70e200542bf3691f10ee1a73a4deb76",
+      "e6785d83536a46b95095d12da8e69a4b5293c2b5",
       [
        null,
        {
@@ -718434,7 +718525,7 @@
       ]
      },
      "out-of-document-rule-set.https.html": [
-      "b0e0253eeb786396fa42d349ff4d9518ca395eae",
+      "1421ac30ee594dca95d3e6e157e3ebebbe51e584",
       [
        "speculation-rules/prefetch/out-of-document-rule-set.https.html?include=BaseCase",
        {}
@@ -718626,7 +718717,7 @@
       ]
      ],
      "referrer-policy-from-rules.https.html": [
-      "f877bd848246fff7b2145edd106ae48af696b24b",
+      "da32465a2578d37d192a597ca0327f05b2ab2119",
       [
        "speculation-rules/prefetch/referrer-policy-from-rules.https.html?1-1",
        {}
@@ -718661,7 +718752,7 @@
       ]
      ],
      "referrer-policy-not-accepted.https.html": [
-      "8cb7388479b9a56c16c79df8e03e00aacab7bf54",
+      "24f75bb9c3c254d041c1d965f99c83f14e14c8d6",
       [
        "speculation-rules/prefetch/referrer-policy-not-accepted.https.html?1-1",
        {}
@@ -718941,7 +719032,7 @@
       }
      },
      "user-pass.https.html": [
-      "c6cc51bdb04ba860142de6a789bc30f9d36cf740",
+      "177c57d1b39a33d06ff42547b6987a29e52cf017",
       [
        "speculation-rules/prefetch/user-pass.https.html?cross-origin=false",
        {
@@ -720641,7 +720732,7 @@
     ],
     "speculation-tags": {
      "cross-site-prefetch.https.html": [
-      "b10aecf40350cf9849b6e36e577a29cd9100ee64",
+      "3eb735cec961996fbca85f6ab6008f9b86f5cc50",
       [
        null,
        {
@@ -720650,7 +720741,7 @@
       ]
      ],
      "cross-site-to-same-site-redirection-prefetch.https.html": [
-      "e264572c2f963ed1b1d63515049c33a221551ef5",
+      "5e84d179ee93f5351dc2efe2ba95f90acacaf9ff",
       [
        null,
        {
@@ -720739,7 +720830,7 @@
       ]
      ],
      "same-site-to-cross-site-redirection-prefetch.https.html": [
-      "27ece0cfde17716cf2846d18c825d7d1d286d538",
+      "fa04055a27b8c08216de18f0b9ce5122b4034333",
       [
        null,
        {
@@ -759830,7 +759921,7 @@
      },
      "the-mediastreamaudiodestinationnode-interface": {
       "ctor-mediastreamaudiodestination.html": [
-       "5d3fd0c26f4aa0347e2682b303d9bedbcc2b7600",
+       "7d67c1e6897c43090cd460f344ebed591f4ffe7a",
        [
         null,
         {}
@@ -779800,7 +779891,7 @@
       ]
      ],
      "qdq_subgraph.https.any.js": [
-      "b7bcdc06228075db5a54494f41f488ccf29f9207",
+      "62312137101c291efbd736da4ee43386450a7bca",
       [
        "webnn/conformance_tests/qdq_subgraph.https.any.html?cpu",
        {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-002.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-002.html
index e3e8376..5e324624 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-002.html
@@ -43,5 +43,4 @@
 </div>
 <script>
   scroller.scrollTop = 400;
-  assert_equals(getComputedStyle(link4).color, "rgb(0, 128, 0)", "link4 should be :target-current");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-003.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-003.html
index 39e1bef..413e99f4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-target-group-003.html
@@ -61,5 +61,4 @@
 </div>
 <script>
   scroller.scrollTop = 400;
-  assert_equals(getComputedStyle(link4).color, "rgb(0, 128, 0)", "link4 should be :target-current");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-2-transforminterop.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-2-transforminterop.html
new file mode 100644
index 0000000..1322fc7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-2-transforminterop.html
@@ -0,0 +1,261 @@
+<!DOCTYPE html>
+<title>More point mapping through 3D transform hierarchies</title>
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style type="text/css" media="screen">
+  body {
+    margin: 0;
+    border: 1px solid black;
+  }
+
+  .test {
+    display: inline-block;
+    height: 200px;
+    width: 200px;
+    border: 1px solid black;
+    margin: 20px;
+  }
+
+  #box1, #box5, #box9 {
+    height: 140px;
+    width: 140px;
+    margin: 20px;
+    background-color: #DDD;
+    border: 1px solid black;
+    box-sizing: border-box;
+    perspective: 400px;
+  }
+
+  #box2, #box6, #box10 {
+    position: relative;
+    height: 100px;
+    width: 100px;
+    padding: 20px;
+    margin: 20px;
+    border: 1px solid black;
+    background-color: #81AA8A;
+    transform-style: preserve-3d;
+    transform: rotateY(-30deg);
+    box-sizing: border-box;
+  }
+
+  #box3 {
+    position: relative;
+    height: 100px;
+    width: 100px;
+    padding: 20px;
+    margin: 20px;
+    border: 1px solid black;
+    background-color: #81AA8A;
+    transform-style: preserve-3d;
+    box-sizing: border-box;
+  }
+
+  #box4, #box8, #box12 {
+    height: 90px;
+    width: 90px;
+    background-color: blue;
+    border: 1px solid black;
+    box-sizing: border-box;
+    transform: rotateY(30deg);
+  }
+
+  #box7 {
+    position: relative;
+    padding-left: 20px;
+    height: 100px;
+    width: 100px;
+    box-sizing: border-box;
+    background-color: #DDD;
+    border: 1px solid black;
+  }
+
+  #box11 {
+    padding-left: 20px;
+    height: 100px;
+    width: 100px;
+    box-sizing: border-box;
+    background-color: #DDD;
+    border: 1px solid black;
+  }
+
+  [id^="box"]:hover {
+    outline: 3px solid orange;
+  }
+</style>
+
+<body>
+
+<div class="test">
+  <!-- preserve-3d element with no transform-->
+  <div id="box1">
+    <div id="box2">
+      <div id="box3">
+        <div id="box4">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="test">
+  <!-- layer with no transform-->
+  <div id="box5">
+    <div id="box6">
+      <div id="box7">
+        <div id="box8">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="test">
+  <!-- non-layer with no transform-->
+  <div id="box9">
+    <div id="box10">
+      <div id="box11">
+        <div id="box12">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<script>
+  class Point {
+    constructor(x, y) {
+      this.x = x;
+      this.y = y;
+    }
+  };
+  // Each test case defines four test points near the corners of an element area.
+  // - Point 1: Top-left
+  // - Point 2: Top-right
+  // - Point 3: Bottom-left
+  // - Point 4: Bottom-right
+  const tests = [{
+    expectedElemId: 'box1',
+      points: [
+        new Point(68, 66), // Hits box1 due to box2's transformation.
+        new Point(175, 45),
+        new Point(62, 155), // Hits box1 due to box2's transformation.
+        new Point(100, 175),
+      ]
+    },
+    {
+      expectedElemId: 'box2',
+      points: [
+        new Point(75, 70),
+        new Point(155, 63),
+        new Point(75, 155),
+        new Point(100, 156), // Hits box2 due to box3 preserving parent's transformed space.
+      ]
+    },
+    {
+      expectedElemId: 'box3',
+      points: [
+        new Point(108, 106),
+        new Point(198, 106),
+        new Point(108, 198),
+        // Bottom-right area is overlapped by box4.
+      ]
+    },
+    {
+      expectedElemId: 'box4',
+      points: [
+        new Point(120, 128), // Hits box3 if box4 were untransformed.
+        new Point(210, 128),
+        new Point(120, 198), // Hits box3 if box4 were untransformed.
+        new Point(210, 215),
+      ]
+    },
+    {
+      expectedElemId: 'box5',
+      points: [
+        new Point(312, 67), // Hits box5 due to box6's transformation.
+        new Point(423, 47),
+        new Point(312, 155), // Hits box5 due to box6's transformation.
+        new Point(331, 175), // Hits box5 due to box7 preserving parent's transformed space.
+      ]
+    },
+    {
+      expectedElemId: 'box6',
+      points: [
+        new Point(328, 86), // Hits box6 due to box7 preserving parent's transformed space.
+        new Point(400, 63),
+        new Point(328, 151), // Hits box6 due to box7 preserving parent's transformed space.
+        // The bottom-right area is overlapped by box7.
+      ]
+    },
+    {
+      expectedElemId: 'box7',
+      points: [
+        new Point(354, 87), // Hits box7 due to box8's transformation.
+        // The top-right area is overlapped by box8.
+        new Point(354, 171), // Hits box7 due to box8's transformation.
+        new Point(421, 185),
+      ]
+    },
+    {
+      expectedElemId: 'box8',
+      points: [
+        new Point(359, 87),
+        new Point(428, 84),
+        new Point(359, 168),
+        new Point(428, 175),
+      ]
+    },
+    {
+      expectedElemId: 'box9',
+      points: [
+        new Point(556, 65), // Hits box9 due to box10's transformation.
+        new Point(669, 46),
+        new Point(556, 157), // Hits box9 due to box10's transformation.
+        new Point(576, 174), // Hits box9 due to box11 preserving parent's transformed space.
+      ]
+    },
+    {
+      expectedElemId: 'box10',
+      points: [
+        new Point(568, 69),
+        new Point(646, 62),
+        new Point(568, 153),
+        new Point(576, 154), // Hits box10 due to box11 preserving parent's transformed space.
+      ]
+    },
+    {
+      expectedElemId: 'box11',
+      points: [
+        new Point(600, 87), // Hits box11 due to box12's transformation.
+        // The top-right area is overlapped by box12.
+        new Point(600, 170),
+        new Point(669, 185),
+      ]
+    },
+    {
+      expectedElemId: 'box12',
+      points: [
+        new Point(605, 87),
+        new Point(673, 85),
+        new Point(605, 170),
+        new Point(675, 175),
+      ]
+    }
+  ];
+
+  tests.forEach(testcase => {
+    test(t => {
+      const expectedElem = document.getElementById(testcase.expectedElemId);
+      for (const point of testcase.points) {
+        const hitElem = document.elementFromPoint(point.x, point.y);
+        assert_equals(hitElem, expectedElem,
+          `point (${point.x}, ${point.y}) is inside element ${testcase.expectedElemId}`);
+      }
+    }, `${document.title}, hittesting ${testcase.expectedElemId})`);
+  });
+</script>
+
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-3.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-3.html
index 906171e2..458ea62 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-3.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-3.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <title>Point mapping through 3D transform hierarchies</title>
-<link rel="help" href="https://svgwg.org/svg2-draft/interact.html#hit-testing">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-coplanar.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-coplanar.html
index 0ae0ab1e..7d028801 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-coplanar.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-coplanar.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <title>Hit test coplanar elements</title>
-<link rel="help" href="https://svgwg.org/svg2-draft/interact.html#hit-testing">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-overlapping.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-overlapping.html
index ffcfc1a..ea93c7e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-overlapping.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping-overlapping.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <title>Hit test overlapping elements</title>
-<link rel="help" href="https://svgwg.org/svg2-draft/interact.html#hit-testing">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping.html
index fd6ea8d..1600031 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/3d-point-mapping.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <title>Point mapping through 3D transforms</title>
-<link rel="help" href="https://svgwg.org/svg2-draft/interact.html#hit-testing">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/drawing-paths-to-the-canvas/fill-path-with-uninvertible-transform-crash.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/drawing-paths-to-the-canvas/fill-path-with-uninvertible-transform-crash.html
new file mode 100644
index 0000000..9d032ddb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/drawing-paths-to-the-canvas/fill-path-with-uninvertible-transform-crash.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+  let context = document.createElement("canvas").getContext("2d");
+  context.moveTo(0, 0);
+  context.setTransform(4, 2, 6, 3, 0, 0); // non-invertible (4 * 3 - 6 * 2 = 0)
+  context.fill("nonzero");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/lcp/tentative/raf-loop.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/lcp/tentative/raf-loop.html
deleted file mode 100644
index 8693aef..0000000
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/lcp/tentative/raf-loop.html
+++ /dev/null
@@ -1,101 +0,0 @@
-<!doctype html>
-<meta charset="utf-8" />
-<title>
-  Largest Contentful Paint after soft navigation: requestAnimationFrame can add additional LCP
-  entry.
-</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="/soft-navigation-heuristics/resources/soft-navigation-test-helper.js"></script>
-<body>
-  <button id="click-target" onclick="clickHandler()">Click!</button>
-</body>
-<script>
-  // The click handler will invoke this function, which uses a RAF
-  // loop to defer some additional work, which ultimately causes
-  // the larger LCP entry to be added. The test will wait for
-  // two soft LCP entries, the first for the small text, and the
-  // second for the large text.
-  function clickHandlerPart2(countdown) {
-    if (countdown > 0) {
-      requestAnimationFrame(() => {
-        clickHandlerPart2(countdown - 1);
-      });
-      return;
-    }
-    const div = document.createElement("div");
-    div.innerHTML = "The quick brown fox jumps over the lazy dog.";
-    div.id = "large-lcp";
-    document.body.appendChild(div);
-  }
-
-  function clickHandler() {
-    document.body.innerHTML = `
-        <div id='small-lcp'>Hello, world./div>
-      `;
-    history.pushState({}, "", "/test");
-    clickHandlerPart2(5);
-  }
-
-  promise_test(async (t) => {
-    assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented");
-    const helper = new SoftNavigationTestHelper(t);
-    const lcpEntries = await helper.getBufferedPerformanceEntriesWithTimeout(
-      /*type=*/ "largest-contentful-paint",
-      /*includeSoftNavigationObservations=*/ false,
-      /*minNumEntries=*/ 1,
-    );
-    assert_equals(lcpEntries.length, 1, "There should be only one LCP entry");
-    assert_equals(lcpEntries[0].id, "click-target", "The first entry should be the button");
-
-    const promise = Promise.all([
-      SoftNavigationTestHelper.getPerformanceEntries(
-        /*type=*/ "soft-navigation",
-        /*includeSoftNavigationObservations=*/ false,
-        /*minNumEntries=*/ 1,
-      ),
-      SoftNavigationTestHelper.getPerformanceEntries(
-        /*type=*/ "largest-contentful-paint",
-        /*includeSoftNavigationObservations=*/ true,
-        /*minNumEntries=*/ 2,
-      ),
-    ]);
-    if (test_driver) {
-      test_driver.click(document.getElementById("click-target"));
-    }
-    const [softNavigationEntries, softLcpEntries] = await promise;
-    assert_equals(
-      softNavigationEntries.length,
-      1,
-      "There should be only one soft navigation entry",
-    );
-    assert_equals(softLcpEntries.length, 2, "There should be two soft LCP entries");
-    assert_equals(
-      softLcpEntries[0].id,
-      "small-lcp",
-      "The first soft LCP entry should be the small text",
-    );
-    assert_equals(
-      softLcpEntries[1].id,
-      "large-lcp",
-      "The second soft LCP entry should be the large text",
-    );
-    assert_equals(
-      softNavigationEntries[0].navigationId,
-      softLcpEntries[0].navigationId,
-      "The soft navigation entry should have the same navigation ID as the first soft LCP entry",
-    );
-    assert_equals(
-      softNavigationEntries[0].navigationId,
-      softLcpEntries[1].navigationId,
-      "The soft navigation entry should have the same navigation ID as the second soft LCP entry",
-    );
-    assert_not_equals(
-      lcpEntries[0].navigationId,
-      softNavigationEntries[0].navigationId,
-      "The soft navigation entry should have a different navigation ID than the initial (hard) LCP entry",
-    );
-  }, "Largest Contentful Paint after soft navigation: requestAnimationFrame can add additional LCP entry.");
-</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/transforms/3d/point-mapping/3d-point-mapping-2-transforminterop-expected.txt b/third_party/blink/web_tests/transforms/3d/point-mapping/3d-point-mapping-2-transforminterop-expected.txt
deleted file mode 100644
index 9ff0ba7d..0000000
--- a/third_party/blink/web_tests/transforms/3d/point-mapping/3d-point-mapping-2-transforminterop-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-PASS: event at (120, 128) hit box4 at offset (1, 1)
-PASS: event at (336, 87) hit box7 at offset (1, 1)
-PASS: event at (348, 86) hit box7 at offset (15, 1)
-PASS: event at (582, 87) hit box11 at offset (1, 1)
-PASS: event at (594, 86) hit box11 at offset (15, 1)
-
- 
- 
diff --git a/third_party/blink/web_tests/transforms/3d/point-mapping/3d-point-mapping-2-transforminterop.html b/third_party/blink/web_tests/transforms/3d/point-mapping/3d-point-mapping-2-transforminterop.html
deleted file mode 100644
index 838a0bb3..0000000
--- a/third_party/blink/web_tests/transforms/3d/point-mapping/3d-point-mapping-2-transforminterop.html
+++ /dev/null
@@ -1,156 +0,0 @@
-<html>
-<head>
-  <title>More point mapping through 3D transform hierarchies</title>
-  <script src="point-mapping-helpers.js" type="text/javascript" charset="utf-8"></script>
-  <script type="text/javascript" charset="utf-8">
-
-    if (window.testRunner)
-      testRunner.dumpAsText()
-
-    function test()
-    {
-      // Scroll so that frame view offsets are non-zero
-      // window.scrollTo(20, 100);
-
-      // document.getElementById('overflow').scrollLeft = 80;
-      // document.getElementById('overflow').scrollTop = 60;
-
-      // In non-test mode, show the mouse coords for testing
-      if (!window.testRunner)
-        document.body.addEventListener('mousemove', mousemoved, false);
-
-      dispatchEvent(120, 128, 'box4', 1, 1);
-      dispatchEvent(336, 87, 'box7', 1, 1);
-      dispatchEvent(348, 86, 'box7', 15, 1);
-
-      dispatchEvent(582, 87, 'box11', 1, 1);
-      dispatchEvent(594, 86, 'box11', 15, 1);
-    }
-  </script>
-  <style type="text/css" media="screen">
-
-    body {
-      margin: 0;
-      border: 1px solid black;
-      cursor: crosshair;
-    }
-
-    .test {
-      display: inline-block;
-      height: 200px;
-      width: 200px;
-      border: 1px solid black;
-      margin: 20px;
-    }
-
-    .box {
-      height: 100px;
-      width: 100px;
-      -webkit-box-sizing: border-box;
-      background-color: #DDD;
-      border: 1px solid black;
-    }
-
-    .box:hover {
-      outline: 3px solid orange;
-    }
-
-    .container {
-      height: 140px;
-      width: 140px;
-      margin: 20px;
-      border: 1px solid black;
-      -webkit-box-sizing: border-box;
-      -webkit-perspective: 400;
-    }
-
-    .transformed-3d {
-      position: relative;
-      height: 100px;
-      width: 100px;
-      padding: 20px;
-      margin: 20px;
-      border: 1px solid black;
-      background-color: #81AA8A;
-      -webkit-transform-style: preserve-3d;
-      -webkit-box-sizing: border-box;
-    }
-
-    .transformed-flat {
-      position: relative;
-      height: 100px;
-      width: 100px;
-      padding: 20px;
-      margin: 20px;
-      border: 1px solid black;
-      background-color: #AA7994;
-      -webkit-transform-style: flat;
-      -webkit-box-sizing: border-box;
-    }
-
-    .inner {
-      background-color: blue;
-      height: 90px;
-      width: 90px;
-      transform: rotateY(30deg);
-    }
-
-    #results {
-      position: absolute;
-      left: 30px;
-      top: 500px;
-    }
-
-    #mousepos {
-      position: absolute;
-      left: 430px;
-      top: 400px;
-      color: gray;
-      font-size: smaller;
-    }
-  </style>
-</head>
-<body onclick="clicked(event)">
-
-<div id="results"></div>
-
-<div class="test">
-  <!-- preserve-3d element with no transform-->
-  <div class="container box" id="box1">
-    <div class="transformed-3d box" style="transform: rotateY(-30deg);" id="box2">
-      <div class="transformed-3d box" id="box3">
-        <div class="inner box" id="box4">
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-
-<div class="test">
-  <!-- layer with no transform-->
-  <div class="container box" id="box5">
-    <div class="transformed-3d box" style="transform: rotateY(-30deg);" id="box6">
-      <div class="box" style="position: relative; padding-left: 20px" id="box7">
-        <div class="inner box" id="box8">
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-
-<div class="test">
-  <!-- non-layer with no transform-->
-  <div class="container box" id="box9">
-    <div class="transformed-3d box" style="transform: rotateY(-30deg);" id="box10">
-      <div class="box" style="padding-left: 20px" id="box11">
-        <div class="inner box" id="box12">
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-
-<div id="mousepos"></div>
-
-</body>
-</html>
diff --git a/third_party/blink/web_tests/virtual/javascript-source-phase-imports/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice-expected.txt b/third_party/blink/web_tests/virtual/javascript-source-phase-imports/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice-expected.txt
new file mode 100644
index 0000000..d2490db
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/javascript-source-phase-imports/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice-expected.txt
@@ -0,0 +1,3 @@
+This is a testharness.js-based test.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice-expected.txt b/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice-expected.txt
new file mode 100644
index 0000000..7bcdda7
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected identifier 'exportedNamesSource'
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice.html b/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice.html
new file mode 100644
index 0000000..9f2e516
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/import-same-wasm-resource-twice.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>Import same wasm resource twice</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script type=module>
+setup({ single_test: true });
+
+import source exportedNamesSource from "./resources/exported-names.wasm";
+import source exportedNamesFoo from "./resources/exported-names.wasm#foo";
+
+let numDownloads = 0;
+const absoluteURL = new URL('resources/exported-names.wasm', location.href).href;
+performance.getEntriesByName(absoluteURL).forEach(entry => {
+    if (entry.transferSize > 0) {
+        numDownloads++;
+    }
+});
+assert_equals(numDownloads, 1);
+
+done();
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/resources/exported-names.wasm b/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/resources/exported-names.wasm
new file mode 100644
index 0000000..ebffad19
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/js/source-phase-imports/resources/exported-names.wasm
Binary files differ
diff --git a/third_party/dawn b/third_party/dawn
index 5602ae0..168d54a 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 5602ae03628ac1ae4ba8d265ac1979abea42d6ba
+Subproject commit 168d54a050758eb88e25757111b850bb1e97ed90
diff --git a/third_party/fontconfig/BUILD.gn b/third_party/fontconfig/BUILD.gn
index bf327ba..82a594e 100644
--- a/third_party/fontconfig/BUILD.gn
+++ b/third_party/fontconfig/BUILD.gn
@@ -12,10 +12,6 @@
       "src",
       "include/fc-lang/",
     ]
-
-    # TODO(drott): Remove after the fix MR lands:
-    # https://gitlab.freedesktop.org/fontconfig/fontconfig/-/merge_requests/433
-    cflags = [ "-Wno-unused-label" ]
   }
 
   component("fontconfig") {
diff --git a/third_party/fontconfig/README.chromium b/third_party/fontconfig/README.chromium
index 4c4907a..6d56036 100644
--- a/third_party/fontconfig/README.chromium
+++ b/third_party/fontconfig/README.chromium
@@ -1,6 +1,6 @@
 Name: fontconfig
 URL: http://www.freedesktop.org/wiki/Software/fontconfig/
-Version: f71f39e7da6bccfb5a803a4adcdfe88d382a6eab
+Version: c527fe1452d469e5fa1a211180dd40bcdb79fb2a
 CPEPrefix: cpe:/a:fontconfig_project:fontconfig:2.16.2
 License: public-domain-md5, MIT-Modern-Variant, HPND-sell-variant, MIT
 License File: src/COPYING
diff --git a/third_party/fontconfig/src b/third_party/fontconfig/src
index f71f39e..c527fe1 160000
--- a/third_party/fontconfig/src
+++ b/third_party/fontconfig/src
@@ -1 +1 @@
-Subproject commit f71f39e7da6bccfb5a803a4adcdfe88d382a6eab
+Subproject commit c527fe1452d469e5fa1a211180dd40bcdb79fb2a
diff --git a/third_party/glslang/src b/third_party/glslang/src
index 05cfcc1..21b4e37 160000
--- a/third_party/glslang/src
+++ b/third_party/glslang/src
@@ -1 +1 @@
-Subproject commit 05cfcc1613c28c1274036f53616d66324f7cd383
+Subproject commit 21b4e37133868b3a50ef15fc027ecd6d3a52c875
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index 5929c42..9f7eff7c 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -20,6 +20,7 @@
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/process/process_metrics.h"
 #include "base/strings/strcat.h"
diff --git a/third_party/pdfium b/third_party/pdfium
index a464668..b6457bc 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit a4646686ab9486809befa1570e0f6849dfa57d48
+Subproject commit b6457bcccc5c86ac7159f957fa8dbea3d5e13f49
diff --git a/third_party/protobuf/python/descriptor_containers.c b/third_party/protobuf/python/descriptor_containers.c
index 47a00e4..fee0ab3 100644
--- a/third_party/protobuf/python/descriptor_containers.c
+++ b/third_party/protobuf/python/descriptor_containers.c
@@ -5,9 +5,9 @@
 // license that can be found in the LICENSE file or at
 // https://developers.google.com/open-source/licenses/bsd
 
-#include "python/descriptor_containers.h"
-
+#include "base/notimplemented.h"
 #include "python/descriptor.h"
+#include "python/descriptor_containers.h"
 #include "python/protobuf.h"
 #include "upb/reflection/def.h"
 
diff --git a/third_party/spirv-tools/src b/third_party/spirv-tools/src
index dab29fb..422150b 160000
--- a/third_party/spirv-tools/src
+++ b/third_party/spirv-tools/src
@@ -1 +1 @@
-Subproject commit dab29fb163948c142b33f0176eb8baa086fa5df3
+Subproject commit 422150b405c2ac2e05e51a19defabb232efd9187
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 17fd4e2..4e2ba67 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 17fd4e2e0ff9c2de2dc9a251d4c2b7832f7735f5
+Subproject commit 4e2ba677d4d655a0b0d69b596f1c076ee0d4b516
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index d004bbb..7cee394 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit d004bbbbeb7e1bfe79533522af631bacec407ad2
+Subproject commit 7cee394fda75d7b33d52b06b9e637abeb23c991c
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index f1f6ab5..b3d34f8 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -25197,7 +25197,7 @@
   </obsolete>
   <owner>ianwen@chromium.org</owner>
   <description>
-    Action indicating the user has clicked the boomkark button on NTP to swith
+    Action indicating the user has clicked the bookmark button on NTP to switch
     to the bookmark manager.
   </description>
 </action>
diff --git a/tools/metrics/histograms/README.md b/tools/metrics/histograms/README.md
index ec4f555..ce8ea2c 100644
--- a/tools/metrics/histograms/README.md
+++ b/tools/metrics/histograms/README.md
@@ -99,12 +99,26 @@
 
 ### Efficiency
 
-Generally, don't be concerned about the processing cost of emitting to a
-histogram (unless you're using [sparse
+In most cases, you don't need to be concerned about the processing cost of
+emitting to a histogram (unless you're using [sparse
 histograms](#When-To-Use-Sparse-Histograms)). The normal histogram code is
-highly optimized. If you are recording to a histogram in particularly
-performance-sensitive or "hot" code, make sure you're using the histogram
-macros; see [reasons above](#Coding-Emitting-to-Histograms).
+highly optimized.
+
+If you are recording to a histogram in particularly
+performance-sensitive or "hot" code, follow one of these guidelines:
+- Use the histogram macros; see [reasons above](#Coding-Emitting-to-Histograms).
+- When total counts aren't important (for example, when measuring latency or
+  ratios) consider subsampling. For example:
+
+  ```c++
+  if (base::ShouldRecordSubsampledMetric(0.01)) {
+    base::UmaHistogramMicrosecondsTimes(
+      "Component.Feature.Duration.Subsampled", timer->Elapsed());
+  }
+  ```
+
+Examples where these optimizations are necessary include histograms that apply
+to every frame or every cookie.
 
 ## Picking Your Histogram Type
 
@@ -187,8 +201,8 @@
 // LINT.ThenChange(//path/to/enums.xml:NewTabPageActionEnum)
 ```
 
-The `LINT.IfChange` / `LINT.ThenChange` comments point between the code and XML
-definitions of the enum, to encourage them to be kept in sync. See
+The `LINT.*` comments point between the code and XML definitions of the enum, to
+encourage them to be kept in sync. See
 [guide](https://www.chromium.org/chromium-os/developer-library/guides/development/keep-files-in-sync/)
 and [more details](http://go/gerrit-ifthisthenthat).
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 453a9ad..efed804 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -9022,6 +9022,7 @@
   <int value="-1846471618"
       label="enable-experimental-accessibility-switch-access-text"/>
   <int value="-1846070594" label="AllowWindowDragUsingSystemDragDrop:disabled"/>
+  <int value="-1845410561" label="EnableNtpBrowserPromos:disabled"/>
   <int value="-1844754731" label="Mash:disabled"/>
   <int value="-1844445413"
       label="NotificationsIgnoreRequireInteraction:disabled"/>
@@ -12177,6 +12178,7 @@
   <int value="-669761849" label="SplitSettings:disabled"/>
   <int value="-669400536" label="FastPairSoftwareScanning:disabled"/>
   <int value="-669383690" label="BluetoothRfcommAndroid:enabled"/>
+  <int value="-668254324" label="EnableNtpBrowserPromos:enabled"/>
   <int value="-668250016" label="HttpsFirstDialogUi:enabled"/>
   <int value="-668114930" label="WindowsFollowCursor:disabled"/>
   <int value="-667952041" label="CCTRealTimeEngagementSignals:enabled"/>
diff --git a/tools/metrics/histograms/metadata/actor/enums.xml b/tools/metrics/histograms/metadata/actor/enums.xml
index 56c46bf5..196115f 100644
--- a/tools/metrics/histograms/metadata/actor/enums.xml
+++ b/tools/metrics/histograms/metadata/actor/enums.xml
@@ -42,8 +42,9 @@
   <int value="21" label="CoordinatesOutOfBounds"/>
   <int value="22" label="ArgumentsInvalid"/>
   <int value="23" label="TaskPaused"/>
-  <int value="24" label="kExecutorDestroyed"/>
-  <int value="25" label="kWindowWentAway"/>
+  <int value="24" label="ExecutorDestroyed"/>
+  <int value="25" label="WindowWentAway"/>
+  <int value="26" label="FrameLocationChangedSinceObservation"/>
   <int value="100" label="NavigateInvalidUrl"/>
   <int value="200" label="ClickSuppressed"/>
   <int value="300" label="DragAndReleaseFromOffscreen"/>
diff --git a/tools/metrics/histograms/metadata/android/enums.xml b/tools/metrics/histograms/metadata/android/enums.xml
index f117969..4a2bd76 100644
--- a/tools/metrics/histograms/metadata/android/enums.xml
+++ b/tools/metrics/histograms/metadata/android/enums.xml
@@ -1681,7 +1681,10 @@
   <int value="2" label="Frequent"/>
   <int value="3" label="Rare"/>
   <int value="4" label="Restricted"/>
-  <int value="5" label="Exempted"/>
+  <int value="5" label="(obsolete) Unsupported"/>
+  <int value="6" label="Exempted"/>
+  <int value="7" label="Never"/>
+  <int value="8" label="Other"/>
 </enum>
 
 <enum name="SupportedConfigurationStrangeInsetsState">
diff --git a/tools/metrics/histograms/metadata/enterprise/enums.xml b/tools/metrics/histograms/metadata/enterprise/enums.xml
index d4000246..ac03886 100644
--- a/tools/metrics/histograms/metadata/enterprise/enums.xml
+++ b/tools/metrics/histograms/metadata/enterprise/enums.xml
@@ -2237,6 +2237,7 @@
   <int value="1367" label="AIModeSettings"/>
   <int value="1368" label="WatermarkStyle"/>
   <int value="1369" label="KioskApplicationLogCollectionEnabled"/>
+  <int value="1370" label="EnableUnsafeSwiftShader"/>
 </enum>
 
 <enum name="EnterprisePoliciesSources">
diff --git a/tools/metrics/histograms/metadata/families/enums.xml b/tools/metrics/histograms/metadata/families/enums.xml
index 3396937..6bebea4a 100644
--- a/tools/metrics/histograms/metadata/families/enums.xml
+++ b/tools/metrics/histograms/metadata/families/enums.xml
@@ -213,6 +213,11 @@
     There must be at least one profile with a parent and no supervision across
     the profiles.
   </int>
+  <int value="5" label="Supervision enabled locally">
+    Users with or without accounts that have supervision applied to their
+    devices locally. These users are mutually exclusive with those with Family
+    Link enabled supervisions. Only available for Android users.
+  </int>
 </enum>
 
 <!-- LINT.ThenChange(//components/supervised_user/core/browser/family_link_user_log_record.h:FamilyLinkUserLogSegment) -->
@@ -278,13 +283,33 @@
 
 <!-- LINT.ThenChange(//chrome/browser/supervised_user/supervised_user_verification_page.h:FamilyLinkUserReauthenticationInterstitialState) -->
 
+<!-- LINT.IfChange(FamilyLinkWebFilterType) -->
+
 <enum name="FamilyLinkWebFilterType">
-  <int value="0" label="Allow All Sites"/>
-  <int value="1" label="Try To Block Mature Sites"/>
-  <int value="2" label="Only allow Certain Sites"/>
-  <int value="3" label="Mixed web filters on device"/>
+  <int value="0" label="Allow all sites">
+    This is the default value; manual blocklists take precedence over this
+    setting.
+  </int>
+  <int value="1" label="Try to block mature sites">
+    Uses external service to detect mature sites. This is the only available
+    setting for local supervision (see FamilyLinkUserLogSegment).
+  </int>
+  <int value="2" label="Only allow Certain Sites">
+    In this mode all sites are blocked, unless explicitly allowlisted.
+  </int>
+  <int value="3" label="Mixed web filters on device">
+    Reported when multiple browser profiles have different web filters set.
+  </int>
+  <int value="4" label="Disabled">
+    Web filter is neutralized: it behaves as if there were no filtering. The
+    difference between this and the &quot;allow all sites&quot; setting with
+    empty blocklist is that this filter type will not emit any metrics related
+    to url classification and web filtering.
+  </int>
 </enum>
 
+<!-- LINT.ThenChange(//components/supervised_user/core/common/supervised_user_constants.h:FamilyLinkWebFilterType) -->
+
 <enum name="FamilyUserLogSegment">
   <summary>Filters family user metrics into categories of interest.</summary>
   <int value="0" label="Other"/>
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml
index 58920212..9fbf3a8 100644
--- a/tools/metrics/histograms/metadata/renderer/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -129,8 +129,9 @@
 </histogram>
 
 <histogram name="Renderer.CriticalFonts.BlockingResourcesLoadTime" units="ms"
-    expires_after="2025-07-06">
+    expires_after="2026-07-06">
   <owner>iclelland@chromium.org</owner>
+  <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Time (in milliseconds) from timeOrigin until all the render blocking
@@ -141,8 +142,9 @@
 </histogram>
 
 <histogram name="Renderer.CriticalFonts.CriticalFontDelay" units="ms"
-    expires_after="2025-11-09">
+    expires_after="2026-07-06">
   <owner>iclelland@chromium.org</owner>
+  <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Time difference (in milliseconds) between `PreloadedFontLoadTime` and
@@ -154,8 +156,9 @@
 </histogram>
 
 <histogram name="Renderer.CriticalFonts.PreloadedFontsLoadTime" units="ms"
-    expires_after="2025-11-09">
+    expires_after="2026-07-06">
   <owner>iclelland@chromium.org</owner>
+  <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Time (in milliseconds) from timeOrigin until all the preloaded fonts were
diff --git a/tools/metrics/histograms/metadata/settings/enums.xml b/tools/metrics/histograms/metadata/settings/enums.xml
index 5f939d83..1d7efca8 100644
--- a/tools/metrics/histograms/metadata/settings/enums.xml
+++ b/tools/metrics/histograms/metadata/settings/enums.xml
@@ -636,6 +636,7 @@
   <int value="33" label="kGoogleServicesLastSignedInUsername"/>
   <int value="34" label="kPolicyRecoveryToken"/>
   <int value="35" label="kExtensionsUIDeveloperMode"/>
+  <int value="36" label="kScheduleToFlushToDisk"/>
 </enum>
 
 </enums>
diff --git a/ui/accessibility/ax_tree_manager_base.cc b/ui/accessibility/ax_tree_manager_base.cc
index 506a749..6c2767d 100644
--- a/ui/accessibility/ax_tree_manager_base.cc
+++ b/ui/accessibility/ax_tree_manager_base.cc
@@ -9,6 +9,7 @@
 
 #include "base/check_op.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "ui/accessibility/ax_node.h"
 
diff --git a/ui/accessibility/ax_tree_source.h b/ui/accessibility/ax_tree_source.h
index 03f9cf5..c35c40b 100644
--- a/ui/accessibility/ax_tree_source.h
+++ b/ui/accessibility/ax_tree_source.h
@@ -10,7 +10,7 @@
 #include <string>
 #include <vector>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/accessibility/ax_node_id_forward.h"
 #include "ui/accessibility/ax_tree_source_observer.h"
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index e52ed94..017f820d 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -25,6 +25,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm
index 3a04af375..27709d5 100644
--- a/ui/accessibility/platform/ax_platform_node_cocoa.mm
+++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm
@@ -13,6 +13,7 @@
 #include "base/mac/mac_util.h"
 #include "base/memory/raw_ptr_exclusion.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "skia/ext/skia_utils_mac.h"
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.cc b/ui/accessibility/platform/ax_platform_node_delegate.cc
index 8771069f..4a96d18 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate.cc
@@ -5,6 +5,7 @@
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 
 #include "base/containers/fixed_flat_set.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 8f9c6a1..4e6cac4 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -23,6 +23,7 @@
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_number_conversions_win.h"
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc
index 150f924f..213d477a 100644
--- a/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -7,7 +7,7 @@
 #include <windows.h>
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/platform/ax_platform_node_win.h"
 #include "ui/display/win/screen_win.h"
diff --git a/ui/accessibility/platform/browser_accessibility.cc b/ui/accessibility/platform/browser_accessibility.cc
index 3a52beb..39447cca 100644
--- a/ui/accessibility/platform/browser_accessibility.cc
+++ b/ui/accessibility/platform/browser_accessibility.cc
@@ -13,6 +13,7 @@
 #include "base/containers/contains.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc b/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
index bf3a55e..5812836 100644
--- a/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
+++ b/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
@@ -5,6 +5,7 @@
 #include "ui/accessibility/platform/inspect/ax_tree_formatter_base.h"
 
 #include "base/containers/contains.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index a50da368..28ac985 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_action_data.h"
diff --git a/ui/accessibility/test_ax_node_helper.cc b/ui/accessibility/test_ax_node_helper.cc
index 11a2e79..58e4818 100644
--- a/ui/accessibility/test_ax_node_helper.cc
+++ b/ui/accessibility/test_ax_node_helper.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_role_properties.h"
diff --git a/ui/android/display_android_manager.cc b/ui/android/display_android_manager.cc
index dc3654e..7a5d2c3 100644
--- a/ui/android/display_android_manager.cc
+++ b/ui/android/display_android_manager.cc
@@ -14,6 +14,7 @@
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/viz_utils.h"
diff --git a/ui/aura/test/event_generator_delegate_aura.cc b/ui/aura/test/event_generator_delegate_aura.cc
index 1cd6b5a..abc20b14 100644
--- a/ui/aura/test/event_generator_delegate_aura.cc
+++ b/ui/aura/test/event_generator_delegate_aura.cc
@@ -5,6 +5,7 @@
 #include "ui/aura/test/event_generator_delegate_aura.h"
 
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/test/default_event_generator_delegate.h"
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 872e3361..ce8ef23 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc
index 54b46ac..0b74aaf 100644
--- a/ui/aura/window_tree_host_platform.cc
+++ b/ui/aura/window_tree_host_platform.cc
@@ -10,6 +10,7 @@
 
 #include "base/check_is_test.h"
 #include "base/functional/bind.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/run_loop.h"
 #include "base/trace_event/trace_event.h"
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index 285db3c..a146097 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -20,7 +20,7 @@
 #include "base/functional/callback.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/string_view_util.h"
diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc
index d2194f3..efedcb48 100644
--- a/ui/base/clipboard/clipboard_ozone.cc
+++ b/ui/base/clipboard/clipboard_ozone.cc
@@ -26,7 +26,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/no_destructor.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ui/base/cursor/cursor_factory.cc b/ui/base/cursor/cursor_factory.cc
index 18fdce3..70fc265 100644
--- a/ui/base/cursor/cursor_factory.cc
+++ b/ui/base/cursor/cursor_factory.cc
@@ -9,6 +9,7 @@
 #include "base/check.h"
 #include "base/check_op.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
diff --git a/ui/base/dragdrop/os_exchange_data_provider_mac.mm b/ui/base/dragdrop/os_exchange_data_provider_mac.mm
index b356705..0108fbe 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_mac.mm
+++ b/ui/base/dragdrop/os_exchange_data_provider_mac.mm
@@ -14,7 +14,7 @@
 #include "base/check_op.h"
 #include "base/containers/span.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/pickle.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ui/base/idle/idle_android.cc b/ui/base/idle/idle_android.cc
index 595a36b..77a1dcb 100644
--- a/ui/base/idle/idle_android.cc
+++ b/ui/base/idle/idle_android.cc
@@ -7,9 +7,8 @@
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/memory/singleton.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/base/idle/idle_internal.h"
-
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "ui/base/ui_base_jni_headers/IdleDetector_jni.h"
 
diff --git a/ui/base/idle/idle_fuchsia.cc b/ui/base/idle/idle_fuchsia.cc
index 5f538a53..13e2c18 100644
--- a/ui/base/idle/idle_fuchsia.cc
+++ b/ui/base/idle/idle_fuchsia.cc
@@ -4,7 +4,7 @@
 
 #include "ui/base/idle/idle.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace ui {
 
diff --git a/ui/base/idle/idle_ios.mm b/ui/base/idle/idle_ios.mm
index d7ab51b..ee70e46 100644
--- a/ui/base/idle/idle_ios.mm
+++ b/ui/base/idle/idle_ios.mm
@@ -6,7 +6,7 @@
 
 #import <UIKit/UIKit.h>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/base/idle/idle_internal.h"
 
 @interface IOSScreenMonitor : NSObject
diff --git a/ui/base/ime/ash/input_method_ash_unittest.cc b/ui/base/ime/ash/input_method_ash_unittest.cc
index 30b23ff2..cfd396d 100644
--- a/ui/base/ime/ash/input_method_ash_unittest.cc
+++ b/ui/base/ime/ash/input_method_ash_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/i18n/char_iterator.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
diff --git a/ui/base/ime/ash/mock_ime_input_context_handler.cc b/ui/base/ime/ash/mock_ime_input_context_handler.cc
index 16e8505..722b0da 100644
--- a/ui/base/ime/ash/mock_ime_input_context_handler.cc
+++ b/ui/base/ime/ash/mock_ime_input_context_handler.cc
@@ -7,7 +7,7 @@
 #include <string_view>
 
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/ime/composition_text.h"
 #include "ui/base/ime/input_method.h"
diff --git a/ui/base/ime/ash/mock_input_method_manager_impl.cc b/ui/base/ime/ash/mock_input_method_manager_impl.cc
index 0d5ac8a..0316e5f 100644
--- a/ui/base/ime/ash/mock_input_method_manager_impl.cc
+++ b/ui/base/ime/ash/mock_input_method_manager_impl.cc
@@ -8,6 +8,7 @@
 #include <optional>
 #include <utility>
 
+#include "base/notimplemented.h"
 #include "ui/base/ime/ash/input_method_util.h"
 
 namespace ash {
diff --git a/ui/base/ime/dummy_text_input_client.cc b/ui/base/ime/dummy_text_input_client.cc
index e9acec7..057ad64 100644
--- a/ui/base/ime/dummy_text_input_client.cc
+++ b/ui/base/ime/dummy_text_input_client.cc
@@ -4,7 +4,7 @@
 
 #include "ui/base/ime/dummy_text_input_client.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "ui/events/event.h"
diff --git a/ui/base/ime/linux/input_method_auralinux_unittest.cc b/ui/base/ime/linux/input_method_auralinux_unittest.cc
index f9f9d8e..0748e1c 100644
--- a/ui/base/ime/linux/input_method_auralinux_unittest.cc
+++ b/ui/base/ime/linux/input_method_auralinux_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/singleton.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index 660fadd..73301406 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -18,6 +18,7 @@
 #include <algorithm>
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
diff --git a/ui/base/win/win_cursor_factory.cc b/ui/base/win/win_cursor_factory.cc
index e0be32a..dfe7864 100644
--- a/ui/base/win/win_cursor_factory.cc
+++ b/ui/base/win/win_cursor_factory.cc
@@ -12,6 +12,7 @@
 
 #include "base/check_op.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/win/scoped_gdi_object.h"
 #include "base/win/windows_types.h"
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
index 9efbca9..3576e11 100644
--- a/ui/base/x/x11_display_util.cc
+++ b/ui/base/x/x11_display_util.cc
@@ -22,6 +22,7 @@
 #include "base/command_line.h"
 #include "base/containers/flat_map.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/numerics/clamped_math.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/ui/base/x/x11_os_exchange_data_provider.cc b/ui/base/x/x11_os_exchange_data_provider.cc
index cbb3fd9..2f1430d 100644
--- a/ui/base/x/x11_os_exchange_data_provider.cc
+++ b/ui/base/x/x11_os_exchange_data_provider.cc
@@ -11,6 +11,7 @@
 #include "base/containers/contains.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/string_view_util.h"
diff --git a/ui/display/ios/screen_ios.mm b/ui/display/ios/screen_ios.mm
index 2447f9e..062d677d 100644
--- a/ui/display/ios/screen_ios.mm
+++ b/ui/display/ios/screen_ios.mm
@@ -6,7 +6,7 @@
 
 #include "base/apple/foundation_util.h"
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/ios_buildflags.h"
 #include "ui/display/display.h"
diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm
index f2c3717..85d9170 100644
--- a/ui/display/mac/screen_mac.mm
+++ b/ui/display/mac/screen_mac.mm
@@ -27,6 +27,7 @@
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/trace_event.h"
diff --git a/ui/display/screen.cc b/ui/display/screen.cc
index 1ee1f561..8208c0d 100644
--- a/ui/display/screen.cc
+++ b/ui/display/screen.cc
@@ -10,7 +10,7 @@
 #include "base/check.h"
 #include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "ui/display/display.h"
diff --git a/ui/display/screen_base.cc b/ui/display/screen_base.cc
index e6e832fb..8700a5a 100644
--- a/ui/display/screen_base.cc
+++ b/ui/display/screen_base.cc
@@ -4,6 +4,7 @@
 
 #include "ui/display/screen_base.h"
 
+#include "base/notimplemented.h"
 #include "ui/display/display_finder.h"
 #include "ui/gfx/native_widget_types.h"
 
diff --git a/ui/events/android/events_android.cc b/ui/events/android/events_android.cc
index 8542e20b..279d2802 100644
--- a/ui/events/android/events_android.cc
+++ b/ui/events/android/events_android.cc
@@ -4,7 +4,7 @@
 
 #include <android/input.h>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "ui/events/android/event_flags_android.h"
 #include "ui/events/android/event_type_android.h"
diff --git a/ui/events/blink/web_input_event.cc b/ui/events/blink/web_input_event.cc
index c41de6e2..69156d88 100644
--- a/ui/events/blink/web_input_event.cc
+++ b/ui/events/blink/web_input_event.cc
@@ -5,6 +5,7 @@
 #include "ui/events/blink/web_input_event.h"
 
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "base/types/cxx23_to_underlying.h"
 #include "build/build_config.h"
 #include "third_party/blink/public/common/features.h"
diff --git a/ui/events/cocoa/events_mac.mm b/ui/events/cocoa/events_mac.mm
index 11e7288..93f57332 100644
--- a/ui/events/cocoa/events_mac.mm
+++ b/ui/events/cocoa/events_mac.mm
@@ -8,7 +8,7 @@
 
 #include "base/check_op.h"
 #import "base/mac/mac_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "ui/events/base_event_utils.h"
diff --git a/ui/events/events_stub.cc b/ui/events/events_stub.cc
index f80c8067..a2abb42 100644
--- a/ui/events/events_stub.cc
+++ b/ui/events/events_stub.cc
@@ -4,7 +4,7 @@
 
 #include <stdint.h>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "ui/events/event_utils.h"
diff --git a/ui/events/ios/events_ios.mm b/ui/events/ios/events_ios.mm
index bad3255..7951951 100644
--- a/ui/events/ios/events_ios.mm
+++ b/ui/events/ios/events_ios.mm
@@ -4,7 +4,7 @@
 
 #import <UIKit/UIKit.h>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "ui/events/base_event_utils.h"
diff --git a/ui/events/keyboard_hook_base.cc b/ui/events/keyboard_hook_base.cc
index d1a07a3c..46cdc7e 100644
--- a/ui/events/keyboard_hook_base.cc
+++ b/ui/events/keyboard_hook_base.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/containers/contains.h"
+#include "base/notimplemented.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 
diff --git a/ui/events/ozone/evdev/testing/fake_cursor_delegate_evdev.h b/ui/events/ozone/evdev/testing/fake_cursor_delegate_evdev.h
index 9705c22c..185e9ab 100644
--- a/ui/events/ozone/evdev/testing/fake_cursor_delegate_evdev.h
+++ b/ui/events/ozone/evdev/testing/fake_cursor_delegate_evdev.h
@@ -5,6 +5,7 @@
 #ifndef UI_EVENTS_OZONE_EVDEV_TESTING_FAKE_CURSOR_DELEGATE_EVDEV_H_
 #define UI_EVENTS_OZONE_EVDEV_TESTING_FAKE_CURSOR_DELEGATE_EVDEV_H_
 
+#include "base/notimplemented.h"
 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
 
 namespace ui {
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
index 53735c2..a274702 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -26,6 +26,7 @@
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
index 4ca3110b..e57b95d 100644
--- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
+++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
@@ -24,6 +24,7 @@
 #include "base/logging.h"
 #include "base/memory/free_deleter.h"
 #include "base/memory/raw_ptr_exclusion.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/task_runner.h"
diff --git a/ui/events/test/keyboard_layout.cc b/ui/events/test/keyboard_layout.cc
index 2a7e407a..d2bb278 100644
--- a/ui/events/test/keyboard_layout.cc
+++ b/ui/events/test/keyboard_layout.cc
@@ -5,7 +5,7 @@
 #include "ui/events/test/keyboard_layout.h"
 
 #include "base/check_op.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_OZONE)
diff --git a/ui/events/velocity_tracker/motion_event.cc b/ui/events/velocity_tracker/motion_event.cc
index 4b01e19..7c6ca6a 100644
--- a/ui/events/velocity_tracker/motion_event.cc
+++ b/ui/events/velocity_tracker/motion_event.cc
@@ -6,6 +6,7 @@
 
 #include <ostream>
 
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "ui/events/velocity_tracker/motion_event_generic.h"
 
diff --git a/ui/events/win/events_win.cc b/ui/events/win/events_win.cc
index 93053ba..e4c9932 100644
--- a/ui/events/win/events_win.cc
+++ b/ui/events/win/events_win.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/platform_event.h"
 #include "ui/events/win/events_win_utils.h"
diff --git a/ui/events/win/events_win_utils.cc b/ui/events/win/events_win_utils.cc
index 20f3f0e3..a489223 100644
--- a/ui/events/win/events_win_utils.cc
+++ b/ui/events/win/events_win_utils.cc
@@ -8,6 +8,7 @@
 
 #include "base/check.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
diff --git a/ui/gfx/color_utils.cc b/ui/gfx/color_utils.cc
index 1846fbbb..1dba147 100644
--- a/ui/gfx/color_utils.cc
+++ b/ui/gfx/color_utils.cc
@@ -19,7 +19,7 @@
 #include <vector>
 
 #include "base/check_op.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/ui/gfx/font_render_params_mac.cc b/ui/gfx/font_render_params_mac.cc
index 6324e40..0877d57 100644
--- a/ui/gfx/font_render_params_mac.cc
+++ b/ui/gfx/font_render_params_mac.cc
@@ -5,7 +5,7 @@
 #include "ui/gfx/font_render_params.h"
 
 #include "base/feature_list.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/base/ui_base_features.h"
 
 namespace gfx {
diff --git a/ui/gfx/font_render_params_skia.cc b/ui/gfx/font_render_params_skia.cc
index 682c2469..80e3739 100644
--- a/ui/gfx/font_render_params_skia.cc
+++ b/ui/gfx/font_render_params_skia.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/notimplemented.h"
 #include "ui/gfx/font_render_params.h"
 
-#include "base/notreached.h"
-
 namespace gfx {
 
 namespace {
diff --git a/ui/gfx/font_render_params_win.cc b/ui/gfx/font_render_params_win.cc
index a37a00d..45cf4367 100644
--- a/ui/gfx/font_render_params_win.cc
+++ b/ui/gfx/font_render_params_win.cc
@@ -11,6 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/singleton.h"
+#include "base/notimplemented.h"
 #include "base/win/registry.h"
 #include "skia/ext/legacy_display_globals.h"
 #include "ui/base/ui_base_features.h"
diff --git a/ui/gfx/gpu_memory_buffer_handle.cc b/ui/gfx/gpu_memory_buffer_handle.cc
index e409b45b..4c3a1fb 100644
--- a/ui/gfx/gpu_memory_buffer_handle.cc
+++ b/ui/gfx/gpu_memory_buffer_handle.cc
@@ -5,6 +5,7 @@
 #include "ui/gfx/gpu_memory_buffer_handle.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "ui/gfx/generic_shared_memory_id.h"
 
diff --git a/ui/gfx/icon_util.cc b/ui/gfx/icon_util.cc
index 7c941c3..5eb37ad 100644
--- a/ui/gfx/icon_util.cc
+++ b/ui/gfx/icon_util.cc
@@ -18,7 +18,7 @@
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/scoped_generic.h"
 #include "base/trace_event/trace_event.h"
 #include "base/win/resource_util.h"
diff --git a/ui/gfx/linux/test/mock_gbm_device.cc b/ui/gfx/linux/test/mock_gbm_device.cc
index 146d371..79f5269 100644
--- a/ui/gfx/linux/test/mock_gbm_device.cc
+++ b/ui/gfx/linux/test/mock_gbm_device.cc
@@ -5,6 +5,7 @@
 #include "ui/gfx/linux/test/mock_gbm_device.h"
 
 #include <xf86drm.h>
+
 #include <memory>
 #include <utility>
 
@@ -12,6 +13,7 @@
 #include "base/containers/contains.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_math.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/gfx/platform_font_skia_unittest.cc b/ui/gfx/platform_font_skia_unittest.cc
index f03fda315..901e099 100644
--- a/ui/gfx/platform_font_skia_unittest.cc
+++ b/ui/gfx/platform_font_skia_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/check_op.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/font.h"
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc
index 5059352..ca0c5c1 100644
--- a/ui/gl/gl_context.cc
+++ b/ui/gl/gl_context.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
diff --git a/ui/gl/gl_fence.cc b/ui/gl/gl_fence.cc
index 95e0be1..e2c60bd 100644
--- a/ui/gl/gl_fence.cc
+++ b/ui/gl/gl_fence.cc
@@ -5,6 +5,7 @@
 #include "ui/gl/gl_fence.h"
 
 #include "base/compiler_specific.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index 6482fcc..3be1120 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -5,6 +5,7 @@
 #include "ui/gl/gl_surface.h"
 
 #include "base/check.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "ui/gfx/swap_result.h"
 #include "ui/gl/gl_context.h"
diff --git a/ui/gl/init/gl_factory_mac.cc b/ui/gl/init/gl_factory_mac.cc
index f205027..aa010f56 100644
--- a/ui/gl/init/gl_factory_mac.cc
+++ b/ui/gl/init/gl_factory_mac.cc
@@ -6,20 +6,20 @@
 
 #include "base/check_op.h"
 #include "base/mac/mac_util.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/gl/buildflags.h"
 #include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_egl.h"
 #include "ui/gl/gl_context_stub.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/gl_surface_stub.h"
 #include "ui/gl/gl_switches.h"
 
-#include "ui/gl/gl_context_egl.h"
-#include "ui/gl/gl_surface_egl.h"
-
 namespace gl {
 namespace init {
 
diff --git a/ui/gl/presenter.cc b/ui/gl/presenter.cc
index 6ddd9d3..27bb0c1 100644
--- a/ui/gl/presenter.cc
+++ b/ui/gl/presenter.cc
@@ -4,6 +4,7 @@
 
 #include "ui/gl/presenter.h"
 
+#include "base/notimplemented.h"
 #include "ui/gfx/gpu_fence.h"
 
 #if BUILDFLAG(IS_WIN)
diff --git a/ui/gl/scoped_binders.cc b/ui/gl/scoped_binders.cc
index 0a5a472..1b20e5df78 100644
--- a/ui/gl/scoped_binders.cc
+++ b/ui/gl/scoped_binders.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "ui/gl/scoped_binders.h"
+
+#include "base/notimplemented.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_state_restorer.h"
diff --git a/ui/gtk/wayland/gtk_ui_platform_wayland.cc b/ui/gtk/wayland/gtk_ui_platform_wayland.cc
index e82ea54..7a8795a 100644
--- a/ui/gtk/wayland/gtk_ui_platform_wayland.cc
+++ b/ui/gtk/wayland/gtk_ui_platform_wayland.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "ui/base/glib/glib_cast.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/events/event_utils.h"
diff --git a/ui/linux/fallback_linux_ui.cc b/ui/linux/fallback_linux_ui.cc
index 91a1b1f6..a6ec960 100644
--- a/ui/linux/fallback_linux_ui.cc
+++ b/ui/linux/fallback_linux_ui.cc
@@ -4,6 +4,7 @@
 
 #include "ui/linux/fallback_linux_ui.h"
 
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "ui/base/ime/linux/linux_input_method_context.h"
 #include "ui/base/ui_base_switches.h"
diff --git a/ui/menus/simple_menu_model.cc b/ui/menus/simple_menu_model.cc
index 9f56505..1e43ac04 100644
--- a/ui/menus/simple_menu_model.cc
+++ b/ui/menus/simple_menu_model.cc
@@ -10,6 +10,7 @@
 
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
diff --git a/ui/native_theme/native_theme_base.cc b/ui/native_theme/native_theme_base.cc
index 75f4c708..b1f1f072 100644
--- a/ui/native_theme/native_theme_base.cc
+++ b/ui/native_theme/native_theme_base.cc
@@ -17,6 +17,7 @@
 #include "base/check.h"
 #include "base/command_line.h"
 #include "base/containers/fixed_flat_set.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "build/build_config.h"
 #include "cc/paint/paint_flags.h"
diff --git a/ui/ozone/platform/drm/host/drm_window_host.cc b/ui/ozone/platform/drm/host/drm_window_host.cc
index cf06fac0..8f1858d 100644
--- a/ui/ozone/platform/drm/host/drm_window_host.cc
+++ b/ui/ozone/platform/drm/host/drm_window_host.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "ui/base/cursor/platform_cursor.h"
 #include "ui/display/display.h"
 #include "ui/events/devices/device_data_manager.h"
diff --git a/ui/ozone/platform/drm/test/ui_controls_system_input_injector.cc b/ui/ozone/platform/drm/test/ui_controls_system_input_injector.cc
index c05f4cd..5b4c645 100644
--- a/ui/ozone/platform/drm/test/ui_controls_system_input_injector.cc
+++ b/ui/ozone/platform/drm/test/ui_controls_system_input_injector.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/drm/test/ui_controls_system_input_injector.h"
 
 #include "base/functional/callback.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
 #include "ui/base/test/ui_controls_aura.h"
diff --git a/ui/ozone/platform/flatland/flatland_screen.cc b/ui/ozone/platform/flatland/flatland_screen.cc
index 1e851a1..e6eeffc 100644
--- a/ui/ozone/platform/flatland/flatland_screen.cc
+++ b/ui/ozone/platform/flatland/flatland_screen.cc
@@ -4,7 +4,7 @@
 
 #include "ui/ozone/platform/flatland/flatland_screen.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/display/display.h"
 #include "ui/display/display_observer.h"
 #include "ui/gfx/geometry/point.h"
diff --git a/ui/ozone/platform/flatland/flatland_window.cc b/ui/ozone/platform/flatland/flatland_window.cc
index 2b1b948..5203d781 100644
--- a/ui/ozone/platform/flatland/flatland_window.cc
+++ b/ui/ozone/platform/flatland/flatland_window.cc
@@ -20,6 +20,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/functional/bind.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "ui/base/cursor/platform_cursor.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/events/event.h"
diff --git a/ui/ozone/platform/flatland/ozone_platform_flatland.cc b/ui/ozone/platform/flatland/ozone_platform_flatland.cc
index 45eeb28..355ecd7d 100644
--- a/ui/ozone/platform/flatland/ozone_platform_flatland.cc
+++ b/ui/ozone/platform/flatland/ozone_platform_flatland.cc
@@ -14,7 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/no_destructor.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/task/current_thread.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc b/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc
index d15373f7..68b7aa3 100644
--- a/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc
+++ b/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc
@@ -13,6 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/fuchsia/vulkan_fuchsia_ext.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
diff --git a/ui/ozone/platform/headless/headless_window.cc b/ui/ozone/platform/headless/headless_window.cc
index e39ce247..78bc3cb 100644
--- a/ui/ozone/platform/headless/headless_window.cc
+++ b/ui/ozone/platform/headless/headless_window.cc
@@ -6,7 +6,7 @@
 
 #include <string>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "ui/base/cursor/platform_cursor.h"
 #include "ui/display/screen.h"
diff --git a/ui/ozone/platform/headless/vulkan_implementation_headless.cc b/ui/ozone/platform/headless/vulkan_implementation_headless.cc
index 0e7db1014..8e8aa4b 100644
--- a/ui/ozone/platform/headless/vulkan_implementation_headless.cc
+++ b/ui/ozone/platform/headless/vulkan_implementation_headless.cc
@@ -9,6 +9,7 @@
 #include "base/base_paths.h"
 #include "base/files/file_path.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/path_service.h"
 #include "base/scoped_environment_variable_override.h"
diff --git a/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc b/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
index a44a53a..a1db0f4 100644
--- a/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
@@ -9,6 +9,7 @@
 #include "base/base_paths.h"
 #include "base/files/file_path.h"
 #include "base/functional/callback_helpers.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/path_service.h"
 #include "gpu/vulkan/vulkan_image.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_data_source.cc b/ui/ozone/platform/wayland/host/wayland_data_source.cc
index 776b726f..761f6a45 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_source.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_source.cc
@@ -13,6 +13,7 @@
 
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_input_method_context.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
index 24bd848..24cb3b2c 100644
--- a/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
@@ -19,7 +19,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/nix/xdg_util.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_offset_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/ui/ozone/platform/wayland/host/wayland_keyboard.cc
index 12fb24c..adb1aa3d 100644
--- a/ui/ozone/platform/wayland/host/wayland_keyboard.cc
+++ b/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -15,6 +15,7 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/notimplemented.h"
 #include "base/unguessable_token.h"
 #include "ui/base/buildflags.h"
 #include "ui/events/base_event_utils.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer.cc b/ui/ozone/platform/wayland/host/wayland_pointer.cc
index 156e3afa..d20350a 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -9,6 +9,7 @@
 #include <optional>
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/version.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index eef5b88..3aec789 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -9,6 +9,7 @@
 
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
+#include "base/notimplemented.h"
 #include "base/observer_list.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_seat.cc b/ui/ozone/platform/wayland/host/wayland_seat.cc
index 5c5ed7c..8df3279 100644
--- a/ui/ozone/platform/wayland/host/wayland_seat.cc
+++ b/ui/ozone/platform/wayland/host/wayland_seat.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/wayland/host/wayland_seat.h"
 
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_event_source.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
index 66388aca..08476447 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -21,6 +21,7 @@
 #include "base/files/scoped_file.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_touch.cc b/ui/ozone/platform/wayland/host/wayland_touch.cc
index 6ab9478..5f6357ea 100644
--- a/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -5,7 +5,7 @@
 #include "ui/ozone/platform/wayland/host/wayland_touch.h"
 
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "ui/events/types/event_type.h"
 #include "ui/gfx/geometry/point_f.h"
diff --git a/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.cc b/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.cc
index 2e7b06a..0d96ac40 100644
--- a/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.cc
@@ -5,10 +5,11 @@
 #include "ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.h"
 
 #include <chrome-color-management-client-protocol.h>
+
 #include <memory>
 
 #include "base/memory/scoped_refptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_output.h"
 
diff --git a/ui/ozone/platform/wayland/host/xdg_popup.cc b/ui/ozone/platform/wayland/host/xdg_popup.cc
index 8b2f204..94987c9 100644
--- a/ui/ozone/platform/wayland/host/xdg_popup.cc
+++ b/ui/ozone/platform/wayland/host/xdg_popup.cc
@@ -12,6 +12,7 @@
 #include "base/environment.h"
 #include "base/logging.h"
 #include "base/nix/xdg_util.h"
+#include "base/notimplemented.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/ozone/platform/wayland/common/wayland_util.h"
diff --git a/ui/ozone/platform/wayland/host/xdg_toplevel.cc b/ui/ozone/platform/wayland/host/xdg_toplevel.cc
index 6db218b..bc4f144c 100644
--- a/ui/ozone/platform/wayland/host/xdg_toplevel.cc
+++ b/ui/ozone/platform/wayland/host/xdg_toplevel.cc
@@ -13,6 +13,7 @@
 #include "base/bit_cast.h"
 #include "base/containers/contains.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/hit_test.h"
diff --git a/ui/ozone/platform/wayland/host/zwp_text_input_v1.cc b/ui/ozone/platform/wayland/host/zwp_text_input_v1.cc
index 7b5c78a7..98a6d38 100644
--- a/ui/ozone/platform/wayland/host/zwp_text_input_v1.cc
+++ b/ui/ozone/platform/wayland/host/zwp_text_input_v1.cc
@@ -15,6 +15,7 @@
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_split.h"
 #include "base/time/time.h"
diff --git a/ui/ozone/platform/wayland/test/test_alpha_blending.cc b/ui/ozone/platform/wayland/test/test_alpha_blending.cc
index 8934827..9aa178a 100644
--- a/ui/ozone/platform/wayland/test/test_alpha_blending.cc
+++ b/ui/ozone/platform/wayland/test/test_alpha_blending.cc
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/test/test_alpha_compositing.h"
-
 #include <alpha-compositing-unstable-v1-server-protocol.h>
 #include <wayland-server-core.h>
 
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_alpha_compositing.h"
 #include "ui/ozone/platform/wayland/test/test_viewport.h"
 
 namespace wl {
diff --git a/ui/ozone/platform/wayland/test/test_data_offer.cc b/ui/ozone/platform/wayland/test/test_data_offer.cc
index d6b565a..82bd1e27 100644
--- a/ui/ozone/platform/wayland/test/test_data_offer.cc
+++ b/ui/ozone/platform/wayland/test/test_data_offer.cc
@@ -5,11 +5,13 @@
 #include "ui/ozone/platform/wayland/test/test_data_offer.h"
 
 #include <wayland-server-core.h>
+
 #include <utility>
 
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h"
 
 namespace wl {
diff --git a/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc b/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc
index b0f1354..49b2a9f 100644
--- a/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc
+++ b/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc
@@ -11,6 +11,7 @@
 #include <memory>
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
diff --git a/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.cc b/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.cc
index c54bfb0..65a4b7b 100644
--- a/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.cc
+++ b/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.cc
@@ -8,7 +8,7 @@
 #include <wayland-server-core.h>
 
 #include "base/logging.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace wl {
 
diff --git a/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc b/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc
index 19baa65..c301b052 100644
--- a/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc
+++ b/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc
@@ -11,6 +11,7 @@
 #include <memory>
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h"
 
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc
index a83b9d9..151c372 100644
--- a/ui/ozone/platform/x11/x11_window.cc
+++ b/ui/ozone/platform/x11/x11_window.cc
@@ -13,6 +13,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/ui/ozone/public/platform_screen.cc b/ui/ozone/public/platform_screen.cc
index f8da649b..2301c56 100644
--- a/ui/ozone/public/platform_screen.cc
+++ b/ui/ozone/public/platform_screen.cc
@@ -6,7 +6,7 @@
 
 #include <optional>
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/time/time.h"
 #include "ui/gfx/geometry/point.h"
 
diff --git a/ui/ozone/public/stub_input_controller.cc b/ui/ozone/public/stub_input_controller.cc
index 00b62e4f6..ef2b9eb 100644
--- a/ui/ozone/public/stub_input_controller.cc
+++ b/ui/ozone/public/stub_input_controller.cc
@@ -8,6 +8,7 @@
 
 #include "base/functional/callback.h"
 #include "base/memory/raw_ref.h"
+#include "base/notimplemented.h"
 #include "ui/events/devices/stylus_state.h"
 
 namespace ui {
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc
index c1266a8..0d40ad3 100644
--- a/ui/ozone/public/surface_factory_ozone.cc
+++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -5,9 +5,11 @@
 #include "ui/ozone/public/surface_factory_ozone.h"
 
 #include <stdlib.h>
+
 #include <memory>
 
 #include "base/command_line.h"
+#include "base/notimplemented.h"
 #include "gpu/vulkan/buildflags.h"
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gl/gl_implementation.h"
diff --git a/ui/platform_window/stub/stub_window.cc b/ui/platform_window/stub/stub_window.cc
index 51ab20e..5f550d9 100644
--- a/ui/platform_window/stub/stub_window.cc
+++ b/ui/platform_window/stub/stub_window.cc
@@ -5,7 +5,7 @@
 #include "ui/platform_window/stub/stub_window.h"
 
 #include "base/memory/scoped_refptr.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/base/cursor/platform_cursor.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/platform_window/platform_window_delegate.h"
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc
index 481413e..62a4d5bd 100644
--- a/ui/platform_window/win/win_window.cc
+++ b/ui/platform_window/win/win_window.cc
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "base/memory/scoped_refptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/strings/string_util_win.h"
 #include "ui/base/cursor/platform_cursor.h"
diff --git a/ui/shell_dialogs/select_file_dialog_android.cc b/ui/shell_dialogs/select_file_dialog_android.cc
index adf17187..677bbbdf 100644
--- a/ui/shell_dialogs/select_file_dialog_android.cc
+++ b/ui/shell_dialogs/select_file_dialog_android.cc
@@ -9,7 +9,7 @@
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/check.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ui/shell_dialogs/shell_dialog_stub.cc b/ui/shell_dialogs/shell_dialog_stub.cc
index a6f2b72..f5b4d18 100644
--- a/ui/shell_dialogs/shell_dialog_stub.cc
+++ b/ui/shell_dialogs/shell_dialog_stub.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 #include "ui/shell_dialogs/select_file_policy.h"
 
@@ -15,4 +15,4 @@
   return nullptr;
 }
 
-}  // namespace ui
\ No newline at end of file
+}  // namespace ui
diff --git a/ui/views/accessibility/ax_virtual_view.cc b/ui/views/accessibility/ax_virtual_view.cc
index 41fce0d..0fb3313 100644
--- a/ui/views/accessibility/ax_virtual_view.cc
+++ b/ui/views/accessibility/ax_virtual_view.cc
@@ -13,6 +13,7 @@
 #include "base/containers/adapters.h"
 #include "base/functional/callback.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_role_properties.h"
diff --git a/ui/views/accessibility/tree/browser_views_ax_manager.cc b/ui/views/accessibility/tree/browser_views_ax_manager.cc
index 839c9be..48b48d8 100644
--- a/ui/views/accessibility/tree/browser_views_ax_manager.cc
+++ b/ui/views/accessibility/tree/browser_views_ax_manager.cc
@@ -9,6 +9,7 @@
 #include "base/auto_reset.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/notimplemented.h"
 #include "base/task/single_thread_task_runner.h"
 #include "components/crash/core/common/crash_key.h"
 #include "ui/accessibility/accessibility_features.h"
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc
index c2e9a8c0..7362a0a 100644
--- a/ui/views/accessibility/view_accessibility.cc
+++ b/ui/views/accessibility/view_accessibility.cc
@@ -10,6 +10,7 @@
 
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/buildflag.h"
 #include "ui/accessibility/accessibility_features.h"
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc
index 27a43fc..6ab93bf 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -17,6 +17,7 @@
 #include "base/i18n/rtl.h"
 #include "base/lazy_instance.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_win.cc b/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
index 51e531e6..19ecb12d 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/memory/singleton.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/windows_version.h"
 #include "third_party/iaccessible2/ia2_api_all.h"
diff --git a/ui/views/controls/menu/menu_host.cc b/ui/views/controls/menu/menu_host.cc
index dd737d0..d22e759 100644
--- a/ui/views/controls/menu/menu_host.cc
+++ b/ui/views/controls/menu/menu_host.cc
@@ -11,7 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/scoped_observation.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
diff --git a/ui/views/controls/native/native_view_host_mac.mm b/ui/views/controls/native/native_view_host_mac.mm
index f567db7..deee086 100644
--- a/ui/views/controls/native/native_view_host_mac.mm
+++ b/ui/views/controls/native/native_view_host_mac.mm
@@ -7,6 +7,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/apple/foundation_util.h"
+#include "base/notimplemented.h"
 #import "ui/accessibility/platform/ax_platform_node_mac.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/ui/views/controls/prefix_selector.cc b/ui/views/controls/prefix_selector.cc
index 675213c..a787c94 100644
--- a/ui/views/controls/prefix_selector.cc
+++ b/ui/views/controls/prefix_selector.cc
@@ -8,6 +8,7 @@
 #include <limits>
 
 #include "base/i18n/case_conversion.h"
+#include "base/notimplemented.h"
 #include "base/time/default_tick_clock.h"
 #include "build/build_config.h"
 #include "ui/base/ime/input_method.h"
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 141312a..e80a634 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -16,6 +16,7 @@
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
diff --git a/ui/views/drag_utils_mac.mm b/ui/views/drag_utils_mac.mm
index 9b00eb9..1e8c26d 100644
--- a/ui/views/drag_utils_mac.mm
+++ b/ui/views/drag_utils_mac.mm
@@ -4,7 +4,7 @@
 
 #include "ui/views/drag_utils.h"
 
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 
 namespace views {
 
diff --git a/ui/views/layout/box_layout.cc b/ui/views/layout/box_layout.cc
index 0ee7a15..735d65ee 100644
--- a/ui/views/layout/box_layout.cc
+++ b/ui/views/layout/box_layout.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/containers/adapters.h"
+#include "base/notimplemented.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/ui/views/layout/flex_layout.cc b/ui/views/layout/flex_layout.cc
index d35b7ba9..8e9324f 100644
--- a/ui/views/layout/flex_layout.cc
+++ b/ui/views/layout/flex_layout.cc
@@ -16,7 +16,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/notreached.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "ui/base/class_property.h"
 #include "ui/events/event_target.h"
diff --git a/ui/views/layout/flex_layout_types.cc b/ui/views/layout/flex_layout_types.cc
index c8f30d1..5b40a06 100644
--- a/ui/views/layout/flex_layout_types.cc
+++ b/ui/views/layout/flex_layout_types.cc
@@ -10,6 +10,7 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/ui/views/test/desktop_test_views_delegate_mac.mm b/ui/views/test/desktop_test_views_delegate_mac.mm
index 33c7f077..66acdd45 100644
--- a/ui/views/test/desktop_test_views_delegate_mac.mm
+++ b/ui/views/test/desktop_test_views_delegate_mac.mm
@@ -4,6 +4,7 @@
 
 #include "ui/views/test/desktop_test_views_delegate.h"
 
+#include "base/notimplemented.h"
 #include "ui/views/widget/native_widget_mac.h"
 
 namespace views {
diff --git a/ui/views/test/widget_show_state_waiter.cc b/ui/views/test/widget_show_state_waiter.cc
index 2a986a2..f0c3fa6 100644
--- a/ui/views/test/widget_show_state_waiter.cc
+++ b/ui/views/test/widget_show_state_waiter.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/test/widget_show_state_waiter.h"
 
+#include "base/notimplemented.h"
 #include "base/run_loop.h"
 #include "ui/base/mojom/window_show_state.mojom.h"
 #include "ui/views/widget/widget.h"
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
index ec3e251..8f4540ad 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/metrics/histogram_macros.h"
+#include "base/notimplemented.h"
 #include "base/threading/hang_watcher.h"
 #include "ui/aura/env.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
diff --git a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index b11bf7d..b2d08a6 100644
--- a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
 
+#include "base/notimplemented.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/aura/client/cursor_shape_client.h"
 #include "ui/aura/window_event_dispatcher.h"
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
index a511406..39ac03f 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/scoped_observation.h"
 #include "ui/aura/null_window_targeter.h"
 #include "ui/aura/scoped_window_targeter.h"
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 0df80a4c..3af6daa 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -12,6 +12,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/notreached.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 97e4ff5..0dd1b665 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -14,6 +14,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/task/single_thread_task_runner.h"
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 486a381..eb271d5 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -18,6 +18,7 @@
 #include "base/functional/callback.h"
 #include "base/lazy_instance.h"
 #include "base/no_destructor.h"
+#include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/crash/core/common/crash_key.h"
 #import "components/remote_cocoa/app_shim/bridged_content_view.h"
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index a7aa574..80333b2 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -25,6 +25,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notimplemented.h"
 #include "base/strings/string_util.h"
 #include "base/strings/string_util_win.h"
 #include "base/strings/stringprintf.h"
diff --git a/ui/webui/examples/browser/ui/aura/aura_context.cc b/ui/webui/examples/browser/ui/aura/aura_context.cc
index eae4edb1..e8f475bd 100644
--- a/ui/webui/examples/browser/ui/aura/aura_context.cc
+++ b/ui/webui/examples/browser/ui/aura/aura_context.cc
@@ -5,6 +5,7 @@
 #include "ui/webui/examples/browser/ui/aura/aura_context.h"
 
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/test/test_screen.h"
diff --git a/ui/wm/core/cursor_manager_unittest.cc b/ui/wm/core/cursor_manager_unittest.cc
index 7a7bf71..d9f7de48 100644
--- a/ui/wm/core/cursor_manager_unittest.cc
+++ b/ui/wm/core/cursor_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
+#include "base/notimplemented.h"
 #include "ui/aura/client/cursor_client_observer.h"
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/base/cursor/cursor_size.h"