diff --git a/.eslintrc.js b/.eslintrc.js
index 31aea06..584404e7 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -94,6 +94,14 @@
         }
       ],
 
+      // https://google.github.io/styleguide/tsguide.html#array-constructor
+      // Note: The rule below only partially enforces the styleguide, since it
+      // it does not flag invocations of the constructor with a single
+      // parameter.
+      'no-array-constructor': 'off',
+      '@typescript-eslint/no-array-constructor': 'error',
+
+      // https://google.github.io/styleguide/tsguide.html#automatic-semicolon-insertion
       'semi': 'off',
       '@typescript-eslint/semi': ['error'],
 
@@ -193,6 +201,7 @@
         },
       ],
 
+      // https://google.github.io/styleguide/tsguide.html#member-property-declarations
       '@typescript-eslint/member-delimiter-style': ['error', {
         multiline: {
           delimiter: 'comma',
diff --git a/.gitmodules b/.gitmodules
index c5fe4f5..1aee623 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -611,6 +611,10 @@
 	path = chrome/browser/media/engagement_internal
 	url = https://chrome-internal.googlesource.com/chrome/browser/media/engagement_internal.git
 	gclient-condition = checkout_src_internal
+[submodule "chrome/browser/nearby_sharing/internal"]
+	path = chrome/browser/nearby_sharing/internal
+	url = https://chrome-internal.googlesource.com/chrome/browser/nearby_sharing/internal.git
+	gclient-condition = checkout_src_internal
 [submodule "chrome/browser/resources/chromeos/quickoffice"]
 	path = chrome/browser/resources/chromeos/quickoffice
 	url = https://chrome-internal.googlesource.com/quickoffice/crx.git
@@ -774,7 +778,7 @@
 [submodule "third_party/ml"]
 	path = third_party/ml
 	url = https://chrome-internal.googlesource.com/chrome/third_party/ml.git
-	gclient-condition = checkout_src_internal and (checkout_win or checkout_mac or checkout_linux)
+	gclient-condition = checkout_third_party_ml
 [submodule "third_party/widevine/cdm/chromeos"]
 	path = third_party/widevine/cdm/chromeos
 	url = https://chrome-internal.googlesource.com/chrome/deps/widevine/cdm/chromeos.git
diff --git a/DEPS b/DEPS
index 54c48d0f..5f9f301 100644
--- a/DEPS
+++ b/DEPS
@@ -313,19 +313,19 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': '302dcc1312975e57a6cb0728959e87aa4d93e1d0',
+  'src_internal_revision': 'f11a7d33a9d0c660a8c3b3b2fca966b25c575b3e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '475286f0f6f1aa711478328e70eceb1d90b36b68',
+  'skia_revision': 'b72fe6f76c61be2fd9cf6878f6e3defd44960af8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'faa4cfb4e3db1580859487805253f952286c9887',
+  'v8_revision': 'c57efa129901e286f562dccac8c5e77b9517b1fd',
   # 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': 'd1cf2d432624fb178868db0f57bcba140ca95071',
+  'angle_revision': '05c21cfc68099ee4edd20c880e99b185700a8c4c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -333,7 +333,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': '85bb72cc15e6797e16f5e36cff917b31026c7f7d',
+  'pdfium_revision': 'cdc2dda5a9576ca869b1a3d7c2104edb45187319',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -392,7 +392,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
-  'chromium_variations_revision': '65b0fed5e12fd5e19eb8da9efa8229103f8c56df',
+  'chromium_variations_revision': 'a6071ce9ef65c87750ea901b57a58185a2253718',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -408,7 +408,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '1616c8df453c98d7f9a48efc3bd4afe7b998a755',
+  'devtools_frontend_revision': '4ef9c73c536379ce499e8771304ef3f999fc86b6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -848,7 +848,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '83800f3f248339c58e3cf76ab5b656a4346ceea9',
+    '5c5f938d64e779438a837a026ff3234e7050b392',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1304,7 +1304,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'cf056dd795e94a797a3a748d07568c8d5f936d41',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '5fde161dd4df5e1bc613121743ca9a6f92e1acf8',
     'condition': 'checkout_src_internal',
   },
 
@@ -1312,7 +1312,7 @@
     Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d',
 
   'src/third_party/eigen3/src':
-    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '18018ed013029ca3f28f52a62360999b5a659eac',
+    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + 'e8515f78ac098329ab9f8cab21c87caede090a3f',
 
   'src/third_party/emoji-metadata/src': {
     'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06',
@@ -1782,7 +1782,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '09a4f3ec842a8932341b195c5b01e141c8a16eb7',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + 'b926e156d3d888dd6df3ecaaf1407ae00b5aa54e',
+    Var('chromium_git') + '/openscreen' + '@' + 'cba24a91356b6d7d2930797541168ff6e0d17885',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '58a00cf85c39ad5ec4dc43a769624e420c06179a',
@@ -1833,7 +1833,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'ZQH8yoO1Ol5rCFRL2hzp4_mcdq23Fk19Z_gVHn5pzk8C',
+              'version': 'tr-hYTpA4Gomi1_TTF1Hvbc0Rwy8guQ4OMLc90Gw0uQC',
           },
       ],
       'condition': 'checkout_android',
@@ -1925,7 +1925,7 @@
     Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
 
   'src/third_party/tflite/src':
-    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '85a1b2f83ce8075b9f1ca23ed6857784ede9965c',
+    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '03d8df0f8d9c51cacea632053ce2c387c41d5aaa',
 
   'src/third_party/turbine': {
       'packages': [
@@ -1975,7 +1975,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f4bf599a8b575df685c31d9c4729a70a04e377ed',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '08a4f176de99034a3089ce1a6ff48797fa4213ff',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '4e91a54a0767cf596a407e9bc0933e4bbc66e8d3',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '756911644f7c82cedc9230dd626e24053b9a50c4',
@@ -3965,9 +3965,15 @@
       'condition': 'checkout_src_internal',
   },
 
+  'src/chrome/browser/nearby_sharing/internal': {
+      'url': Var('chrome_git') + '/chrome/browser/nearby_sharing/internal.git' + '@' +
+        'f4c4312a51a12bd060d3a012345e273a58f26601',
+      'condition': 'checkout_src_internal',
+  },
+
   'src/chrome/browser/resources/chromeos/quickoffice': {
       'url': Var('chrome_git') + '/quickoffice/crx.git' + '@' +
-        '79e797d69d4675a2f0ef916dbb65457fe9485fc9',
+        '23bde3495989fbc0112213613d2498030be51417',
       'condition': '(checkout_chromeos or checkout_linux) and checkout_src_internal',
   },
 
@@ -4140,7 +4146,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '51e348d2f6443ffa00ae6db783ba2257f434d95e',
+        'd8dd6ed38966faf2a6db0ac48dfbe1e33c671755',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
@@ -4219,7 +4225,7 @@
   },
 
   'src/third_party/ml': {
-      'url': Var('chrome_git') + '/chrome/third_party/ml.git' + '@' + 'bfd95492122f567f2d3163bb0fb2b56f450618de',
+      'url': Var('chrome_git') + '/chrome/third_party/ml.git' + '@' + '9797a0977fd4de5ca4398943e6a6a61fc3ac5180',
       'condition': 'checkout_third_party_ml',
   },
 
diff --git a/OWNERS b/OWNERS
index d89c442..77f3ff60 100644
--- a/OWNERS
+++ b/OWNERS
@@ -215,6 +215,7 @@
 per-file chrome/browser/google/linkdoctor_internal=*
 per-file chrome/browser/internal=*
 per-file chrome/browser/media/engagement_internal=*
+per-file chrome/browser/nearby_sharing/internal=*
 per-file chrome/browser/resources/chromeos/quickoffice=*
 per-file chrome/browser/resources/settings_internal=*
 per-file chrome/browser/spellchecker/internal=*
diff --git a/ash/components/arc/arc_prefs.cc b/ash/components/arc/arc_prefs.cc
index b6fef67..d960401 100644
--- a/ash/components/arc/arc_prefs.cc
+++ b/ash/components/arc/arc_prefs.cc
@@ -183,6 +183,10 @@
 // enterprise user.
 const char kArcVmDataMigrationStrategy[] = "arc.vm_data_migration_strategy";
 
+// A preference representing if ARC is allowed on unaffiliated devices
+// of an enterprise account
+const char kUnaffiliatedDeviceArcAllowed[] = "arc.unaffiliated.device.allowed";
+
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
   // Sorted in lexicographical order.
   RegisterDailyMetricsPrefs(registry);
@@ -246,6 +250,7 @@
   registry->RegisterIntegerPref(
       kArcVmDataMigrationStrategy,
       static_cast<int>(ArcVmDataMigrationStrategy::kDoNotPrompt));
+  registry->RegisterBooleanPref(kUnaffiliatedDeviceArcAllowed, true);
 }
 
 }  // namespace prefs
diff --git a/ash/components/arc/arc_prefs.h b/ash/components/arc/arc_prefs.h
index 5703f5a..89f2464f 100644
--- a/ash/components/arc/arc_prefs.h
+++ b/ash/components/arc/arc_prefs.h
@@ -53,6 +53,7 @@
 ARC_EXPORT extern const char kEcryptfsMigrationStrategy[];
 ARC_EXPORT extern const char kEngagementPrefsPrefix[];
 ARC_EXPORT extern const char kArcVmDataMigrationStrategy[];
+ARC_EXPORT extern const char kUnaffiliatedDeviceArcAllowed[];
 
 // Local state prefs in lexicographical order.
 ARC_EXPORT extern const char kAnrPendingCount[];
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 0b76c37..ac31cc3 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1446,6 +1446,13 @@
 const base::FeatureParam<bool> kHoldingSpaceTourEnabledCounterfactually{
     &kHoldingSpaceTour, "is-counterfactual", false};
 
+// Ignores the rate limiting of holding space tour so that it will show every
+// time a user drags a file over the wallpaper. Enabling this flag does nothing
+// unless `kHoldingSpaceTour` is also enabled.
+BASE_FEATURE(kHoldingSpaceTourIgnoreRateLimiting,
+             "HoldingSpaceTourIgnoreRateLimiting",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kHomeButtonQuickAppAccess,
              "HomeButtonQuickAppAccess",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -3477,6 +3484,11 @@
          kHoldingSpaceTourEnabledCounterfactually.Get();
 }
 
+bool IsHoldingSpaceTourRateLimitingEnabled() {
+  return IsHoldingSpaceTourEnabled() &&
+         !base::FeatureList::IsEnabled(kHoldingSpaceTourIgnoreRateLimiting);
+}
+
 bool IsHomeButtonQuickAppAccessEnabled() {
   return base::FeatureList::IsEnabled(kHomeButtonQuickAppAccess) ||
          base::FeatureList::IsEnabled(kQuickAppAccessTestUI);
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index cc059c2..f629e9e 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -445,6 +445,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHoldingSpaceRefresh);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHoldingSpaceSuggestions);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHoldingSpaceTour);
+COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kHoldingSpaceTourIgnoreRateLimiting);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHomeButtonQuickAppAccess);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHotspot);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVirtualKeyboardNewHeader);
@@ -1001,6 +1003,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceTourEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsHoldingSpaceTourEnabledCounterfactually();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceTourRateLimitingEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS)
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHomeButtonQuickAppAccessEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHomeButtonWithTextEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHostnameSettingEnabled();
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 8c366e4..d6686a41 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -488,6 +488,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "accelerator_actions_unittest.cc",
     "accelerator_keycode_lookup_cache_unittest.cc",
     "accelerators_util_unittest.cc",
     "ambient/ambient_prefs_unittest.cc",
diff --git a/ash/public/cpp/accelerator_actions.h b/ash/public/cpp/accelerator_actions.h
index 9f8b516b..bc39cd0 100644
--- a/ash/public/cpp/accelerator_actions.h
+++ b/ash/public/cpp/accelerator_actions.h
@@ -9,6 +9,11 @@
 
 namespace ash {
 
+// IMPORTANT PLEASE READ.
+// Please ensure that the order of these enums are stable. If adding a new
+// accelerator action, please but at the end and before DEBUG-related
+// accelerator actions.
+//
 // Please keep the ActionName in sync with the ActionName under
 // <histogram name="Ash.Accelerators.Actions.{ActionName}" in this file
 // tools/metrics/histograms/metadata/ash/histograms.xml.
diff --git a/ash/public/cpp/accelerator_actions_unittest.cc b/ash/public/cpp/accelerator_actions_unittest.cc
new file mode 100644
index 0000000..0703660f
--- /dev/null
+++ b/ash/public/cpp/accelerator_actions_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/public/cpp/accelerator_actions.h"
+
+#include "base/containers/fixed_flat_map.h"
+#include "base/hash/md5.h"
+#include "base/hash/md5_boringssl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+
+namespace {
+
+// The total number of accelerator actions.
+constexpr int kAcceleratorActionsTotalNum = 155;
+// The toal number of debug accelerators, these will not be used for hashing.
+constexpr int kDebugAcceleratorActionsNum = 26;
+// The hash of accelerator actions. Please update this when adding a new
+// accelerator action.
+constexpr char kAcceleratorActionsHash[] = "69ca25642d0ee9a9cf3eee1c3ac14419";
+
+// Define the mapping between an AcceleratorAction and its string name.
+// Example:
+//   AcceleratorAction::kDevToggleUnifiedDesktop -> "DevToggleUnifiedDesktop".
+constexpr static auto kAcceleratorActionToName =
+    base::MakeFixedFlatMap<AcceleratorAction, const char*>({
+#define ACCELERATOR_ACTION_ENTRY(action) \
+  {AcceleratorAction::k##action, #action},
+        ACCELERATOR_ACTIONS
+#undef ACCELERATOR_ACTION_ENTRY
+    });
+
+class AcceleratorActionsTest : public testing::Test {
+ public:
+  AcceleratorActionsTest() = default;
+
+  AcceleratorActionsTest(const AcceleratorActionsTest&) = delete;
+  AcceleratorActionsTest& operator=(const AcceleratorActionsTest&) = delete;
+
+  ~AcceleratorActionsTest() override = default;
+};
+
+}  // namespace
+
+TEST_F(AcceleratorActionsTest, AcceleratorActionsHash) {
+  const char kCommonMessage[] =
+      "If you are adding a non-debug accelerator action, please ensure that "
+      "you add the new action to be bottom of the enums but before the"
+      "DEBUG accelerator actions. Please update the values "
+      "`kAcceleratorActionsTotalNum` and `kDebugAcceleratorActionsNum` "
+      "(if applicable)."
+      "Please then update `kAcceleratorActionsHash`";
+
+  // First check that the size of the enum is correct.
+  const int current_actions_size = kAcceleratorActionToName.size();
+  EXPECT_EQ(current_actions_size, kAcceleratorActionsTotalNum)
+      << kCommonMessage;
+
+  // Then check that the hash is correct.
+  base::MD5Context context;
+  base::MD5Init(&context);
+  int iter_count = 0;
+  for (const auto iter : kAcceleratorActionToName) {
+    base::MD5Update(&context, iter.second);
+    // Only hash up non-debug accelerator actions.
+    if (++iter_count >= current_actions_size - kDebugAcceleratorActionsNum) {
+      break;
+    }
+  }
+
+  base::MD5Digest digest;
+  base::MD5Final(&digest, &context);
+  const std::string current_hash = MD5DigestToBase16(digest);
+
+  EXPECT_EQ(current_hash, kAcceleratorActionsHash)
+      << kCommonMessage << "kAcceleratorActionsHash=\"" << current_hash
+      << "\"\n";
+}
+
+}  // namespace ash
diff --git a/ash/system/session/logout_button_tray_unittest.cc b/ash/system/session/logout_button_tray_unittest.cc
index 81c8ebc..7740d7e9 100644
--- a/ash/system/session/logout_button_tray_unittest.cc
+++ b/ash/system/session/logout_button_tray_unittest.cc
@@ -74,7 +74,8 @@
   EXPECT_FALSE(button->GetVisible());
 }
 
-TEST_F(LogoutButtonTrayTest, ButtonPressed) {
+// TODO(crbug.com/1491544): Test is flaky.
+TEST_F(LogoutButtonTrayTest, DISABLED_ButtonPressed) {
   constexpr char kUserAction[] = "DemoMode.ExitFromShelf";
 
   LogoutButtonTray* const tray = Shell::GetPrimaryRootWindowController()
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index 2da5c486..4d65ec4 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -404,17 +404,38 @@
 
 void UnifiedSystemTray::ShowAudioDetailedViewBubble() {
   ShowBubble();
-  bubble_->ShowAudioDetailedView();
+
+  // There is a case that `bubble_` is still a nullptr after `ShowBubble()` is
+  // called (e.g. in kiosk mode, `ShowBubbleInternal()` will early return, and
+  // `bubble_` is still uninitialized). Only show detailed view if `bubble_` is
+  // not null.
+  if (bubble_) {
+    bubble_->ShowAudioDetailedView();
+  }
 }
 
 void UnifiedSystemTray::ShowDisplayDetailedViewBubble() {
   ShowBubble();
-  bubble_->ShowDisplayDetailedView();
+
+  // There is a case that `bubble_` is still a nullptr after `ShowBubble()` is
+  // called (e.g. in kiosk mode, `ShowBubbleInternal()` will early return, and
+  // `bubble_` is still uninitialized). Only show detailed view if `bubble_` is
+  // not null.
+  if (bubble_) {
+    bubble_->ShowDisplayDetailedView();
+  }
 }
 
 void UnifiedSystemTray::ShowNetworkDetailedViewBubble() {
   ShowBubble();
-  bubble_->ShowNetworkDetailedView(true /* force */);
+
+  // There is a case that `bubble_` is still a nullptr after `ShowBubble()` is
+  // called (e.g. in kiosk mode, `ShowBubbleInternal()` will early return, and
+  // `bubble_` is still uninitialized). Only show detailed view if `bubble_` is
+  // not null.
+  if (bubble_) {
+    bubble_->ShowNetworkDetailedView(/*force=*/true);
+  }
 }
 
 void UnifiedSystemTray::NotifySecondaryBubbleHeight(int height) {
diff --git a/ash/system/unified/unified_system_tray_unittest.cc b/ash/system/unified/unified_system_tray_unittest.cc
index afd7d421..4f86f64e 100644
--- a/ash/system/unified/unified_system_tray_unittest.cc
+++ b/ash/system/unified/unified_system_tray_unittest.cc
@@ -1065,6 +1065,27 @@
   EXPECT_FALSE(tray->camera_view());
 }
 
+// Tests that there's no bubble in the kiosk mode.
+TEST_P(UnifiedSystemTrayTest, NoBubbleAndNoDetailedViewInKioskMode) {
+  SimulateKioskMode(user_manager::USER_TYPE_KIOSK_APP);
+
+  auto* tray = GetPrimaryUnifiedSystemTray();
+  tray->ShowBubble();
+
+  // In the kiosk mode, the bubble doesn't exist.
+  EXPECT_FALSE(IsBubbleShown());
+
+  // Trying to show any of the detailed view will not show the bubble.
+  tray->ShowAudioDetailedViewBubble();
+  EXPECT_FALSE(IsBubbleShown());
+
+  tray->ShowNetworkDetailedViewBubble();
+  EXPECT_FALSE(IsBubbleShown());
+
+  tray->ShowDisplayDetailedViewBubble();
+  EXPECT_FALSE(IsBubbleShown());
+}
+
 // Test suite for the system tray when `kPrivacyIndicators` is enabled.
 class UnifiedSystemTrayPrivacyIndicatorsTest
     : public AshTestBase,
diff --git a/ash/user_education/holding_space_tour/holding_space_tour_controller.cc b/ash/user_education/holding_space_tour/holding_space_tour_controller.cc
index 1ea79c19..f003e07 100644
--- a/ash/user_education/holding_space_tour/holding_space_tour_controller.cc
+++ b/ash/user_education/holding_space_tour/holding_space_tour_controller.cc
@@ -277,6 +277,11 @@
     CHECK(wallpaper_highlight_);
     wallpaper_highlight_.reset();
 
+    // Immediately close the help bubble so that it does not block the holding
+    // space. If it has already closed, e.g. due to timeout, the internal
+    // callback will have already been canceled and no-op.
+    scoped_help_bubble_closer_.RunAndReset();
+
     // No-op if no holding space `client` is registered since we will be unable
     // to handle the dropped `data`.
     HoldingSpaceClient* const client = HoldingSpaceController::Get()->client();
@@ -389,11 +394,18 @@
                     HoldingSpaceController::ScopedForceShowInShelf>()));
 
     // Attempt to show the help bubble.
-    if (UserEducationHelpBubbleController::Get()->CreateHelpBubble(
-            HelpBubbleId::kHoldingSpaceTour, std::move(help_bubble_params),
-            kHoldingSpaceTrayElementId,
-            views::ElementTrackerViews::GetContextForView(holding_space_tray),
-            std::move(close_callback))) {
+    if (auto scoped_help_bubble_closer =
+            UserEducationHelpBubbleController::Get()->CreateScopedHelpBubble(
+                HelpBubbleId::kHoldingSpaceTour, std::move(help_bubble_params),
+                kHoldingSpaceTrayElementId,
+                views::ElementTrackerViews::GetContextForView(
+                    holding_space_tray),
+                std::move(close_callback))) {
+      // If we successfully created a help bubble, then it is safe to replace
+      // the current `base::ScopedClosureRunner` because any previous help
+      // bubbles have already closed.
+      scoped_help_bubble_closer_ = std::move(scoped_help_bubble_closer);
+
       // If successful in showing the help bubble, ping the `holding_space_tray`
       // to further attract the user's attention.
       UserEducationPingController::Get()->CreatePing(PingId::kHoldingSpaceTour,
@@ -414,6 +426,9 @@
   std::unique_ptr<HoldingSpaceController::ScopedForceShowInShelf>
       force_holding_space_show_in_shelf_;
 
+  // Used to close the help bubble on drop-to-pin.
+  base::ScopedClosureRunner scoped_help_bubble_closer_;
+
   // Used to highlight the wallpaper when data is dragged over it so that the
   // user better understands the wallpaper is a drop target.
   std::unique_ptr<Highlight> wallpaper_highlight_;
diff --git a/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc b/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc
index f0b2e07b0..9b99139 100644
--- a/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc
+++ b/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc
@@ -562,10 +562,16 @@
   ReleaseLeftButton();
   FlushMessageLoop();
 
-  // Expect the holding space tray on the primary display to have a help bubble
-  // and a ping if and only if Files app data was dragged. The holding space
-  // tray on the secondary display should have neither.
-  EXPECT_EQ(HasHelpBubble(primary_tray), drag_files_app_data());
+  // Expect the holding space tray on the primary display to have a ping if and
+  // only if Files app data was dragged. If Files app data was dragged and the
+  // drop-to-pin action was not taken, then expect the help bubble on the
+  // primary display to still exist. The help bubble should have been closed
+  // immediately if the drop-to-pin action was taken. The holding space tray on
+  // the secondary display should have neither.
+  const bool help_bubble_should_be_fast_closed =
+      complete_drop() && drop_to_pin_enabled().value_or(false);
+  EXPECT_EQ(HasHelpBubble(primary_tray),
+            drag_files_app_data() && !help_bubble_should_be_fast_closed);
   EXPECT_EQ(HasPing(primary_tray), drag_files_app_data());
   EXPECT_FALSE(HasHelpBubble(secondary_tray));
   EXPECT_FALSE(HasPing(secondary_tray));
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 02e4f4c..0a012952 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -424,6 +424,7 @@
     "memory/raw_ptr_exclusion.h",
     "memory/raw_ref.h",
     "memory/raw_scoped_refptr_mismatch_checker.h",
+    "memory/raw_span.h",
     "memory/read_only_shared_memory_region.cc",
     "memory/read_only_shared_memory_region.h",
     "memory/ref_counted.cc",
@@ -2698,6 +2699,12 @@
   }
 }
 
+executable("containers_memory_benchmark") {
+  sources = [ "containers/containers_memory_benchmark.cc" ]
+  deps = [ ":base" ]
+  testonly = true
+}
+
 test("base_perftests") {
   sources = [
     "big_endian_perftest.cc",
@@ -3199,6 +3206,7 @@
     "memory/ptr_util_unittest.cc",
     "memory/raw_ptr_asan_unittest.cc",
     "memory/raw_ptr_chromium_unittest.cc",
+    "memory/raw_span_unittest.cc",
     "memory/ref_counted_memory_unittest.cc",
     "memory/ref_counted_unittest.cc",
     "memory/safe_ref_unittest.cc",
diff --git a/base/containers/DEPS b/base/containers/DEPS
new file mode 100644
index 0000000..91f179a
--- /dev/null
+++ b/base/containers/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+  # Needed to memory benchmark different containers against each other.
+  "containers_memory_benchmark\.cc": [
+    "+third_party/abseil-cpp/absl/container",
+  ],
+}
diff --git a/base/containers/analyze_containers_memory_benchmark.py b/base/containers/analyze_containers_memory_benchmark.py
new file mode 100755
index 0000000..6b7d622
--- /dev/null
+++ b/base/containers/analyze_containers_memory_benchmark.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Processes the raw output from containers_memory_usage into CSV files. Each CSV
+# file contains the results for all tested container types for a given key and
+# value type.
+#
+# Usage:
+# $ out/release/containers_memory_benchmark &> output.txt
+# $ python3 analyze_containers_memory_benchmark.py < output.txt -o bench-results
+
+import argparse
+from collections.abc import Sequence
+import csv
+import os.path
+import re
+import sys
+from typing import Optional
+
+
+_HEADER_RE = re.compile(r'===== (?P<name>.+) =====')
+_ITER_RE = re.compile(r'iteration (?P<iter>\d+)')
+_ALLOC_RE = re.compile(r'alloc address (?P<alloc_addr>.+) size (?P<size>\d+)')
+_FREED_RE = re.compile(r'freed address (?P<freed_addr>.+)')
+
+
+class ContainerStatsProcessor:
+
+  def __init__(self, name: str):
+    # e.g. base::flat_map
+    self._name = name
+    # current number of elements in the container
+    self._n = None
+    # map of address to size for currently active allocations. Needed because
+    # the free handler only records an address, and not a size.
+    self._addr_to_size = {}
+    # running count of the number of bytes needed at the current iteration
+    self._running_size = 0
+    # map of container size to number of bytes used to store a container of that
+    # size. Keys are expected to be contiguous from 0 to the total iteration
+    # count.
+    self._data = {}
+
+  @property
+  def name(self):
+    return self._name
+
+  @property
+  def data(self):
+    return self._data
+
+  def did_alloc(self, addr: str, size: int):
+    self._addr_to_size[addr] = size
+    self._running_size += size
+
+  def did_free(self, addr: str):
+    size = self._addr_to_size.pop(addr)
+    self._running_size -= size
+
+  def did_iterate(self, n: int):
+    if self._n is not None:
+      self.flush_current_iteration_if_needed()
+    self._n = n
+
+  def flush_current_iteration_if_needed(self):
+    self._data[self._n] = self._running_size
+
+
+class TestCaseProcessor:
+
+  def __init__(self, name: str):
+    # e.g. int -> std::string
+    self._name = name
+    # containers for which all allocation data has been processed and finalized.
+    self._finalized_stats: list[ContainerStatsProcessor] = []
+    # the current container being processed.
+    self._current_container_stats: Optional[ContainerStatsProcessor] = None
+
+  @property
+  def current_container_stats(self):
+    return self._current_container_stats
+
+  def did_begin_container_stats(self, container_type: str):
+    self._finalize_current_container_stats_if_needed()
+    self._current_container_stats = ContainerStatsProcessor(container_type)
+
+  def did_finish_container_stats(self, output_dir: str):
+    self._finalize_current_container_stats_if_needed()
+    with open(
+        os.path.join(output_dir, f'{self._name}.csv'), 'w', newline=''
+    ) as f:
+      writer = csv.writer(f)
+      # First the column headers...
+      writer.writerow(
+          ['size'] + [stats.name for stats in self._finalized_stats]
+      )
+      # In theory, all processed containers should have the same number of keys,
+      # but assert just to be sure.
+      keys = []
+      for stats in self._finalized_stats:
+        if not keys:
+          keys = sorted(stats.data.keys())
+        else:
+          assert keys == sorted(stats.data.keys())
+      for key in keys:
+        writer.writerow(
+            [key] + [stats.data[key] for stats in self._finalized_stats]
+        )
+
+  def _finalize_current_container_stats_if_needed(self):
+    if self._current_container_stats:
+      self._current_container_stats.flush_current_iteration_if_needed()
+      self._finalized_stats.append(self._current_container_stats)
+      self._current_container_stats = None
+
+
+def main(argv: Sequence[str]) -> None:
+  parser = argparse.ArgumentParser(
+      description='Processes raw output from containers_memory_usage into CSVs.'
+  )
+  parser.add_argument(
+      '-o', help='directory to write CSV files to', required=True
+  )
+  args = parser.parse_args()
+
+  # It would be nicer to use a ContextManager, but that complicates splitting up
+  # the input and iterating through it. This is "good enough".
+  processor: Optional[TestCaseProcessor] = None
+
+  for line in sys.stdin:
+    line = line.strip()
+    if '->' in line:
+      if processor:
+        processor.did_finish_container_stats(args.o)
+      processor = TestCaseProcessor(line)
+      continue
+
+    match = _HEADER_RE.match(line)
+    if match:
+      processor.did_begin_container_stats(match.group('name'))
+
+    match = _ITER_RE.match(line)
+    if match:
+      processor.current_container_stats.did_iterate(int(match.group('iter')))
+      continue
+
+    match = _ALLOC_RE.match(line)
+    if match:
+      processor.current_container_stats.did_alloc(
+          match.group('alloc_addr'), int(match.group('size'))
+      )
+      continue
+
+    match = _FREED_RE.match(line)
+    if match:
+      processor.current_container_stats.did_free(match.group('freed_addr'))
+      continue
+
+  if processor:
+    processor.did_finish_container_stats(args.o)
+
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/base/containers/containers_memory_benchmark.cc b/base/containers/containers_memory_benchmark.cc
new file mode 100644
index 0000000..af726fc4
--- /dev/null
+++ b/base/containers/containers_memory_benchmark.cc
@@ -0,0 +1,252 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This is a framework to measure the memory overhead of different containers.
+// Under the hood, it works by logging allocations and frees using an allocator
+// hook.
+//
+// Since the free callback does not report a size, and the allocator hooks run
+// in the middle of allocation, the logger simply takes the simplest approach
+// and logs out the raw data, relying on analyze_containers_memory_usage.py to
+// turn the raw output into useful numbers.
+//
+// The output of consists of m (number of different key/value combinations being
+// tested) x n (number of different map types being tested) sections:
+//
+// <key type 1> -> <value type 1>
+// ===== <map type 1> =====
+// iteration 0
+// alloc <address 1> size <size 1>
+// iteration 1
+// alloc <address 2> size <size 2>
+// free <address 1>
+// iteration 2
+// alloc <address 3> size <size 3>
+// free <address 2>
+// ...
+// ...
+// ...
+// ===== <map type n>
+// iteration 0
+// alloc <address 1000> size <size 1000>
+// iteration 1
+// alloc <address 1001> size <size 1001>
+// free <address 1000>
+// iteration 2
+// alloc <address 1002> size <size 1002>
+// free <address 1001>
+// ...
+// ...
+// ...
+// <key type m> -> <value type m>
+// ===== <map type 1> =====
+// ...
+// ...
+// ===== <map type n> =====
+//
+// Alternate output strategies are possible, but most of them are worse/more
+// complex, and do not eliminate the postprocessing step.
+
+#include <array>
+#include <atomic>
+#include <charconv>
+#include <limits>
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "base/allocator/dispatcher/dispatcher.h"
+#include "base/containers/flat_map.h"
+#include "base/logging.h"
+#include "base/strings/safe_sprintf.h"
+#include "base/unguessable_token.h"
+#include "base/values.h"
+#include "third_party/abseil-cpp/absl/container/btree_map.h"
+#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
+#include "third_party/abseil-cpp/absl/container/node_hash_map.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace {
+
+std::atomic<bool> log_allocs_and_frees;
+
+struct AllocationLogger {
+ public:
+  void OnAllocation(void* address,
+                    size_t size,
+                    base::allocator::dispatcher::AllocationSubsystem sub_system,
+                    const char* type_name) {
+    if (log_allocs_and_frees.load(std::memory_order_acquire)) {
+      char buffer[128];
+      // Assume success; ignore return value.
+      base::strings::SafeSPrintf(buffer, "alloc address %p size %d\n", address,
+                                 size);
+      RAW_LOG(INFO, buffer);
+    }
+  }
+
+  void OnFree(void* address) {
+    if (log_allocs_and_frees.load(std::memory_order_acquire)) {
+      char buffer[128];
+      // Assume success; ignore return value.
+      base::strings::SafeSPrintf(buffer, "freed address %p\n", address);
+      RAW_LOG(INFO, buffer);
+    }
+  }
+
+  static void Install() {
+    static AllocationLogger logger;
+    base::allocator::dispatcher::Dispatcher::GetInstance().InitializeForTesting(
+        &logger);
+  }
+};
+
+class ScopedLogAllocAndFree {
+ public:
+  ScopedLogAllocAndFree() {
+    log_allocs_and_frees.store(true, std::memory_order_release);
+  }
+
+  ~ScopedLogAllocAndFree() {
+    log_allocs_and_frees.store(false, std::memory_order_release);
+  }
+};
+
+// Measures the memory usage for a container with type `Container` from 0 to
+// 6857 elements, using `inserter` to insert a single element at a time.
+// `inserter` should be a functor that takes a `Container& container` as its
+// first parameter and a `size_t current_index` as its second parameter.
+//
+// Note that `inserter` can't use `base::FunctionRef` since the inserter is
+// passed through several layers before actually being instantiated below in
+// this function.
+template <typename Container, typename Inserter>
+void MeasureOneContainer(const Inserter& inserter) {
+  char buffer[128];
+
+  RAW_LOG(INFO, "iteration 0");
+  // Record any initial allocations made by an empty container.
+  absl::optional<ScopedLogAllocAndFree> base_size_logger;
+  base_size_logger.emplace();
+  Container c;
+  base_size_logger.reset();
+  // As a hack, also log out sizeof(c) since the initial base size of the
+  // container should be counted too. The exact placeholder used for the address
+  // (in this case "(stack)") isn't important as long as it will not have a
+  // corresponding free line logged for it.
+  base::strings::SafeSPrintf(buffer, "alloc address (stack) size %d",
+                             sizeof(c));
+  RAW_LOG(INFO, buffer);
+
+  // Swisstables resizes the backing store around 6858 elements.
+  for (size_t i = 1; i <= 6857; ++i) {
+    base::strings::SafeSPrintf(buffer, "iteration %d", i);
+    RAW_LOG(INFO, buffer);
+    inserter(c, i);
+  }
+}
+
+// Measures the memory usage for all the container types under test. `inserter`
+// is used to insert a single element at a time into the tested container.
+template <typename K, typename V, typename Inserter>
+void Measure(const Inserter& inserter) {
+  using Hasher = std::conditional_t<std::is_same_v<base::UnguessableToken, K>,
+                                    base::UnguessableTokenHash, std::hash<K>>;
+
+  RAW_LOG(INFO, "===== base::flat_map =====");
+  MeasureOneContainer<base::flat_map<K, V>>(inserter);
+  RAW_LOG(INFO, "===== std::map =====");
+  MeasureOneContainer<std::map<K, V>>(inserter);
+  RAW_LOG(INFO, "===== std::unordered_map =====");
+  MeasureOneContainer<std::unordered_map<K, V, Hasher>>(inserter);
+  RAW_LOG(INFO, "===== absl::btree_map =====");
+  MeasureOneContainer<absl::btree_map<K, V>>(inserter);
+  RAW_LOG(INFO, "===== absl::flat_hash_map =====");
+  MeasureOneContainer<absl::flat_hash_map<K, V, Hasher>>(inserter);
+  RAW_LOG(INFO, "===== absl::node_hash_map =====");
+  MeasureOneContainer<absl::node_hash_map<K, V, Hasher>>(inserter);
+}
+
+}  // namespace
+
+int main() {
+  AllocationLogger::Install();
+
+  RAW_LOG(INFO, "int -> int");
+  Measure<int, int>([](auto& container, size_t i) {
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({i, 0});
+  });
+  RAW_LOG(INFO, "int -> void*");
+  Measure<int, void*>([](auto& container, size_t i) {
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({i, nullptr});
+  });
+  RAW_LOG(INFO, "int -> std::string");
+  Measure<int, std::string>([](auto& container, size_t i) {
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({i, ""});
+  });
+  RAW_LOG(INFO, "size_t -> int");
+  Measure<size_t, int>([](auto& container, size_t i) {
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({i, 0});
+  });
+  RAW_LOG(INFO, "size_t -> void*");
+  Measure<size_t, void*>([](auto& container, size_t i) {
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({i, nullptr});
+  });
+  RAW_LOG(INFO, "size_t -> std::string");
+  Measure<size_t, std::string>([](auto& container, size_t i) {
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({i, ""});
+  });
+  RAW_LOG(INFO, "std::string -> std::string");
+  Measure<std::string, std::string>([](auto& container, size_t i) {
+    std::string key;
+    key.resize(std::numeric_limits<size_t>::digits10 + 1);
+    auto result = std::to_chars(&key.front(), &key.back(), i);
+    key.resize(result.ptr - &key.front());
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({key, ""});
+  });
+  RAW_LOG(INFO, "base::UnguessableToken -> void*");
+  Measure<base::UnguessableToken, void*>([](auto& container, size_t i) {
+    auto token = base::UnguessableToken::Create();
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({token, nullptr});
+  });
+  RAW_LOG(INFO, "base::UnguessableToken -> base::Value");
+  Measure<base::UnguessableToken, base::Value>([](auto& container, size_t i) {
+    auto token = base::UnguessableToken::Create();
+    base::Value value;
+    ScopedLogAllocAndFree scoped_logging;
+    container.insert({token, std::move(value)});
+  });
+  RAW_LOG(INFO, "base::UnguessableToken -> std::array<std::string, 4>");
+  Measure<base::UnguessableToken, std::array<std::string, 4>>(
+      [](auto& container, size_t i) {
+        auto token = base::UnguessableToken::Create();
+        ScopedLogAllocAndFree scoped_logging;
+        container.insert({token, {}});
+      });
+  RAW_LOG(INFO, "base::UnguessableToken -> std::array<std::string, 8>");
+  Measure<base::UnguessableToken, std::array<std::string, 8>>(
+      [](auto& container, size_t i) {
+        auto token = base::UnguessableToken::Create();
+        ScopedLogAllocAndFree scoped_logging;
+        container.insert({token, {}});
+      });
+  RAW_LOG(INFO, "base::UnguessableToken -> std::array<std::string, 16>");
+  Measure<base::UnguessableToken, std::array<std::string, 16>>(
+      [](auto& container, size_t i) {
+        auto token = base::UnguessableToken::Create();
+        ScopedLogAllocAndFree scoped_logging;
+        container.insert({token, {}});
+      });
+
+  return 0;
+}
diff --git a/base/containers/span.h b/base/containers/span.h
index 8b94e87e..cbb56d19 100644
--- a/base/containers/span.h
+++ b/base/containers/span.h
@@ -27,7 +27,9 @@
 // [views.constants]
 constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
 
-template <typename T, size_t Extent = dynamic_extent>
+template <typename T,
+          size_t Extent = dynamic_extent,
+          typename InternalPtrType = T*>
 class span;
 
 namespace internal {
@@ -233,7 +235,7 @@
 // appropriate make_span() utility functions are provided.
 
 // [span], class template span
-template <typename T, size_t Extent>
+template <typename T, size_t Extent, typename InternalPtrType>
 class GSL_POINTER span : public internal::ExtentStorage<Extent> {
  private:
   using ExtentStorage = internal::ExtentStorage<Extent>;
@@ -452,13 +454,13 @@
  private:
   // This field is not a raw_ptr<> because it was filtered by the rewriter
   // for: #constexpr-ctor-field-initializer, #global-scope, #union
-  RAW_PTR_EXCLUSION T* data_;
+  InternalPtrType data_;
 };
 
 // span<T, Extent>::extent can not be declared inline prior to C++17, hence this
 // definition is required.
-template <class T, size_t Extent>
-constexpr size_t span<T, Extent>::extent;
+template <class T, size_t Extent, typename InternalPtrType>
+constexpr size_t span<T, Extent, InternalPtrType>::extent;
 
 template <typename It,
           typename T = std::remove_reference_t<iter_reference_t<It>>>
diff --git a/base/memory/raw_span.h b/base/memory/raw_span.h
new file mode 100644
index 0000000..a2cfe10
--- /dev/null
+++ b/base/memory/raw_span.h
@@ -0,0 +1,27 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_RAW_SPAN_H_
+#define BASE_MEMORY_RAW_SPAN_H_
+
+#include "base/containers/span.h"
+#include "base/memory/raw_ptr.h"
+
+namespace base {
+
+// raw_span<T> is a type that provides the spatial safety of span<T> along
+// with the temporal safety of raw_ptr<T>. This is intended to be a safer
+// replacement for classes that store pointer + size fields. As is the case
+// with raw_ptr<>, raw_span<> should be used for class members only, with
+// ordinary span<> used for function arguments and the like. Note that
+// raw_span<> will implicitly convert to span<> for ease of use in these
+// cases.
+
+template <typename T, RawPtrTraits Traits = RawPtrTraits::kEmpty>
+using raw_span =
+    span<T, dynamic_extent, raw_ptr<T, Traits | AllowPtrArithmetic>>;
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_RAW_SPAN_H_
diff --git a/base/memory/raw_span_unittest.cc b/base/memory/raw_span_unittest.cc
new file mode 100644
index 0000000..4b12720
--- /dev/null
+++ b/base/memory/raw_span_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/raw_span.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// This file contains tests related to raw_span, to show that they
+// convert to span.
+
+TEST(RawSpan, ConvertToSpan) {
+  int arr[3] = {100, 101, 102};
+  base::raw_span<int> span1(arr);
+  base::span<int> span2(span1);
+  base::span<int> span3;
+  span3 = span1;
+
+  EXPECT_THAT(span1, ::testing::ElementsAre(100, 101, 102));
+  EXPECT_THAT(span2, ::testing::ElementsAre(100, 101, 102));
+  EXPECT_THAT(span3, ::testing::ElementsAre(100, 101, 102));
+}
+
+TEST(RawSpan, ConvertFromSpan) {
+  int arr[3] = {100, 101, 102};
+  base::span<int> span1(arr);
+  base::raw_span<int> span2(span1);
+  base::raw_span<int> span3;
+  span3 = span1;
+
+  EXPECT_THAT(span1, ::testing::ElementsAre(100, 101, 102));
+  EXPECT_THAT(span2, ::testing::ElementsAre(100, 101, 102));
+  EXPECT_THAT(span3, ::testing::ElementsAre(100, 101, 102));
+}
diff --git a/cc/raster/one_copy_raster_buffer_provider.cc b/cc/raster/one_copy_raster_buffer_provider.cc
index a1c02800..b51df6f7 100644
--- a/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/cc/raster/one_copy_raster_buffer_provider.cc
@@ -44,14 +44,6 @@
 // default batch size for copy operations.
 const int kMaxBytesPerCopyOperation = 1024 * 1024 * 4;
 
-// When enabled, OneCopyRasterBufferProvider::RasterBufferImpl::Playback() runs
-// at normal thread priority.
-// TODO(crbug.com/1072756): Cleanup the feature when the Stable experiment is
-// complete, on November 25, 2020.
-BASE_FEATURE(kOneCopyRasterBufferPlaybackNormalThreadPriority,
-             "OneCopyRasterBufferPlaybackNormalThreadPriority",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kAlwaysUseMappableSIForOneCopyRaster,
              "AlwaysUseMappableSIForOneCopyRaster",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -145,8 +137,7 @@
   // the GpuChannelHost lock, which is acquired at normal thread priority by
   // other code. Acquiring it at background thread priority can cause a priority
   // inversion. https://crbug.com/1072756
-  return !base::FeatureList::IsEnabled(
-      kOneCopyRasterBufferPlaybackNormalThreadPriority);
+  return false;
 }
 
 OneCopyRasterBufferProvider::OneCopyRasterBufferProvider(
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 78e717af..7a5dcb3 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -50,6 +50,7 @@
   import("//chrome/version.gni")
   import("//content/public/app/mac_helpers.gni")
   import("//media/cdm/library_cdm/cdm_paths.gni")
+  import("//services/on_device_model/on_device_model.gni")
   import("//third_party/icu/config.gni")
 }
 
@@ -1033,6 +1034,14 @@
     }
   }
 
+  if (enable_ml_internal) {
+    bundle_data("chrome_ml_library") {
+      sources = [ "$root_out_dir/libchrome_ml.dylib" ]
+      outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
+      public_deps = [ "//third_party/ml:chrome_ml_library_copy" ]
+    }
+  }
+
   group("angle_library") {
     if (bundle_egl_libraries) {
       deps = [ ":angle_binaries" ]
@@ -1253,6 +1262,10 @@
       "//chrome/browser/resources/media/mei_preload:component_bundle",
     ]
 
+    if (enable_ml_internal) {
+      bundle_deps += [ ":chrome_ml_library" ]
+    }
+
     if (is_chrome_branded) {
       bundle_deps += [ ":preinstalled_apps" ]
     }
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
index 6daeb13..4cadc8c 100644
--- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
+++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
@@ -134,6 +134,11 @@
     public void makeCredential(byte[] serializedParams) {
         PublicKeyCredentialCreationOptions params =
                 PublicKeyCredentialCreationOptions.deserialize(ByteBuffer.wrap(serializedParams));
+        // The Chrome hybrid authenticator never supported creation-time
+        // evaluation of PRFs and, by the time we added support in general, we
+        // were already in the process of rolling out the hybrid authenticator
+        // in Play Services and so it continued not to be supported.
+        params.prfInput = null;
 
         if (DeviceFeatureMap.isEnabled(DeviceFeatureList.WEBAUTHN_CABLE_VIA_CREDMAN)) {
             final Fido2CredentialRequest request = new Fido2CredentialRequest(mUi);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java
index a21ddec..34d8ad7 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java
@@ -726,15 +726,18 @@
         }
         mTabJavaView.runOnNextLayoutRunnable();
         if (mNewTabAnimation != null) {
-            if (mNewTabAnimation.isRunning()) {
+            if (mNewTabAnimation.isStarted()) {
                 mNewTabAnimation.end();
             }
+            mNewTabAnimation = null;
         }
         if (mTabToSwitcherAnimation != null) {
-            if (mTabToSwitcherAnimation.isRunning()) {
+            if (mTabToSwitcherAnimation.isStarted()) {
                 mTabToSwitcherAnimation.end();
             }
+            mTabToSwitcherAnimation = null;
         }
+        mTabJavaView.setVisibility(View.GONE);
     }
 
     /**
@@ -924,11 +927,14 @@
         // animation starts otherwise it might jank.
         mAnimationTransitionType = TransitionType.SHRINK;
         mTabJavaView.invalidate();
-        mTabJavaView.setOnNextLayoutRunnable(() -> {
-            mTabJavaView.setVisibility(View.VISIBLE);
-            mAnimationTracker.onStart();
-            mTabToSwitcherAnimation.start();
-        });
+        mTabJavaView.setOnNextLayoutRunnable(
+                () -> {
+                    mTabJavaView.setVisibility(View.VISIBLE);
+                    mAnimationTracker.onStart();
+                    if (mTabToSwitcherAnimation != null) {
+                        mTabToSwitcherAnimation.start();
+                    }
+                });
     }
 
     /**
@@ -992,7 +998,9 @@
                             mTabJavaView.setOnNextLayoutRunnable(
                                     () -> {
                                         mAnimationTracker.onStart();
-                                        mTabToSwitcherAnimation.start();
+                                        if (mTabToSwitcherAnimation != null) {
+                                            mTabToSwitcherAnimation.start();
+                                        }
                                     });
                         });
         // Quick and layout completed don't matter for expand, but set them so the animation will
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 b2fcbe7..2174a6b 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
@@ -517,8 +517,13 @@
         }
 
         // Mediator should be created before any Stream changes.
+        boolean useUiConfig =
+            ntpHeader != null
+                && ChromeFeatureList.sSurfacePolish.isEnabled()
+                && DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity);
         mMediator = new FeedSurfaceMediator(this, mActivity, snapScrollHelper, mSectionHeaderModel,
-                getTabIdFromLaunchOrigin(launchOrigin), actionDelegate, optionsCoordinator);
+            getTabIdFromLaunchOrigin(launchOrigin), actionDelegate, optionsCoordinator,
+            useUiConfig ? mUiConfig : null);
 
         FeedSurfaceTracker.getInstance().trackSurface(this);
 
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
index 425e6fd..ee37bc4b 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
@@ -50,6 +50,9 @@
 import org.chromium.chrome.browser.ui.signin.SyncPromoController;
 import org.chromium.chrome.browser.xsurface.ListLayoutHelper;
 import org.chromium.chrome.browser.xsurface.feed.StreamType;
+import org.chromium.components.browser_ui.widget.displaystyle.DisplayStyleObserver;
+import org.chromium.components.browser_ui.widget.displaystyle.HorizontalDisplayStyle;
+import org.chromium.components.browser_ui.widget.displaystyle.UiConfig;
 import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
 import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
 import org.chromium.components.prefs.PrefService;
@@ -207,6 +210,10 @@
     private final FeedActionDelegate mActionDelegate;
     private final FeedOptionsCoordinator mOptionsCoordinator;
 
+    // It is non-null for NTP on tablets when SurfacePolish is enabled.
+    private @Nullable final UiConfig mUiConfig;
+    private final DisplayStyleObserver mDisplayStyleObserver = this::onDisplayStyleChanged;
+
     private @Nullable RecyclerView.OnScrollListener mStreamScrollListener;
     private final ObserverList<ScrollListener> mScrollListeners = new ObserverList<>();
     private HasContentListener mHasContentListener;
@@ -248,11 +255,12 @@
      * @param headerModel The {@link PropertyModel} that contains this mediator should work with.
      * @param openingTabId The {@link FeedSurfaceCoordinator.StreamTabId} the feed should open to.
      * @param optionsCoordinator The {@link FeedOptionsCoordinator} for the feed.
+     * @param uiConfig The {@link UiConfig} for screen display.
      */
     FeedSurfaceMediator(FeedSurfaceCoordinator coordinator, Context context,
             @Nullable SnapScrollHelper snapScrollHelper, PropertyModel headerModel,
             @FeedSurfaceCoordinator.StreamTabId int openingTabId, FeedActionDelegate actionDelegate,
-            FeedOptionsCoordinator optionsCoordinator) {
+            FeedOptionsCoordinator optionsCoordinator, @Nullable UiConfig uiConfig) {
         mCoordinator = coordinator;
         mHasContentListener = coordinator;
         mContext = context;
@@ -265,6 +273,7 @@
         mOptionsCoordinator.setOptionsListener(this);
         mIsNewTabSearchEngineUrlAndroidEnabled =
                 DseNewTabUrlManager.isNewTabSearchEngineUrlAndroidEnabled();
+        mUiConfig = uiConfig;
 
         /**
          * When feature flag isNewTabSearchEngineUrlAndroidEnabled is enabled, the Feeds may be
@@ -305,6 +314,11 @@
                 -> mRecyclerViewAnimationFinishDetector.runWhenAnimationComplete(
                         this::onContentsChanged);
 
+        if (mUiConfig != null) {
+            mUiConfig.addObserver(mDisplayStyleObserver);
+            onDisplayStyleChanged(mUiConfig.getCurrentDisplayStyle());
+        }
+
         initialize();
     }
 
@@ -371,6 +385,9 @@
         destroyPropertiesForStream();
         mPrefChangeRegistrar.destroy();
         mTemplateUrlService.removeObserver(this);
+        if (mUiConfig != null) {
+            mUiConfig.removeObserver(mDisplayStyleObserver);
+        }
     }
 
     public void destroyForTesting() {
@@ -1294,4 +1311,10 @@
     int getTabToStreamSizeForTesting() {
         return mTabToStreamMap.size();
     }
+
+    private void onDisplayStyleChanged(UiConfig.DisplayStyle newDisplayStyle) {
+        mSectionHeaderModel.set(
+                SectionHeaderListProperties.IS_NARROW_WINDOW_ON_TABLET_KEY,
+                newDisplayStyle.horizontal < HorizontalDisplayStyle.WIDE);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UndoRefocusHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/UndoRefocusHelper.java
index eddc2fd9..f0979b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/UndoRefocusHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/UndoRefocusHelper.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.browser.lifecycle.DestroyObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabSelectionType;
+import org.chromium.chrome.browser.tabmodel.TabList;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
@@ -118,6 +119,10 @@
             public void willCloseAllTabs(boolean incognito) {
                 if (incognito) return;
                 int selectedTabIdx = mModelSelector.getModel(false).index();
+                // Selected tab will be invalid when there are already no tabs in a window when
+                // this method is invoked.
+                if (selectedTabIdx == TabList.INVALID_TAB_INDEX) return;
+
                 Tab selectedTab = mModelSelector.getModel(false).getTabAt(selectedTabIdx);
                 maybeSetSelectedTabId(selectedTab);
                 // Record metric only once for the set.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 1a892f8..d0568f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -228,6 +228,13 @@
         Profile profile = Profile.getLastUsedRegularProfile();
         mIsTablet = isTablet;
 
+        // On first run, the NewTabPageLayout is initialized behind the First Run Experience,
+        // meaning the UiConfig will pickup the screen layout then. However onConfigurationChanged
+        // is not called on orientation changes until the FRE is completed. This means that if a
+        // user starts the FRE in one orientation, changes an orientation and then leaves the FRE
+        // the UiConfig will have the wrong orientation. https://crbug.com/683886.
+        mUiConfig.updateDisplayStyle();
+
         mSearchBoxCoordinator = new SearchBoxCoordinator(getContext(), this);
         mSearchBoxCoordinator.initialize(lifecycleDispatcher, mIsIncognito, mWindowAndroid);
         if (isSurfacePolishEnabled) {
@@ -888,13 +895,6 @@
     protected void onWindowVisibilityChanged(int visibility) {
         super.onWindowVisibilityChanged(visibility);
 
-        // On first run, the NewTabPageLayout is initialized behind the First Run Experience,
-        // meaning the UiConfig will pickup the screen layout then. However onConfigurationChanged
-        // is not called on orientation changes until the FRE is completed. This means that if a
-        // user starts the FRE in one orientation, changes an orientation and then leaves the FRE
-        // the UiConfig will have the wrong orientation. https://crbug.com/683886.
-        mUiConfig.updateDisplayStyle();
-
         if (visibility == VISIBLE) {
             updateActionButtonVisibility();
         }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java
index 7c66890..8640fb27e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java
@@ -6,6 +6,8 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -61,6 +63,11 @@
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.components.browser_ui.widget.displaystyle.DisplayStyleObserver;
+import org.chromium.components.browser_ui.widget.displaystyle.HorizontalDisplayStyle;
+import org.chromium.components.browser_ui.widget.displaystyle.UiConfig;
+import org.chromium.components.browser_ui.widget.displaystyle.UiConfig.DisplayStyle;
+import org.chromium.components.browser_ui.widget.displaystyle.VerticalDisplayStyle;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
@@ -123,8 +130,10 @@
     private FeedOptionsCoordinator mOptionsCoordinator;
     @Mock
     private FeedReliabilityLogger mReliabilityLogger;
+    @Mock private UiConfig mUiConfig;
     @Captor
     private ArgumentCaptor<TemplateUrlServiceObserver> mTemplateUrlServiceObserverCaptor;
+    @Captor private ArgumentCaptor<DisplayStyleObserver> mDisplayStyleObserverCaptor;
 
     private Activity mActivity;
     private FeedSurfaceMediator mFeedSurfaceMediator;
@@ -884,6 +893,48 @@
                 forYou.get(SectionHeaderProperties.OPTIONS_INDICATOR_VISIBILITY_KEY));
     }
 
+    @Test
+    public void testUpdateHeaderWithUiConfigChanged() {
+        // Sets the current display style to be the default wide window.
+        UiConfig.DisplayStyle displayStyleWide =
+                new DisplayStyle(HorizontalDisplayStyle.WIDE, VerticalDisplayStyle.REGULAR);
+        when(mUiConfig.getCurrentDisplayStyle()).thenReturn(displayStyleWide);
+
+        PropertyModel sectionHeaderModel = SectionHeaderListProperties.create(TOOLBAR_HEIGHT);
+        mFeedSurfaceMediator =
+                createMediator(
+                        FeedSurfaceCoordinator.StreamTabId.FOR_YOU, sectionHeaderModel, mUiConfig);
+        verify(mUiConfig).addObserver(mDisplayStyleObserverCaptor.capture());
+        assertFalse(
+                sectionHeaderModel.get(SectionHeaderListProperties.IS_NARROW_WINDOW_ON_TABLET_KEY));
+
+        UiConfig.DisplayStyle displayStyleRegular =
+                new DisplayStyle(HorizontalDisplayStyle.REGULAR, VerticalDisplayStyle.REGULAR);
+        mDisplayStyleObserverCaptor.getValue().onDisplayStyleChanged(displayStyleRegular);
+        assertTrue(
+                sectionHeaderModel.get(SectionHeaderListProperties.IS_NARROW_WINDOW_ON_TABLET_KEY));
+
+        mFeedSurfaceMediator.destroy();
+        verify(mUiConfig).removeObserver(mDisplayStyleObserverCaptor.capture());
+    }
+
+    @Test
+    public void testInitializeHeaderWithCurrentUiConfig() {
+        // Sets the current display style to be a narrow window.
+        UiConfig.DisplayStyle displayStylRegular =
+                new DisplayStyle(HorizontalDisplayStyle.REGULAR, VerticalDisplayStyle.REGULAR);
+        when(mUiConfig.getCurrentDisplayStyle()).thenReturn(displayStylRegular);
+
+        PropertyModel sectionHeaderModel = SectionHeaderListProperties.create(TOOLBAR_HEIGHT);
+        mFeedSurfaceMediator =
+                createMediator(
+                        FeedSurfaceCoordinator.StreamTabId.FOR_YOU, sectionHeaderModel, mUiConfig);
+
+        verify(mUiConfig).addObserver(mDisplayStyleObserverCaptor.capture());
+        assertTrue(
+                sectionHeaderModel.get(SectionHeaderListProperties.IS_NARROW_WINDOW_ON_TABLET_KEY));
+    }
+
     private FeedSurfaceMediator createMediator() {
         return createMediator(FeedSurfaceCoordinator.StreamTabId.FOR_YOU,
                 SectionHeaderListProperties.create(TOOLBAR_HEIGHT));
@@ -891,7 +942,14 @@
 
     private FeedSurfaceMediator createMediator(
             @FeedSurfaceCoordinator.StreamTabId int tabId, PropertyModel sectionHeaderModel) {
+        return createMediator(tabId, sectionHeaderModel, /* uiConfig= */ null);
+    }
+
+    private FeedSurfaceMediator createMediator(
+            @FeedSurfaceCoordinator.StreamTabId int tabId,
+            PropertyModel sectionHeaderModel,
+            UiConfig uiConfig) {
         return new FeedSurfaceMediator(mFeedSurfaceCoordinator, mActivity, null, sectionHeaderModel,
-                tabId, /*actionDelegate=*/null, mOptionsCoordinator);
+                tabId, /*actionDelegate=*/null, mOptionsCoordinator, uiConfig);
     }
 }
diff --git a/chrome/android/modules/readaloud/public/BUILD.gn b/chrome/android/modules/readaloud/public/BUILD.gn
index 77c4821..da0917ac 100644
--- a/chrome/android/modules/readaloud/public/BUILD.gn
+++ b/chrome/android/modules/readaloud/public/BUILD.gn
@@ -6,7 +6,6 @@
 
 android_library("java") {
   sources = [
-    "java/src/org/chromium/chrome/modules/readaloud/ExpandedPlayer.java",
     "java/src/org/chromium/chrome/modules/readaloud/Playback.java",
     "java/src/org/chromium/chrome/modules/readaloud/PlaybackArgs.java",
     "java/src/org/chromium/chrome/modules/readaloud/PlaybackListener.java",
diff --git a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/ExpandedPlayer.java b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/ExpandedPlayer.java
deleted file mode 100644
index 32d5da9..0000000
--- a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/ExpandedPlayer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.modules.readaloud;
-
-import org.chromium.chrome.browser.readaloud.PlayerState;
-
-/** Interface for controlling the Read Aloud expanded player. */
-public interface ExpandedPlayer {
-    /** Interface for getting updates about the expanded player. */
-    public interface Observer {
-        /** Called when the user has tapped the close button. */
-        void onCloseClicked();
-    }
-
-    /**
-     * Add an observer.
-     * @param observer Observer to add.
-     */
-    default void addObserver(Observer observer) {}
-
-    /**
-     * Remove an observer. Has no effect if `observer` wasn't previously added.
-     * @param observer Observer to remove.
-     */
-    default void removeObserver(Observer observer) {}
-
-    /**
-     * Show the expanded player.
-     *
-     * If current state is GONE or HIDING, switch to SHOWING. No effect if state is
-     * VISIBLE or SHOWING.
-     * @param playback Current playback object. Should not be null.
-     */
-    default void show(Playback playback) {}
-
-    /**
-     * Dismiss the expanded player.
-     *
-     * If current state is SHOWING or VISIBLE, switch to HIDING. No effect if state
-     * is GONE or HIDING.
-     */
-    default void dismiss() {}
-
-    /** Returns the expanded player state. */
-    default @PlayerState int getState() {
-        return PlayerState.GONE;
-    }
-}
diff --git a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/ReadAloudPlaybackHooks.java b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/ReadAloudPlaybackHooks.java
index 65c033b0..c5a8404 100644
--- a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/ReadAloudPlaybackHooks.java
+++ b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/ReadAloudPlaybackHooks.java
@@ -7,7 +7,6 @@
 import android.view.ViewStub;
 
 import org.chromium.chrome.modules.readaloud.contentjs.Highlighter;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 
 /** Interface for creating ReadAloud playback. */
 public interface ReadAloudPlaybackHooks {
@@ -42,15 +41,6 @@
     default void createPlayback(PlaybackArgs playbackArgs, CreatePlaybackCallback callback) {}
 
     /**
-     * Create the expanded player UI component.
-     * @param bottomSheetController BottomSheetController for showing the expanded player sheet.
-     * @return a new ExpandedPlayer.
-     */
-    default ExpandedPlayer createExpandedPlayer(BottomSheetController bottomSheetController) {
-        return new ExpandedPlayer() {};
-    }
-
-    /**
      * Create the player UI.
      * @param miniPlayerViewStub View stub that can create the mini player UI.
      * @param delegate Delegate providing the UI with outside dependencies.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 96bdd09..8ef60a1 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8833,6 +8833,9 @@
       <message name="IDS_TAB_ORGANIZE" desc="The text label of the Tab Organization button." translateable="false">
         Organize tabs?
       </message>
+      <message name="IDS_TOOLTIP_TAB_ORGANIZE_CLOSE" desc="The tooltip for the close button within the Tab Organization button." translateable="false">
+        Close
+      </message>
 
       <!-- Strings for intent picker -->
       <if expr="not is_android">
@@ -8858,14 +8861,15 @@
           Open in app
         </message>
 
+        <message name="IDR_INTENT_PICKER_SUPPORTED_LINKS_INFOBAR_MESSAGE" desc="The text of an infobar asking if the user wants to open web links supported by a particular app (e.g. https://www.youtube.com) in that app.">
+          Always use the <ph name="APP">$1<ex>YouTube</ex></ph> app to open supported web links?
+        </message>
+        <message name="IDR_INTENT_PICKER_SUPPORTED_LINKS_INFOBAR_OK_LABEL" desc="The label of a confirm button for an infobar asking if the user wants to open web links in an app. If clicked, the selected app will always be opened when clicking supported web links.">
+          Always use
+        </message>
+
         <if expr="is_chromeos">
           <then>
-            <message name="IDR_INTENT_PICKER_SUPPORTED_LINKS_INFOBAR_MESSAGE" desc="The text of an infobar asking if the user wants to open web links supported by a particular app (e.g. https://www.youtube.com) in that app.">
-              Always use the <ph name="APP">$1<ex>YouTube</ex></ph> app to open supported web links?
-            </message>
-            <message name="IDR_INTENT_PICKER_SUPPORTED_LINKS_INFOBAR_OK_LABEL" desc="The label of a confirm button for an infobar asking if the user wants to open web links in an app. If clicked, the selected app will always be opened when clicking supported web links.">
-              Always use
-            </message>
             <message name="IDS_INTENT_PICKER_SELECT_AN_APP_SUBTITLE" desc="The subtitle of a dialog containing a list of installed applications. The dialog allows the user to select an app to open a web link.">
               Select an app on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> to open this link
             </message>
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 1f8995f..3fd0879a 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -3337,107 +3337,106 @@
   <message name="IDS_SETTINGS_SIX_PACK_KEY_OPTION_DISABLED" desc="In the keyboard settings subpage, the dropdown list item for the disabled option.">
     Disabled
   </message>
-    <!-- TODO(b/298073742): Finalize and translate these strings -->
-  <message name="IDS_SETTINGS_F11_KEY_LABEL" translateable="false" desc="In the keyboard settings subpage, the label for the F11 row.">
+  <message name="IDS_SETTINGS_F11_KEY_LABEL" desc="In the keyboard settings subpage, the label for the F11 row.">
     F11
   </message>
-  <message name="IDS_SETTINGS_F12_KEY_LABEL" translateable="false" desc="In the keyboard settings subpage, the label for the F12 row.">
+  <message name="IDS_SETTINGS_F12_KEY_LABEL" desc="In the keyboard settings subpage, the label for the F12 row.">
     F12
   </message>
-  <message name="IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_SEARCH" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_SEARCH" desc="">
     search + shift + <ph name="TOP_ROW_KEY">$1<ex>back</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_LAUNCHER" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_LAUNCHER" desc="">
     launcher + shift + <ph name="TOP_ROW_KEY">$1<ex>refresh</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_SEARCH" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_SEARCH" desc="">
     search + alt + <ph name="TOP_ROW_KEY">$1<ex>back</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_LAUNCHER" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_LAUNCHER" desc="">
     launcher + alt + <ph name="TOP_ROW_KEY">$1<ex>refresh</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_SEARCH" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_SEARCH" desc="">
     search + ctrl + shift + <ph name="TOP_ROW_KEY">$1<ex>back</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_LAUNCHER" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_LAUNCHER" desc="">
     launcher + ctrl + shift + <ph name="TOP_ROW_KEY">$1<ex>refresh</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION" desc="">
     shift + <ph name="TOP_ROW_KEY">$1<ex>back</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION" desc="">
     alt + <ph name="TOP_ROW_KEY">$1<ex>back</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION" translateable="false" desc="">
+  <message name="IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION" desc="">
     ctrl + shift + <ph name="TOP_ROW_KEY">$1<ex>refresh</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_BACK" translateable="false" desc="Describes the Back key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_BACK" desc="Describes the Back key on the top row of a ChromeOS keyboard.">
     back
   </message>
-  <message name="IDS_SETTINGS_FORWARD" translateable="false" desc="Describes the Forward key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_FORWARD" desc="Describes the Forward key on the top row of a ChromeOS keyboard.">
     forward
   </message>
-  <message name="IDS_SETTINGS_FULLSCREEN" translateable="false" desc="Describes the Fullscreen key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_FULLSCREEN" desc="Describes the Fullscreen key on the top row of a ChromeOS keyboard.">
     fullscreen
   </message>
-  <message name="IDS_SETTINGS_KEYBOARD_BACKLIGHT_DOWN" translateable="false" desc="Describes the key for decreasing keyboard backlight brightness on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_KEYBOARD_BACKLIGHT_DOWN" desc="Describes the key for decreasing keyboard backlight brightness on the top row of a ChromeOS keyboard.">
     keyboard brightness down
   </message>
-  <message name="IDS_SETTINGS_KEYBOARD_BACKLIGHT_TOGGLE" translateable="false" desc="Describes the key for toggling the keyboard backlight on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_KEYBOARD_BACKLIGHT_TOGGLE" desc="Describes the key for toggling the keyboard backlight on the top row of a ChromeOS keyboard.">
     keyboard backlight toggle
   </message>
-  <message name="IDS_SETTINGS_KEYBOARD_BACKLIGHT_UP" translateable="false" desc="Describes the key for increasing keyboard backlight brightness on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_KEYBOARD_BACKLIGHT_UP" desc="Describes the key for increasing keyboard backlight brightness on the top row of a ChromeOS keyboard.">
     keyboard brightness up
   </message>
-  <message name="IDS_SETTINGS_MICROPHONE_MUTE" translateable="false" desc="Describes the key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_MICROPHONE_MUTE" desc="Describes the key on the top row of a ChromeOS keyboard.">
     microphone mute
   </message>
-  <message name="IDS_SETTINGS_MUTE" translateable="false" desc="Describes the Mute key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_MUTE" desc="Describes the Mute key on the top row of a ChromeOS keyboard.">
     mute
   </message>
-  <message name="IDS_SETTINGS_OVERVIEW" translateable="false" desc="Describes the Overview key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_OVERVIEW" desc="Describes the Overview key on the top row of a ChromeOS keyboard.">
     overview
   </message>
-  <message name="IDS_SETTINGS_PLAY_PAUSE" translateable="false" desc="Describes the play/pause key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_PLAY_PAUSE" desc="Describes the play/pause key on the top row of a ChromeOS keyboard.">
     play/pause
   </message>
-  <message name="IDS_SETTINGS_PRIVACY_SCREEN_TOGGLE" translateable="false" desc="Describes the key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_PRIVACY_SCREEN_TOGGLE" desc="Describes the key on the top row of a ChromeOS keyboard.">
     privacy screen toggle
   </message>
-  <message name="IDS_SETTINGS_REFRESH" translateable="false" desc="Describes the Refresh key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_REFRESH" desc="Describes the Refresh key on the top row of a ChromeOS keyboard.">
     refresh
   </message>
-  <message name="IDS_SETTINGS_SCREENSHOT" translateable="false" desc="Describes the Screenshot key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_SCREENSHOT" desc="Describes the Screenshot key on the top row of a ChromeOS keyboard.">
     screenshot
   </message>
-  <message name="IDS_SETTINGS_SCREEN_BRIGHTNESS_DOWN" translateable="false" desc="Describes the key for decreasing display brightness on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_SCREEN_BRIGHTNESS_DOWN" desc="Describes the key for decreasing display brightness on the top row of a ChromeOS keyboard.">
     display brightness down
   </message>
-  <message name="IDS_SETTINGS_SCREEN_BRIGHTNESS_UP" translateable="false" desc="Describes the key for increasing display brightness on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_SCREEN_BRIGHTNESS_UP" desc="Describes the key for increasing display brightness on the top row of a ChromeOS keyboard.">
     display brightness up
   </message>
-  <message name="IDS_SETTINGS_SCREEN_MIRROR" translateable="false" desc="Describes the key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_SCREEN_MIRROR" desc="Describes the key on the top row of a ChromeOS keyboard.">
     screen mirror
   </message>
-  <message name="IDS_SETTINGS_TRACK_NEXT" translateable="false" desc="Describes the next track key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_TRACK_NEXT" desc="Describes the next track key on the top row of a ChromeOS keyboard.">
     next track
   </message>
-  <message name="IDS_SETTINGS_TRACK_PREVIOUS" translateable="false" desc="Describes the previous track key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_TRACK_PREVIOUS" desc="Describes the previous track key on the top row of a ChromeOS keyboard.">
     previous track
   </message>
-  <message name="IDS_SETTINGS_VOLUME_DOWN" translateable="false" desc="Describes the volume down key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_VOLUME_DOWN" desc="Describes the volume down key on the top row of a ChromeOS keyboard.">
     volume down
   </message>
-  <message name="IDS_SETTINGS_VOLUME_UP" translateable="false" desc="Describes the volume up key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_VOLUME_UP" desc="Describes the volume up key on the top row of a ChromeOS keyboard.">
     volume up
   </message>
-  <message name="IDS_SETTINGS_ALL_APPLICATIONS" translateable="false" desc="Describes the all applications key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_ALL_APPLICATIONS" desc="Describes the all applications key on the top row of a ChromeOS keyboard.">
     all applications
   </message>
-  <message name="IDS_SETTINGS_EMOJI_PICKER" translateable="false" desc="Describes the emoji picker key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_EMOJI_PICKER" desc="Describes the emoji picker key on the top row of a ChromeOS keyboard.">
     emoji pciker
   </message>
-  <message name="IDS_SETTINGS_DICTATION" translateable="false" desc="Describes the dictation key on the top row of a ChromeOS keyboard.">
+  <message name="IDS_SETTINGS_DICTATION" desc="Describes the dictation key on the top row of a ChromeOS keyboard.">
     dictation
   </message>
 
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ALL_APPLICATIONS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ALL_APPLICATIONS.png.sha1
new file mode 100644
index 0000000..542fe874
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ALL_APPLICATIONS.png.sha1
@@ -0,0 +1 @@
+097979eb320b1dcf265a5e00117594059063671f
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_BACK.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_BACK.png.sha1
new file mode 100644
index 0000000..0c5ec83e
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_BACK.png.sha1
@@ -0,0 +1 @@
+87824e3eafa18f5f30a0d970f00b8849bad292ad
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DICTATION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DICTATION.png.sha1
new file mode 100644
index 0000000..94808a3
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DICTATION.png.sha1
@@ -0,0 +1 @@
+da203b3b111d416282fc59214e16a9ac224b697c
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_EMOJI_PICKER.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_EMOJI_PICKER.png.sha1
new file mode 100644
index 0000000..94808a3
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_EMOJI_PICKER.png.sha1
@@ -0,0 +1 @@
+da203b3b111d416282fc59214e16a9ac224b697c
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F11_KEY_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F11_KEY_LABEL.png.sha1
new file mode 100644
index 0000000..3f3c727
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F11_KEY_LABEL.png.sha1
@@ -0,0 +1 @@
+fb525fd5535d899ff2f5e7f8e679834f4a0800bc
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F12_KEY_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F12_KEY_LABEL.png.sha1
new file mode 100644
index 0000000..3f3c727
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F12_KEY_LABEL.png.sha1
@@ -0,0 +1 @@
+fb525fd5535d899ff2f5e7f8e679834f4a0800bc
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_FORWARD.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_FORWARD.png.sha1
new file mode 100644
index 0000000..2a5d4da
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_FORWARD.png.sha1
@@ -0,0 +1 @@
+2db89814d1c16225c6d637e6796c78deece1407d
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_FULLSCREEN.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_FULLSCREEN.png.sha1
new file mode 100644
index 0000000..fba682f
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_FULLSCREEN.png.sha1
@@ -0,0 +1 @@
+ab2baf6976c1fabc59e3e571a1bce9c22088ed19
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION.png.sha1
new file mode 100644
index 0000000..0c5ec83e
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION.png.sha1
@@ -0,0 +1 @@
+87824e3eafa18f5f30a0d970f00b8849bad292ad
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_LAUNCHER.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_LAUNCHER.png.sha1
new file mode 100644
index 0000000..c42b0ce5
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_LAUNCHER.png.sha1
@@ -0,0 +1 @@
+b85f696bd5b48449518984d969790b27f60aa9a6
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_SEARCH.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_SEARCH.png.sha1
new file mode 100644
index 0000000..3f3c727
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_ALT_DROPDOWN_OPTION_SEARCH.png.sha1
@@ -0,0 +1 @@
+fb525fd5535d899ff2f5e7f8e679834f4a0800bc
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN.png.sha1
new file mode 100644
index 0000000..0c5ec83e
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN.png.sha1
@@ -0,0 +1 @@
+87824e3eafa18f5f30a0d970f00b8849bad292ad
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION.png.sha1
new file mode 100644
index 0000000..94808a3
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION.png.sha1
@@ -0,0 +1 @@
+da203b3b111d416282fc59214e16a9ac224b697c
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_LAUNCHER.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_LAUNCHER.png.sha1
new file mode 100644
index 0000000..c42b0ce5
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_LAUNCHER.png.sha1
@@ -0,0 +1 @@
+b85f696bd5b48449518984d969790b27f60aa9a6
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_SEARCH.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_SEARCH.png.sha1
new file mode 100644
index 0000000..3f3c727
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_CTRL_SHIFT_DROPDOWN_OPTION_SEARCH.png.sha1
@@ -0,0 +1 @@
+fb525fd5535d899ff2f5e7f8e679834f4a0800bc
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION.png.sha1
new file mode 100644
index 0000000..0c5ec83e
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION.png.sha1
@@ -0,0 +1 @@
+87824e3eafa18f5f30a0d970f00b8849bad292ad
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_LAUNCHER.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_LAUNCHER.png.sha1
new file mode 100644
index 0000000..c42b0ce5
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_LAUNCHER.png.sha1
@@ -0,0 +1 @@
+b85f696bd5b48449518984d969790b27f60aa9a6
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_SEARCH.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_SEARCH.png.sha1
new file mode 100644
index 0000000..3f3c727
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_F_KEY_SHIFT_DROPDOWN_OPTION_SEARCH.png.sha1
@@ -0,0 +1 @@
+fb525fd5535d899ff2f5e7f8e679834f4a0800bc
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_DOWN.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_DOWN.png.sha1
new file mode 100644
index 0000000..fba682f
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_DOWN.png.sha1
@@ -0,0 +1 @@
+ab2baf6976c1fabc59e3e571a1bce9c22088ed19
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_TOGGLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_TOGGLE.png.sha1
new file mode 100644
index 0000000..1cdd242
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_TOGGLE.png.sha1
@@ -0,0 +1 @@
+3772a86a1f6f27487c1f7c981ccc4758755d2dab
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_UP.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_UP.png.sha1
new file mode 100644
index 0000000..fba682f
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_KEYBOARD_BACKLIGHT_UP.png.sha1
@@ -0,0 +1 @@
+ab2baf6976c1fabc59e3e571a1bce9c22088ed19
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MICROPHONE_MUTE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MICROPHONE_MUTE.png.sha1
new file mode 100644
index 0000000..b206de5
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MICROPHONE_MUTE.png.sha1
@@ -0,0 +1 @@
+44d97d859695462ba93a72e96f812ca76132ab1c
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MUTE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MUTE.png.sha1
new file mode 100644
index 0000000..b206de5
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MUTE.png.sha1
@@ -0,0 +1 @@
+44d97d859695462ba93a72e96f812ca76132ab1c
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_OVERVIEW.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_OVERVIEW.png.sha1
new file mode 100644
index 0000000..b206de5
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_OVERVIEW.png.sha1
@@ -0,0 +1 @@
+44d97d859695462ba93a72e96f812ca76132ab1c
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PLAY_PAUSE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PLAY_PAUSE.png.sha1
new file mode 100644
index 0000000..8b49c801
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PLAY_PAUSE.png.sha1
@@ -0,0 +1 @@
+b687f7b383b7a3e0a18ff3e8641bdef4e4154c29
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRIVACY_SCREEN_TOGGLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRIVACY_SCREEN_TOGGLE.png.sha1
new file mode 100644
index 0000000..8b49c801
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRIVACY_SCREEN_TOGGLE.png.sha1
@@ -0,0 +1 @@
+b687f7b383b7a3e0a18ff3e8641bdef4e4154c29
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_REFRESH.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_REFRESH.png.sha1
new file mode 100644
index 0000000..8b49c801
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_REFRESH.png.sha1
@@ -0,0 +1 @@
+b687f7b383b7a3e0a18ff3e8641bdef4e4154c29
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREENSHOT.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREENSHOT.png.sha1
new file mode 100644
index 0000000..1b306e0
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREENSHOT.png.sha1
@@ -0,0 +1 @@
+0775d5ca2b263f8960df7cd14b01bf3f5403a5ae
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_BRIGHTNESS_DOWN.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_BRIGHTNESS_DOWN.png.sha1
new file mode 100644
index 0000000..1b306e0
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_BRIGHTNESS_DOWN.png.sha1
@@ -0,0 +1 @@
+0775d5ca2b263f8960df7cd14b01bf3f5403a5ae
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_BRIGHTNESS_UP.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_BRIGHTNESS_UP.png.sha1
new file mode 100644
index 0000000..1b306e0
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_BRIGHTNESS_UP.png.sha1
@@ -0,0 +1 @@
+0775d5ca2b263f8960df7cd14b01bf3f5403a5ae
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_MIRROR.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_MIRROR.png.sha1
new file mode 100644
index 0000000..c0a6fe7
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SCREEN_MIRROR.png.sha1
@@ -0,0 +1 @@
+b0ec8c1192cc444c9f443004617a63b1c96dc930
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_TRACK_NEXT.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_TRACK_NEXT.png.sha1
new file mode 100644
index 0000000..c0a6fe7
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_TRACK_NEXT.png.sha1
@@ -0,0 +1 @@
+b0ec8c1192cc444c9f443004617a63b1c96dc930
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_TRACK_PREVIOUS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_TRACK_PREVIOUS.png.sha1
new file mode 100644
index 0000000..c0a6fe7
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_TRACK_PREVIOUS.png.sha1
@@ -0,0 +1 @@
+b0ec8c1192cc444c9f443004617a63b1c96dc930
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_VOLUME_DOWN.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_VOLUME_DOWN.png.sha1
new file mode 100644
index 0000000..542fe874
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_VOLUME_DOWN.png.sha1
@@ -0,0 +1 @@
+097979eb320b1dcf265a5e00117594059063671f
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_VOLUME_UP.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_VOLUME_UP.png.sha1
new file mode 100644
index 0000000..542fe874
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_VOLUME_UP.png.sha1
@@ -0,0 +1 @@
+097979eb320b1dcf265a5e00117594059063671f
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 5854637..fbb8ae0 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3255,7 +3255,10 @@
     Most sites should work as expected
   </message>
   <message name="IDS_SETTINGS_TRACKING_PROTECTION_BULLET_TWO_DESCRIPTION" desc="Description of the second bullet for Tracking Protection settings. Explains that you can temporarilty allow a site to use third-party cookies if it isn't working. Contains a learn more link to a help center article.">
-    If a site isn’t working, you can try giving it temporary permission to use third-party cookies. <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>
+    If a site isn’t working, you can try giving it temporary permission to use third-party cookies. <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1" aria-label="$2"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>
+  </message>
+  <message name="IDS_SETTINGS_TRACKING_PROTECTION_BULLET_TWO_LEARN_MORE_ARIA_LABEL" desc="Screenreader text for the 'Learn more' link in the second bullet of Tracking Protection settings.">
+    Learn more about giving a site temporary permission to use third-party cookies
   </message>
   <message name="IDS_SETTINGS_TRACKING_PROTECTION_ADVANCED_LABEL" desc="Label for a section on the Tracking Protection settings page containing advanced options.">
     Advanced
@@ -3266,6 +3269,9 @@
   <message name="IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_TOGGLE_SUB_LABEL" desc="Sub-label for the third-party cookie blocking toggle. Explains that features on some sites may not work when the toggle is on and third-party cookies are blocked.">
     Features on some sites may not work.
   </message>
+  <message name="IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_LEARN_MORE_ARIA_LABEL" desc="Screenreader text for the 'Learn more' link in the sub-label of the third-party cookie blocking toggle.">
+    Learn more about sites that may not work when blocking third-party cookies
+  </message>
   <message name="IDS_SETTINGS_TRACKING_PROTECTION_DO_NOT_TRACK_TOGGLE_SUB_LABEL" desc="Sub-label for the Do Not Track toggle. Explains that sites may not respond to 'do not track' requests even when this toggle is on.">
     Sites use their discretion when responding to this request
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_TRACKING_PROTECTION_BULLET_TWO_LEARN_MORE_ARIA_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_TRACKING_PROTECTION_BULLET_TWO_LEARN_MORE_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..520a1d8
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_TRACKING_PROTECTION_BULLET_TWO_LEARN_MORE_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+9e5e5e521a66ec94c0f6bb68259aac3f503fb834
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_LEARN_MORE_ARIA_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_LEARN_MORE_ARIA_LABEL.png.sha1
new file mode 100644
index 0000000..ccbbfa4
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_LEARN_MORE_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@
+9dab175dc27fe100084726cb93ae9dc7124e11e1
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7c1b7254e..f8c84f37 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1834,8 +1834,10 @@
     "tpcd/metadata/updater_service.h",
     "tpcd/metadata/updater_service_factory.cc",
     "tpcd/metadata/updater_service_factory.h",
-    "tpcd/support/tpcd_support_manager.cc",
-    "tpcd/support/tpcd_support_manager.h",
+    "tpcd/support/tpcd_support_service.cc",
+    "tpcd/support/tpcd_support_service.h",
+    "tpcd/support/tpcd_support_service_factory.cc",
+    "tpcd/support/tpcd_support_service_factory.h",
     "tracing/background_tracing_field_trial.cc",
     "tracing/background_tracing_field_trial.h",
     "tracing/chrome_background_tracing_metrics_provider.cc",
@@ -2161,9 +2163,11 @@
     "//components/certificate_transparency:proto",
     "//components/client_hints/browser",
     "//components/cloud_devices/common",
+    "//components/color",
     "//components/commerce/content/browser:browser",
     "//components/commerce/core:commerce_heuristics_data",
     "//components/commerce/core:commerce_subscription_db_content_proto",
+    "//components/commerce/core:country_code_checker",
     "//components/commerce/core:feature_list",
     "//components/commerce/core:parcel_tracking_db_content_proto",
     "//components/commerce/core:persisted_state_db_content_proto",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index f2b321d..1e50bfa 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -91,6 +91,7 @@
   "+components/client_hints/browser",
   "+components/client_hints/common",
   "+components/cloud_devices/common",
+  "+components/color",
   "+components/commerce",
   "+components/component_updater",
   "+components/component_updater/installer_policies",
@@ -291,6 +292,7 @@
   "+components/safe_browsing/core/browser",
   "+components/safe_browsing/core/common",
   "+components/tpcd/metadata",
+  "+components/tpcd/support",
   "+components/safe_search_api",
   "+components/saved_tab_groups",
   "+components/schema_org",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e8971d1..d906384 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -82,7 +82,6 @@
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browsing_data/core/features.h"
 #include "components/commerce/core/commerce_feature_list.h"
-#include "components/commerce/core/commerce_utils.h"
 #include "components/commerce/core/flag_descriptions.h"
 #include "components/component_updater/component_updater_command_line_config_policy.h"
 #include "components/component_updater/component_updater_switches.h"
@@ -149,6 +148,7 @@
 #include "components/segmentation_platform/public/features.h"
 #include "components/send_tab_to_self/features.h"
 #include "components/services/heap_profiling/public/cpp/switches.h"
+#include "components/services/storage/public/cpp/buckets/bucket_info.h"
 #include "components/shared_highlighting/core/common/shared_highlighting_features.h"
 #include "components/signin/core/browser/dice_account_reconcilor_delegate.h"
 #include "components/signin/public/base/signin_buildflags.h"
@@ -2824,6 +2824,29 @@
          kPhotoPickerAdoptionStudyChromePickerWithoutBrowse,
          std::size(kPhotoPickerAdoptionStudyChromePickerWithoutBrowse),
          nullptr}};
+
+const FeatureEntry::FeatureParam kAuxiliarySearchDonation_MaxDonation_20[] = {
+    {chrome::android::kAuxiliarySearchMaxBookmarksCountParam.name, "20"},
+    {chrome::android::kAuxiliarySearchMaxTabsCountParam.name, "20"}};
+const FeatureEntry::FeatureParam kAuxiliarySearchDonation_MaxDonation_100[] = {
+    {chrome::android::kAuxiliarySearchMaxBookmarksCountParam.name, "100"},
+    {chrome::android::kAuxiliarySearchMaxTabsCountParam.name, "100"}};
+const FeatureEntry::FeatureParam kAuxiliarySearchDonation_MaxDonation_200[] = {
+    {chrome::android::kAuxiliarySearchMaxBookmarksCountParam.name, "200"},
+    {chrome::android::kAuxiliarySearchMaxTabsCountParam.name, "200"}};
+const FeatureEntry::FeatureParam kAuxiliarySearchDonation_MaxDonation_500[] = {
+    {chrome::android::kAuxiliarySearchMaxBookmarksCountParam.name, "500"},
+    {chrome::android::kAuxiliarySearchMaxTabsCountParam.name, "500"}};
+const FeatureEntry::FeatureVariation kAuxiliarySearchDonationVariations[] = {
+    {"50 counts", kAuxiliarySearchDonation_MaxDonation_20,
+     std::size(kAuxiliarySearchDonation_MaxDonation_20), nullptr},
+    {"100 counts", kAuxiliarySearchDonation_MaxDonation_100,
+     std::size(kAuxiliarySearchDonation_MaxDonation_100), nullptr},
+    {"200 counts", kAuxiliarySearchDonation_MaxDonation_200,
+     std::size(kAuxiliarySearchDonation_MaxDonation_200), nullptr},
+    {"500 counts", kAuxiliarySearchDonation_MaxDonation_500,
+     std::size(kAuxiliarySearchDonation_MaxDonation_500), nullptr},
+};
 #endif  // BUILDFLAG(IS_ANDROID)
 
 // TODO(crbug.com/991082,1015377): Remove after proper support for back/forward
@@ -4763,6 +4786,10 @@
          "1",
          autofill::switches::kWalletServiceUseSandbox,
          "0")},
+    {"web-authentication-filter-google-passkeys",
+     flag_descriptions::kWebAuthnFilterGooglePasskeysName,
+     flag_descriptions::kWebAuthnFilterGooglePasskeysDescription, kOsAll,
+     FEATURE_VALUE_TYPE(device::kWebAuthnFilterGooglePasskeys)},
     {"enable-web-bluetooth", flag_descriptions::kWebBluetoothName,
      flag_descriptions::kWebBluetoothDescription, kOsLinux,
      FEATURE_VALUE_TYPE(features::kWebBluetooth)},
@@ -6111,6 +6138,13 @@
      flag_descriptions::kAndroidAppIntegrationSafeSearchName,
      flag_descriptions::kAndroidAppIntegrationSafeSearchDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kAndroidAppIntegrationSafeSearch)},
+
+    {"auxiliary-search-donation",
+     flag_descriptions::kAuxiliarySearchDonationName,
+     flag_descriptions::kAuxiliarySearchDonationDescription, kOsAndroid,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kAuxiliarySearchDonation,
+                                    kAuxiliarySearchDonationVariations,
+                                    "AuxiliarySearchDonation")},
 #endif  // BUILDFLAG(IS_ANDROID)
 
     {"omnibox-local-history-zero-suggest-beyond-ntp",
@@ -6951,6 +6985,11 @@
      flag_descriptions::kNtpDesktopLensDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(ntp_features::kNtpRealboxLensSearch)},
 
+    {"ntp-tab-resumption-module",
+     flag_descriptions::kNtpTabResumptionModuleName,
+     flag_descriptions::kNtpTabResumptionModuleDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(ntp_features::kNtpTabResumptionModule)},
+
     {"price-insights", commerce::flag_descriptions::kPriceInsightsName,
      commerce::flag_descriptions::kPriceInsightsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(commerce::kPriceInsights)},
@@ -7485,18 +7524,6 @@
          kResamplingScrollEventsExperimentalPredictionVariations,
          "ResamplingScrollEventsExperimentalLatency")},
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    {"enable-vaapi-jpeg-image-decode-acceleration",
-     flag_descriptions::kVaapiJpegImageDecodeAccelerationName,
-     flag_descriptions::kVaapiJpegImageDecodeAccelerationDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kVaapiJpegImageDecodeAcceleration)},
-
-    {"enable-vaapi-webp-image-decode-acceleration",
-     flag_descriptions::kVaapiWebPImageDecodeAccelerationName,
-     flag_descriptions::kVaapiWebPImageDecodeAccelerationDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kVaapiWebPImageDecodeAcceleration)},
-#endif
-
 #if BUILDFLAG(IS_WIN)
     {"calculate-native-win-occlusion",
      flag_descriptions::kCalculateNativeWinOcclusionName,
@@ -11014,6 +11041,11 @@
      flag_descriptions::kIndexedDBCompressValuesWithSnappyDescription, kOsAll,
      FEATURE_VALUE_TYPE(blink::features::kIndexedDBCompressValuesWithSnappy)},
 
+    {"indexed-db-default-durability-relaxed",
+     flag_descriptions::kIndexedDBDefaultDurabilityRelaxed,
+     flag_descriptions::kIndexedDBDefaultDurabilityRelaxed, kOsAll,
+     FEATURE_VALUE_TYPE(storage::kDefaultBucketUsesRelaxedDurability)},
+
     {"autofill-enable-server-iban",
      flag_descriptions::kAutofillEnableServerIbanName,
      flag_descriptions::kAutofillEnableServerIbanDescription, kOsDesktop,
diff --git a/chrome/browser/android/auxiliary_search/auxiliary_search_provider.cc b/chrome/browser/android/auxiliary_search/auxiliary_search_provider.cc
index c4c2d24..fe48d56 100644
--- a/chrome/browser/android/auxiliary_search/auxiliary_search_provider.cc
+++ b/chrome/browser/android/auxiliary_search/auxiliary_search_provider.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/android/persisted_tab_data/sensitivity_persisted_tab_data_android.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
@@ -29,9 +30,6 @@
 
 namespace {
 
-const size_t kMaxBookmarksCount = 100u;
-const size_t kMaxTabsCount = 100u;
-
 using BackToJavaCallback =
     base::OnceCallback<void(std::unique_ptr<std::vector<TabAndroid*>>)>;
 
@@ -84,6 +82,7 @@
 void FilterNonSensitiveSearchableTabs(
     std::unique_ptr<std::vector<TabAndroid*>> all_tabs,
     int current_tab_index,
+    size_t max_tab_count,
     std::unique_ptr<std::vector<TabAndroid*>> non_sensitive_tabs,
     BackToJavaCallback callback,
     PersistedTabDataAndroid* persisted_tab_data) {
@@ -96,7 +95,7 @@
   }
   int next_tab_index = current_tab_index - 1;
 
-  if (next_tab_index < 0 || kMaxTabsCount <= non_sensitive_tabs->size()) {
+  if (next_tab_index < 0 || max_tab_count <= non_sensitive_tabs->size()) {
     std::move(callback).Run(std::move(non_sensitive_tabs));
     return;
   }
@@ -105,14 +104,19 @@
   SensitivityPersistedTabDataAndroid::From(
       next_tab,
       base::BindOnce(&FilterNonSensitiveSearchableTabs, std::move(all_tabs),
-                     next_tab_index, std::move(non_sensitive_tabs),
-                     std::move(callback)));
+                     next_tab_index, max_tab_count,
+                     std::move(non_sensitive_tabs), std::move(callback)));
 }
 
 }  // namespace
 
 AuxiliarySearchProvider::AuxiliarySearchProvider(Profile* profile)
-    : profile_(profile) {}
+    : profile_(profile) {
+  max_bookmark_donation_count_ =
+      chrome::android::kAuxiliarySearchMaxBookmarksCountParam.Get();
+  max_tab_donation_count_ =
+      chrome::android::kAuxiliarySearchMaxTabsCountParam.Get();
+}
 
 AuxiliarySearchProvider::~AuxiliarySearchProvider() = default;
 
@@ -162,7 +166,8 @@
 AuxiliarySearchProvider::GetBookmarks(bookmarks::BookmarkModel* model) const {
   auxiliary_search::AuxiliarySearchBookmarkGroup group;
   std::vector<const BookmarkNode*> nodes;
-  bookmarks::GetMostRecentlyUsedEntries(model, kMaxBookmarksCount, &nodes);
+  bookmarks::GetMostRecentlyUsedEntries(model, max_bookmark_donation_count_,
+                                        &nodes);
   for (const BookmarkNode* node : nodes) {
     GURL url = node->url();
     if (!IsSchemeAllowed(url)) {
@@ -211,8 +216,8 @@
       next_tab,
       base::BindOnce(&FilterNonSensitiveSearchableTabs,
                      std::make_unique<std::vector<TabAndroid*>>(filtered_tabs),
-                     filtered_tabs.size() - 1, std::move(non_sensitive_tabs),
-                     std::move(callback)));
+                     filtered_tabs.size() - 1, max_tab_donation_count_,
+                     std::move(non_sensitive_tabs), std::move(callback)));
 }
 
 // static
diff --git a/chrome/browser/android/auxiliary_search/auxiliary_search_provider.h b/chrome/browser/android/auxiliary_search/auxiliary_search_provider.h
index 2b0063c..4749898d 100644
--- a/chrome/browser/android/auxiliary_search/auxiliary_search_provider.h
+++ b/chrome/browser/android/auxiliary_search/auxiliary_search_provider.h
@@ -48,12 +48,16 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderTest, QueryBookmarks);
   FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderTest,
+                           QueryBookmarks_flagTest);
+  FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderTest,
                            QueryBookmarks_nativePageShouldBeFiltered);
   FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderBrowserTest,
                            QuerySensitiveTab);
   FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderBrowserTest,
                            QueryNonSensitiveTab);
   FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderBrowserTest,
+                           QueryNonSensitiveTab_flagTest);
+  FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderBrowserTest,
                            QueryEmptyTabList);
   FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderBrowserTest, NativeTabTest);
   FRIEND_TEST_ALL_PREFIXES(AuxiliarySearchProviderBrowserTest, FilterTabsTest);
@@ -71,6 +75,8 @@
                                    NonSensitiveTabsCallback callback) const;
 
   raw_ptr<Profile> profile_;
+  size_t max_bookmark_donation_count_;
+  size_t max_tab_donation_count_;
 
   base::WeakPtrFactory<AuxiliarySearchProvider> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/android/auxiliary_search/auxiliary_search_provider_browsertest.cc b/chrome/browser/android/auxiliary_search/auxiliary_search_provider_browsertest.cc
index f21ab07f..53e2573e 100644
--- a/chrome/browser/android/auxiliary_search/auxiliary_search_provider_browsertest.cc
+++ b/chrome/browser/android/auxiliary_search/auxiliary_search_provider_browsertest.cc
@@ -6,9 +6,11 @@
 
 #include "base/android/jni_android.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/android/persisted_tab_data/persisted_tab_data_android.h"
 #include "chrome/browser/android/persisted_tab_data/sensitivity_persisted_tab_data_android.h"
 #include "chrome/browser/android/tab_android.h"
+#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
@@ -21,9 +23,18 @@
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
+namespace {
+constexpr size_t kMaxDonatedTabs = 2;
+constexpr char kMaxDonatedTabsValue[] = "2";
+}  // namespace
+
 class AuxiliarySearchProviderBrowserTest : public AndroidBrowserTest {
  public:
-  AuxiliarySearchProviderBrowserTest() = default;
+  AuxiliarySearchProviderBrowserTest() {
+    scoped_feature_list_.InitAndEnableFeatureWithParameters(
+        chrome::android::kAuxiliarySearchDonation,
+        {{"auxiliary_search_max_donation_tab", kMaxDonatedTabsValue}});
+  }
 
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
@@ -64,6 +75,7 @@
 
  private:
   std::unique_ptr<AuxiliarySearchProvider> auxiliary_search_provider_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest, QuerySensitiveTab) {
@@ -110,6 +122,45 @@
   run_loop.Run();
 }
 
+IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest,
+                       QueryNonSensitiveTab_flagTest) {
+  base::RunLoop run_loop;
+  std::vector<TabAndroid*> tab_vec = CreateOneTab(false);
+
+  TabModel* tab_model = TabModelList::GetTabModelForWebContents(web_contents());
+  TabAndroid* second_tab = TabAndroid::FromWebContents(web_contents());
+  std::unique_ptr<content::WebContents> contents = content::WebContents::Create(
+      content::WebContents::CreateParams(profile()));
+  content::WebContents* second_web_contents = contents.release();
+  tab_model->CreateTab(second_tab, second_web_contents);
+  std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda2 =
+      std::make_unique<SensitivityPersistedTabDataAndroid>(second_tab);
+  sptda2->set_is_sensitive(false);
+  tab_vec.push_back(second_tab);
+
+  TabAndroid* third_tab = TabAndroid::FromWebContents(web_contents());
+  contents = content::WebContents::Create(
+      content::WebContents::CreateParams(profile()));
+  content::WebContents* third_web_contents = contents.release();
+  tab_model->CreateTab(third_tab, third_web_contents);
+  std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda3 =
+      std::make_unique<SensitivityPersistedTabDataAndroid>(third_tab);
+  sptda3->set_is_sensitive(false);
+  tab_vec.push_back(third_tab);
+
+  provider()->GetNonSensitiveTabsInternal(
+      tab_vec,
+      base::BindOnce(
+          [](base::OnceClosure done,
+             std::unique_ptr<std::vector<TabAndroid*>> non_sensitive_tab) {
+            // Only 2 should be here since the flag is set to 2.
+            EXPECT_EQ(kMaxDonatedTabs, non_sensitive_tab->size());
+            std::move(done).Run();
+          },
+          run_loop.QuitClosure()));
+  run_loop.Run();
+}
+
 IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest, QueryEmptyTabList) {
   base::RunLoop run_loop;
 
diff --git a/chrome/browser/android/auxiliary_search/auxiliary_search_provider_unittest.cc b/chrome/browser/android/auxiliary_search/auxiliary_search_provider_unittest.cc
index 7f7e168..9db816c7 100644
--- a/chrome/browser/android/auxiliary_search/auxiliary_search_provider_unittest.cc
+++ b/chrome/browser/android/auxiliary_search/auxiliary_search_provider_unittest.cc
@@ -6,8 +6,10 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/android/auxiliary_search/proto/auxiliary_search_group.pb.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
@@ -33,12 +35,16 @@
     provider = std::make_unique<AuxiliarySearchProvider>(profile_.get());
   }
 
-  void TearDown() override { profile_.reset(nullptr); }
+  void TearDown() override {
+    profile_.reset(nullptr);
+    scoped_feature_list_.Reset();
+  }
 
  protected:
   std::unique_ptr<AuxiliarySearchProvider> provider;
   std::unique_ptr<BookmarkModel> model_;
   std::unique_ptr<TestingProfile> profile_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 
  private:
   content::BrowserTaskEnvironment task_environment_;
@@ -82,6 +88,39 @@
   EXPECT_EQ(100u, bookmark_titles_int.size());
 }
 
+TEST_F(AuxiliarySearchProviderTest, QueryBookmarks_flagTest) {
+  scoped_feature_list_.InitAndEnableFeatureWithParameters(
+      chrome::android::kAuxiliarySearchDonation,
+      {{"auxiliary_search_max_donation_bookmark", "150"}});
+  provider = std::make_unique<AuxiliarySearchProvider>(profile_.get());
+  for (int i = 0; i < 200; i++) {
+    std::string number = base::NumberToString(i);
+    BookmarkNode* node = AsMutable(model_->AddURL(
+        model_->bookmark_bar_node(), i, base::UTF8ToUTF16(number),
+        GURL("http://foo.com/" + number)));
+    node->set_date_last_used(base::Time::FromTimeT(i));
+  }
+  auxiliary_search::AuxiliarySearchBookmarkGroup group =
+      provider->GetBookmarks(model_.get());
+
+  EXPECT_EQ(150, group.bookmark_size());
+
+  std::unordered_set<int> bookmark_titles_int;
+  for (int i = 0; i < 150; i++) {
+    auxiliary_search::AuxiliarySearchEntry bookmark = group.bookmark(i);
+    int title_int;
+
+    EXPECT_TRUE(bookmark.has_creation_timestamp());
+    EXPECT_TRUE(bookmark.has_last_access_timestamp());
+    EXPECT_FALSE(bookmark.has_last_modification_timestamp());
+    EXPECT_TRUE(base::StringToInt(bookmark.title(), &title_int));
+
+    EXPECT_TRUE(title_int >= 50 && title_int <= 199);
+    bookmark_titles_int.insert(title_int);
+  }
+  EXPECT_EQ(150u, bookmark_titles_int.size());
+}
+
 TEST_F(AuxiliarySearchProviderTest, QueryBookmarks_nativePageShouldBeFiltered) {
   std::vector<GURL> urls_should_be_filtered = {
       GURL(chrome::kChromeUINativeNewTabURL),
diff --git a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
index d031dd9..8e9b2b2c 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
@@ -14,11 +14,16 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h"
 #include "chrome/browser/apps/intent_helper/intent_chip_display_prefs.h"
+#include "chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h"
 #include "chrome/browser/apps/link_capturing/intent_picker_info.h"
 #include "chrome/browser/apps/link_capturing/link_capturing_features.h"
+#include "chrome/browser/infobars/confirm_infobar_creator.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/share/share_attempt.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
+#include "chrome/common/chrome_features.h"
+#include "components/infobars/content/content_infobar_manager.h"
+#include "components/infobars/core/infobar.h"
 #include "components/services/app_service/public/cpp/app_update.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/gfx/favicon_size.h"
@@ -145,6 +150,17 @@
   switch (app_type) {
     case apps::PickerEntryType::kWeb:
       web_app::ReparentWebContentsIntoAppBrowser(web_contents, launch_name);
+#if !BUILDFLAG(IS_CHROMEOS)
+      if (base::FeatureList::IsEnabled(features::kDesktopPWAsLinkCapturing)) {
+        std::unique_ptr<EnableLinkCapturingInfoBarDelegate> delegate =
+            EnableLinkCapturingInfoBarDelegate::MaybeCreate(web_contents,
+                                                            launch_name);
+        if (delegate) {
+          infobars::ContentInfoBarManager::FromWebContents(web_contents)
+              ->AddInfoBar(CreateConfirmInfoBar(std::move(delegate)));
+        }
+      }
+#endif
       break;
     case apps::PickerEntryType::kMacOs:
 #if BUILDFLAG(IS_MAC)
diff --git a/chrome/browser/apps/intent_helper/supported_links_infobar_delegate.h b/chrome/browser/apps/intent_helper/supported_links_infobar_delegate.h
index 22be36c..88ce35bd 100644
--- a/chrome/browser/apps/intent_helper/supported_links_infobar_delegate.h
+++ b/chrome/browser/apps/intent_helper/supported_links_infobar_delegate.h
@@ -24,6 +24,8 @@
 
 // An infobar delegate asking if the user wants to enable the Supported Links
 // setting for an app.
+// Note: This is only used for CrOS, see EnableLinkCapturingInfoBarDelegate for
+// the infobar used for other platforms.
 class SupportedLinksInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
   explicit SupportedLinksInfoBarDelegate(Profile* profile,
diff --git a/chrome/browser/apps/link_capturing/BUILD.gn b/chrome/browser/apps/link_capturing/BUILD.gn
index 2215104..d559989 100644
--- a/chrome/browser/apps/link_capturing/BUILD.gn
+++ b/chrome/browser/apps/link_capturing/BUILD.gn
@@ -43,9 +43,18 @@
     ]
   } else {
     sources += [
+      "enable_link_capturing_infobar_delegate.cc",
+      "enable_link_capturing_infobar_delegate.h",
       "web_app_link_capturing_delegate.cc",
       "web_app_link_capturing_delegate.h",
     ]
+    deps += [
+      "//chrome/app:generated_resources_grit",
+      "//components/infobars/content",
+      "//components/infobars/core",
+      "//components/strings:components_strings_grit",
+      "//components/vector_icons",
+    ]
   }
 
   if (is_chromeos_ash) {
diff --git a/chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.cc b/chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.cc
new file mode 100644
index 0000000..32302d9
--- /dev/null
+++ b/chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.cc
@@ -0,0 +1,250 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h"
+
+#include <memory>
+
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/numerics/clamped_math.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/locks/app_lock.h"
+#include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_registry_update.h"
+#include "chrome/browser/web_applications/web_app_sync_bridge.h"
+#include "chrome/browser/web_applications/web_app_ui_manager.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/infobars/content/content_infobar_manager.h"
+#include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/vector_icons/vector_icons.h"
+#include "components/webapps/common/web_app_id.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/vector_icon_types.h"
+
+namespace apps {
+namespace {
+base::Value IncrementIgnoreCount(webapps::AppId app_id,
+                                 web_app::AppLock& app_lock) {
+  web_app::ScopedRegistryUpdate update = app_lock.sync_bridge().BeginUpdate();
+  web_app::WebApp* app = update->UpdateApp(app_id);
+
+  base::Value::Dict debug_result;
+  debug_result.Set("app_id", app_id);
+  if (!app) {
+    debug_result.Set("error", "AppId does not exist.");
+    return base::Value(std::move(debug_result));
+  }
+  int new_count =
+      base::ClampedNumeric(app->supported_links_offer_ignore_count()) + 1;
+  app->SetSupportedLinksOfferIgnoreCount(new_count);
+
+  debug_result.Set("supported_links_offer_ignore_count", new_count);
+  return base::Value(std::move(debug_result));
+}
+
+base::Value IncrementDismissCount(webapps::AppId app_id,
+                                  web_app::AppLock& app_lock) {
+  web_app::ScopedRegistryUpdate update = app_lock.sync_bridge().BeginUpdate();
+  web_app::WebApp* app = update->UpdateApp(app_id);
+
+  base::Value::Dict debug_result;
+  debug_result.Set("app_id", app_id);
+  if (!app) {
+    debug_result.Set("error", "AppId does not exist.");
+    return base::Value(std::move(debug_result));
+  }
+  int new_count =
+      base::ClampedNumeric(app->supported_links_offer_dismiss_count()) + 1;
+  app->SetSupportedLinksOfferDismissCount(new_count);
+
+  debug_result.Set("supported_links_offer_dismiss_count", new_count);
+  return base::Value(std::move(debug_result));
+}
+
+base::Value EnableUserLinkCapturing(webapps::AppId app_id,
+                                    web_app::AppLock& app_lock) {
+  web_app::ScopedRegistryUpdate update = app_lock.sync_bridge().BeginUpdate();
+  web_app::WebApp* app = update->UpdateApp(app_id);
+
+  base::Value::Dict debug_result;
+  debug_result.Set("app_id", app_id);
+  if (!app) {
+    debug_result.Set("error", "AppId does not exist.");
+    debug_result.Set("user_link_capturing_set", false);
+    return base::Value(std::move(debug_result));
+  }
+  app->SetIsUserSelectedAppForSupportedLinks(true);
+
+  debug_result.Set("user_link_capturing_set", true);
+  return base::Value(std::move(debug_result));
+}
+}  // namespace
+
+// Searches the toolbar on this web contents for this infobar, and returns it
+// if found.
+infobars::InfoBar* EnableLinkCapturingInfoBarDelegate::FindInfoBar(
+    content::WebContents* web_contents) {
+  CHECK(web_contents);
+  auto* infobar_manager =
+      infobars::ContentInfoBarManager::FromWebContents(web_contents);
+  CHECK(infobar_manager);
+  for (size_t i = 0; i < infobar_manager->infobar_count(); ++i) {
+    auto* infobar = infobar_manager->infobar_at(i);
+    if (infobar->delegate()->GetIdentifier() ==
+        infobars::InfoBarDelegate::ENABLE_LINK_CAPTURING_INFOBAR_DELEGATE) {
+      return infobar;
+    }
+  }
+  return nullptr;
+}
+
+// static
+std::unique_ptr<EnableLinkCapturingInfoBarDelegate>
+EnableLinkCapturingInfoBarDelegate::MaybeCreate(
+    content::WebContents* web_contents,
+    const std::string& app_id) {
+  CHECK(web_contents);
+
+  // Check that no infobar has already been added.
+  CHECK(!EnableLinkCapturingInfoBarDelegate::FindInfoBar(web_contents));
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  CHECK(profile);
+
+  web_app::WebAppProvider* provider =
+      web_app::WebAppProvider::GetForWebApps(profile);
+  if (!provider) {
+    return nullptr;
+  }
+
+  // Do not show the infobar if links are already captured.
+  if (provider->registrar_unsafe().CapturesLinksInScope(app_id)) {
+    return nullptr;
+  }
+
+  const GURL& url = web_contents->GetLastCommittedURL();
+  if (!web_app::IsValidScopeForLinkCapturing(url)) {
+    return nullptr;
+  }
+
+  // A 'outer' app can still be launched from the intent picker, even if there
+  // is a more applicable 'nested' app. This is allowed, but the 'outer' app can
+  // never capture links. Thus, disable this infobar in that case.
+  if (!provider->registrar_unsafe().IsLinkCapturableByApp(app_id, url)) {
+    return nullptr;
+  }
+
+  const web_app::WebApp* app = provider->registrar_unsafe().GetAppById(app_id);
+  CHECK(app);
+  constexpr int kSupportedLinksMaxIgnoreCount = 3;
+  if (app->supported_links_offer_ignore_count() >=
+      kSupportedLinksMaxIgnoreCount) {
+    return nullptr;
+  }
+  constexpr int kSupportedLinksMaxDismissCount = 2;
+  if (app->supported_links_offer_dismiss_count() >=
+      kSupportedLinksMaxDismissCount) {
+    return nullptr;
+  }
+
+  return base::WrapUnique(
+      new EnableLinkCapturingInfoBarDelegate(*profile, app_id));
+}
+
+// static
+void EnableLinkCapturingInfoBarDelegate::RemoveInfoBar(
+    content::WebContents* web_contents) {
+  CHECK(web_contents);
+  auto* infobar_manager =
+      infobars::ContentInfoBarManager::FromWebContents(web_contents);
+  CHECK(infobar_manager);
+  infobars::InfoBar* infobar =
+      EnableLinkCapturingInfoBarDelegate::FindInfoBar(web_contents);
+  if (infobar) {
+    infobar_manager->RemoveInfoBar(infobar);
+  }
+}
+
+EnableLinkCapturingInfoBarDelegate::~EnableLinkCapturingInfoBarDelegate() {
+  if (action_taken_) {
+    return;
+  }
+  base::RecordAction(
+      base::UserMetricsAction("LinkCapturingIgnoredFromInfoBar"));
+  provider_->scheduler().ScheduleCallbackWithLock(
+      "IncrementSupportedLinksOfferIgnoreCount",
+      std::make_unique<web_app::AppLockDescription>(app_id_),
+      base::BindOnce(&IncrementIgnoreCount, app_id_));
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+EnableLinkCapturingInfoBarDelegate::GetIdentifier() const {
+  return infobars::InfoBarDelegate::InfoBarIdentifier::
+      ENABLE_LINK_CAPTURING_INFOBAR_DELEGATE;
+}
+
+std::u16string EnableLinkCapturingInfoBarDelegate::GetMessageText() const {
+  std::string name;
+  name = provider_->registrar_unsafe().GetAppShortName(app_id_);
+  return l10n_util::GetStringFUTF16(
+      IDR_INTENT_PICKER_SUPPORTED_LINKS_INFOBAR_MESSAGE,
+      base::UTF8ToUTF16(name));
+}
+
+std::u16string EnableLinkCapturingInfoBarDelegate::GetButtonLabel(
+    InfoBarButton button) const {
+  return l10n_util::GetStringUTF16(
+      button == BUTTON_OK ? IDR_INTENT_PICKER_SUPPORTED_LINKS_INFOBAR_OK_LABEL
+                          : IDS_NO_THANKS);
+}
+
+const gfx::VectorIcon& EnableLinkCapturingInfoBarDelegate::GetVectorIcon()
+    const {
+  return vector_icons::kSettingsIcon;
+}
+
+bool EnableLinkCapturingInfoBarDelegate::IsCloseable() const {
+  return true;
+}
+
+bool EnableLinkCapturingInfoBarDelegate::Accept() {
+  action_taken_ = true;
+  base::RecordAction(
+      base::UserMetricsAction("LinkCapturingAcceptedFromInfoBar"));
+  provider_->scheduler().ScheduleCallbackWithLock(
+      "EnableUserLinkCapturing",
+      std::make_unique<web_app::AppLockDescription>(app_id_),
+      base::BindOnce(&EnableUserLinkCapturing, app_id_));
+  return true;
+}
+
+bool EnableLinkCapturingInfoBarDelegate::Cancel() {
+  action_taken_ = true;
+  base::RecordAction(
+      base::UserMetricsAction("LinkCapturingCancelledFromInfoBar"));
+  provider_->scheduler().ScheduleCallbackWithLock(
+      "IncrementSupportedLinksOfferDismissCount",
+      std::make_unique<web_app::AppLockDescription>(app_id_),
+      base::BindOnce(&IncrementDismissCount, app_id_));
+  return true;
+}
+
+EnableLinkCapturingInfoBarDelegate::EnableLinkCapturingInfoBarDelegate(
+    Profile& profile,
+    const webapps::AppId& app_id)
+    : profile_(profile),
+      provider_(*web_app::WebAppProvider::GetForWebApps(&profile)),
+      app_id_(app_id) {}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h b/chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h
new file mode 100644
index 0000000..76ea1df8
--- /dev/null
+++ b/chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h
@@ -0,0 +1,86 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_APPS_LINK_CAPTURING_ENABLE_LINK_CAPTURING_INFOBAR_DELEGATE_H_
+#define CHROME_BROWSER_APPS_LINK_CAPTURING_ENABLE_LINK_CAPTURING_INFOBAR_DELEGATE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/raw_ref.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "components/webapps/common/web_app_id.h"
+
+class Profile;
+
+namespace infobars {
+class InfoBar;
+}
+
+namespace content {
+class WebContents;
+}
+
+namespace gfx {
+struct VectorIcon;
+}
+
+namespace web_app {
+class WebAppProvider;
+}
+
+namespace apps {
+
+// An infobar delegate asking if the user wants to enable link capturing for
+// the given application. This is only created when the app doesn't have link
+// capturing already enabled.
+// Note: This implementation is only used for non-CrOS platforms. See
+// SupportedLinksInfoBarDelegate for the infobar used for CrOS.
+class EnableLinkCapturingInfoBarDelegate : public ConfirmInfoBarDelegate {
+ public:
+  EnableLinkCapturingInfoBarDelegate(
+      const EnableLinkCapturingInfoBarDelegate&) = delete;
+  EnableLinkCapturingInfoBarDelegate& operator=(
+      const EnableLinkCapturingInfoBarDelegate&) = delete;
+  ~EnableLinkCapturingInfoBarDelegate() override;
+
+  // Searches the toolbar on the web contents for this infobar, and returns it
+  // if found.
+  static infobars::InfoBar* FindInfoBar(content::WebContents* web_contents);
+
+  // Creates and shows a supported links infobar for the given |web_contents|.
+  // The infobar will only be created if it is suitable for the given |app_id|
+  // (e.g. the app does not already have the supported links setting enabled).
+  // This will CHECK-fail if this infobar is already added to the web contents,
+  // so ensure that doesn't happen.
+  static std::unique_ptr<EnableLinkCapturingInfoBarDelegate> MaybeCreate(
+      content::WebContents* web_contents,
+      const webapps::AppId& app_id);
+
+  // Removes the supported links infobar (if there is one) from the given
+  // |web_contents|.
+  static void RemoveInfoBar(content::WebContents* web_contents);
+
+  // ConfirmInfoBarDelegate:
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  std::u16string GetMessageText() const override;
+  std::u16string GetButtonLabel(InfoBarButton button) const override;
+  const gfx::VectorIcon& GetVectorIcon() const override;
+  bool IsCloseable() const override;
+  bool Accept() override;
+  bool Cancel() override;
+
+ private:
+  EnableLinkCapturingInfoBarDelegate(Profile& profile,
+                                     const webapps::AppId& app_id);
+
+  raw_ref<Profile> profile_;
+  raw_ref<web_app::WebAppProvider> provider_;
+  webapps::AppId app_id_;
+  bool action_taken_ = false;
+};
+
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_LINK_CAPTURING_ENABLE_LINK_CAPTURING_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 2b8ba95..204db0a 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -704,11 +704,6 @@
     "borealis/borealis_context_manager_impl.h",
     "borealis/borealis_credits.cc",
     "borealis/borealis_credits.h",
-    "borealis/borealis_disk_manager.h",
-    "borealis/borealis_disk_manager_dispatcher.cc",
-    "borealis/borealis_disk_manager_dispatcher.h",
-    "borealis/borealis_disk_manager_impl.cc",
-    "borealis/borealis_disk_manager_impl.h",
     "borealis/borealis_engagement_metrics.cc",
     "borealis/borealis_engagement_metrics.h",
     "borealis/borealis_features.cc",
@@ -4929,6 +4924,7 @@
     "../ui/webui/ash/settings/pages/device/device_keyboard_handler_unittest.cc",
     "../ui/webui/ash/settings/pages/device/device_section_unittest.cc",
     "../ui/webui/ash/settings/pages/device/input_device_settings/input_device_settings_provider_unittest.cc",
+    "../ui/webui/ash/settings/pages/internet/internet_handler_unittest.cc",
     "../ui/webui/ash/settings/pages/search/search_engines_handler_unittest.cc",
     "../ui/webui/ash/settings/pages/storage/device_storage_handler_unittest.cc",
     "../ui/webui/ash/settings/search/search_handler_unittest.cc",
@@ -4936,7 +4932,6 @@
     "../ui/webui/settings/about_handler_unittest.cc",
     "../ui/webui/settings/ash/display_settings/display_settings_provider_unittest.cc",
     "../ui/webui/settings/ash/hierarchy_unittest.cc",
-    "../ui/webui/settings/ash/internet_handler_unittest.cc",
     "../ui/webui/settings/ash/metrics_consent_handler_unittest.cc",
     "../ui/webui/settings/ash/multidevice_handler_unittest.cc",
     "../ui/webui/settings/ash/multidevice_section_unittest.cc",
@@ -5219,8 +5214,6 @@
     "borealis/borealis_app_uninstaller_unittest.cc",
     "borealis/borealis_context_manager_unittest.cc",
     "borealis/borealis_context_unittest.cc",
-    "borealis/borealis_disk_manager_dispatcher_unittest.cc",
-    "borealis/borealis_disk_manager_unittest.cc",
     "borealis/borealis_features_unittest.cc",
     "borealis/borealis_install_url_handler_unittest.cc",
     "borealis/borealis_installer_unittest.cc",
@@ -6119,7 +6112,7 @@
     "//chromeos/ash/components/disks:test_support",
     "//chromeos/ash/components/drivefs/mojom",
     "//chromeos/ash/components/drivefs/mojom:mojom_shared",
-    "//chromeos/ash/components/drivefs/mojom:pin_manager_types",
+    "//chromeos/ash/components/drivefs/mojom:pinning_manager_types",
     "//chromeos/ash/components/feature_usage",
     "//chromeos/ash/components/install_attributes",
     "//chromeos/ash/components/install_attributes:test_support",
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.cc b/chrome/browser/ash/accessibility/accessibility_manager.cc
index 387d7de4..90afa9e0 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager.cc
+++ b/chrome/browser/ash/accessibility/accessibility_manager.cc
@@ -103,6 +103,7 @@
 #include "services/accessibility/buildflags.h"
 #include "services/audio/public/cpp/sounds/sounds_manager.h"
 #include "ui/accessibility/accessibility_features.h"
+#include "ui/accessibility/accessibility_switches.h"
 #include "ui/accessibility/ax_enum_util.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/base/ime/ash/extension_ime_util.h"
@@ -489,11 +490,21 @@
       extension_misc::kSelectToSpeakGuestManifestFilename,
       base::BindRepeating(&AccessibilityManager::PostUnloadSelectToSpeak,
                           weak_ptr_factory_.GetWeakPtr())));
+
+  const bool enable_v3_manifest =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ::switches::kEnableExperimentalAccessibilityManifestV3);
+  const base::FilePath::CharType* switchAccessManifestFilename =
+      enable_v3_manifest ? extension_misc::kSwitchAccessManifestV3Filename
+                         : extension_misc::kSwitchAccessManifestFilename;
+  const base::FilePath::CharType* switchAccessGuestManifestFilename =
+      enable_v3_manifest ? extension_misc::kSwitchAccessGuestManifestV3Filename
+                         : extension_misc::kSwitchAccessGuestManifestFilename;
+
   switch_access_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
       extension_misc::kSwitchAccessExtensionId,
       resources_path.Append(extension_misc::kSwitchAccessExtensionPath),
-      extension_misc::kSwitchAccessManifestFilename,
-      extension_misc::kSwitchAccessGuestManifestFilename,
+      switchAccessManifestFilename, switchAccessGuestManifestFilename,
       base::BindRepeating(&AccessibilityManager::PostUnloadSwitchAccess,
                           weak_ptr_factory_.GetWeakPtr())));
 
diff --git a/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc b/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
index 822d2409..af8beeb 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
+++ b/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
@@ -54,6 +54,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/accessibility/accessibility_features.h"
+#include "ui/accessibility/accessibility_switches.h"
 #include "ui/base/ime/ash/component_extension_ime_manager.h"
 #include "ui/base/ime/ash/extension_ime_util.h"
 #include "ui/base/ime/ash/input_method_manager.h"
@@ -1971,6 +1972,37 @@
   SetMagnifierEnabled(false);
 }
 
+class AccessibilityManagerWithManifestV3Test : public AccessibilityManagerTest {
+ public:
+  AccessibilityManagerWithManifestV3Test() = default;
+  AccessibilityManagerWithManifestV3Test(
+      const AccessibilityManagerWithManifestV3Test&) = delete;
+  AccessibilityManagerWithManifestV3Test& operator=(
+      const AccessibilityManagerWithManifestV3Test&) = delete;
+  ~AccessibilityManagerWithManifestV3Test() override = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(
+        ::switches::kEnableExperimentalAccessibilityManifestV3);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(AccessibilityManagerWithManifestV3Test, DoesNotCrash) {
+  SetSpokenFeedbackEnabled(true);
+  SetSelectToSpeakEnabled(true);
+  SetSwitchAccessEnabled(true);
+  SetAutoclickEnabled(true);
+  SetDictationEnabled(true);
+  SetMagnifierEnabled(true);
+
+  SetSpokenFeedbackEnabled(false);
+  SetSelectToSpeakEnabled(false);
+  SetSwitchAccessEnabled(false);
+  SetAutoclickEnabled(false);
+  SetDictationEnabled(false);
+  SetMagnifierEnabled(false);
+}
+
 enum class DictationKeyboardShortcutType { kKey, kKeyboardCombo };
 
 class AccessibilityManagerDictationKeyboardImprovementsTest
diff --git a/chrome/browser/ash/accessibility/service/accessibility_service_client_browsertest.cc b/chrome/browser/ash/accessibility/service/accessibility_service_client_browsertest.cc
index 7ef99ca7..8f3a498 100644
--- a/chrome/browser/ash/accessibility/service/accessibility_service_client_browsertest.cc
+++ b/chrome/browser/ash/accessibility/service/accessibility_service_client_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "ash/accessibility/ui/accessibility_focus_ring_controller_impl.h"
+#include "ash/accessibility/ui/accessibility_highlight_layer.h"
 #include "ash/public/cpp/accessibility_focus_ring_info.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
@@ -959,4 +960,31 @@
   waiter.Run();
 }
 
+IN_PROC_BROWSER_TEST_F(AccessibilityServiceClientTest, SetHighlights) {
+  auto client =
+      TurnOnAccessibilityService(AssistiveTechnologyType::kSwitchAccess);
+  fake_service_->BindAnotherUserInterface();
+
+  std::vector<gfx::Rect> rects;
+  rects.emplace_back(gfx::Rect(0, 1, 22, 1973));
+
+  base::RunLoop waiter;
+  AccessibilityManager::Get()->SetHighlightsObserverForTest(
+      base::BindLambdaForTesting([&waiter, &rects] {
+        waiter.Quit();
+        AccessibilityFocusRingControllerImpl* controller =
+            Shell::Get()->accessibility_focus_ring_controller();
+        AccessibilityHighlightLayer* highlight_layer =
+            controller->highlight_layer_for_testing();
+        EXPECT_TRUE(highlight_layer);
+        ASSERT_EQ(1u, highlight_layer->rects_for_test().size());
+        EXPECT_EQ(rects[0], highlight_layer->rects_for_test()[0]);
+        EXPECT_EQ(SK_ColorMAGENTA, highlight_layer->color_for_test());
+      }));
+
+  fake_service_->RequestSetHighlights(rects, SK_ColorMAGENTA);
+
+  waiter.Run();
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/accessibility/service/fake_accessibility_service.cc b/chrome/browser/ash/accessibility/service/fake_accessibility_service.cc
index a68e7f5..d5e3f647 100644
--- a/chrome/browser/ash/accessibility/service/fake_accessibility_service.cc
+++ b/chrome/browser/ash/accessibility/service/fake_accessibility_service.cc
@@ -208,4 +208,12 @@
   }
 }
 
+void FakeAccessibilityService::RequestSetHighlights(
+    const std::vector<gfx::Rect>& rects,
+    SkColor color) {
+  for (auto& ux_client : ux_remotes_) {
+    ux_client->SetHighlights(rects, color);
+  }
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/accessibility/service/fake_accessibility_service.h b/chrome/browser/ash/accessibility/service/fake_accessibility_service.h
index d1d3286a..d01de2d 100644
--- a/chrome/browser/ash/accessibility/service/fake_accessibility_service.h
+++ b/chrome/browser/ash/accessibility/service/fake_accessibility_service.h
@@ -142,6 +142,8 @@
       std::vector<ax::mojom::FocusRingInfoPtr> focus_rings,
       ax::mojom::AssistiveTechnologyType at_type);
 
+  void RequestSetHighlights(const std::vector<gfx::Rect>& rects, SkColor color);
+
   // Getters for automation events.
   std::vector<ui::AXTreeID> tree_destroyed_events() const {
     return tree_destroyed_events_;
diff --git a/chrome/browser/ash/accessibility/service/user_interface_impl.cc b/chrome/browser/ash/accessibility/service/user_interface_impl.cc
index b0a6af9..26e25292 100644
--- a/chrome/browser/ash/accessibility/service/user_interface_impl.cc
+++ b/chrome/browser/ash/accessibility/service/user_interface_impl.cc
@@ -81,4 +81,9 @@
   }
 }
 
+void UserInterfaceImpl::SetHighlights(const std::vector<gfx::Rect>& rects,
+                                      SkColor color) {
+  AccessibilityManager::Get()->SetHighlights(rects, color);
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/accessibility/service/user_interface_impl.h b/chrome/browser/ash/accessibility/service/user_interface_impl.h
index cde6fb3..95d09e9 100644
--- a/chrome/browser/ash/accessibility/service/user_interface_impl.h
+++ b/chrome/browser/ash/accessibility/service/user_interface_impl.h
@@ -27,6 +27,8 @@
   // ax::mojom::UserInterface:
   void SetFocusRings(std::vector<ax::mojom::FocusRingInfoPtr> focus_rings,
                      ax::mojom::AssistiveTechnologyType at_type) override;
+  void SetHighlights(const std::vector<gfx::Rect>& rects,
+                     SkColor color) override;
 
  private:
   mojo::ReceiverSet<ax::mojom::UserInterface> ui_receivers_;
diff --git a/chrome/browser/ash/authpolicy/OWNERS b/chrome/browser/ash/authpolicy/OWNERS
index cf144fc..b153dada9 100644
--- a/chrome/browser/ash/authpolicy/OWNERS
+++ b/chrome/browser/ash/authpolicy/OWNERS
@@ -6,9 +6,4 @@
 fsandrade@chromium.org
 
 # Secondary owner(s)
-rsorokin@google.com
-
-# Previous owners (for general questions, if current owners are not available)
-# Commented out so automatic tools don't prefer.
-# ljusten@chromium.org
-# tomdobro@hromium.org
+emaxx@chromium.org
diff --git a/chrome/browser/ash/borealis/borealis_context.cc b/chrome/browser/ash/borealis/borealis_context.cc
index 246a920..b22f36d 100644
--- a/chrome/browser/ash/borealis/borealis_context.cc
+++ b/chrome/browser/ash/borealis/borealis_context.cc
@@ -15,7 +15,6 @@
 #include "base/scoped_observation.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager_impl.h"
 #include "chrome/browser/ash/borealis/borealis_engagement_metrics.h"
 #include "chrome/browser/ash/borealis/borealis_metrics.h"
 #include "chrome/browser/ash/borealis/borealis_power_controller.h"
@@ -97,11 +96,6 @@
 
 BorealisContext::~BorealisContext() = default;
 
-void BorealisContext::SetDiskManagerForTesting(
-    std::unique_ptr<BorealisDiskManager> disk_manager) {
-  disk_manager_ = std::move(disk_manager);
-}
-
 void BorealisContext::NotifyUnexpectedVmShutdown() {
   guest_os_stability_monitor_->LogUnexpectedVmShutdown();
 }
@@ -113,7 +107,6 @@
           std::make_unique<guest_os::GuestOsStabilityMonitor>(
               kBorealisStabilityHistogram)),
       engagement_metrics_(std::make_unique<BorealisEngagementMetrics>(profile)),
-      disk_manager_(std::make_unique<BorealisDiskManagerImpl>(this)),
       power_controller_(std::make_unique<BorealisPowerController>(profile)) {}
 
 std::unique_ptr<BorealisContext>
diff --git a/chrome/browser/ash/borealis/borealis_context.h b/chrome/browser/ash/borealis/borealis_context.h
index 343a5d9d..c33ce1b 100644
--- a/chrome/browser/ash/borealis/borealis_context.h
+++ b/chrome/browser/ash/borealis/borealis_context.h
@@ -19,7 +19,6 @@
 }
 namespace borealis {
 
-class BorealisDiskManager;
 class BorealisEngagementMetrics;
 class BorealisLifetimeObserver;
 class BorealisPowerController;
@@ -56,10 +55,6 @@
   const base::FilePath& disk_path() const { return disk_path_; }
   void set_disk_path(base::FilePath path) { disk_path_ = std::move(path); }
 
-  BorealisDiskManager& get_disk_manager() { return *disk_manager_.get(); }
-  void SetDiskManagerForTesting(
-      std::unique_ptr<BorealisDiskManager> disk_manager);
-
   // Called to signal that this Borealis VM is being unexpectedly shut down.
   // Not to be called during intentional shutdowns.
   void NotifyUnexpectedVmShutdown();
@@ -83,8 +78,6 @@
 
   std::unique_ptr<BorealisEngagementMetrics> engagement_metrics_;
 
-  std::unique_ptr<BorealisDiskManager> disk_manager_;
-
   std::unique_ptr<BorealisPowerController> power_controller_;
 };
 
diff --git a/chrome/browser/ash/borealis/borealis_context_manager_impl.cc b/chrome/browser/ash/borealis/borealis_context_manager_impl.cc
index 5e1dbc738..2a56030 100644
--- a/chrome/browser/ash/borealis/borealis_context_manager_impl.cc
+++ b/chrome/browser/ash/borealis/borealis_context_manager_impl.cc
@@ -208,7 +208,6 @@
   task_queue.push(std::make_unique<StartBorealisVm>());
   task_queue.push(std::make_unique<AwaitBorealisStartup>());
   task_queue.push(std::make_unique<UpdateChromeFlags>(profile_));
-  task_queue.push(std::make_unique<SyncBorealisDisk>());
   return task_queue;
 }
 
diff --git a/chrome/browser/ash/borealis/borealis_context_unittest.cc b/chrome/browser/ash/borealis/borealis_context_unittest.cc
index a3f29c6..0e6b85cd 100644
--- a/chrome/browser/ash/borealis/borealis_context_unittest.cc
+++ b/chrome/browser/ash/borealis/borealis_context_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h"
 #include "chrome/browser/ash/borealis/borealis_launch_options.h"
 #include "chrome/browser/ash/borealis/borealis_metrics.h"
 #include "chrome/browser/ash/borealis/borealis_service_fake.h"
@@ -41,16 +40,12 @@
   BorealisContextTest()
       : new_window_provider_(std::make_unique<ash::TestNewWindowDelegate>()) {
     profile_ = std::make_unique<TestingProfile>();
-    borealis_disk_manager_dispatcher_ =
-        std::make_unique<BorealisDiskManagerDispatcher>();
     borealis_shutdown_monitor_ =
         std::make_unique<BorealisShutdownMonitor>(profile_.get());
     borealis_window_manager_ =
         std::make_unique<BorealisWindowManager>(profile_.get());
 
     service_fake_ = BorealisServiceFake::UseFakeForTesting(profile_.get());
-    service_fake_->SetDiskManagerDispatcherForTesting(
-        borealis_disk_manager_dispatcher_.get());
     service_fake_->SetShutdownMonitorForTesting(
         borealis_shutdown_monitor_.get());
     service_fake_->SetWindowManagerForTesting(borealis_window_manager_.get());
@@ -87,8 +82,6 @@
   std::unique_ptr<borealis::BorealisContext> borealis_context_;
   std::unique_ptr<TestingProfile> profile_;
   raw_ptr<BorealisServiceFake, ExperimentalAsh> service_fake_;
-  std::unique_ptr<BorealisDiskManagerDispatcher>
-      borealis_disk_manager_dispatcher_;
   std::unique_ptr<BorealisShutdownMonitor> borealis_shutdown_monitor_;
   std::unique_ptr<BorealisWindowManager> borealis_window_manager_;
   base::HistogramTester histogram_tester_;
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager.h b/chrome/browser/ash/borealis/borealis_disk_manager.h
deleted file mode 100644
index afd8d0b..0000000
--- a/chrome/browser/ash/borealis/borealis_disk_manager.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_H_
-#define CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_H_
-
-#include "base/functional/callback.h"
-#include "base/types/expected.h"
-#include "chrome/browser/ash/borealis/infra/described.h"
-
-namespace borealis {
-
-class BorealisContext;
-enum class BorealisGetDiskInfoResult;
-enum class BorealisResizeDiskResult;
-enum class BorealisSyncDiskSizeResult;
-
-// Service responsible for managing borealis' disk space.
-class BorealisDiskManager {
- public:
-  // Struct for storing the response of a GetDiskInfoRequest.
-  struct GetDiskInfoResponse {
-    // The number of bytes available for the client to use on the VM's disk.
-    // (This is the true amount of available space on the disk minus any space
-    // that is reserved for the buffer)
-    uint64_t available_bytes = 0;
-    // The number of bytes that the VM disk can be expanded by.
-    uint64_t expandable_bytes = 0;
-    // The current size of the disk in bytes.
-    uint64_t disk_size = 0;
-  };
-
-  BorealisDiskManager() = default;
-  virtual ~BorealisDiskManager() = default;
-
-  // Gets information about the borealis disk and the host device, returns
-  // information about how the disk could be resized or an error.
-  virtual void GetDiskInfo(
-      base::OnceCallback<void(
-          base::expected<GetDiskInfoResponse,
-                         Described<BorealisGetDiskInfoResult>>)> callback) = 0;
-
-  // Attempt to expand the VM disk by the number of bytes specified. Returns the
-  // actual size increase in bytes, or an error.
-  virtual void RequestSpace(
-      uint64_t bytes_requested,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback) = 0;
-
-  // Attempt to shrink the VM disk by the number of bytes specified. Returns the
-  // actual size decrease in bytes, or an error.
-  virtual void ReleaseSpace(
-      uint64_t bytes_to_release,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback) = 0;
-
-  // Assesses the disk and resizes it so that it fits within the desired
-  // constraints. This only fails if the process fails to get information
-  // about the disk, the resize transition fails or if another SyncDiskSize
-  // is already in progress. This means that we consider partial resizes or
-  // cases where the disk size is inadequate, but we don't have room to expand
-  // it, as successes. It will return an enum on success or an enum, with an
-  // error string, on failure.
-  virtual void SyncDiskSize(
-      base::OnceCallback<void(
-          base::expected<BorealisSyncDiskSizeResult,
-                         Described<BorealisSyncDiskSizeResult>>)> callback) = 0;
-};
-
-}  // namespace borealis
-
-#endif  // CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_H_
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.cc b/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.cc
deleted file mode 100644
index e6cbeee..0000000
--- a/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h"
-
-#include "chrome/browser/ash/borealis/borealis_metrics.h"
-#include "chrome/browser/ash/borealis/borealis_util.h"
-
-namespace borealis {
-
-// TODO(b/188863477): stop hardcoding these values once they're more
-// accessible.
-constexpr char kBorealisVmName[] = "borealis";
-constexpr char kBorealisContainerName[] = "penguin";
-
-BorealisDiskManagerDispatcher::BorealisDiskManagerDispatcher()
-    : disk_manager_delegate_(nullptr) {}
-
-void BorealisDiskManagerDispatcher::GetDiskInfo(
-    const std::string& origin_vm_name,
-    const std::string& origin_container_name,
-    base::OnceCallback<
-        void(base::expected<BorealisDiskManager::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>)> callback) {
-  std::string error = ValidateRequest(origin_vm_name, origin_container_name);
-  if (!error.empty()) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisGetDiskInfoResult>(
-            BorealisGetDiskInfoResult::kInvalidRequest, std::move(error))));
-    return;
-  }
-  disk_manager_delegate_->GetDiskInfo(std::move(callback));
-}
-
-void BorealisDiskManagerDispatcher::RequestSpace(
-    const std::string& origin_vm_name,
-    const std::string& origin_container_name,
-    uint64_t bytes_requested,
-    base::OnceCallback<
-        void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-        callback) {
-  std::string error = ValidateRequest(origin_vm_name, origin_container_name);
-  if (!error.empty()) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kInvalidRequest, std::move(error))));
-    return;
-  }
-  disk_manager_delegate_->RequestSpace(bytes_requested, std::move(callback));
-}
-
-void BorealisDiskManagerDispatcher::ReleaseSpace(
-    const std::string& origin_vm_name,
-    const std::string& origin_container_name,
-    uint64_t bytes_to_release,
-    base::OnceCallback<
-        void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-        callback) {
-  std::string error = ValidateRequest(origin_vm_name, origin_container_name);
-  if (!error.empty()) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kInvalidRequest, std::move(error))));
-    return;
-  }
-  disk_manager_delegate_->ReleaseSpace(bytes_to_release, std::move(callback));
-}
-
-std::string BorealisDiskManagerDispatcher::ValidateRequest(
-    const std::string& origin_vm_name,
-    const std::string& origin_container_name) {
-  if (origin_vm_name != kBorealisVmName ||
-      origin_container_name != kBorealisContainerName) {
-    return "request does not originate from Borealis";
-  }
-  if (!disk_manager_delegate_) {
-    return "disk manager delegate not set, Borealis probably isn't running";
-  }
-  return "";
-}
-void BorealisDiskManagerDispatcher::SetDiskManagerDelegate(
-    BorealisDiskManager* disk_manager) {
-  DCHECK(!disk_manager_delegate_);
-  disk_manager_delegate_ = disk_manager;
-}
-
-void BorealisDiskManagerDispatcher::RemoveDiskManagerDelegate(
-    BorealisDiskManager* disk_manager) {
-  DCHECK(disk_manager == disk_manager_delegate_);
-  disk_manager_delegate_ = nullptr;
-}
-
-}  // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h b/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h
deleted file mode 100644
index 67a1cc3..0000000
--- a/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_DISPATCHER_H_
-#define CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_DISPATCHER_H_
-
-#include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager.h"
-
-namespace borealis {
-
-// This service dispatches work to the disk manager owned by the running
-// Borealis context (if any). Other services are able to access this service
-// (BorealisDiskManagerDispatcher) in order to dispatch commands directly to the
-// disk manager (which is created at run-time and doesn't live forever). If no
-// disk manager/context exists, the dispatcher will return an error.
-class BorealisDiskManagerDispatcher {
- public:
-  BorealisDiskManagerDispatcher();
-  virtual ~BorealisDiskManagerDispatcher() = default;
-
-  virtual void GetDiskInfo(
-      const std::string& origin_vm_name,
-      const std::string& origin_container_name,
-      base::OnceCallback<
-          void(base::expected<BorealisDiskManager::GetDiskInfoResponse,
-                              Described<BorealisGetDiskInfoResult>>)> callback);
-
-  virtual void RequestSpace(
-      const std::string& origin_vm_name,
-      const std::string& origin_container_name,
-      uint64_t bytes_requested,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback);
-
-  virtual void ReleaseSpace(
-      const std::string& origin_vm_name,
-      const std::string& origin_container_name,
-      uint64_t bytes_to_release,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback);
-
-  virtual void SetDiskManagerDelegate(BorealisDiskManager* disk_manager);
-  virtual void RemoveDiskManagerDelegate(BorealisDiskManager* disk_manager);
-
- private:
-  // Verifies the origin of the request and checks that a delegate exists.
-  std::string ValidateRequest(const std::string& origin_vm_name,
-                              const std::string& origin_container_name);
-
-  // Not owned by us.
-  raw_ptr<BorealisDiskManager, ExperimentalAsh> disk_manager_delegate_;
-};
-
-}  // namespace borealis
-
-#endif  // CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_DISPATCHER_H_
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher_unittest.cc b/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher_unittest.cc
deleted file mode 100644
index 14224f5..0000000
--- a/chrome/browser/ash/borealis/borealis_disk_manager_dispatcher_unittest.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h"
-
-#include "chrome/browser/ash/borealis/borealis_disk_manager.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager_impl.h"
-#include "chrome/browser/ash/borealis/borealis_metrics.h"
-#include "chrome/browser/ash/borealis/testing/callback_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace borealis {
-namespace {
-
-class DiskManagerMock : public BorealisDiskManager {
- public:
-  DiskManagerMock() = default;
-  ~DiskManagerMock() override = default;
-  MOCK_METHOD(void,
-              GetDiskInfo,
-              (base::OnceCallback<
-                  void(base::expected<GetDiskInfoResponse,
-                                      Described<BorealisGetDiskInfoResult>>)>),
-              ());
-  MOCK_METHOD(
-      void,
-      RequestSpace,
-      (uint64_t,
-       base::OnceCallback<void(
-           base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>),
-      ());
-  MOCK_METHOD(
-      void,
-      ReleaseSpace,
-      (uint64_t,
-       base::OnceCallback<void(
-           base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>),
-      ());
-  MOCK_METHOD(void,
-              SyncDiskSize,
-              (base::OnceCallback<
-                  void(base::expected<BorealisSyncDiskSizeResult,
-                                      Described<BorealisSyncDiskSizeResult>>)>),
-              ());
-};
-
-using DiskInfoCallbackFactory = NiceCallbackFactory<void(
-    base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                   Described<BorealisGetDiskInfoResult>>)>;
-
-using RequestDeltaCallbackFactory = NiceCallbackFactory<void(
-    base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>;
-
-TEST(BorealisDiskManagerDispatcherTest, GetDiskInfoFailsIfNamesDontMatch) {
-  BorealisDiskManagerDispatcher dispatcher;
-  DiskManagerMock disk_mock;
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(testing::_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kInvalidRequest);
-          }));
-
-  dispatcher.SetDiskManagerDelegate(&disk_mock);
-  dispatcher.GetDiskInfo("NOTBOREALIS", "penguin", callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, GetDiskInfoFailsIfDelegateNotSet) {
-  BorealisDiskManagerDispatcher dispatcher;
-  DiskInfoCallbackFactory callback_factory;
-
-  EXPECT_CALL(callback_factory, Call(testing::_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kInvalidRequest);
-          }));
-
-  dispatcher.GetDiskInfo("borealis", "penguin", callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, GetDiskInfoSucceedsAndCallsDelegate) {
-  BorealisDiskManagerDispatcher dispatcher;
-  DiskManagerMock disk_mock;
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(disk_mock, GetDiskInfo(testing::_));
-
-  dispatcher.SetDiskManagerDelegate(&disk_mock);
-  dispatcher.GetDiskInfo("borealis", "penguin", callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, RequestSpaceFailsIfNamesDontMatch) {
-  BorealisDiskManagerDispatcher dispatcher;
-  DiskManagerMock disk_mock;
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(testing::_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-
-  dispatcher.SetDiskManagerDelegate(&disk_mock);
-  dispatcher.RequestSpace("borealis", "NOTPENGUIN", 1,
-                          callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, RequestSpaceFailsIfDelegateNotSet) {
-  BorealisDiskManagerDispatcher dispatcher;
-  RequestDeltaCallbackFactory callback_factory;
-
-  EXPECT_CALL(callback_factory, Call(testing::_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-
-  dispatcher.RequestSpace("borealis", "penguin", 1,
-                          callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, RequestSpaceSucceedsAndCallsDelegate) {
-  BorealisDiskManagerDispatcher dispatcher;
-  DiskManagerMock disk_mock;
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(disk_mock, RequestSpace(1, testing::_));
-
-  dispatcher.SetDiskManagerDelegate(&disk_mock);
-  dispatcher.RequestSpace("borealis", "penguin", 1,
-                          callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, ReleaseSpaceFailsIfNamesDontMatch) {
-  BorealisDiskManagerDispatcher dispatcher;
-  DiskManagerMock disk_mock;
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(testing::_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-
-  dispatcher.SetDiskManagerDelegate(&disk_mock);
-  dispatcher.ReleaseSpace("NOTBOREALIS", "NOTPENGUIN", 1,
-                          callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, ReleaseSpaceFailsIfDelegateNotSet) {
-  BorealisDiskManagerDispatcher dispatcher;
-  RequestDeltaCallbackFactory callback_factory;
-
-  EXPECT_CALL(callback_factory, Call(testing::_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-
-  dispatcher.ReleaseSpace("borealis", "penguin", 1,
-                          callback_factory.BindOnce());
-}
-
-TEST(BorealisDiskManagerDispatcherTest, ReleaseSpaceSucceedsAndCallsDelegate) {
-  BorealisDiskManagerDispatcher dispatcher;
-  DiskManagerMock disk_mock;
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(disk_mock, ReleaseSpace(1, testing::_));
-
-  dispatcher.SetDiskManagerDelegate(&disk_mock);
-  dispatcher.ReleaseSpace("borealis", "penguin", 1,
-                          callback_factory.BindOnce());
-}
-
-}  // namespace
-}  // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_impl.cc b/chrome/browser/ash/borealis/borealis_disk_manager_impl.cc
deleted file mode 100644
index 1cf6066..0000000
--- a/chrome/browser/ash/borealis/borealis_disk_manager_impl.cc
+++ /dev/null
@@ -1,749 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/borealis/borealis_disk_manager_impl.h"
-
-#include <string>
-
-#include "ash/constants/ash_features.h"
-#include "base/functional/bind.h"
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "base/ranges/algorithm.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task/thread_pool.h"
-#include "chrome/browser/ash/borealis/borealis_context.h"
-#include "chrome/browser/ash/borealis/borealis_context_manager.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h"
-#include "chrome/browser/ash/borealis/borealis_metrics.h"
-#include "chrome/browser/ash/borealis/borealis_service.h"
-#include "chrome/browser/ash/borealis/infra/transition.h"
-#include "chrome/browser/ash/crostini/crostini_util.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
-#include "chromeos/ash/components/dbus/spaced/spaced_client.h"
-#include "chromeos/ash/components/dbus/vm_concierge/concierge_service.pb.h"
-
-namespace borealis {
-
-struct Nothing {};
-
-enum class DiskManagementVersion {
-  UNMANAGED,  // Disk is unmanaged.
-  CROSDISK,   // Disk is managed by crosdisk and disk manager.
-  BALLOON,    // Disk is managed by a sparse disk and ballooning.
-};
-
-// Helper function to evaluate which disk management settings to use.
-DiskManagementVersion DiskManagementVersion() {
-  if (base::FeatureList::IsEnabled(ash::features::kBorealisStorageBallooning)) {
-    return DiskManagementVersion::BALLOON;
-  }
-  if (base::FeatureList::IsEnabled(ash::features::kBorealisDiskManagement)) {
-    return DiskManagementVersion::CROSDISK;
-  }
-  return DiskManagementVersion::UNMANAGED;
-}
-
-constexpr int64_t kGiB = 1024 * 1024 * 1024;
-constexpr int64_t kDiskHeadroomBytes = 1 * kGiB;
-constexpr int64_t kTargetBufferBytes = 2 * kGiB;
-constexpr int64_t kDiskRoundingBytes = 2 * 1024 * 1024;
-constexpr int64_t kTargetBufferLowerBound = kTargetBufferBytes * 0.9;
-constexpr int64_t kTargetBufferUpperBound = kTargetBufferBytes * 1.1;
-
-void BorealisDiskManagerImpl::FreeSpaceProvider::Get(
-    base::OnceCallback<void(absl::optional<int64_t>)> callback) {
-  ash::SpacedClient::Get()->GetFreeDiskSpace(crostini::kHomeDirectory,
-                                             std::move(callback));
-}
-
-struct BorealisDiskManagerImpl::BorealisDiskInfo {
-  // How much the disk can be expanded by (free space on the host device minus
-  // a |kDiskHeadroomBytes| buffer).
-  int64_t expandable_space = 0;
-  // How much available space is left on the disk.
-  int64_t available_space = 0;
-  // The current size of the disk.
-  int64_t disk_size = 0;
-  // The minimum size that the disk can currently be shrunk to,
-  int64_t min_size = 0;
-  // Image type of the disk.
-  vm_tools::concierge::DiskImageType disk_type;
-  // If the disk isn't fixed, we shouldn't be resizing it.
-  bool has_fixed_size = false;
-};
-
-BorealisDiskManagerImpl::BorealisDiskManagerImpl(const BorealisContext* context)
-    : context_(context),
-      service_(borealis::BorealisService::GetForProfile(context_->profile())),
-      free_space_provider_(std::make_unique<FreeSpaceProvider>()),
-      weak_factory_(this) {
-  service_->DiskManagerDispatcher().SetDiskManagerDelegate(this);
-}
-
-BorealisDiskManagerImpl::~BorealisDiskManagerImpl() {
-  service_->DiskManagerDispatcher().RemoveDiskManagerDelegate(this);
-}
-
-// Helper function that returns how many bytes the |available_space| would
-// need to be expanded by in order to regenreate the buffer.
-int64_t MissingBufferBytes(int64_t available_space) {
-  return std::max(int64_t(kTargetBufferBytes - available_space), int64_t(0));
-}
-
-// Helper function that returns how much space is available when excluding
-// the buffer space.
-int64_t ExcludeBufferBytes(int64_t available_space) {
-  return std::max(int64_t(available_space - kTargetBufferBytes), int64_t(0));
-}
-
-class BorealisDiskManagerImpl::BuildDiskInfo
-    : public Transition<BorealisDiskInfo,
-                        BorealisDiskInfo,
-                        Described<BorealisGetDiskInfoResult>> {
- public:
-  explicit BuildDiskInfo(
-      BorealisDiskManagerImpl::FreeSpaceProvider* free_space_provider,
-      const BorealisContext* context)
-      : free_space_provider_(free_space_provider),
-        context_(context),
-        weak_factory_(this) {}
-
-  void Start(std::unique_ptr<BorealisDiskManagerImpl::BorealisDiskInfo>
-                 start_instance) override {
-    disk_info_ = std::move(start_instance);
-    free_space_provider_->Get(base::BindOnce(
-        &BuildDiskInfo::HandleFreeSpaceResult, weak_factory_.GetWeakPtr()));
-  }
-
- private:
-  void HandleFreeSpaceResult(absl::optional<int64_t> free_space) {
-    if (!free_space.has_value() || free_space.value() < 0) {
-      Fail(Described<BorealisGetDiskInfoResult>(
-          BorealisGetDiskInfoResult::kFailedGettingExpandableSpace,
-          "failed to get the amount of free disk space on the host"));
-      return;
-    }
-    disk_info_->expandable_space =
-        std::max(int64_t(free_space.value() - kDiskHeadroomBytes), int64_t(0));
-    vm_tools::concierge::ListVmDisksRequest request;
-    request.set_cryptohome_id(
-        ash::ProfileHelper::GetUserIdHashFromProfile(context_->profile()));
-    request.set_storage_location(vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT);
-    request.set_vm_name(context_->vm_name());
-    ash::ConciergeClient::Get()->ListVmDisks(
-        std::move(request),
-        base::BindOnce(&BuildDiskInfo::HandleListVmDisksResult,
-                       weak_factory_.GetWeakPtr()));
-  }
-
-  void HandleListVmDisksResult(
-      absl::optional<vm_tools::concierge::ListVmDisksResponse> response) {
-    if (!response) {
-      Fail(Described<BorealisGetDiskInfoResult>(
-          BorealisGetDiskInfoResult::kConciergeFailed,
-          "failed to get response from concierge"));
-      return;
-    }
-    if (!response->success()) {
-      Fail(Described<BorealisGetDiskInfoResult>(
-          BorealisGetDiskInfoResult::kConciergeFailed,
-          "concierge failed to list vm disks, returned error: " +
-              response->failure_reason()));
-      return;
-    }
-    const std::string& vm_name = context_->vm_name();
-    auto image = base::ranges::find(response->images(), vm_name,
-                                    &vm_tools::concierge::VmDiskInfo::name);
-    if (image == response->images().end()) {
-      Fail(Described<BorealisGetDiskInfoResult>(
-          BorealisGetDiskInfoResult::kConciergeFailed,
-          "no VM found with name " + vm_name));
-      return;
-    }
-
-    disk_info_->available_space = image->available_space();
-    disk_info_->min_size = image->min_size();
-    disk_info_->disk_size = image->size();
-    disk_info_->disk_type = image->image_type();
-    disk_info_->has_fixed_size = image->user_chosen_size();
-
-    Succeed(std::move(disk_info_));
-  }
-
-  raw_ptr<BorealisDiskManagerImpl::FreeSpaceProvider, ExperimentalAsh>
-      free_space_provider_;
-  const raw_ptr<const BorealisContext, ExperimentalAsh> context_;
-  std::unique_ptr<BorealisDiskManagerImpl::BorealisDiskInfo> disk_info_;
-  base::WeakPtrFactory<BuildDiskInfo> weak_factory_;
-};
-
-class BorealisDiskManagerImpl::ResizeDisk
-    : public Transition<BorealisDiskInfo,
-                        std::pair<BorealisDiskInfo, BorealisDiskInfo>,
-                        Described<BorealisResizeDiskResult>>,
-      public ash::ConciergeClient::DiskImageObserver {
- public:
-  explicit ResizeDisk(
-      int64_t space_delta,
-      bool client_request,
-      BorealisDiskManagerImpl::FreeSpaceProvider* free_space_provider,
-      const BorealisContext* context)
-      : space_delta_(space_delta),
-        client_request_(client_request),
-        free_space_provider_(free_space_provider),
-        context_(context),
-        weak_factory_(this) {}
-
-  ~ResizeDisk() override {
-    ash::ConciergeClient::Get()->RemoveDiskImageObserver(this);
-  }
-
-  void Start(std::unique_ptr<BorealisDiskManagerImpl::BorealisDiskInfo>
-                 start_instance) override {
-    DCHECK(!build_disk_info_transition_);
-    build_disk_info_transition_ =
-        std::make_unique<BuildDiskInfo>(free_space_provider_, context_);
-    build_disk_info_transition_->Begin(
-        std::move(start_instance), base::BindOnce(&ResizeDisk::HandleDiskInfo,
-                                                  weak_factory_.GetWeakPtr()));
-  }
-
- private:
-  // Sparse disks can be converted to fixed disks through a regular resize
-  // operation. This function adjusts how the resize flow uses the disk
-  // information from sparse disks.
-  void ConvertToFixedIfNeeded() {
-    if (!original_disk_info_.has_fixed_size) {
-      // Based on how sparse disks work, it's hard to know exactly what the
-      // state of the disk is. I.E sometimes the "minimum size" of the disk is
-      // larger than the actual size of the disk and the "available space" on
-      // the disk is typically much greater than what the disk actually has. To
-      // remedy this, we set the disk size so that it is at least the minimum
-      // disk size and then add the target buffer so that we know that the
-      // resized disk will have at least the target buffer size as available
-      // space (before any additional changes).
-      original_disk_info_.disk_size = std::max(original_disk_info_.min_size,
-                                               original_disk_info_.disk_size) +
-                                      kTargetBufferBytes;
-      original_disk_info_.available_space = kTargetBufferBytes;
-      original_disk_info_.expandable_space -= kTargetBufferBytes;
-
-      // When shrinking a sparse disk, we are more interested in converting it
-      // to a fixed size disk, we set the delta to 0 to loosen the success
-      // criteria.
-      if (space_delta_ < 0) {
-        space_delta_ = 0;
-      }
-    }
-  }
-
-  void HandleDiskInfo(
-      base::expected<std::unique_ptr<BorealisDiskInfo>,
-                     Described<BorealisGetDiskInfoResult>> disk_info_or_error) {
-    build_disk_info_transition_.reset();
-    if (!disk_info_or_error.has_value()) {
-      Fail(Described<BorealisResizeDiskResult>(
-          BorealisResizeDiskResult::kFailedToGetDiskInfo,
-          "BuildDiskInfo failed: " + disk_info_or_error.error().description()));
-      return;
-    }
-    original_disk_info_ = *disk_info_or_error.value();
-    if (original_disk_info_.disk_type !=
-        vm_tools::concierge::DiskImageType::DISK_IMAGE_RAW) {
-      Fail(Described<BorealisResizeDiskResult>(
-          BorealisResizeDiskResult::kInvalidDiskType,
-          "cannot resize disk: disk type '" +
-              base::NumberToString(original_disk_info_.disk_type) +
-              "' cannot be resized"));
-      return;
-    }
-
-    // The information we get on sparse disks is accurate, but needs to be used
-    // differently during a resize so that we can:
-    // 1. convert the sparse disk to a parameter-conforming fixed size disk.
-    // 2. verify that we resized the disk by the requested delta, on top of any
-    //    changes we needed to make because of the sparse->fixed conversion.
-    ConvertToFixedIfNeeded();
-    if (space_delta_ > 0) {
-      if (client_request_) {
-        // Regenerate the buffer, if needed, by tacking it onto the existing
-        // request.
-        space_delta_ += MissingBufferBytes(original_disk_info_.available_space);
-      }
-      if (original_disk_info_.expandable_space < space_delta_) {
-        Fail(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kNotEnoughExpandableSpace,
-            "the space requested exceeds the space that is expandable"));
-        return;
-      }
-    }
-    if (space_delta_ < 0) {
-      if (original_disk_info_.available_space + space_delta_ <
-          kTargetBufferBytes) {
-        Fail(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kWouldNotLeaveEnoughSpace,
-            "shrinking the disk would not leave enough space available"));
-        return;
-      }
-      if (original_disk_info_.disk_size + space_delta_ <=
-          original_disk_info_.min_size) {
-        if (original_disk_info_.disk_size < original_disk_info_.min_size) {
-          Fail(Described<BorealisResizeDiskResult>(
-              BorealisResizeDiskResult::kViolatesMinimumSize,
-              "cannot shrink the disk below its minimum size"));
-          return;
-        }
-        space_delta_ = original_disk_info_.min_size -
-                       original_disk_info_.disk_size + kDiskRoundingBytes;
-      }
-    }
-    vm_tools::concierge::ResizeDiskImageRequest request;
-    request.set_cryptohome_id(
-        ash::ProfileHelper::GetUserIdHashFromProfile(context_->profile()));
-    request.set_vm_name(context_->vm_name());
-    request.set_disk_size(space_delta_ + original_disk_info_.disk_size);
-    ash::ConciergeClient::Get()->ResizeDiskImage(
-        std::move(request), base::BindOnce(&ResizeDisk::HandleResizeResponse,
-                                           weak_factory_.GetWeakPtr()));
-  }
-
-  void HandleResizeResponse(
-      absl::optional<vm_tools::concierge::ResizeDiskImageResponse> response) {
-    if (!response) {
-      GetUpdatedDiskInfo("got null response from concierge resizing");
-      return;
-    } else if (response->status() ==
-               vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED) {
-      GetUpdatedDiskInfo("");
-    } else if (response->status() ==
-               vm_tools::concierge::DiskImageStatus::DISK_STATUS_IN_PROGRESS) {
-      uuid_ = response->command_uuid();
-      ash::ConciergeClient::Get()->AddDiskImageObserver(this);
-    } else {
-      GetUpdatedDiskInfo(
-          "got an unexpected or error status from concierge when resizing: " +
-          base::NumberToString(response->status()));
-      return;
-    }
-  }
-
-  // ash::ConciergeClient::DiskImageObserver
-  void OnDiskImageProgress(
-      const vm_tools::concierge::DiskImageStatusResponse& signal) override {
-    if (signal.command_uuid() != uuid_) {
-      return;
-    }
-    switch (signal.status()) {
-      case vm_tools::concierge::DiskImageStatus::DISK_STATUS_IN_PROGRESS:
-        break;
-      case vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED:
-        GetUpdatedDiskInfo("");
-        break;
-      default:
-        GetUpdatedDiskInfo(
-            "received failed or unrecognised status when resizing: " +
-            base::NumberToString(signal.status()) + " " +
-            signal.failure_reason());
-    }
-  }
-
-  void GetUpdatedDiskInfo(std::string error) {
-    if (!error.empty()) {
-      Fail(Described<BorealisResizeDiskResult>(
-          BorealisResizeDiskResult::kConciergeFailed, std::move(error)));
-      return;
-    }
-    DCHECK(!build_disk_info_transition_);
-    auto disk_info = std::make_unique<BorealisDiskInfo>();
-    build_disk_info_transition_ =
-        std::make_unique<BuildDiskInfo>(free_space_provider_, context_);
-    build_disk_info_transition_->Begin(
-        std::move(disk_info), base::BindOnce(&ResizeDisk::HandleUpdatedDiskInfo,
-                                             weak_factory_.GetWeakPtr()));
-  }
-
-  void HandleUpdatedDiskInfo(
-      base::expected<std::unique_ptr<BorealisDiskInfo>,
-                     Described<BorealisGetDiskInfoResult>> disk_info_or_error) {
-    if (!disk_info_or_error.has_value()) {
-      Fail(Described<BorealisResizeDiskResult>(
-          BorealisResizeDiskResult::kFailedGettingUpdate,
-          "GetUpdatedDiskInfo failed: " +
-              disk_info_or_error.error().description()));
-      return;
-    }
-    updated_disk_info_ = *disk_info_or_error.value();
-    Succeed(std::make_unique<std::pair<BorealisDiskInfo, BorealisDiskInfo>>(
-        std::make_pair(original_disk_info_, updated_disk_info_)));
-  }
-
-  int64_t space_delta_;
-  // Will emit additional metrics if the transition is for a client request.
-  bool client_request_;
-  raw_ptr<BorealisDiskManagerImpl::FreeSpaceProvider, ExperimentalAsh>
-      free_space_provider_;
-  std::string uuid_;
-  BorealisDiskInfo original_disk_info_;
-  BorealisDiskInfo updated_disk_info_;
-  const raw_ptr<const BorealisContext, ExperimentalAsh> context_;
-  std::unique_ptr<BuildDiskInfo> build_disk_info_transition_;
-  base::WeakPtrFactory<ResizeDisk> weak_factory_;
-};
-
-class BorealisDiskManagerImpl::SyncDisk
-    : public Transition<Nothing,
-                        BorealisSyncDiskSizeResult,
-                        Described<BorealisSyncDiskSizeResult>> {
- public:
-  explicit SyncDisk(
-      BorealisDiskManagerImpl::FreeSpaceProvider* free_space_provider,
-      const BorealisContext* context)
-      : free_space_provider_(free_space_provider),
-        context_(context),
-        build_disk_info_transition_(free_space_provider_, context_),
-        weak_factory_(this) {}
-
-  void Start(std::unique_ptr<Nothing> start_instance) override {
-    build_disk_info_transition_.Begin(
-        std::make_unique<BorealisDiskInfo>(),
-        base::BindOnce(&SyncDisk::HandleDiskInfo, weak_factory_.GetWeakPtr()));
-  }
-
- private:
-  void HandleDiskInfo(
-      base::expected<std::unique_ptr<BorealisDiskInfo>,
-                     Described<BorealisGetDiskInfoResult>> disk_info_or_error) {
-    if (!disk_info_or_error.has_value()) {
-      Fail(Described<BorealisSyncDiskSizeResult>(
-          BorealisSyncDiskSizeResult::kFailedToGetDiskInfo,
-          "BuildDiskInfo failed: " + disk_info_or_error.error().description()));
-      return;
-    }
-    if (!disk_info_or_error.value()->has_fixed_size) {
-      // We're currently not handling sparse sized disks.
-      Succeed(std::make_unique<BorealisSyncDiskSizeResult>(
-          BorealisSyncDiskSizeResult::kDiskNotFixed));
-      return;
-    }
-    const BorealisDiskInfo& disk_info = *disk_info_or_error.value();
-    if (IsDiskSizeWithinBounds(disk_info)) {
-      Succeed(std::make_unique<BorealisSyncDiskSizeResult>(
-          BorealisSyncDiskSizeResult::kNoActionNeeded));
-      return;
-    }
-    int64_t delta = kTargetBufferBytes - disk_info.available_space;
-    if (delta > disk_info.expandable_space) {
-      delta = disk_info.expandable_space;
-    }
-    if (delta == 0) {
-      LOG(WARNING) << "borealis' available space is not within parameters, "
-                      "but there is not enough free space to expand it";
-      Succeed(std::make_unique<BorealisSyncDiskSizeResult>(
-          BorealisSyncDiskSizeResult::kNotEnoughSpaceToExpand));
-      return;
-    }
-    resize_disk_transition_ = std::make_unique<ResizeDisk>(
-        delta, /*client_request=*/false, free_space_provider_, context_);
-    resize_disk_transition_->Begin(
-        std::move(disk_info_or_error.value()),
-        base::BindOnce(&SyncDisk::HandleResizeAttempt,
-                       weak_factory_.GetWeakPtr()));
-    return;
-  }
-
-  void HandleResizeAttempt(
-      base::expected<
-          std::unique_ptr<std::pair<BorealisDiskInfo, BorealisDiskInfo>>,
-          Described<BorealisResizeDiskResult>> disk_info_or_error) {
-    if (!disk_info_or_error.has_value()) {
-      // Sometimes the disk size can get out of sync, so that btrfs reports that
-      // the minimum size of the disk is larger than the actual disk size. In
-      // this case we will get a kViolatesMinimumSize from trying to resize the
-      // disk. We don't want to block the startup process because of this error
-      // so we special case it as a success.
-      if (disk_info_or_error.error().error() ==
-          BorealisResizeDiskResult::kViolatesMinimumSize) {
-        LOG(WARNING) << "disk was unable to be shrunk due to the disk "
-                        "already being smaller than the minimum size";
-        Succeed(std::make_unique<BorealisSyncDiskSizeResult>(
-            BorealisSyncDiskSizeResult::kDiskSizeSmallerThanMin));
-        return;
-      }
-      Fail(Described<BorealisSyncDiskSizeResult>(
-          BorealisSyncDiskSizeResult::kResizeFailed,
-          "resize failed: " + disk_info_or_error.error().description()));
-      return;
-    }
-    if (!IsDiskSizeWithinBounds(disk_info_or_error.value()->second)) {
-      LOG(WARNING) << "disk resized successfully, but available space is not "
-                      "within its parameters";
-      Succeed(std::make_unique<BorealisSyncDiskSizeResult>(
-          BorealisSyncDiskSizeResult::kResizedPartially));
-    }
-    Succeed(std::make_unique<BorealisSyncDiskSizeResult>(
-        BorealisSyncDiskSizeResult::kResizedSuccessfully));
-    return;
-  }
-
-  bool IsDiskSizeWithinBounds(const BorealisDiskInfo& disk_info) {
-    return disk_info.available_space >= kTargetBufferLowerBound &&
-           disk_info.available_space <= kTargetBufferUpperBound;
-  }
-
-  raw_ptr<BorealisDiskManagerImpl::FreeSpaceProvider, ExperimentalAsh>
-      free_space_provider_;
-  const raw_ptr<const BorealisContext, ExperimentalAsh> context_;
-  BuildDiskInfo build_disk_info_transition_;
-  std::unique_ptr<ResizeDisk> resize_disk_transition_;
-  base::WeakPtrFactory<SyncDisk> weak_factory_;
-};
-
-void BorealisDiskManagerImpl::GetDiskInfo(
-    base::OnceCallback<
-        void(base::expected<GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>)> callback) {
-  if (!base::FeatureList::IsEnabled(ash::features::kBorealisDiskManagement)) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisGetDiskInfoResult>(
-            BorealisGetDiskInfoResult::kInvalidRequest,
-            "GetDiskInfo failed: feature not enabled")));
-    return;
-  }
-  auto disk_info = std::make_unique<BorealisDiskInfo>();
-  request_count_++;
-  if (build_disk_info_transition_) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisGetDiskInfoResult>(
-            BorealisGetDiskInfoResult::kAlreadyInProgress,
-            "another GetDiskInfo request is in progress")));
-    return;
-  }
-
-  build_disk_info_transition_ =
-      std::make_unique<BuildDiskInfo>(free_space_provider_.get(), context_);
-  build_disk_info_transition_->Begin(
-      std::move(disk_info),
-      base::BindOnce(&BorealisDiskManagerImpl::BuildGetDiskInfoResponse,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void BorealisDiskManagerImpl::BuildGetDiskInfoResponse(
-    base::OnceCallback<
-        void(base::expected<GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>)> callback,
-    base::expected<std::unique_ptr<BorealisDiskInfo>,
-                   Described<BorealisGetDiskInfoResult>> disk_info_or_error) {
-  build_disk_info_transition_.reset();
-  if (!disk_info_or_error.has_value()) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisGetDiskInfoResult>(
-            std::move(disk_info_or_error.error()))));
-    return;
-  }
-  GetDiskInfoResponse response;
-  // We are not supporting the case where users enable the flag and then later
-  // disable it (after their disk has been converted to a fixed size). The
-  // workaround for this is to reinstall the VM or use VMC to manually manage
-  // the disk.
-  if (base::FeatureList::IsEnabled(ash::features::kBorealisDiskManagement)) {
-    if (disk_info_or_error.value()->has_fixed_size) {
-      response.available_bytes =
-          ExcludeBufferBytes(disk_info_or_error.value()->available_space);
-    } else {
-      // If the disk is still sparse, then we set the available space to 0 in
-      // order to force the client to request for more space if it needs any.
-      response.available_bytes = 0;
-    }
-    // Space for regenerating the buffer needs to be set aside, so we mark it
-    // as non-expandable to the client in our response.
-    response.expandable_bytes =
-        disk_info_or_error.value()->expandable_space -
-        MissingBufferBytes(disk_info_or_error.value()->available_space);
-    response.disk_size = disk_info_or_error.value()->disk_size;
-  } else {
-    // If the flag is not active, then the disk should not be resized and the VM
-    // can only make use of what it has available.
-    response.available_bytes = disk_info_or_error.value()->available_space;
-    response.expandable_bytes = 0;
-    response.disk_size = 0;
-  }
-  std::move(callback).Run(
-      base::expected<GetDiskInfoResponse, Described<BorealisGetDiskInfoResult>>(
-          response));
-}
-
-void BorealisDiskManagerImpl::RequestSpaceDelta(
-    int64_t target_delta,
-    base::OnceCallback<
-        void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-        callback) {
-  DCHECK(target_delta != 0);
-  if (resize_disk_transition_) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kAlreadyInProgress,
-            "another ResizeDisk request is in progress")));
-    return;
-  }
-
-  auto disk_info = std::make_unique<BorealisDiskInfo>();
-  int64_t space_delta =
-      target_delta + (target_delta > 0 ? kDiskRoundingBytes : 0);
-  resize_disk_transition_ =
-      std::make_unique<ResizeDisk>(space_delta, /*client_request=*/true,
-                                   free_space_provider_.get(), context_);
-  resize_disk_transition_->Begin(
-      std::move(disk_info),
-      base::BindOnce(&BorealisDiskManagerImpl::OnRequestSpaceDelta,
-                     weak_factory_.GetWeakPtr(), target_delta,
-                     std::move(callback)));
-}
-
-void BorealisDiskManagerImpl::OnRequestSpaceDelta(
-    int64_t target_delta,
-    base::OnceCallback<
-        void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-        callback,
-    base::expected<
-        std::unique_ptr<std::pair<BorealisDiskInfo, BorealisDiskInfo>>,
-        Described<BorealisResizeDiskResult>> disk_info_or_error) {
-  bool expanding = target_delta > 0;
-  resize_disk_transition_.reset();
-  if (!disk_info_or_error.has_value()) {
-    std::move(callback).Run(
-        base::unexpected(std::move(disk_info_or_error.error())));
-    return;
-  }
-  int64_t delta = disk_info_or_error.value()->second.disk_size -
-                  disk_info_or_error.value()->first.disk_size;
-  if (expanding) {
-    // Exclude the space that was required to regenerate the buffer.
-    delta -=
-        MissingBufferBytes(disk_info_or_error.value()->first.available_space);
-    if (delta < target_delta) {
-      std::move(callback).Run(
-          base::unexpected(Described<BorealisResizeDiskResult>(
-              BorealisResizeDiskResult::kFailedToFulfillRequest,
-              "requested " + base::NumberToString(target_delta) +
-                  " bytes but got " + base::NumberToString(delta) + " bytes")));
-      return;
-    }
-  } else {
-    if (delta >= 0) {
-      if (!disk_info_or_error.value()->first.has_fixed_size &&
-          disk_info_or_error.value()->second.has_fixed_size) {
-        // We succeeded in trying to convert the disk to a fixed size.
-        std::move(callback).Run(
-            base::expected<uint64_t, Described<BorealisResizeDiskResult>>(0));
-        return;
-      }
-      std::move(callback).Run(
-          base::unexpected(Described<BorealisResizeDiskResult>(
-              BorealisResizeDiskResult::kFailedToFulfillRequest,
-              "failed to shrink the disk")));
-      return;
-    }
-  }
-  std::move(callback).Run(
-      base::expected<uint64_t, Described<BorealisResizeDiskResult>>(
-          abs(delta)));
-}
-
-void BorealisDiskManagerImpl::RequestSpace(
-    uint64_t bytes_requested,
-    base::OnceCallback<
-        void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-        callback) {
-  if (!base::FeatureList::IsEnabled(ash::features::kBorealisDiskManagement)) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kInvalidRequest,
-            "RequestSpace failed: feature not enabled")));
-    return;
-  }
-  request_count_++;
-  if (bytes_requested == 0) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kInvalidRequest,
-            "requested_bytes must not be 0")));
-    return;
-  }
-  RequestSpaceDelta(bytes_requested, std::move(callback));
-}
-
-void BorealisDiskManagerImpl::ReleaseSpace(
-    uint64_t bytes_to_release,
-    base::OnceCallback<
-        void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-        callback) {
-  if (!base::FeatureList::IsEnabled(ash::features::kBorealisDiskManagement)) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kInvalidRequest,
-            "ReleaseSpace failed: feature not enabled")));
-    return;
-  }
-  request_count_++;
-  if (bytes_to_release == 0) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kInvalidRequest,
-            "bytes_to_release must not be 0")));
-    return;
-  }
-  if (bytes_to_release > std::numeric_limits<int64_t>::max()) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisResizeDiskResult>(
-            BorealisResizeDiskResult::kOverflowError,
-            "bytes_to_release overflowed")));
-    return;
-  }
-  RequestSpaceDelta(int64_t(bytes_to_release) * -1, std::move(callback));
-}
-
-void BorealisDiskManagerImpl::SyncDiskSize(
-    base::OnceCallback<
-        void(base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>>)> callback) {
-  if (!base::FeatureList::IsEnabled(ash::features::kBorealisDiskManagement)) {
-    std::move(callback).Run(
-        base::expected<BorealisSyncDiskSizeResult,
-                       Described<BorealisSyncDiskSizeResult>>(
-            BorealisSyncDiskSizeResult::kNoActionNeeded));
-    return;
-  }
-  if (sync_disk_transition_) {
-    std::move(callback).Run(
-        base::unexpected(Described<BorealisSyncDiskSizeResult>(
-            BorealisSyncDiskSizeResult::kAlreadyInProgress,
-            "another SyncDiskSize request is in progress")));
-    return;
-  }
-  sync_disk_transition_ =
-      std::make_unique<SyncDisk>(free_space_provider_.get(), context_);
-  sync_disk_transition_->Begin(
-      std::make_unique<Nothing>(),
-      base::BindOnce(&BorealisDiskManagerImpl::OnSyncDiskSize,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void BorealisDiskManagerImpl::OnSyncDiskSize(
-    base::OnceCallback<
-        void(base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>>)> callback,
-    base::expected<std::unique_ptr<BorealisSyncDiskSizeResult>,
-                   Described<BorealisSyncDiskSizeResult>> result) {
-  sync_disk_transition_.reset();
-  if (!result.has_value()) {
-    std::move(callback).Run(base::unexpected(std::move(result.error())));
-    return;
-  }
-  std::move(callback).Run(*result.value());
-}
-
-}  // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_impl.h b/chrome/browser/ash/borealis/borealis_disk_manager_impl.h
deleted file mode 100644
index 2ecae21..0000000
--- a/chrome/browser/ash/borealis/borealis_disk_manager_impl.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_IMPL_H_
-#define CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_IMPL_H_
-
-#include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/ash/borealis/borealis_context.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager.h"
-#include "chrome/browser/ash/borealis/borealis_service.h"
-
-namespace borealis {
-// Amount of space, in bytes, that borealis needs to leave free on the host.
-extern const int64_t kTargetBufferBytes;
-// Amount of space, in bytes, that should be left available on the VM disk.
-extern const int64_t kDiskHeadroomBytes;
-
-// Service responsible for managing borealis' disk space.
-class BorealisDiskManagerImpl : public BorealisDiskManager {
- public:
-  // Provider for returning the number of free bytes left on the host device.
-  class FreeSpaceProvider {
-   public:
-    FreeSpaceProvider() = default;
-    virtual ~FreeSpaceProvider() = default;
-    virtual void Get(
-        base::OnceCallback<void(absl::optional<int64_t>)> callback);
-  };
-
-  explicit BorealisDiskManagerImpl(const BorealisContext* context);
-  BorealisDiskManagerImpl(const BorealisDiskManagerImpl&) = delete;
-  BorealisDiskManagerImpl& operator=(const BorealisDiskManagerImpl&) = delete;
-  ~BorealisDiskManagerImpl() override;
-
-  void GetDiskInfo(base::OnceCallback<
-                   void(base::expected<GetDiskInfoResponse,
-                                       Described<BorealisGetDiskInfoResult>>)>
-                       callback) override;
-  void RequestSpace(
-      uint64_t bytes_requested,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback) override;
-  void ReleaseSpace(
-      uint64_t bytes_to_release,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback) override;
-  void SyncDiskSize(base::OnceCallback<
-                    void(base::expected<BorealisSyncDiskSizeResult,
-                                        Described<BorealisSyncDiskSizeResult>>)>
-                        callback) override;
-
-  void SetFreeSpaceProviderForTesting(
-      std::unique_ptr<FreeSpaceProvider> provider) {
-    free_space_provider_ = std::move(provider);
-  }
-
- private:
-  // Struct for storing information about the VM's disk (space is considered in
-  // bytes).
-  struct BorealisDiskInfo;
-
-  // Transition class representing the process of getting information about the
-  // host and VM disk. Returns an error (string) or a result (BorealisDiskInfo).
-  class BuildDiskInfo;
-
-  // Transition class representing the process of resizing the disk. Returns an
-  // error (string) or a result (pair of BorealisDiskInfos, The first references
-  // the original state and the second references the updated state after the
-  // resize).
-  class ResizeDisk;
-
-  // Transition class representing the process of assessing the state of the VM
-  // disk and adjusting it to fit within the appropriate parameters if needed.
-  // Specifically, when the available space on the disk does not match the
-  // target buffer size +/-10%, we will resize the disk.
-  class SyncDisk;
-
-  // Handles the results of a GetDiskInfo request.
-  void BuildGetDiskInfoResponse(
-      base::OnceCallback<
-          void(base::expected<GetDiskInfoResponse,
-                              Described<BorealisGetDiskInfoResult>>)> callback,
-      base::expected<std::unique_ptr<BorealisDiskInfo>,
-                     Described<BorealisGetDiskInfoResult>> disk_info_or_error);
-
-  // Handles the RequestSpace and ReleaseSpace requests. |bytes_requested| from
-  // RequestSpace becomes a positive delta that expands the disk and the
-  // |bytes_to_release| from ReleaseSpace becomes a negative delta that shrinks
-  // the disk (an error is returned if the unit64_t can't be converted to a
-  // negative int64_t).
-  void RequestSpaceDelta(
-      int64_t target_delta,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback);
-
-  void OnRequestSpaceDelta(
-      int64_t target_delta,
-      base::OnceCallback<
-          void(base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>
-          callback,
-      base::expected<
-          std::unique_ptr<std::pair<BorealisDiskInfo, BorealisDiskInfo>>,
-          Described<BorealisResizeDiskResult>> success_or_error);
-
-  void OnSyncDiskSize(
-      base::OnceCallback<
-          void(base::expected<BorealisSyncDiskSizeResult,
-                              Described<BorealisSyncDiskSizeResult>>)> callback,
-      base::expected<std::unique_ptr<BorealisSyncDiskSizeResult>,
-                     Described<BorealisSyncDiskSizeResult>> success_or_error);
-
-  const raw_ptr<const BorealisContext, ExperimentalAsh> context_;
-  const raw_ptr<BorealisService, ExperimentalAsh> service_;
-  int request_count_{0};
-  std::unique_ptr<BuildDiskInfo> build_disk_info_transition_;
-  std::unique_ptr<ResizeDisk> resize_disk_transition_;
-  std::unique_ptr<SyncDisk> sync_disk_transition_;
-  std::unique_ptr<FreeSpaceProvider> free_space_provider_;
-  base::WeakPtrFactory<BorealisDiskManagerImpl> weak_factory_;
-};
-
-}  // namespace borealis
-
-#endif  // CHROME_BROWSER_ASH_BOREALIS_BOREALIS_DISK_MANAGER_IMPL_H_
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_unittest.cc b/chrome/browser/ash/borealis/borealis_disk_manager_unittest.cc
deleted file mode 100644
index e0f0d42..0000000
--- a/chrome/browser/ash/borealis/borealis_disk_manager_unittest.cc
+++ /dev/null
@@ -1,1602 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/borealis/borealis_disk_manager_impl.h"
-
-#include <memory>
-#include <queue>
-
-#include "ash/constants/ash_features.h"
-#include "base/functional/callback.h"
-#include "base/functional/callback_helpers.h"
-#include "base/memory/raw_ptr.h"
-#include "base/test/bind.h"
-#include "chrome/browser/ash/borealis/borealis_context.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h"
-#include "chrome/browser/ash/borealis/borealis_features.h"
-#include "chrome/browser/ash/borealis/borealis_metrics.h"
-#include "chrome/browser/ash/borealis/borealis_service_fake.h"
-#include "chrome/browser/ash/borealis/borealis_window_manager.h"
-#include "chrome/browser/ash/borealis/testing/callback_factory.h"
-#include "chrome/browser/ash/guest_os/dbus_test_helper.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chromeos/ash/components/dbus/cicerone/fake_cicerone_client.h"
-#include "chromeos/ash/components/dbus/concierge/fake_concierge_client.h"
-#include "chromeos/ash/components/dbus/dbus_thread_manager.h"
-#include "chromeos/ash/components/dbus/seneschal/seneschal_client.h"
-#include "chromeos/ash/components/dbus/vm_concierge/concierge_service.pb.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace borealis {
-namespace {
-
-using ::testing::_;
-using ::testing::Not;
-
-constexpr uint64_t kGiB = 1024 * 1024 * 1024;
-
-using BorealisGetDiskSpaceInfoCallback =
-    base::OnceCallback<void(absl::optional<int64_t>)>;
-
-class FreeSpaceProviderMock
-    : public BorealisDiskManagerImpl::FreeSpaceProvider {
- public:
-  MOCK_METHOD(void, Get, (BorealisGetDiskSpaceInfoCallback), ());
-};
-
-using DiskInfoCallbackFactory = StrictCallbackFactory<void(
-    base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                   Described<BorealisGetDiskInfoResult>>)>;
-
-using RequestDeltaCallbackFactory = StrictCallbackFactory<void(
-    base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>;
-
-using SyncDiskCallbackFactory = NiceCallbackFactory<void(
-    base::expected<BorealisSyncDiskSizeResult,
-                   Described<BorealisSyncDiskSizeResult>>)>;
-
-class BorealisDiskDispatcherMock : public BorealisDiskManagerDispatcher {
- public:
-  MOCK_METHOD(void,
-              GetDiskInfo,
-              (const std::string&,
-               const std::string&,
-               base::OnceCallback<
-                   void(base::expected<BorealisDiskManager::GetDiskInfoResponse,
-                                       Described<BorealisGetDiskInfoResult>>)>),
-              ());
-  MOCK_METHOD(
-      void,
-      RequestSpace,
-      (const std::string&,
-       const std::string&,
-       uint64_t,
-       base::OnceCallback<void(
-           base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>),
-      ());
-  MOCK_METHOD(
-      void,
-      ReleaseSpace,
-      (const std::string&,
-       const std::string&,
-       uint64_t,
-       base::OnceCallback<void(
-           base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>),
-      ());
-  MOCK_METHOD(void,
-              SetDiskManagerDelegate,
-              (BorealisDiskManager * disk_manager),
-              ());
-  MOCK_METHOD(void,
-              RemoveDiskManagerDelegate,
-              (BorealisDiskManager * disk_manager),
-              ());
-};
-
-class BorealisDiskManagerTest : public testing::Test,
-                                protected guest_os::FakeVmServicesHelper {
- public:
-  BorealisDiskManagerTest() = default;
-  ~BorealisDiskManagerTest() override = default;
-  BorealisDiskManagerTest(const BorealisDiskManagerTest&) = delete;
-  BorealisDiskManagerTest& operator=(const BorealisDiskManagerTest&) = delete;
-
- protected:
-  void SetUp() override {
-    CreateProfile();
-    mock_dispatcher_ =
-        std::make_unique<testing::NiceMock<BorealisDiskDispatcherMock>>();
-    borealis_window_manager_ =
-        std::make_unique<BorealisWindowManager>(profile_.get());
-    borealis_features_ = std::make_unique<BorealisFeatures>(profile_.get());
-
-    service_fake_ = BorealisServiceFake::UseFakeForTesting(profile_.get());
-    service_fake_->SetDiskManagerDispatcherForTesting(mock_dispatcher_.get());
-    service_fake_->SetWindowManagerForTesting(borealis_window_manager_.get());
-    service_fake_->SetFeaturesForTesting(borealis_features_.get());
-
-    context_ = BorealisContext::CreateBorealisContextForTesting(profile_.get());
-    context_->set_vm_name("vm_name1");
-    features_.InitAndEnableFeature(ash::features::kBorealisDiskManagement);
-    disk_manager_ = std::make_unique<BorealisDiskManagerImpl>(context_.get());
-    auto free_space_provider = std::make_unique<FreeSpaceProviderMock>();
-    free_space_provider_ = free_space_provider.get();
-    disk_manager_->SetFreeSpaceProviderForTesting(
-        std::move(free_space_provider));
-    run_loop_ = std::make_unique<base::RunLoop>();
-  }
-
-  void TearDown() override {
-    disk_manager_.reset();
-    context_.reset();
-    profile_.reset();
-    run_loop_.reset();
-  }
-
-  void CreateProfile() {
-    TestingProfile::Builder profile_builder;
-    profile_builder.SetProfileName("defaultprofile");
-    profile_ = profile_builder.Build();
-  }
-
-  vm_tools::concierge::ListVmDisksResponse BuildValidListVmDisksResponse(
-      uint64_t min_size,
-      uint64_t size,
-      uint64_t available_space) {
-    vm_tools::concierge::ListVmDisksResponse response;
-    auto* image = response.add_images();
-    response.set_success(true);
-    image->set_name("vm_name1");
-    image->set_image_type(vm_tools::concierge::DiskImageType::DISK_IMAGE_RAW);
-    image->set_user_chosen_size(true);
-    image->set_min_size(min_size);
-    image->set_size(size);
-    image->set_available_space(available_space);
-    return response;
-  }
-
-  base::RunLoop* run_loop() { return run_loop_.get(); }
-
-  std::unique_ptr<TestingProfile> profile_;
-  std::unique_ptr<BorealisContext> context_;
-  std::unique_ptr<BorealisDiskManagerImpl> disk_manager_;
-  raw_ptr<FreeSpaceProviderMock, DanglingUntriaged | ExperimentalAsh>
-      free_space_provider_;
-  raw_ptr<BorealisServiceFake, DanglingUntriaged | ExperimentalAsh>
-      service_fake_;
-  std::unique_ptr<testing::NiceMock<BorealisDiskDispatcherMock>>
-      mock_dispatcher_;
-  std::unique_ptr<BorealisFeatures> borealis_features_;
-  std::unique_ptr<BorealisWindowManager> borealis_window_manager_;
-  base::test::ScopedFeatureList features_;
-  std::unique_ptr<base::RunLoop> run_loop_;
-  content::BrowserTaskEnvironment task_environment_;
-};
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoFailsOnFreeSpaceProviderError) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(testing::Invoke([](BorealisGetDiskSpaceInfoCallback callback) {
-        std::move(callback).Run(-1);
-      }));
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kFailedGettingExpandableSpace);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoFailsOnNoResponseFromConcierge) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            // Concierge will return an empty ListVmDisksResponse.
-            FakeConciergeClient()->set_list_vm_disks_response(
-                absl::optional<vm_tools::concierge::ListVmDisksResponse>());
-            std::move(callback).Run(1 * kGiB);
-          }));
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kConciergeFailed);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest,
-       GetDiskInfoFailsOnUnsuccessfulResponseFromConcierge) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/8 * kGiB,
-                /*available_space=*/1 * kGiB);
-            response.set_success(false);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(1 * kGiB);
-          }));
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kConciergeFailed);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoFailsOnVmMismatch) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/8 * kGiB,
-                /*available_space=*/1 * kGiB);
-            response.mutable_images()->at(0).set_name("UNMATCHED_VM");
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(1 * kGiB);
-          }));
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kConciergeFailed);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoSucceedsAndReturnsResponse) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(2 * kGiB);
-          }));
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            // 3GB of disk space less 2GB of buffer is 1GB of available space.
-            EXPECT_EQ(response_or_error.value().available_bytes, 1 * kGiB);
-            // 2GB of expandable space less 1GB of headroom is 1GB of expandable
-            // space.
-            EXPECT_EQ(response_or_error.value().expandable_bytes, 1 * kGiB);
-            EXPECT_EQ(response_or_error.value().disk_size, 20 * kGiB);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoReservesExpandableSpaceForBuffer) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/1 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(3 * kGiB);
-          }));
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            // Buffer is undersized so 0 space is available
-            EXPECT_EQ(response_or_error.value().available_bytes, 0u);
-            // 3GB of expandable space less 1GB of headroom and less 1GB (needed
-            // to regenerate the buffer) leaves 1GB free.
-            EXPECT_EQ(response_or_error.value().expandable_bytes, 1 * kGiB);
-            EXPECT_EQ(response_or_error.value().disk_size, 20 * kGiB);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest,
-       GetDiskInfoReturns0AvailableSpaceForSparseDisks) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            response.mutable_images()->at(0).set_user_chosen_size(false);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(2 * kGiB);
-          }));
-
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            // 0GB of disk space, we always return 0 for sparse disks.
-            EXPECT_EQ(response_or_error.value().available_bytes, 0 * kGiB);
-            // 2GB of expandable space less 1GB of headroom is 1GB of expandable
-            // space.
-            EXPECT_EQ(response_or_error.value().expandable_bytes, 1 * kGiB);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoFailsOnConcurrentAttempt) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(2 * kGiB);
-          }));
-
-  DiskInfoCallbackFactory first_callback_factory;
-  DiskInfoCallbackFactory second_callback_factory;
-  EXPECT_CALL(first_callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-          }));
-  EXPECT_CALL(second_callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kAlreadyInProgress);
-          }));
-  disk_manager_->GetDiskInfo(first_callback_factory.BindOnce());
-  disk_manager_->GetDiskInfo(second_callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoSubsequentAttemptSucceeds) {
-  auto response =
-      BuildValidListVmDisksResponse(/*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                                    /*available_space=*/3 * kGiB);
-
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(testing::Invoke([this, response = response](
-                                    BorealisGetDiskSpaceInfoCallback callback) {
-        FakeConciergeClient()->set_list_vm_disks_response(response);
-        std::move(callback).Run(2 * kGiB);
-      }));
-
-  DiskInfoCallbackFactory first_callback_factory;
-  EXPECT_CALL(first_callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-          }));
-  disk_manager_->GetDiskInfo(first_callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(testing::Invoke([this, response = response](
-                                    BorealisGetDiskSpaceInfoCallback callback) {
-        FakeConciergeClient()->set_list_vm_disks_response(response);
-        std::move(callback).Run(2 * kGiB);
-      }));
-
-  DiskInfoCallbackFactory second_callback_factory;
-  EXPECT_CALL(second_callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-          }));
-  disk_manager_->GetDiskInfo(second_callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestSpaceFailsIf0SpaceRequested) {
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-  disk_manager_->RequestSpace(0, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, ReleaseSpaceFailsIf0SpaceReleased) {
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-  disk_manager_->ReleaseSpace(0, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, ReleaseSpaceFailsIfRequestExceedsInt64) {
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kOverflowError);
-          }));
-  disk_manager_->ReleaseSpace(uint64_t(std::numeric_limits<int64_t>::max()) + 1,
-                              callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsIfBuildDiskInfoFails) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            response.mutable_images()->at(0).set_name("UNMATCHED_VM");
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kFailedToGetDiskInfo);
-          }));
-  disk_manager_->RequestSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsIfDiskTypeNotRaw) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            response.mutable_images()->at(0).set_image_type(
-                vm_tools::concierge::DiskImageType::DISK_IMAGE_AUTO);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidDiskType);
-          }));
-  disk_manager_->RequestSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsIfRequestTooHigh) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kNotEnoughExpandableSpace);
-          }));
-  // 6GB > 4GB of expandable space.
-  disk_manager_->RequestSpace(6 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest,
-       RequestDeltaFailsIfRequestWouldNotLeaveEnoughSpace) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kWouldNotLeaveEnoughSpace);
-          }));
-  // Release space is requesting a negative delta. 2GB > 1GB of unused available
-  // space.
-  disk_manager_->ReleaseSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsIfDiskIsBelowMinimum) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/8 * kGiB, /*size=*/7 * kGiB,
-                /*available_space=*/4 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kViolatesMinimumSize);
-          }));
-  // Release space is requesting a negative delta. 7GB-2GB < 8GB min_size, and
-  // min size is already smaller than the disk, so the disk cannot be shrunk
-  // at all.
-  disk_manager_->ReleaseSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaShrinksAsSmallAsPossible) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/7 * kGiB,
-                /*available_space=*/4 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/6 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(6 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.value(), 1 * kGiB);
-          }));
-
-  // Release space is requesting a negative delta. 7GB-2GB < 6GB min_size, but
-  // as the disk size is greater than the min size, the disk can still be
-  // partially shrunk (whilst maintaining enough available space and not going
-  // below the minimum disk size).
-  disk_manager_->ReleaseSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsOnNoResizeDiskResponse) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kConciergeFailed);
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsOnFailedResizeDiskResponse) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_FAILED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kConciergeFailed);
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsOnDelayedConciergeFailure) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  vm_tools::concierge::DiskImageStatusResponse in_progress;
-  vm_tools::concierge::DiskImageStatusResponse failed;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_IN_PROGRESS);
-  in_progress.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_IN_PROGRESS);
-  failed.set_status(vm_tools::concierge::DiskImageStatus::DISK_STATUS_FAILED);
-  std::vector<vm_tools::concierge::DiskImageStatusResponse> signals{in_progress,
-                                                                    failed};
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-  FakeConciergeClient()->set_disk_image_status_signals(signals);
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kConciergeFailed);
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaFailsOnFailureToGetUpdate) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(testing::Invoke([](BorealisGetDiskSpaceInfoCallback callback) {
-        std::move(callback).Run(-1 * kGiB);
-      }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kFailedGettingUpdate);
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestSpaceFailsIfResizeTooSmall) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(testing::Invoke(
-          [this](base::OnceCallback<void(absl::optional<int64_t>)> callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/21 * kGiB,
-                /*available_space=*/5 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(4 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kFailedToFulfillRequest);
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, ReleaseSpaceFailsIfDiskExpanded) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/4 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/21 * kGiB,
-                /*available_space=*/5 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(4 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kFailedToFulfillRequest);
-          }));
-  disk_manager_->ReleaseSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestSpaceSuccessful) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/22 * kGiB,
-                /*available_space=*/4 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(3 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.value(), 2 * kGiB);
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, ReleaseSpaceSuccessful) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/4 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/19 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(6 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.value(), 1 * kGiB);
-          }));
-  disk_manager_->ReleaseSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestSpaceConvertsSparseDiskToFixed) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/100 * kGiB);
-            response.mutable_images()->at(0).set_user_chosen_size(false);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(100 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            // Note: available_space goes from 100 GB to 3 GB, when requesting
-            // for more space. In a sparse disk, the available space on the
-            // disk is more like the expandable space on the disk, so it makes
-            // sense that when we convert to a fixed disk, it will decrease so
-            // that it reflects the actual space available on the disk.
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/23 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(97 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.value(), 1 * kGiB);
-          }));
-  disk_manager_->RequestSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, ReleaseSpaceConvertsSparseDiskToFixed) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/100 * kGiB);
-            response.mutable_images()->at(0).set_user_chosen_size(false);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(100 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            // Note: available_space goes from 100 GB to 2 GB, when releasing
-            // space. In a sparse disk, the available space on the disk is more
-            // like the expandable space on the disk, so it makes sense that
-            // when we convert to a fixed disk, it will decrease so that it
-            // reflects the actual space available on the disk.
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/22 * kGiB,
-                /*available_space=*/2 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(98 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.value(), 0u);
-          }));
-  disk_manager_->ReleaseSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestSpaceSuccessfullyRegeneratesBuffer) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/1 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/23 * kGiB,
-                /*available_space=*/4 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(2 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            // Though the disk size and total available space has increased
-            // by 3GB, the space available for the client has only increased
-            // by 2GB.
-            EXPECT_EQ(response_or_error.value(), 2 * kGiB);
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaConcurrentAttemptFails) {
-  // We don't use a sequence here because the ordering of expectations is not
-  // guaranteed, because of that we need to declare the free space provider
-  // expectations in reverse order and retire the first expecation when
-  // fulfilled.
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/22 * kGiB,
-                /*available_space=*/5 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(3 * kGiB);
-          }));
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }))
-      .RetiresOnSaturation();
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-          }));
-  RequestDeltaCallbackFactory second_callback_factory;
-  EXPECT_CALL(second_callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  disk_manager_->RequestSpace(2 * kGiB, second_callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestDeltaSubsequentAttemptSucceeds) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/22 * kGiB,
-                /*available_space=*/5 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(3 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-          }));
-  disk_manager_->RequestSpace(2 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/22 * kGiB,
-                /*available_space=*/5 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(3 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse second_disk_response;
-  second_disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(second_disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/21 * kGiB,
-                /*available_space=*/4 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(4 * kGiB);
-          }));
-
-  RequestDeltaCallbackFactory second_callback_factory;
-  EXPECT_CALL(second_callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_TRUE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.value(), 1 * kGiB);
-          }));
-  disk_manager_->ReleaseSpace(1 * kGiB, second_callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeFailsIfGetDiskInfoFails) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            response.mutable_images()->at(0).set_name("UNMATCHED_VM");
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_FALSE(result.has_value());
-            EXPECT_EQ(result.error().error(),
-                      BorealisSyncDiskSizeResult::kFailedToGetDiskInfo);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeSucceedsIfDiskNotFixedSize) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/3 * kGiB);
-            response.mutable_images()->at(0).set_user_chosen_size(false);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-            EXPECT_EQ(result.value(),
-                      BorealisSyncDiskSizeResult::kDiskNotFixed);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeSucceedsIfDiskCantExpand) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/1 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(0 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-            EXPECT_EQ(result.value(),
-                      BorealisSyncDiskSizeResult::kNotEnoughSpaceToExpand);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeSucceedsIfDiskDoesntNeedToExpand) {
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/20 * kGiB,
-                /*available_space=*/2 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(10 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-            EXPECT_EQ(result.value(),
-                      BorealisSyncDiskSizeResult::kNoActionNeeded);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeFailsIfResizeAttemptFails) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .Times(2)
-      .WillRepeatedly(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/6 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_FALSE(result.has_value());
-            EXPECT_EQ(result.error().error(),
-                      BorealisSyncDiskSizeResult::kResizeFailed);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest,
-       SyncDiskSizeSucceedsIfDiskBelowMinSizeDuringShrink) {
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .Times(2)
-      .WillRepeatedly(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/5 * kGiB,
-                /*available_space=*/3 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(5 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-            EXPECT_EQ(result.value(),
-                      BorealisSyncDiskSizeResult::kDiskSizeSmallerThanMin);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizePartialResizeSucceeds) {
-  // This is considered "partial" as it should log a warning. There is not
-  // enough space on the device to fully rebuild the buffer to 2GB, but it will
-  // succeed in rebuilding it to 1.5GB.
-
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .Times(2)
-      .WillRepeatedly(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/7 * kGiB,
-                /*available_space=*/1 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(1.5 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/7.5 * kGiB,
-                /*available_space=*/1.5 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(1 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-            EXPECT_EQ(result.value(),
-                      BorealisSyncDiskSizeResult::kResizedPartially);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeCompleteResizeSucceeds) {
-  // This is a complete success as the buffer is fully resized to 2GB.
-
-  // This object forces all EXPECT_CALLs to occur in the order they are
-  // declared.
-  testing::InSequence sequence;
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .Times(2)
-      .WillRepeatedly(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/7 * kGiB,
-                /*available_space=*/1 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(2 * kGiB);
-          }));
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/8 * kGiB,
-                /*available_space=*/2 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(1 * kGiB);
-          }));
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-            EXPECT_EQ(result.value(),
-                      BorealisSyncDiskSizeResult::kResizedSuccessfully);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeConcurrentAttemptFails) {
-  // We don't use a sequence here because the ordering of expectations is not
-  // guaranteed, because of that we need to declare the free space provider
-  // expectations in reverse order and retire the first expecation when
-  // fulfilled.
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .WillOnce(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/8 * kGiB,
-                /*available_space=*/2 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(1 * kGiB);
-          }));
-
-  EXPECT_CALL(*free_space_provider_, Get(_))
-      .Times(2)
-      .WillRepeatedly(
-          testing::Invoke([this](BorealisGetDiskSpaceInfoCallback callback) {
-            auto response = BuildValidListVmDisksResponse(
-                /*min_size=*/6 * kGiB, /*size=*/7 * kGiB,
-                /*available_space=*/1 * kGiB);
-            FakeConciergeClient()->set_list_vm_disks_response(response);
-            std::move(callback).Run(2 * kGiB);
-          }))
-      .RetiresOnSaturation();
-
-  vm_tools::concierge::ResizeDiskImageResponse disk_response;
-  disk_response.set_status(
-      vm_tools::concierge::DiskImageStatus::DISK_STATUS_RESIZED);
-  FakeConciergeClient()->set_resize_disk_image_response(disk_response);
-
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-          }));
-
-  SyncDiskCallbackFactory second_callback_factory;
-  EXPECT_CALL(second_callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_FALSE(result.has_value());
-            EXPECT_EQ(result.error().error(),
-                      BorealisSyncDiskSizeResult::kAlreadyInProgress);
-          }));
-
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  disk_manager_->SyncDiskSize(second_callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, GetDiskInfoFailsWhenFeatureDisabled) {
-  features_.Reset();
-  features_.InitAndDisableFeature(ash::features::kBorealisDiskManagement);
-  DiskInfoCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisDiskManagerImpl::GetDiskInfoResponse,
-                            Described<BorealisGetDiskInfoResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisGetDiskInfoResult::kInvalidRequest);
-          }));
-  disk_manager_->GetDiskInfo(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, RequestSpaceFailsWhenFeatureDisabled) {
-  features_.Reset();
-  features_.InitAndDisableFeature(ash::features::kBorealisDiskManagement);
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-  disk_manager_->RequestSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, ReleaseSpaceFailsWhenFeatureDisabled) {
-  features_.Reset();
-  features_.InitAndDisableFeature(ash::features::kBorealisDiskManagement);
-  RequestDeltaCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<uint64_t, Described<BorealisResizeDiskResult>>
-                 response_or_error) {
-            EXPECT_FALSE(response_or_error.has_value());
-            EXPECT_EQ(response_or_error.error().error(),
-                      BorealisResizeDiskResult::kInvalidRequest);
-          }));
-  disk_manager_->ReleaseSpace(1 * kGiB, callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-TEST_F(BorealisDiskManagerTest, SyncDiskSizeSucceedsWhenFeatureDisabled) {
-  features_.Reset();
-  features_.InitAndDisableFeature(ash::features::kBorealisDiskManagement);
-  SyncDiskCallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(_))
-      .WillOnce(testing::Invoke(
-          [](base::expected<BorealisSyncDiskSizeResult,
-                            Described<BorealisSyncDiskSizeResult>> result) {
-            EXPECT_TRUE(result.has_value());
-            EXPECT_EQ(result.value(),
-                      BorealisSyncDiskSizeResult::kNoActionNeeded);
-          }));
-  disk_manager_->SyncDiskSize(callback_factory.BindOnce());
-  run_loop()->RunUntilIdle();
-}
-
-}  // namespace
-}  // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_service.h b/chrome/browser/ash/borealis/borealis_service.h
index 1079456f..cd117fc 100644
--- a/chrome/browser/ash/borealis/borealis_service.h
+++ b/chrome/browser/ash/borealis/borealis_service.h
@@ -14,7 +14,6 @@
 class BorealisAppLauncher;
 class BorealisAppUninstaller;
 class BorealisContextManager;
-class BorealisDiskManagerDispatcher;
 class BorealisFeatures;
 class BorealisInstaller;
 class BorealisInstallUrlHandler;
@@ -34,7 +33,6 @@
   virtual BorealisAppLauncher& AppLauncher() = 0;
   virtual BorealisAppUninstaller& AppUninstaller() = 0;
   virtual BorealisContextManager& ContextManager() = 0;
-  virtual BorealisDiskManagerDispatcher& DiskManagerDispatcher() = 0;
   virtual BorealisFeatures& Features() = 0;
   virtual BorealisInstaller& Installer() = 0;
   virtual BorealisInstallUrlHandler& InstallUrlHandler() = 0;
diff --git a/chrome/browser/ash/borealis/borealis_service_fake.cc b/chrome/browser/ash/borealis/borealis_service_fake.cc
index 9c94788..22ff5e13 100644
--- a/chrome/browser/ash/borealis/borealis_service_fake.cc
+++ b/chrome/browser/ash/borealis/borealis_service_fake.cc
@@ -39,11 +39,6 @@
   return *context_manager_;
 }
 
-BorealisDiskManagerDispatcher& BorealisServiceFake::DiskManagerDispatcher() {
-  CHECK(borealis_disk_manager_dispatcher_);
-  return *borealis_disk_manager_dispatcher_;
-}
-
 BorealisFeatures& BorealisServiceFake::Features() {
   CHECK(features_);
   return *features_;
@@ -94,11 +89,6 @@
   context_manager_ = context_manager;
 }
 
-void BorealisServiceFake::SetDiskManagerDispatcherForTesting(
-    BorealisDiskManagerDispatcher* borealis_disk_manager_dispatcher) {
-  borealis_disk_manager_dispatcher_ = borealis_disk_manager_dispatcher;
-}
-
 void BorealisServiceFake::SetFeaturesForTesting(BorealisFeatures* features) {
   features_ = features;
 }
diff --git a/chrome/browser/ash/borealis/borealis_service_fake.h b/chrome/browser/ash/borealis/borealis_service_fake.h
index 2c778a13..d951acc4 100644
--- a/chrome/browser/ash/borealis/borealis_service_fake.h
+++ b/chrome/browser/ash/borealis/borealis_service_fake.h
@@ -28,7 +28,6 @@
   BorealisAppLauncher& AppLauncher() override;
   BorealisAppUninstaller& AppUninstaller() override;
   BorealisContextManager& ContextManager() override;
-  BorealisDiskManagerDispatcher& DiskManagerDispatcher() override;
   BorealisFeatures& Features() override;
   BorealisInstaller& Installer() override;
   BorealisInstallUrlHandler& InstallUrlHandler() override;
@@ -40,8 +39,6 @@
   void SetAppLauncherForTesting(BorealisAppLauncher* app_launcher);
   void SetAppUninstallerForTesting(BorealisAppUninstaller* app_uninstaller);
   void SetContextManagerForTesting(BorealisContextManager* context_manager);
-  void SetDiskManagerDispatcherForTesting(
-      BorealisDiskManagerDispatcher* borealis_disk_manager_dispatcher);
   void SetFeaturesForTesting(BorealisFeatures* features);
   void SetInstallerForTesting(BorealisInstaller* installer);
   void SetInstallUrlHandlerForTesting(
@@ -55,8 +52,6 @@
   raw_ptr<BorealisAppLauncher, ExperimentalAsh> app_launcher_ = nullptr;
   raw_ptr<BorealisAppUninstaller, ExperimentalAsh> app_uninstaller_ = nullptr;
   raw_ptr<BorealisContextManager, ExperimentalAsh> context_manager_ = nullptr;
-  raw_ptr<BorealisDiskManagerDispatcher, DanglingUntriaged | ExperimentalAsh>
-      borealis_disk_manager_dispatcher_ = nullptr;
   raw_ptr<BorealisFeatures, DanglingUntriaged | ExperimentalAsh> features_ =
       nullptr;
   raw_ptr<BorealisInstaller, ExperimentalAsh> installer_ = nullptr;
diff --git a/chrome/browser/ash/borealis/borealis_service_impl.cc b/chrome/browser/ash/borealis/borealis_service_impl.cc
index f60400f..e11ff9f 100644
--- a/chrome/browser/ash/borealis/borealis_service_impl.cc
+++ b/chrome/browser/ash/borealis/borealis_service_impl.cc
@@ -33,10 +33,6 @@
   return context_manager_;
 }
 
-BorealisDiskManagerDispatcher& BorealisServiceImpl::DiskManagerDispatcher() {
-  return disk_manager_dispatcher_;
-}
-
 BorealisFeatures& BorealisServiceImpl::Features() {
   return features_;
 }
diff --git a/chrome/browser/ash/borealis/borealis_service_impl.h b/chrome/browser/ash/borealis/borealis_service_impl.h
index 57f270a..91434fe 100644
--- a/chrome/browser/ash/borealis/borealis_service_impl.h
+++ b/chrome/browser/ash/borealis/borealis_service_impl.h
@@ -9,7 +9,6 @@
 #include "chrome/browser/ash/borealis/borealis_app_launcher_impl.h"
 #include "chrome/browser/ash/borealis/borealis_app_uninstaller.h"
 #include "chrome/browser/ash/borealis/borealis_context_manager_impl.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h"
 #include "chrome/browser/ash/borealis/borealis_features.h"
 #include "chrome/browser/ash/borealis/borealis_install_url_handler.h"
 #include "chrome/browser/ash/borealis/borealis_installer_impl.h"
@@ -32,7 +31,6 @@
   BorealisAppLauncher& AppLauncher() override;
   BorealisAppUninstaller& AppUninstaller() override;
   BorealisContextManager& ContextManager() override;
-  BorealisDiskManagerDispatcher& DiskManagerDispatcher() override;
   BorealisFeatures& Features() override;
   BorealisInstaller& Installer() override;
   BorealisInstallUrlHandler& InstallUrlHandler() override;
@@ -45,7 +43,6 @@
 
   BorealisAppLauncherImpl app_launcher_;
   BorealisAppUninstaller app_uninstaller_;
-  BorealisDiskManagerDispatcher disk_manager_dispatcher_;
   BorealisContextManagerImpl context_manager_;
   BorealisFeatures features_;
   BorealisInstallerImpl installer_;
diff --git a/chrome/browser/ash/borealis/borealis_task.cc b/chrome/browser/ash/borealis/borealis_task.cc
index 2e82c49..5da25370 100644
--- a/chrome/browser/ash/borealis/borealis_task.cc
+++ b/chrome/browser/ash/borealis/borealis_task.cc
@@ -21,7 +21,6 @@
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/borealis/borealis_context.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager.h"
 #include "chrome/browser/ash/borealis/borealis_features.h"
 #include "chrome/browser/ash/borealis/borealis_launch_options.h"
 #include "chrome/browser/ash/borealis/borealis_service.h"
@@ -364,25 +363,4 @@
   Complete(BorealisStartupResult::kSuccess, "");
 }
 
-SyncBorealisDisk::SyncBorealisDisk() : BorealisTask("SyncBorealisDisk") {}
-SyncBorealisDisk::~SyncBorealisDisk() = default;
-
-void SyncBorealisDisk::RunInternal(BorealisContext* context) {
-  context->get_disk_manager().SyncDiskSize(
-      base::BindOnce(&SyncBorealisDisk::OnSyncBorealisDisk,
-                     weak_factory_.GetWeakPtr(), context));
-}
-
-void SyncBorealisDisk::OnSyncBorealisDisk(
-    BorealisContext* context,
-    base::expected<BorealisSyncDiskSizeResult,
-                   Described<BorealisSyncDiskSizeResult>> result) {
-  // This step should not block startup, so just log the error and declare
-  // success.
-  if (!result.has_value()) {
-    LOG(ERROR) << "Failed to sync disk: " << result.error().description();
-  }
-  Complete(BorealisStartupResult::kSuccess, "");
-}
-
 }  // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_task.h b/chrome/browser/ash/borealis/borealis_task.h
index 9f53111..a99e9a8 100644
--- a/chrome/browser/ash/borealis/borealis_task.h
+++ b/chrome/browser/ash/borealis/borealis_task.h
@@ -153,21 +153,6 @@
   base::WeakPtrFactory<UpdateChromeFlags> weak_factory_{this};
 };
 
-// Checks the size of the disk and adjusts it if necessary.
-class SyncBorealisDisk : public BorealisTask {
- public:
-  SyncBorealisDisk();
-  ~SyncBorealisDisk() override;
-  void RunInternal(BorealisContext* context) override;
-
- private:
-  void OnSyncBorealisDisk(
-      BorealisContext* context,
-      base::expected<BorealisSyncDiskSizeResult,
-                     Described<BorealisSyncDiskSizeResult>> result);
-  base::WeakPtrFactory<SyncBorealisDisk> weak_factory_{this};
-};
-
 }  // namespace borealis
 
 #endif  // CHROME_BROWSER_ASH_BOREALIS_BOREALIS_TASK_H_
diff --git a/chrome/browser/ash/borealis/borealis_task_unittest.cc b/chrome/browser/ash/borealis/borealis_task_unittest.cc
index 7e5c1bc..966132c 100644
--- a/chrome/browser/ash/borealis/borealis_task_unittest.cc
+++ b/chrome/browser/ash/borealis/borealis_task_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/test/test_future.h"
 #include "chrome/browser/ash/borealis/borealis_context.h"
 #include "chrome/browser/ash/borealis/borealis_context_manager.h"
-#include "chrome/browser/ash/borealis/borealis_disk_manager.h"
 #include "chrome/browser/ash/borealis/borealis_metrics.h"
 #include "chrome/browser/ash/borealis/testing/callback_factory.h"
 #include "chrome/browser/ash/guest_os/dbus_test_helper.h"
@@ -33,38 +32,6 @@
 
 namespace {
 
-class DiskManagerMock : public BorealisDiskManager {
- public:
-  DiskManagerMock() = default;
-  ~DiskManagerMock() override = default;
-  MOCK_METHOD(void,
-              GetDiskInfo,
-              (base::OnceCallback<
-                  void(base::expected<GetDiskInfoResponse,
-                                      Described<BorealisGetDiskInfoResult>>)>),
-              ());
-  MOCK_METHOD(
-      void,
-      RequestSpace,
-      (uint64_t,
-       base::OnceCallback<void(
-           base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>),
-      ());
-  MOCK_METHOD(
-      void,
-      ReleaseSpace,
-      (uint64_t,
-       base::OnceCallback<void(
-           base::expected<uint64_t, Described<BorealisResizeDiskResult>>)>),
-      ());
-  MOCK_METHOD(void,
-              SyncDiskSize,
-              (base::OnceCallback<
-                  void(base::expected<BorealisSyncDiskSizeResult,
-                                      Described<BorealisSyncDiskSizeResult>>)>),
-              ());
-};
-
 using CallbackFactory =
     NiceCallbackFactory<void(BorealisStartupResult, std::string)>;
 
@@ -256,50 +223,6 @@
   task_environment_.FastForwardBy(base::Seconds(31));
 }
 
-TEST_F(BorealisTasksTest, SyncBorealisDiskFailureIgnored) {
-  auto disk_mock = std::make_unique<DiskManagerMock>();
-  EXPECT_CALL(*disk_mock, SyncDiskSize(_))
-      .WillOnce(testing::Invoke(
-          [](base::OnceCallback<void(
-                 base::expected<BorealisSyncDiskSizeResult,
-                                Described<BorealisSyncDiskSizeResult>>)>
-                 callback) {
-            std::move(callback).Run(
-                base::unexpected(Described<BorealisSyncDiskSizeResult>(
-                    BorealisSyncDiskSizeResult::kFailedToGetDiskInfo,
-                    "error message")));
-          }));
-
-  CallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(BorealisStartupResult::kSuccess, ""));
-  context_->SetDiskManagerForTesting(std::move(disk_mock));
-  SyncBorealisDisk task;
-  task.Run(context_.get(), callback_factory.BindOnce());
-  task_environment_.RunUntilIdle();
-}
-
-TEST_F(BorealisTasksTest, SyncBorealisDiskSucceeds) {
-  auto disk_mock = std::make_unique<DiskManagerMock>();
-  EXPECT_CALL(*disk_mock, SyncDiskSize(_))
-      .WillOnce(testing::Invoke(
-          [](base::OnceCallback<void(
-                 base::expected<BorealisSyncDiskSizeResult,
-                                Described<BorealisSyncDiskSizeResult>>)>
-                 callback) {
-            std::move(callback).Run(
-                base::expected<BorealisSyncDiskSizeResult,
-                               Described<BorealisSyncDiskSizeResult>>(
-                    BorealisSyncDiskSizeResult::kNoActionNeeded));
-          }));
-
-  CallbackFactory callback_factory;
-  EXPECT_CALL(callback_factory, Call(BorealisStartupResult::kSuccess, _));
-  context_->SetDiskManagerForTesting(std::move(disk_mock));
-  SyncBorealisDisk task;
-  task.Run(context_.get(), callback_factory.BindOnce());
-  task_environment_.RunUntilIdle();
-}
-
 TEST_F(BorealisTasksTest, DlcRetries) {
   FakeDlcserviceClient()->set_install_error(dlcservice::kErrorInternal);
   base::test::TestFuture<BorealisStartupResult, std::string> result;
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index 7b3e860..acf128a 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -122,6 +122,8 @@
     "environment_provider.h",
     "extension_info_private_ash.cc",
     "extension_info_private_ash.h",
+    "eye_dropper_ash.cc",
+    "eye_dropper_ash.h",
     "feedback_ash.cc",
     "feedback_ash.h",
     "field_trial_service_ash.cc",
@@ -354,6 +356,7 @@
     "//components/arc",
     "//components/crash/core/app",
     "//components/exo",
+    "//components/eye_dropper",
     "//components/feature_engagement",
     "//components/flags_ui",
     "//components/keyed_service/content",
diff --git a/chrome/browser/ash/crosapi/DEPS b/chrome/browser/ash/crosapi/DEPS
index b7a068e..77bca698 100644
--- a/chrome/browser/ash/crosapi/DEPS
+++ b/chrome/browser/ash/crosapi/DEPS
@@ -5,6 +5,9 @@
   "crosapi_ash\.h": [
     "+media/gpu/buildflags.h",
   ],
+  "eye_dropper_ash\.cc": [
+    "+components/eye_dropper",
+  ],
   "message_center_ash(\.cc|_unittest\.cc)": [
     # Provides a mojo interface around the message center, but lives in this
     # directory for consistency with other crosapi classes.
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc
index 9cac088..f9f488e 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.cc
+++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -52,6 +52,7 @@
 #include "chrome/browser/ash/crosapi/embedded_accessibility_helper_client_ash.h"
 #include "chrome/browser/ash/crosapi/emoji_picker_ash.h"
 #include "chrome/browser/ash/crosapi/extension_info_private_ash.h"
+#include "chrome/browser/ash/crosapi/eye_dropper_ash.h"
 #include "chrome/browser/ash/crosapi/feedback_ash.h"
 #include "chrome/browser/ash/crosapi/field_trial_service_ash.h"
 #include "chrome/browser/ash/crosapi/file_manager_ash.h"
@@ -132,6 +133,7 @@
 #include "chromeos/crosapi/mojom/device_local_account_extension_service.mojom.h"
 #include "chromeos/crosapi/mojom/drive_integration_service.mojom.h"
 #include "chromeos/crosapi/mojom/embedded_accessibility_helper.mojom.h"
+#include "chromeos/crosapi/mojom/eye_dropper.mojom.h"
 #include "chromeos/crosapi/mojom/feedback.mojom.h"
 #include "chromeos/crosapi/mojom/file_manager.mojom.h"
 #include "chromeos/crosapi/mojom/firewall_hole.mojom.h"
@@ -230,6 +232,7 @@
           std::make_unique<EmbeddedAccessibilityHelperClientAsh>()),
       emoji_picker_ash_(std::make_unique<EmojiPickerAsh>()),
       extension_info_private_ash_(std::make_unique<ExtensionInfoPrivateAsh>()),
+      eye_dropper_ash_(std::make_unique<EyeDropperAsh>()),
       feedback_ash_(std::make_unique<FeedbackAsh>()),
       field_trial_service_ash_(std::make_unique<FieldTrialServiceAsh>()),
       file_manager_ash_(std::make_unique<FileManagerAsh>()),
@@ -542,6 +545,11 @@
   extensions->RegisterCrosapiHost(std::move(receiver));
 }
 
+void CrosapiAsh::BindEyeDropper(
+    mojo::PendingReceiver<mojom::EyeDropper> receiver) {
+  eye_dropper_ash_->BindReceiver(std::move(receiver));
+}
+
 void CrosapiAsh::BindFeedback(mojo::PendingReceiver<mojom::Feedback> receiver) {
   feedback_ash_->BindReceiver(std::move(receiver));
 }
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.h b/chrome/browser/ash/crosapi/crosapi_ash.h
index ce49ae53..2039a05 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.h
+++ b/chrome/browser/ash/crosapi/crosapi_ash.h
@@ -69,6 +69,7 @@
 class EmbeddedAccessibilityHelperClientAsh;
 class EmojiPickerAsh;
 class ExtensionInfoPrivateAsh;
+class EyeDropperAsh;
 class FeedbackAsh;
 class FieldTrialServiceAsh;
 class FileManagerAsh;
@@ -227,6 +228,8 @@
       mojo::PendingReceiver<mojom::ExtensionInfoPrivate> receiver) override;
   void BindExtensionPublisher(
       mojo::PendingReceiver<mojom::AppPublisher> receiver) override;
+  void BindEyeDropper(
+      mojo::PendingReceiver<mojom::EyeDropper> receiver) override;
   void BindFeedback(mojo::PendingReceiver<mojom::Feedback> receiver) override;
   void BindFieldTrialService(
       mojo::PendingReceiver<mojom::FieldTrialService> receiver) override;
@@ -601,6 +604,7 @@
       embedded_accessibility_helper_client_ash_;
   std::unique_ptr<EmojiPickerAsh> emoji_picker_ash_;
   std::unique_ptr<ExtensionInfoPrivateAsh> extension_info_private_ash_;
+  std::unique_ptr<EyeDropperAsh> eye_dropper_ash_;
   std::unique_ptr<FeedbackAsh> feedback_ash_;
   std::unique_ptr<FieldTrialServiceAsh> field_trial_service_ash_;
   std::unique_ptr<FileManagerAsh> file_manager_ash_;
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc
index ecbba502..a5511d0 100644
--- a/chrome/browser/ash/crosapi/crosapi_util.cc
+++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -81,6 +81,7 @@
 #include "chromeos/crosapi/mojom/embedded_accessibility_helper.mojom.h"
 #include "chromeos/crosapi/mojom/emoji_picker.mojom.h"
 #include "chromeos/crosapi/mojom/extension_info_private.mojom.h"
+#include "chromeos/crosapi/mojom/eye_dropper.mojom.h"
 #include "chromeos/crosapi/mojom/feedback.mojom.h"
 #include "chromeos/crosapi/mojom/file_manager.mojom.h"
 #include "chromeos/crosapi/mojom/file_system_access_cloud_identifier.mojom.h"
@@ -296,7 +297,7 @@
   return {T::Uuid_, T::Version_};
 }
 
-static_assert(crosapi::mojom::Crosapi::Version_ == 119,
+static_assert(crosapi::mojom::Crosapi::Version_ == 120,
               "If you add a new crosapi, please add it to "
               "kInterfaceVersionEntries below.");
 
@@ -344,6 +345,7 @@
     MakeInterfaceVersionEntry<crosapi::mojom::EditorPanelManager>(),
     MakeInterfaceVersionEntry<crosapi::mojom::EmojiPicker>(),
     MakeInterfaceVersionEntry<crosapi::mojom::ExtensionInfoPrivate>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::EyeDropper>(),
     MakeInterfaceVersionEntry<crosapi::mojom::Feedback>(),
     MakeInterfaceVersionEntry<crosapi::mojom::FieldTrialService>(),
     MakeInterfaceVersionEntry<crosapi::mojom::FileManager>(),
diff --git a/chrome/browser/ash/crosapi/eye_dropper_ash.cc b/chrome/browser/ash/crosapi/eye_dropper_ash.cc
new file mode 100644
index 0000000..2dcdb6c
--- /dev/null
+++ b/chrome/browser/ash/crosapi/eye_dropper_ash.cc
@@ -0,0 +1,50 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/crosapi/eye_dropper_ash.h"
+
+#include <memory>
+
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/shell.h"
+#include "components/eye_dropper/eye_dropper_view.h"
+#include "ui/aura/window.h"
+
+namespace crosapi {
+
+EyeDropperAsh::EyeDropperAsh() = default;
+
+EyeDropperAsh::~EyeDropperAsh() = default;
+
+void EyeDropperAsh::BindReceiver(
+    mojo::PendingReceiver<mojom::EyeDropper> receiver) {
+  receivers_.Add(this, std::move(receiver));
+}
+
+void EyeDropperAsh::ShowEyeDropper(
+    mojo::PendingRemote<mojom::EyeDropperListener> listener) {
+  listener_ = mojo::Remote<mojom::EyeDropperListener>(std::move(listener));
+  listener_.set_disconnect_handler(
+      base::BindOnce(&EyeDropperAsh::OnDisconnect, weak_factory_.GetWeakPtr()));
+  auto* root = ash::Shell::GetRootWindowForNewWindows();
+  auto* parent = root->GetChildById(ash::kShellWindowId_MenuContainer);
+  eye_dropper_ =
+      std::make_unique<eye_dropper::EyeDropperView>(parent, root, this);
+}
+
+void EyeDropperAsh::ColorSelected(SkColor color) {
+  listener_->ColorSelected(color);
+  eye_dropper_.reset();
+}
+
+void EyeDropperAsh::ColorSelectionCanceled() {
+  listener_->ColorSelectionCanceled();
+  eye_dropper_.reset();
+}
+
+void EyeDropperAsh::OnDisconnect() {
+  eye_dropper_.reset();
+}
+
+}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/eye_dropper_ash.h b/chrome/browser/ash/crosapi/eye_dropper_ash.h
new file mode 100644
index 0000000..09d8db9e
--- /dev/null
+++ b/chrome/browser/ash/crosapi/eye_dropper_ash.h
@@ -0,0 +1,53 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_CROSAPI_EYE_DROPPER_ASH_H_
+#define CHROME_BROWSER_ASH_CROSAPI_EYE_DROPPER_ASH_H_
+
+#include "base/memory/weak_ptr.h"
+#include "chromeos/crosapi/mojom/eye_dropper.mojom.h"
+#include "content/public/browser/eye_dropper_listener.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace content {
+class EyeDropper;
+}
+
+namespace crosapi {
+
+// Implements the crosapi EyeDropper interface. Lives in ash-chrome on the
+// UI thread. Shows EyeDropper in response to mojo IPCs from lacros-chrome.
+class EyeDropperAsh : public mojom::EyeDropper,
+                      public content::EyeDropperListener {
+ public:
+  EyeDropperAsh();
+  EyeDropperAsh(const EyeDropperAsh&) = delete;
+  EyeDropperAsh& operator=(const EyeDropperAsh&) = delete;
+  ~EyeDropperAsh() override;
+
+  void BindReceiver(mojo::PendingReceiver<mojom::EyeDropper> receiver);
+
+  // crosapi::mojom::EyeDropper:
+  void ShowEyeDropper(
+      mojo::PendingRemote<mojom::EyeDropperListener> listener) override;
+
+ private:
+  // content::EyeDropperListener:
+  void ColorSelected(SkColor color) override;
+  void ColorSelectionCanceled() override;
+
+  void OnDisconnect();
+
+  std::unique_ptr<content::EyeDropper> eye_dropper_;
+  mojo::Remote<mojom::EyeDropperListener> listener_;
+  mojo::ReceiverSet<mojom::EyeDropper> receivers_;
+  base::WeakPtrFactory<EyeDropperAsh> weak_factory_{this};
+};
+
+}  // namespace crosapi
+
+#endif  // CHROME_BROWSER_ASH_CROSAPI_EYE_DROPPER_ASH_H_
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc
index 484cc72..38e3760 100644
--- a/chrome/browser/ash/drive/drive_integration_service.cc
+++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -49,7 +49,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/drivefs/drivefs_bootstrap.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/drivefs/sync_status_tracker.h"
 #include "chromeos/components/drivefs/mojom/drivefs_native_messaging.mojom.h"
 #include "chromeos/constants/chromeos_features.h"
@@ -87,7 +87,7 @@
 using base::TimeDelta;
 using content::BrowserThread;
 using drivefs::mojom::DriveFs;
-using drivefs::pinning::PinManager;
+using drivefs::pinning::PinningManager;
 using prefs::kDriveFsBulkPinningEnabled;
 using util::ConnectionStatus;
 
@@ -952,9 +952,9 @@
   }
   GetDriveFsHost()->Unmount();
 
-  if (pin_manager_) {
-    pin_manager_->Stop();
-    pin_manager_.reset();
+  if (pinning_manager_) {
+    pinning_manager_->Stop();
+    pinning_manager_.reset();
   }
 }
 
@@ -1041,23 +1041,23 @@
   if (util::IsDriveFsBulkPinningAvailable(profile_)) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    // Instantiate a PinManager.
-    DCHECK(!pin_manager_);
+    // Instantiate a PinningManager.
+    DCHECK(!pinning_manager_);
     const int queue_size = ash::features::GetDriveFsBulkPinningQueueSize();
     VLOG(1) << "Bulk-pinning queue size: " << queue_size;
-    pin_manager_ = std::make_unique<PinManager>(
+    pinning_manager_ = std::make_unique<PinningManager>(
         profile_->GetPath(), mount_path, GetDriveFsInterface(), queue_size);
 
-    // Listen to progress events from this PinManager.
-    pin_manager_->AddObserver(this);
+    // Listen to progress events from this PinningManager.
+    pinning_manager_->AddObserver(this);
     if (!observers_.empty()) {
-      OnProgress(pin_manager_->GetProgress());
+      OnProgress(pinning_manager_->GetProgress());
     }
 
-    pin_manager_->SetDriveFsHost(GetDriveFsHost());
+    pinning_manager_->SetDriveFsHost(GetDriveFsHost());
 
-    // Ensure the new PinManager has the right view of the network state.
-    pin_manager_->SetOnline(is_online_);
+    // Ensure the new PinningManager has the right view of the network state.
+    pinning_manager_->SetOnline(is_online_);
 
     ToggleBulkPinning();
 
@@ -1210,16 +1210,16 @@
 void DriveIntegrationService::ToggleBulkPinning() {
   VLOG(1) << "ToggleBulkPinning";
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!pin_manager_) {
+  if (!pinning_manager_) {
     VLOG(1) << "No bulk-pinning manager";
     return;
   }
 
   if (GetPrefs()->GetBoolean(kDriveFsBulkPinningEnabled)) {
-    pin_manager_->ShouldPin();
-    pin_manager_->Start();
+    pinning_manager_->ShouldPin();
+    pinning_manager_->Start();
   } else {
-    pin_manager_->Stop();
+    pinning_manager_->Stop();
   }
 }
 
@@ -1630,9 +1630,9 @@
   auth_service_->StartAuthentication(std::move(callback));
 }
 
-PinManager* DriveIntegrationService::GetPinManager() const {
+PinningManager* DriveIntegrationService::GetPinningManager() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  return pin_manager_.get();
+  return pinning_manager_.get();
 }
 
 void DriveIntegrationService::RegisterDriveFsNativeMessageHostBridge(
@@ -1675,8 +1675,8 @@
     AddDriveMountPoint();
   }
 
-  if (pin_manager_) {
-    pin_manager_->SetOnline(is_online_);
+  if (pinning_manager_) {
+    pinning_manager_->SetOnline(is_online_);
   }
 }
 
diff --git a/chrome/browser/ash/drive/drive_integration_service.h b/chrome/browser/ash/drive/drive_integration_service.h
index 21d84c9..a132bcd 100644
--- a/chrome/browser/ash/drive/drive_integration_service.h
+++ b/chrome/browser/ash/drive/drive_integration_service.h
@@ -22,7 +22,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "chromeos/ash/components/drivefs/drivefs_host.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/drivefs/sync_status_tracker.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
@@ -89,7 +89,7 @@
 // created per-profile.
 class DriveIntegrationService : public KeyedService,
                                 public drivefs::DriveFsHost::MountObserver,
-                                drivefs::pinning::PinManager::Observer,
+                                drivefs::pinning::PinningManager::Observer,
                                 ash::NetworkStateHandler::Observer {
  public:
   using DriveFsMojoListenerFactory = base::RepeatingCallback<
@@ -207,7 +207,7 @@
   void OnMountFailed(MountFailure failure,
                      absl::optional<base::TimeDelta> remount_delay) override;
 
-  // PinManager::Observer implementation
+  // PinningManager::Observer implementation
   using Progress = drivefs::pinning::Progress;
   void OnProgress(const Progress& progress) override;
 
@@ -221,9 +221,10 @@
   // Returns the DriveFsHost if it is enabled.
   drivefs::DriveFsHost* GetDriveFsHost() const;
 
-  // Returns the PinManager if DriveFS is mounted and bulk-pinning is enabled.
-  using PinManager = drivefs::pinning::PinManager;
-  PinManager* GetPinManager() const;
+  // Returns the PinningManager if DriveFS is mounted and bulk-pinning is
+  // enabled.
+  using PinningManager = drivefs::pinning::PinningManager;
+  PinningManager* GetPinningManager() const;
 
   // Returns the mojo interface to the DriveFs daemon if it is enabled and
   // connected.
@@ -518,7 +519,7 @@
 
   std::unique_ptr<DriveFsHolder> drivefs_holder_;
 
-  std::unique_ptr<PinManager> pin_manager_;
+  std::unique_ptr<PinningManager> pinning_manager_;
 
   int drivefs_total_failures_count_ = 0;
   int drivefs_consecutive_failures_count_ = 0;
diff --git a/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc b/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc
index 594df86..9f6c9af 100644
--- a/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc
+++ b/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc
@@ -145,8 +145,8 @@
 // Drive cloud Trash.
 class DeleteOperation : public base::RefCountedThreadSafe<DeleteOperation> {
  public:
-  using PinManager = drivefs::pinning::PinManager;
-  using Id = PinManager::Id;
+  using PinningManager = drivefs::pinning::PinningManager;
+  using Id = PinningManager::Id;
 
   DeleteOperation(Profile* const profile,
                   base::FilePath path,
@@ -174,7 +174,7 @@
       return;
     }
 
-    if (drive_->GetPinManager() &&
+    if (drive_->GetPinningManager() &&
         drive_->GetRelativeDrivePath(path_, &drive_path_)) {
       // TODO(b/266168982): In the case this is a folder, only the folder will
       // get unpinned leaving all the children pinned. When the new method is
@@ -228,10 +228,10 @@
 
   void OnDeleted() {
     DCHECK(drive_);
-    if (PinManager* const pin_manager = drive_->GetPinManager()) {
+    if (PinningManager* const pinning_manager = drive_->GetPinningManager()) {
       // TODO(b/267225898) Local delete events are currently not sent via
-      // DriveFS, so for now we notify the `PinManager` for local deletes.
-      pin_manager->NotifyDelete(id_, drive_path_);
+      // DriveFS, so for now we notify the `PinningManager` for local deletes.
+      pinning_manager->NotifyDelete(id_, drive_path_);
     }
   }
 
diff --git a/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc b/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc
index 3d6f019..9eccfbc1 100644
--- a/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc
+++ b/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/ash/extensions/file_manager/private_api_util.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "chromeos/ash/components/drivefs/drivefs_host.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/drivefs/sync_status_tracker.h"
 #include "extensions/browser/extension_event_histogram_value.h"
 
diff --git a/chrome/browser/ash/extensions/file_manager/drivefs_event_router.h b/chrome/browser/ash/extensions/file_manager/drivefs_event_router.h
index 2ee6b1d1..4fc4816 100644
--- a/chrome/browser/ash/extensions/file_manager/drivefs_event_router.h
+++ b/chrome/browser/ash/extensions/file_manager/drivefs_event_router.h
@@ -17,7 +17,7 @@
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #include "chrome/browser/ash/extensions/file_manager/system_notification_manager.h"
 #include "chromeos/ash/components/drivefs/drivefs_host.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/ash/components/drivefs/sync_status_tracker.h"
 #include "extensions/browser/extension_event_histogram_value.h"
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_drive.cc b/chrome/browser/ash/extensions/file_manager/private_api_drive.cc
index 7e0960d..25bd990 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_drive.cc
@@ -51,7 +51,7 @@
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "chrome/common/extensions/api/file_manager_private_internal.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/drivefs/drivefs_util.h"
 #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/ash/components/network/network_handler.h"
@@ -86,7 +86,7 @@
 using content::BrowserThread;
 using drive::DriveIntegrationService;
 using drive::util::GetIntegrationServiceByProfile;
-using drivefs::pinning::PinManager;
+using drivefs::pinning::PinningManager;
 using extensions::api::file_manager_private::EntryProperties;
 using extensions::api::file_manager_private::EntryPropertyName;
 using file_manager::util::EntryDefinition;
@@ -909,7 +909,7 @@
     return RespondNow(Error("Drive not available"));
   }
 
-  PinManager* const p = service->GetPinManager();
+  PinningManager* const p = service->GetPinningManager();
   if (!p) {
     return RespondNow(Error("Pin Manager not available"));
   }
@@ -937,7 +937,7 @@
     return RespondNow(Error("Drive not available"));
   }
 
-  PinManager* const p = service->GetPinManager();
+  PinningManager* const p = service->GetPinningManager();
   if (!p) {
     return RespondNow(Error("Pin Manager not available"));
   }
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 bf53672..3ce9316 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_misc.cc
@@ -71,7 +71,7 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/settings/timezone_settings.h"
 #include "components/account_id/account_id.h"
 #include "components/drive/drive_pref_names.h"
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_util.cc b/chrome/browser/ash/extensions/file_manager/private_api_util.cc
index 53b7dad..a328ec6 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_util.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_util.cc
@@ -34,7 +34,7 @@
 #include "chrome/browser/ash/guest_os/public/types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/drivefs/drivefs_util.h"
 #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/ash/components/drivefs/sync_status_tracker.h"
@@ -283,7 +283,7 @@
       drive::prefs::kDriveFsBulkPinningEnabled);
 }
 
-drivefs::pinning::PinManager* GetPinManager(Profile* profile) {
+drivefs::pinning::PinningManager* GetPinningManager(Profile* profile) {
   if (!profile) {
     return nullptr;
   }
@@ -293,7 +293,7 @@
     return nullptr;
   }
 
-  return integration_service->GetPinManager();
+  return integration_service->GetPinningManager();
 }
 
 bool IsPathUnderMyDrive(const base::FilePath& relative_path) {
@@ -427,19 +427,19 @@
 
     if (IsBulkPinningEnabledForProfile(running_profile_) &&
         IsPathUnderMyDrive(relative_path_)) {
-      drivefs::pinning::PinManager* const pin_manager =
-          GetPinManager(running_profile_);
+      drivefs::pinning::PinningManager* const pinning_manager =
+          GetPinningManager(running_profile_);
 
       const auto stable_id =
-          drivefs::pinning::PinManager::Id(metadata->stable_id);
+          drivefs::pinning::PinningManager::Id(metadata->stable_id);
       if (properties_->sync_status ==
               file_manager_private::SYNC_STATUS_NOT_FOUND &&
-          pin_manager->IsTrackedAndUnpinned(stable_id)) {
-        // The `PinManager` maintains a list of 200 items that it pins, if the
-        // item is not within these 200 items it will eventually be pinned, but
-        // does not enter into a queued state just yet. This ensures the queued
-        // state is reflected for items that will be pinned but haven't called
-        // `SetPinned` yet.
+          pinning_manager->IsTrackedAndUnpinned(stable_id)) {
+        // The `PinningManager` maintains a list of 200 items that it pins, if
+        // the item is not within these 200 items it will eventually be pinned,
+        // but does not enter into a queued state just yet. This ensures the
+        // queued state is reflected for items that will be pinned but haven't
+        // called `SetPinned` yet.
         properties_->sync_status = file_manager_private::SYNC_STATUS_QUEUED;
       }
 
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 792dec10..2582dcdf 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -505,32 +505,32 @@
     FilesAppBrowserTest,
     ::testing::Values(
         TestCase("checkNewFolderEnabledInsideReadWriteFolder")
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("checkNewFolderDisabledInsideReadOnlyFolder")
-            .FilesExperimental(),
-        TestCase("checkPasteEnabledInsideReadWriteFolder").FilesExperimental(),
-        TestCase("checkPasteDisabledInsideReadOnlyFolder").FilesExperimental(),
-        TestCase("checkDownloadsContextMenu").FilesExperimental(),
-        TestCase("checkPlayFilesContextMenu").FilesExperimental(),
-        TestCase("checkLinuxFilesContextMenu").FilesExperimental(),
+            .NewDirectoryTree(),
+        TestCase("checkPasteEnabledInsideReadWriteFolder").NewDirectoryTree(),
+        TestCase("checkPasteDisabledInsideReadOnlyFolder").NewDirectoryTree(),
+        TestCase("checkDownloadsContextMenu").NewDirectoryTree(),
+        TestCase("checkPlayFilesContextMenu").NewDirectoryTree(),
+        TestCase("checkLinuxFilesContextMenu").NewDirectoryTree(),
         TestCase("checkDeleteDisabledInDocProvider")
             .EnableGenericDocumentsProvider()
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("checkDeleteEnabledInDocProvider")
             .EnableGenericDocumentsProvider()
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("checkRenameDisabledInDocProvider")
             .EnableGenericDocumentsProvider()
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("checkRenameEnabledInDocProvider")
             .EnableGenericDocumentsProvider()
-            .FilesExperimental(),
-        TestCase("checkDeleteEnabledInRecents").FilesExperimental(),
-        TestCase("checkGoToFileLocationEnabledInRecents").FilesExperimental(),
+            .NewDirectoryTree(),
+        TestCase("checkDeleteEnabledInRecents").NewDirectoryTree(),
+        TestCase("checkGoToFileLocationEnabledInRecents").NewDirectoryTree(),
         TestCase("checkGoToFileLocationDisabledInMultipleSelection")
-            .FilesExperimental(),
-        TestCase("checkEncryptedCrossVolumeMoveDisabled").FilesExperimental(),
-        TestCase("checkEncryptedMoveEnabled").FilesExperimental(),
+            .NewDirectoryTree(),
+        TestCase("checkEncryptedCrossVolumeMoveDisabled").NewDirectoryTree(),
+        TestCase("checkEncryptedMoveEnabled").NewDirectoryTree(),
         TestCase("checkDeleteEnabledForReadWriteFile"),
         TestCase("checkDeleteDisabledForReadOnlyDocument"),
         TestCase("checkDeleteDisabledForReadOnlyFile"),
@@ -726,21 +726,21 @@
     DirectoryTree, /* directory_tree.js */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("directoryTreeActiveDirectory").FilesExperimental(),
-        TestCase("directoryTreeSelectedDirectory").FilesExperimental(),
-        TestCase("directoryTreeHorizontalScroll").FilesExperimental(),
-        TestCase("directoryTreeExpandHorizontalScroll").FilesExperimental(),
-        TestCase("directoryTreeExpandHorizontalScrollRTL").FilesExperimental(),
-        TestCase("directoryTreeVerticalScroll").FilesExperimental(),
-        TestCase("directoryTreeExpandFolder").FilesExperimental(),
+        TestCase("directoryTreeActiveDirectory").NewDirectoryTree(),
+        TestCase("directoryTreeSelectedDirectory").NewDirectoryTree(),
+        TestCase("directoryTreeHorizontalScroll").NewDirectoryTree(),
+        TestCase("directoryTreeExpandHorizontalScroll").NewDirectoryTree(),
+        TestCase("directoryTreeExpandHorizontalScrollRTL").NewDirectoryTree(),
+        TestCase("directoryTreeVerticalScroll").NewDirectoryTree(),
+        TestCase("directoryTreeExpandFolder").NewDirectoryTree(),
         TestCase("directoryTreeExpandFolderWithHiddenFileAndShowHiddenFilesOff")
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("directoryTreeExpandFolderWithHiddenFileAndShowHiddenFilesOn")
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("directoryTreeExpandFolderOnNonDelayExpansionVolume")
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("directoryTreeExpandFolderOnDelayExpansionVolume")
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("directoryTreeActiveDirectory"),
         TestCase("directoryTreeSelectedDirectory"),
         TestCase("directoryTreeHorizontalScroll"),
@@ -875,7 +875,7 @@
         TestCase("driveItemsOutOfViewportShouldUpdateTheirSyncStatus")
             .EnableBulkPinning()
             .EnableInlineSyncStatusProgressEvents(),
-        TestCase("driveAllItemsShouldBeQueuedIfTrackedByPinManager")
+        TestCase("driveAllItemsShouldBeQueuedIfTrackedByPinningManager")
             .EnableBulkPinning()
             .EnableInlineSyncStatusProgressEvents(),
         TestCase("driveDirtyItemsShouldBeDisplayedAsQueued")
@@ -1238,8 +1238,8 @@
     CopyBetweenWindows, /* copy_between_windows.js */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("copyBetweenWindowsLocalToUsb").FilesExperimental(),
-        TestCase("copyBetweenWindowsUsbToLocal").FilesExperimental(),
+        TestCase("copyBetweenWindowsLocalToUsb").NewDirectoryTree(),
+        TestCase("copyBetweenWindowsUsbToLocal").NewDirectoryTree(),
         TestCase("copyBetweenWindowsLocalToDrive"),
         TestCase("copyBetweenWindowsLocalToUsb"),
         // TODO(b/189173190): Enable
@@ -1349,10 +1349,10 @@
     Crostini, /* crostini.js */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("mountCrostini").FilesExperimental(),
-        TestCase("enableDisableCrostini").FilesExperimental(),
+        TestCase("mountCrostini").NewDirectoryTree(),
+        TestCase("enableDisableCrostini").NewDirectoryTree(),
         TestCase("sharePathWithCrostini")
-            .FilesExperimental()
+            .NewDirectoryTree()
             .FeatureIds({"screenplay-122c00f8-9842-4666-8ca0-b6bf47454551"}),
         TestCase("mountCrostini"),
         TestCase("enableDisableCrostini"),
@@ -1515,20 +1515,20 @@
     Breadcrumbs, /* breadcrumbs.js */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("breadcrumbsNavigate").FilesExperimental(),
-        TestCase("breadcrumbsDownloadsTranslation").FilesExperimental(),
-        TestCase("breadcrumbsRenderShortPath").FilesExperimental(),
-        TestCase("breadcrumbsEliderButtonNotExist").FilesExperimental(),
-        TestCase("breadcrumbsRenderLongPath").FilesExperimental(),
-        TestCase("breadcrumbsMainButtonClick").FilesExperimental(),
-        TestCase("breadcrumbsMainButtonEnterKey").FilesExperimental(),
-        TestCase("breadcrumbsEliderButtonClick").FilesExperimental(),
-        TestCase("breadcrumbsEliderButtonKeyboard").FilesExperimental(),
-        TestCase("breadcrumbsEliderMenuClickOutside").FilesExperimental(),
-        TestCase("breadcrumbsEliderMenuItemClick").FilesExperimental(),
-        TestCase("breadcrumbsEliderMenuItemTabLeft").FilesExperimental(),
-        TestCase("breadcrumbNavigateBackToSharedWithMe").FilesExperimental(),
-        TestCase("breadcrumbsEliderMenuItemTabRight").FilesExperimental(),
+        TestCase("breadcrumbsNavigate").NewDirectoryTree(),
+        TestCase("breadcrumbsDownloadsTranslation").NewDirectoryTree(),
+        TestCase("breadcrumbsRenderShortPath").NewDirectoryTree(),
+        TestCase("breadcrumbsEliderButtonNotExist").NewDirectoryTree(),
+        TestCase("breadcrumbsRenderLongPath").NewDirectoryTree(),
+        TestCase("breadcrumbsMainButtonClick").NewDirectoryTree(),
+        TestCase("breadcrumbsMainButtonEnterKey").NewDirectoryTree(),
+        TestCase("breadcrumbsEliderButtonClick").NewDirectoryTree(),
+        TestCase("breadcrumbsEliderButtonKeyboard").NewDirectoryTree(),
+        TestCase("breadcrumbsEliderMenuClickOutside").NewDirectoryTree(),
+        TestCase("breadcrumbsEliderMenuItemClick").NewDirectoryTree(),
+        TestCase("breadcrumbsEliderMenuItemTabLeft").NewDirectoryTree(),
+        TestCase("breadcrumbNavigateBackToSharedWithMe").NewDirectoryTree(),
+        TestCase("breadcrumbsEliderMenuItemTabRight").NewDirectoryTree(),
         TestCase("breadcrumbsNavigate"),
         TestCase("breadcrumbsDownloadsTranslation"),
         TestCase("breadcrumbsRenderShortPath"),
@@ -1620,11 +1620,11 @@
     ::testing::Values(
         TestCase("androidPhotosBanner")
             .EnablePhotosDocumentsProvider()
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("androidPhotosBanner")
             .EnablePhotosDocumentsProvider()
             .EnableCrosComponents()
-            .FilesExperimental(),
+            .NewDirectoryTree(),
         TestCase("androidPhotosBanner").EnablePhotosDocumentsProvider(),
         TestCase("androidPhotosBanner")
             .EnablePhotosDocumentsProvider()
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
index 741117d..098185e5 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -124,7 +124,7 @@
 #include "chromeos/ash/components/dbus/vm_concierge/concierge_service.pb.h"
 #include "chromeos/ash/components/disks/mount_point.h"
 #include "chromeos/ash/components/drivefs/drivefs_host.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "chromeos/ash/components/drivefs/fake_drivefs.h"
 #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/ash/components/smbfs/smbfs_host.h"
@@ -2393,6 +2393,12 @@
     }
   }
 
+  if (options.enable_new_directory_tree) {
+    enabled_features.push_back(ash::features::kFilesNewDirectoryTree);
+  } else {
+    disabled_features.push_back(ash::features::kFilesNewDirectoryTree);
+  }
+
   // This is destroyed in |TearDown()|. We cannot initialize this in the
   // constructor due to this feature values' above dependence on virtual
   // method calls, but by convention subclasses of this fixture may initialize
@@ -3368,12 +3374,12 @@
     return;
   }
 
-  if (name == "forcePinManagerSpaceCheck") {
+  if (name == "forcePinningManagerSpaceCheck") {
     auto* integration_service =
         drive::DriveIntegrationServiceFactory::FindForProfile(profile());
     ASSERT_NE(integration_service, nullptr);
-    ASSERT_NE(integration_service->GetPinManager(), nullptr);
-    integration_service->GetPinManager()->CheckFreeSpace();
+    ASSERT_NE(integration_service->GetPinningManager(), nullptr);
+    integration_service->GetPinningManager()->CheckFreeSpace();
     return;
   }
 
@@ -3391,8 +3397,8 @@
     auto* integration_service =
         drive::DriveIntegrationServiceFactory::FindForProfile(profile());
     ASSERT_NE(integration_service, nullptr);
-    ASSERT_NE(integration_service->GetPinManager(), nullptr);
-    integration_service->GetPinManager()->SetOnline(enabled.value());
+    ASSERT_NE(integration_service->GetPinningManager(), nullptr);
+    integration_service->GetPinningManager()->SetOnline(enabled.value());
     return;
   }
 
@@ -3400,8 +3406,9 @@
     auto* integration_service =
         drive::DriveIntegrationServiceFactory::FindForProfile(profile());
     ASSERT_NE(integration_service, nullptr);
-    ASSERT_NE(integration_service->GetPinManager(), nullptr);
-    ASSERT_TRUE(integration_service->GetPinManager()->CalculateRequiredSpace());
+    ASSERT_NE(integration_service->GetPinningManager(), nullptr);
+    ASSERT_TRUE(
+        integration_service->GetPinningManager()->CalculateRequiredSpace());
     return;
   }
 
@@ -3409,8 +3416,8 @@
     auto* integration_service =
         drive::DriveIntegrationServiceFactory::FindForProfile(profile());
     ASSERT_NE(integration_service, nullptr);
-    ASSERT_NE(integration_service->GetPinManager(), nullptr);
-    auto progress = integration_service->GetPinManager()->GetProgress();
+    ASSERT_NE(integration_service->GetPinningManager(), nullptr);
+    auto progress = integration_service->GetPinningManager()->GetProgress();
     *output = drivefs::pinning::ToString(progress.stage);
     return;
   }
@@ -3419,8 +3426,8 @@
     auto* integration_service =
         drive::DriveIntegrationServiceFactory::FindForProfile(profile());
     ASSERT_NE(integration_service, nullptr);
-    ASSERT_NE(integration_service->GetPinManager(), nullptr);
-    auto progress = integration_service->GetPinManager()->GetProgress();
+    ASSERT_NE(integration_service->GetPinningManager(), nullptr);
+    auto progress = integration_service->GetPinningManager()->GetProgress();
     *output = base::NumberToString(progress.required_space);
     return;
   }
@@ -3432,8 +3439,8 @@
     auto* integration_service =
         drive::DriveIntegrationServiceFactory::FindForProfile(profile());
     ASSERT_NE(integration_service, nullptr);
-    ASSERT_NE(integration_service->GetPinManager(), nullptr);
-    integration_service->GetPinManager()->SetShouldPinFilesForTesting(
+    ASSERT_NE(integration_service->GetPinningManager(), nullptr);
+    integration_service->GetPinningManager()->SetShouldPinFilesForTesting(
         enabled.value());
     return;
   }
@@ -3690,6 +3697,11 @@
     return;
   }
 
+  if (name == "isNewDirectoryTreeEnabled") {
+    *output = options.enable_new_directory_tree ? "true" : "false";
+    return;
+  }
+
   if (name == "switchLanguage") {
     const std::string* language = value.FindString("language");
     ASSERT_TRUE(language);
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
index b784b3f..a963e88 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -204,6 +204,9 @@
     // Whether to enable jellybean UI elements.
     bool enable_cros_components = false;
 
+    // Whether to enable new directory tree implementation.
+    bool enable_new_directory_tree = false;
+
     // Feature IDs associated for mapping test cases and features.
     std::vector<std::string> feature_ids;
   };
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc
index 5bfb12f..64337521 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.cc
@@ -93,6 +93,11 @@
   return *this;
 }
 
+TestCase& TestCase::NewDirectoryTree() {
+  options.enable_new_directory_tree = true;
+  return *this;
+}
+
 // Show the startup browser. Some tests invoke the file picker dialog during
 // the test. Requesting a file picker from a background page is forbidden by
 // the apps platform, and it's a bug that these tests do so.
@@ -294,6 +299,10 @@
     full_name += "_CrosComponents";
   }
 
+  if (options.enable_new_directory_tree) {
+    full_name += "_NewDirectoryTree";
+  }
+
   switch (options.device_mode) {
     case kDeviceModeNotSet:
       break;
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h
index 03e8391..ebb8f32 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_utils.h
@@ -58,6 +58,8 @@
 
   TestCase& EnableSinglePartitionFormat();
 
+  TestCase& NewDirectoryTree();
+
   // Show the startup browser. Some tests invoke the file picker dialog during
   // the test. Requesting a file picker from a background page is forbidden by
   // the apps platform, and it's a bug that these tests do so.
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc
index dd09e280..8fa1b9b6 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -1360,6 +1360,9 @@
 
   dict->Set("CROS_COMPONENTS", chromeos::features::IsCrosComponentsEnabled());
 
+  dict->Set("NEW_DIRECTORY_TREE", base::FeatureList::IsEnabled(
+                                      ash::features::kFilesNewDirectoryTree));
+
   if (base::FeatureList::IsEnabled(features::kDataLeakPreventionPolicy) &&
       base::FeatureList::IsEnabled(
           features::kDataLeakPreventionFilesRestriction)) {
diff --git a/chrome/browser/ash/file_manager/office_file_tasks.cc b/chrome/browser/ash/file_manager/office_file_tasks.cc
index b1a666d..09f6e36 100644
--- a/chrome/browser/ash/file_manager/office_file_tasks.cc
+++ b/chrome/browser/ash/file_manager/office_file_tasks.cc
@@ -79,8 +79,7 @@
     std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics) {
   switch (fallback_reason) {
     case ash::office_fallback::FallbackReason::kOffline:
-      UMA_HISTOGRAM_ENUMERATION(
-          ash::cloud_upload::kOneDriveErrorMetricName,
+      cloud_open_metrics->LogOneDriveOpenError(
           ash::cloud_upload::OfficeOneDriveOpenErrors::kOffline);
       break;
     case ash::office_fallback::FallbackReason::kDriveDisabled:
diff --git a/chrome/browser/ash/kerberos/OWNERS b/chrome/browser/ash/kerberos/OWNERS
index cf144fc..b153dada9 100644
--- a/chrome/browser/ash/kerberos/OWNERS
+++ b/chrome/browser/ash/kerberos/OWNERS
@@ -6,9 +6,4 @@
 fsandrade@chromium.org
 
 # Secondary owner(s)
-rsorokin@google.com
-
-# Previous owners (for general questions, if current owners are not available)
-# Commented out so automatic tools don't prefer.
-# ljusten@chromium.org
-# tomdobro@hromium.org
+emaxx@chromium.org
diff --git a/chrome/browser/ash/login/screens/drive_pinning_screen.cc b/chrome/browser/ash/login/screens/drive_pinning_screen.cc
index caa689ac..27b8f2bd 100644
--- a/chrome/browser/ash/login/screens/drive_pinning_screen.cc
+++ b/chrome/browser/ash/login/screens/drive_pinning_screen.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/ash/login/wizard_controller.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/ash/login/drive_pinning_screen_handler.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "components/drive/drive_pref_names.h"
 #include "ui/base/text/bytes_formatting.h"
 
@@ -24,7 +24,7 @@
 constexpr const char kUserActionNext[] = "driveNext";
 constexpr const char kUserActionReturn[] = "return";
 
-using drivefs::pinning::PinManager;
+using drivefs::pinning::PinningManager;
 using drivefs::pinning::Progress;
 
 bool ShouldShowChoobeReturnButton(ChoobeFlowController* controller) {
@@ -43,11 +43,12 @@
       DrivePinningScreenView::kScreenId);
 }
 
-PinManager* GetPinManager() {
+PinningManager* GetPinningManager() {
   drive::DriveIntegrationService* const service =
       drive::DriveIntegrationServiceFactory::FindForProfile(
           ProfileManager::GetActiveUserProfile());
-  return service && service->IsMounted() ? service->GetPinManager() : nullptr;
+  return service && service->IsMounted() ? service->GetPinningManager()
+                                         : nullptr;
 }
 
 void RecordOOBEScreenSkippedMetric(drivefs::pinning::Stage stage) {
@@ -158,8 +159,8 @@
 
   Observe(service);
 
-  PinManager* const pin_manager = GetPinManager();
-  if (!pin_manager) {
+  PinningManager* const pinning_manager = GetPinningManager();
+  if (!pinning_manager) {
     VLOG(1) << "No bulk-pinning manager";
     return;
   }
@@ -169,7 +170,7 @@
   }
 
   RecordCHOOBEScreenBulkPinningInitializations(bulk_pinning_initializations_);
-  LOG_IF(ERROR, !pin_manager->CalculateRequiredSpace())
+  LOG_IF(ERROR, !pinning_manager->CalculateRequiredSpace())
       << "Cannot calculate required space";
 }
 
diff --git a/chrome/browser/ash/login/screens/drive_pinning_screen.h b/chrome/browser/ash/login/screens/drive_pinning_screen.h
index 2200cf9..6c03987e 100644
--- a/chrome/browser/ash/login/screens/drive_pinning_screen.h
+++ b/chrome/browser/ash/login/screens/drive_pinning_screen.h
@@ -11,7 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 
 class Profile;
 
diff --git a/chrome/browser/ash/login/screens/drive_pinning_screen_browsertest.cc b/chrome/browser/ash/login/screens/drive_pinning_screen_browsertest.cc
index 304a3bd..f6d7c4b 100644
--- a/chrome/browser/ash/login/screens/drive_pinning_screen_browsertest.cc
+++ b/chrome/browser/ash/login/screens/drive_pinning_screen_browsertest.cc
@@ -75,7 +75,7 @@
         &DrivePinningBaseScreenTest::HandleScreenExit, base::Unretained(this)));
   }
 
-  void SetPinManagerProgress(Progress progress) {
+  void SetPinningManagerProgress(Progress progress) {
     WizardController::default_controller()
         ->GetScreen<DrivePinningScreen>()
         ->OnProgressForTest(progress);
@@ -132,7 +132,7 @@
   current_progress.free_space = 100LL * 1024LL * 1024LL * 1024LL;
   current_progress.required_space = 512 * 1024 * 1024;
 
-  SetPinManagerProgress(current_progress);
+  SetPinningManagerProgress(current_progress);
   ShowDrivePinningScreen();
 
   test::OobeJS().ExpectVisiblePath(kDrivePinningDialoguePath);
@@ -159,7 +159,7 @@
   current_progress.free_space = 100LL * 1024LL * 1024LL * 1024LL;
   current_progress.required_space = 512 * 1024 * 1024;
 
-  SetPinManagerProgress(current_progress);
+  SetPinningManagerProgress(current_progress);
   ShowDrivePinningScreen();
 
   test::OobeJS().ExpectVisiblePath(kDrivePinningDialoguePath);
@@ -177,7 +177,7 @@
   Progress current_progress = Progress();
   current_progress.stage = GetParam();
 
-  SetPinManagerProgress(current_progress);
+  SetPinningManagerProgress(current_progress);
   ShowDrivePinningScreen();
 
   WaitForScreenExit();
@@ -232,8 +232,9 @@
 
   void WaitForSuccessStateChange() {
     auto* drive_service = GetDriveServiceForActiveProfile();
-    auto* const pin_manager = drive_service->GetPinManager();
-    if (pin_manager && pin_manager->GetProgress().stage == Stage::kSuccess) {
+    auto* const pinning_manager = drive_service->GetPinningManager();
+    if (pinning_manager &&
+        pinning_manager->GetProgress().stage == Stage::kSuccess) {
       return;
     }
 
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.cc
index 5cad2157b..ec2c1a2 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.h"
 
+#include <algorithm>
+#include <iterator>
 #include <sstream>
 #include <string>
 #include <string_view>
@@ -169,9 +171,6 @@
                                      upload_info->offset);
       return;
     }
-
-    // TODO(b/266018440): If the crash is found to have been uploaded, need to
-    // mark it as stale in reported local IDs.
   }
 
   MetricData metric_data = FillFatalCrashTelemetry(crash_event_info);
@@ -195,6 +194,13 @@
     uploaded_crash_info_manager_->Update(
         crash_event_info->upload_info->creation_time,
         crash_event_info->upload_info->offset);
+    // Once uploaded, the crash's local ID must be removed from saved local IDs.
+    // Reason is that when the number of saved local IDs reach the max, the
+    // crash with the earliest capture time will be removed. However, crashes do
+    // not come in the order of capture time. If we leave uploaded crashes in
+    // the saved local IDs, some late-coming crashes with early capture time may
+    // not get reported because of this.
+    reported_local_id_manager_->Remove(crash_event_info->local_id);
   }
 }
 
@@ -281,9 +287,8 @@
 
 bool FatalCrashEventsObserver::ReportedLocalIdManager::ShouldReport(
     const std::string& local_id,
-    int64_t capture_timestamp_us) const {
+    int64_t capture_timestamp_us) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK_EQ(local_id_entries_.size(), local_ids_.size());
 
   if (capture_timestamp_us < 0) {
     // Only possible when loading a corrupt save file.
@@ -298,8 +303,8 @@
   }
 
   // Max number of crash events reached and the current crash event is too old.
-  if (local_id_entries_.size() >= kMaxNumOfLocalIds &&
-      capture_timestamp_us <= local_id_entries_.top().capture_timestamp_us) {
+  if (local_ids_.size() >= kMaxNumOfLocalIds &&
+      capture_timestamp_us <= GetEarliestLocalIdEntry().capture_timestamp_us) {
     return false;
   }
 
@@ -318,20 +323,40 @@
   // Keep only the most recent kMaxNumOfLocalIds local IDs. Remove that oldest
   // local IDs if too many are saved.
   if (local_ids_.size() >= kMaxNumOfLocalIds) {
-    local_ids_.erase(local_id_entries_.top().local_id);
-    local_id_entries_.pop();
+    RemoveEarliestLocalIdEntry();
   }
 
-  CHECK(local_ids_.try_emplace(local_id, capture_timestamp_us).second)
-      << "Local ID " << local_id << " already saved while trying to emplace.";
-  local_id_entries_.emplace(local_id, capture_timestamp_us);
-  WriteSaveFile();
+  return Add(local_id, capture_timestamp_us);
+}
 
+bool FatalCrashEventsObserver::ReportedLocalIdManager::Add(
+    const std::string& local_id,
+    int64_t capture_timestamp_us) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Clean up before adding more entries. Otherwise it is possible that the
+  // queue can grow uncontrolled.
+  CleanUpLocalIdEntryQueue();
+  if (!local_ids_.try_emplace(local_id, capture_timestamp_us).second) {
+    return false;
+  }
+  local_id_entries_.emplace(local_id, capture_timestamp_us);
+
+  WriteSaveFile();
   return true;
 }
 
+void FatalCrashEventsObserver::ReportedLocalIdManager::Remove(
+    const std::string& local_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  local_ids_.erase(local_id);
+  WriteSaveFile();
+}
+
 void FatalCrashEventsObserver::ReportedLocalIdManager::LoadSaveFile() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!base::PathExists(save_file_)) {
     // File has never been written yet, skip loading it.
     return;
@@ -394,6 +419,64 @@
   }
 }
 
+void FatalCrashEventsObserver::ReportedLocalIdManager::
+    CleanUpLocalIdEntryQueue() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (local_id_entries_.size() >= kMaxSizeOfLocalIdEntryQueue) {
+    // In extreme situations, such as when the oldest unuploaded crash remains
+    // unuploaded for an extended amount of time, it's possible to leave a lot
+    // of uploaded crashes' local IDs in local_id_entries_. In this case,
+    // rebuild the queue.
+    ReconstructLocalIdEntries();
+    return;
+  }
+
+  // Clean up uploaded crashes from the top of the priority queue.
+  while (!local_id_entries_.empty()) {
+    if (base::Contains(local_ids_, local_id_entries_.top().local_id)) {
+      break;
+    }
+    local_id_entries_.pop();
+  }
+}
+
+void FatalCrashEventsObserver::ReportedLocalIdManager::
+    ReconstructLocalIdEntries() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // First build the container.
+  std::vector<LocalIdEntry> queue_container;
+  queue_container.reserve(local_ids_.size());
+  std::transform(local_ids_.begin(), local_ids_.end(),
+                 std::back_inserter(queue_container),
+                 [](const std::pair<std::string, int64_t>& input) {
+                   return LocalIdEntry{.local_id = input.first,
+                                       .capture_timestamp_us = input.second};
+                 });
+
+  // Then reconstruct the local ID entries priority queue from the container.
+  local_id_entries_ = decltype(local_id_entries_)(
+      decltype(local_id_entries_)::value_compare(), std::move(queue_container));
+}
+
+const FatalCrashEventsObserver::LocalIdEntry&
+FatalCrashEventsObserver::ReportedLocalIdManager::GetEarliestLocalIdEntry() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CleanUpLocalIdEntryQueue();
+  // After the cleanup, the top of `local_id_entries_` is the earliest.
+  return local_id_entries_.top();
+}
+
+void FatalCrashEventsObserver::ReportedLocalIdManager::
+    RemoveEarliestLocalIdEntry() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CleanUpLocalIdEntryQueue();
+  // After the cleanup, the top of `local_id_entries_` is the earliest.
+  local_ids_.erase(local_id_entries_.top().local_id);
+  local_id_entries_.pop();
+}
+
 bool FatalCrashEventsObserver::ReportedLocalIdManager::LocalIdEntryComparator::
 operator()(const LocalIdEntry& a, const LocalIdEntry& b) const {
   return a.capture_timestamp_us > b.capture_timestamp_us;
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.h b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.h
index a777b3b..f98521d6 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.h
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.h
@@ -32,11 +32,15 @@
   // A RAII class that setups the environment for testing this class.
   class TestEnvironment;
 
+  // An entry corresponds to a crash that is saved in the save file of reported
+  // local IDs.
   struct LocalIdEntry {
     std::string local_id;
     int64_t capture_timestamp_us;
   };
 
+  using SkippedUnuploadedCrashCallback =
+      base::RepeatingCallback<void(LocalIdEntry)>;
   using SkippedUploadedCrashCallback =
       base::RepeatingCallback<void(std::string /* crash_report_id */,
                                    base::Time /* creation_time */,
@@ -56,17 +60,18 @@
 
   // Sets the callback that is called when an unuploaded crash is skipped.
   void SetSkippedUnuploadedCrashCallback(
-      base::RepeatingCallback<void(LocalIdEntry)> callback);
+      SkippedUnuploadedCrashCallback callback);
 
   // Sets the callback that is called when an uploaded crash is skipped.
   void SetSkippedUploadedCrashCallback(SkippedUploadedCrashCallback callback);
 
  private:
-  // Give `TestEnvironment` the access to the private constructor that specifies
-  // the path for the save file.
+  // Give `TestEnvironment` the access to the private constructor that
+  // specifies the path for the save file.
   friend class FatalCrashEventsObserver::TestEnvironment;
 
-  // Manages reported local IDs.
+  // Manages the local IDs corresponding to reported unuploaded crashes. Once
+  // a crash is uploaded, it is outside the purview of this class.
   class ReportedLocalIdManager {
    public:
     static std::unique_ptr<ReportedLocalIdManager> Create(
@@ -82,7 +87,7 @@
     // the timestamp is no later than the earliest timestamp corresponding to
     // reported local IDs.
     bool ShouldReport(const std::string& local_id,
-                      int64_t capture_timestamp_us) const;
+                      int64_t capture_timestamp_us);
 
     // Updates local ID. Does nothing and returns false if a crash with the
     // given local ID and capture timestamp should not be reported. Otherwise,
@@ -91,6 +96,14 @@
     bool UpdateLocalId(const std::string& local_id,
                        int64_t capture_timestamp_us);
 
+    // Adds a local ID and its corresponding capture timestamp. Returns true if
+    // the local ID can be saved to memory.
+    bool Add(const std::string& local_id, int64_t capture_timestamp_us);
+
+    // Removes a local ID, e.g., it has been reported again as uploaded. If the
+    // local ID is not found, does nothing.
+    void Remove(const std::string& local_id);
+
    private:
     // Give `TestEnvironment` the access to `kMaxNumOfLocalIds`.
     friend class FatalCrashEventsObserver::TestEnvironment;
@@ -107,6 +120,10 @@
     // The maximum number of local IDs to save.
     static constexpr size_t kMaxNumOfLocalIds = 128u;
 
+    // The maximum size of the priority queue before reconstructing it.
+    static constexpr size_t kMaxSizeOfLocalIdEntryQueue{kMaxNumOfLocalIds *
+                                                        10u};
+
     explicit ReportedLocalIdManager(base::FilePath save_file_path);
 
     // Loads save file. Logs and ignores errors. If there is a parsing error,
@@ -117,10 +134,25 @@
     // Writes save file based on the currently saved reported local IDs. Ignores
     // and logs any errors encountered. If the device reboots before the write
     // succeeds next time, this may lead to a repeated report of an unuploaded
-    // crash, which is, however, better than the opposite,
-    // i.e., missing unuploaded crash.
+    // crash, which is, however, better than the opposite, i.e., missing
+    // unuploaded crash.
     void WriteSaveFile() const;
 
+    // Cleans up local IDs corresponding to crashes that have been reported
+    // again as uploaded in an efficient manner.
+    void CleanUpLocalIdEntryQueue();
+
+    // (Re)constructs `local_id_entries_` from `local_ids_`.
+    void ReconstructLocalIdEntries();
+
+    // Gets the local ID entry corresponding to the earliest unuploaded crash.
+    // Must be used before the earliest local ID is removed by any operations on
+    // `local_id_entries_`.
+    const LocalIdEntry& GetEarliestLocalIdEntry();
+
+    // Remove the local ID entry corresponding to the earliest unuploaded crash.
+    void RemoveEarliestLocalIdEntry();
+
     SEQUENCE_CHECKER(sequence_checker_);
 
     // The file that saves reported local IDs. It is in the CSV format: csv
@@ -131,16 +163,25 @@
     const base::FilePath save_file_tmp_ GUARDED_BY_CONTEXT(sequence_checker_){
         save_file_.AddExtension(".tmp")};
 
-    // The priority queue that makes popping out the oldest crash efficient.
+    // A map that maps local IDs to their respective capture timestamps in
+    // microseconds. Only local IDs corresponding to crashes that has been
+    // reported as unuploaded crashes are here. If a crash has been uploaded
+    // then, its local ID would then be removed from this map.
+    std::unordered_map</*local_id*/ std::string, /*timestamp*/ int64_t>
+        local_ids_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+    // The priority queue that makes popping out the oldest crash efficient. The
+    // local IDs in this priority queue constitute a super set of those in
+    // `local_ids_`, which implies that some local IDs corresponding to crashes
+    // that have already been reported again as uploaded crashes. This is to
+    // avoid removing removing non-top elements from a priority queue as this
+    // operation is inefficient.
+    // TODO(b/266018440): Rename this variable to a string that contains the
+    // word "queue".
     std::priority_queue<LocalIdEntry,
                         std::vector<LocalIdEntry>,
                         LocalIdEntryComparator>
         local_id_entries_ GUARDED_BY_CONTEXT(sequence_checker_);
-
-    // A map that maps local IDs to their respective capture timestamps in
-    // microseconds.
-    std::unordered_map<std::string, int64_t> local_ids_
-        GUARDED_BY_CONTEXT(sequence_checker_);
   };
 
   // Manages uploaded crash info, namely the creation time and offset of
@@ -233,9 +274,9 @@
   std::unique_ptr<UploadedCrashInfoManager> uploaded_crash_info_manager_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
-  // Called when an unuploaded crash is skipped and not reported. Currently only
-  // used in tests but production code may also use it in the future.
-  base::RepeatingCallback<void(LocalIdEntry)> skipped_unuploaded_callback_
+  // Called when an unuploaded crash is skipped and not reported. Currently
+  // only used in tests but production code may also use it in the future.
+  SkippedUnuploadedCrashCallback skipped_unuploaded_callback_
       GUARDED_BY_CONTEXT(sequence_checker_){base::DoNothing()};
 
   // Called when an uploaded crash is skipped and not reported. Currently only
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.cc
index a1c8494..8883e5b6 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.cc
@@ -8,6 +8,7 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/ptr_util.h"
+#include "base/sequence_checker.h"
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer.h"
 
 namespace reporting {
@@ -41,4 +42,14 @@
   observer.SetInterruptedAfterEventObservedForTest(
       interrupted_after_event_observed);
 }
+
+// static
+size_t FatalCrashEventsObserver::TestEnvironment::GetLocalIdEntryQueueSize(
+    FatalCrashEventsObserver& observer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(observer.sequence_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(
+      observer.reported_local_id_manager_->sequence_checker_);
+  return observer.reported_local_id_manager_->local_id_entries_.size();
+}
+
 }  // namespace reporting
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.h b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.h
index 5bd85b6c..ada26f0 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.h
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_test_util.h
@@ -18,6 +18,8 @@
  public:
   static constexpr size_t kMaxNumOfLocalIds{
       ReportedLocalIdManager::kMaxNumOfLocalIds};
+  static constexpr size_t kMaxSizeOfLocalIdEntryQueue{
+      ReportedLocalIdManager::kMaxSizeOfLocalIdEntryQueue};
   static constexpr std::string_view kCreationTimestampMsJsonKey{
       UploadedCrashInfoManager::kCreationTimestampMsJsonKey};
   static constexpr std::string_view kOffsetJsonKey{
@@ -41,10 +43,18 @@
 
   // Sets whether to continue postprocessing after event observed callback is
   // called.
+  // TODO(b/266018440): Create a scoped class to set and unset.
   static void SetInterruptedAfterEventObserved(
       FatalCrashEventsObserver& observer,
       bool interrupted_after_event_observed);
 
+  // Gets the size of the queue that saves local IDs. In tests, an access to a
+  // private member is not normally recommended since it is generally not
+  // testing the behavior from the perspective of the user. Here, we expose the
+  // queue size to the test for the sole purpose of examining whether the memory
+  // usage is correctly limited.
+  static size_t GetLocalIdEntryQueueSize(FatalCrashEventsObserver& observer);
+
  private:
   base::FilePath temp_dir_{base::CreateUniqueTempDirectoryScopedToTest()};
   base::FilePath reported_local_id_save_file_path_{
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_unittest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_unittest.cc
index 3abb86fac..605cda5 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_unittest.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/fatal_crash/fatal_crash_events_observer_unittest.cc
@@ -419,6 +419,9 @@
   // The maximum number of local IDs to save.
   static constexpr size_t kMaxNumOfLocalIds{
       FatalCrashEventsObserver::TestEnvironment::kMaxNumOfLocalIds};
+  // The maximum size of the priority queue before reconstructing it.
+  static constexpr size_t kMaxSizeOfLocalIdEntryQueue{
+      FatalCrashEventsObserver::TestEnvironment::kMaxSizeOfLocalIdEntryQueue};
   static constexpr std::string_view kLocalId = "local ID";
   static constexpr base::Time kCaptureTime = base::Time::FromTimeT(14);
   static constexpr std::string_view kLocalIdEarly = "local ID Early";
@@ -440,10 +443,21 @@
       std::string_view local_id,
       base::Time capture_time,
       FatalCrashEventsObserver& fatal_crash_observer,
-      base::test::TestFuture<MetricData>* test_event = nullptr) {
-    auto crash_event_info = NewCrashEventInfo(/*is_uploaded=*/false);
+      base::test::TestFuture<MetricData>* test_event = nullptr,
+      bool is_uploaded = false) {
+    static uint64_t offset = 0u;
+
+    auto crash_event_info = NewCrashEventInfo(is_uploaded);
     crash_event_info->local_id = local_id;
     crash_event_info->capture_time = capture_time;
+    if (is_uploaded) {
+      // Keep offset increasing so that uploaded crash event would not be
+      // blocked because the offset is smaller than previous. Not allowing fine
+      // tuning offset here because the test focuses on
+      // `ReportedLocalIdManager`, not the role offset plays in uploaded
+      // crashes.
+      crash_event_info->upload_info->offset = offset++;
+    }
 
     const auto fatal_crash_telemetry = WaitForFatalCrashTelemetry(
         std::move(crash_event_info), &fatal_crash_observer, test_event);
@@ -585,6 +599,52 @@
       FatalCrashEventsObserver::ConvertTimeToMicroseconds(kCaptureTimeLate));
 }
 
+TEST_P(FatalCrashEventsObserverReportedLocalIdsTest,
+       CrashReportedAsUploadedIsRemoved) {
+  base::test::TestFuture<MetricData> result_metric_data;
+  auto fatal_crash_events_observer =
+      CreateAndEnableFatalCrashEventsObserver(&result_metric_data);
+
+  // Same crash, first reported as unuploaded, then reported again as uploaded.
+  CreateFatalCrashEvent(/*local_id=*/kLocalId, /*capture_time=*/kCaptureTime,
+                        *fatal_crash_events_observer, &result_metric_data,
+                        /*is_uploaded=*/false);
+  CreateFatalCrashEvent(/*local_id=*/kLocalId, /*capture_time=*/kCaptureTime,
+                        *fatal_crash_events_observer, &result_metric_data,
+                        /*is_uploaded=*/true);
+
+  if (reload()) {
+    fatal_crash_events_observer =
+        CreateAndEnableFatalCrashEventsObserver(&result_metric_data);
+  }
+
+  // Create kMaxNumOfLocalIds - 1 crashes with an earlier capture time.
+  for (size_t i = 0u; i < kMaxNumOfLocalIds - 1u; ++i) {
+    std::ostringstream ss;
+    ss << kLocalIdEarly << i;
+    CreateFatalCrashEvent(/*local_id=*/ss.str(),
+                          /*capture_time=*/kCaptureTimeEarly,
+                          *fatal_crash_events_observer, &result_metric_data,
+                          /*is_uploaded=*/false);
+  }
+
+  // Because the first crash (which has a later capture time) has been uploaded,
+  // it should no longer be saved. Therefore, the kMaxNumOfLocalIds'th early
+  // crash should be saved.
+  auto crash_event_info = NewCrashEventInfo(/*is_uploaded=*/false);
+  crash_event_info->local_id = kLocalIdEarly;
+  crash_event_info->capture_time = kCaptureTimeEarly;
+  const auto fatal_crash_telemetry = WaitForFatalCrashTelemetry(
+      std::move(crash_event_info), fatal_crash_events_observer.get(),
+      &result_metric_data);
+  ASSERT_TRUE(fatal_crash_telemetry.has_local_id());
+  EXPECT_EQ(fatal_crash_telemetry.local_id(), kLocalIdEarly);
+  ASSERT_TRUE(fatal_crash_telemetry.has_timestamp_us());
+  EXPECT_EQ(
+      fatal_crash_telemetry.timestamp_us(),
+      FatalCrashEventsObserver::ConvertTimeToMicroseconds(kCaptureTimeEarly));
+}
+
 // Tests that if the thread is interrupted somehow when the event is being
 // processed (e.g., ash crashes), a crash with the same local ID should still be
 // reported.
@@ -622,10 +682,103 @@
             FatalCrashEventsObserver::ConvertTimeToMicroseconds(kCaptureTime));
 }
 
-// TODO(b/266018440): After implementing the logic that controls whether an
-// uploaded crash should be reported (which would include the logic to remove
-// crashes from saved unuploaded crashes), test here that the earliest crash has
-// been removed after a sufficient amount of later crashes are reported.
+TEST_F(FatalCrashEventsObserverReportedLocalIdsTest,
+       CrashReportedAsUploadedIsNotRemovedIfInterrupted) {
+  base::test::TestFuture<MetricData> result_metric_data;
+  auto fatal_crash_events_observer =
+      CreateAndEnableFatalCrashEventsObserver(&result_metric_data);
+
+  // Same crash, first reported as unuploaded, then reported again as uploaded.
+  CreateFatalCrashEvent(/*local_id=*/kLocalId, /*capture_time=*/kCaptureTime,
+                        *fatal_crash_events_observer, &result_metric_data,
+                        /*is_uploaded=*/false);
+
+  // Simulate the thread is interrupted after event observed callback is called.
+  fatal_crash_test_environment_.SetInterruptedAfterEventObserved(
+      *fatal_crash_events_observer, /*interrupted_after_event_observed=*/true);
+  CreateFatalCrashEvent(/*local_id=*/kLocalId, /*capture_time=*/kCaptureTime,
+                        *fatal_crash_events_observer, &result_metric_data,
+                        /*is_uploaded=*/true);
+  // Back to normal.
+  fatal_crash_test_environment_.SetInterruptedAfterEventObserved(
+      *fatal_crash_events_observer, /*interrupted_after_event_observed=*/false);
+
+  // Reload.
+  fatal_crash_events_observer =
+      CreateAndEnableFatalCrashEventsObserver(&result_metric_data);
+
+  // Create kMaxNumOfLocalIds - 1 crashes with an earlier capture time.
+  for (size_t i = 0u; i < kMaxNumOfLocalIds - 1u; ++i) {
+    std::ostringstream ss;
+    ss << kLocalIdEarly << i;
+    CreateFatalCrashEvent(/*local_id=*/ss.str(),
+                          /*capture_time=*/kCaptureTimeEarly,
+                          *fatal_crash_events_observer, &result_metric_data,
+                          /*is_uploaded=*/false);
+  }
+
+  // Because the first crash (which has a later capture time) has been uploaded,
+  // it should no longer be saved. However, because the thread is interrupted,
+  // it remains in the saved local IDs. Therefore, the kMaxNumOfLocalIds'th
+  // early crash would not be saved here.
+  auto local_id_entry = WaitForSkippedFatalCrashEvent(
+      /*local_id=*/kLocalIdEarly,
+      /*capture_time=*/kCaptureTimeEarly, *fatal_crash_events_observer);
+  EXPECT_EQ(local_id_entry.local_id, kLocalIdEarly);
+  EXPECT_EQ(
+      local_id_entry.capture_timestamp_us,
+      FatalCrashEventsObserver::ConvertTimeToMicroseconds(kCaptureTimeEarly));
+  local_id_entry = WaitForSkippedFatalCrashEvent(
+      /*local_id=*/kLocalIdEarly,
+      /*capture_time=*/kCaptureTimeEarly, *fatal_crash_events_observer);
+  EXPECT_EQ(local_id_entry.local_id, kLocalIdEarly);
+  EXPECT_EQ(
+      local_id_entry.capture_timestamp_us,
+      FatalCrashEventsObserver::ConvertTimeToMicroseconds(kCaptureTimeEarly));
+}
+
+TEST_F(FatalCrashEventsObserverReportedLocalIdsTest,
+       ReconstructLocalIdEntryQueueAfterMaxIsReached) {
+  base::test::TestFuture<MetricData> result_metric_data;
+  auto fatal_crash_events_observer =
+      CreateAndEnableFatalCrashEventsObserver(&result_metric_data);
+
+  // Report an unuploaded crash with an early capture time.
+  CreateFatalCrashEvent(/*local_id=*/kLocalIdEarly,
+                        /*capture_time=*/kCaptureTimeEarly,
+                        *fatal_crash_events_observer, &result_metric_data,
+                        /*is_uploaded=*/false);
+
+  // Create kMaxSizeOfLocalIdEntryQueue - 1 crashes with a later capture time.
+  // Report them as unuploaded first and then uploaded. This should be able to
+  // fill the priority queue up with the local IDs of uploaded crashes.
+  for (size_t i = 0u; i < kMaxSizeOfLocalIdEntryQueue - 1u; ++i) {
+    std::ostringstream ss;
+    ss << kLocalIdLate << i;
+    CreateFatalCrashEvent(/*local_id=*/ss.str(),
+                          /*capture_time=*/kCaptureTimeLate,
+                          *fatal_crash_events_observer, &result_metric_data,
+                          /*is_uploaded=*/false);
+    CreateFatalCrashEvent(/*local_id=*/ss.str(),
+                          /*capture_time=*/kCaptureTimeLate,
+                          *fatal_crash_events_observer, &result_metric_data,
+                          /*is_uploaded=*/true);
+  }
+
+  // Sanity check: The priority queue is large.
+  ASSERT_EQ(fatal_crash_test_environment_.GetLocalIdEntryQueueSize(
+                *fatal_crash_events_observer),
+            kMaxSizeOfLocalIdEntryQueue);
+
+  // One more unuploaded crash and the queue should be constructed.
+  CreateFatalCrashEvent(/*local_id=*/kLocalIdLate,
+                        /*capture_time=*/kCaptureTimeLate,
+                        *fatal_crash_events_observer, &result_metric_data,
+                        /*is_uploaded=*/false);
+  EXPECT_EQ(fatal_crash_test_environment_.GetLocalIdEntryQueueSize(
+                *fatal_crash_events_observer),
+            2u);
+}
 
 INSTANTIATE_TEST_SUITE_P(
     FatalCrashEventsObserverReportedLocalIdsTests,
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index f52703c..96ef0a7 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -122,6 +122,7 @@
 #include "chrome/grit/branded_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/installer/util/google_update_settings.h"
+#include "components/color/color_mixers.h"
 #include "components/device_event_log/device_event_log.h"
 #include "components/embedder_support/origin_trials/component_updater_utils.h"
 #include "components/embedder_support/origin_trials/origin_trials_settings_storage.h"
@@ -810,6 +811,8 @@
   // theme that, in turn, adds the GTK core color mixer; core mixers should all
   // be added before we add chrome mixers.
   ui::ColorProviderManager::Get().AppendColorProviderInitializer(
+      base::BindRepeating(color::AddComponentsColorMixers));
+  ui::ColorProviderManager::Get().AppendColorProviderInitializer(
       base::BindRepeating(AddChromeColorMixers));
 }
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 6136e00..418c417 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -7125,6 +7125,8 @@
 }
 
 bool ChromeContentBrowserClient::ShouldRunOutOfProcessSystemDnsResolution() {
+// This enterprise policy is supported on Android, but the feature will not be
+// launched there.
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
   // This is possibly called before `g_browser_process` is initialized.
   PrefService* local_state;
@@ -7138,11 +7140,9 @@
     return local_state->GetBoolean(
         prefs::kOutOfProcessSystemDnsResolutionEnabled);
   }
-#endif
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
 
-  // If no policy is specified, then delegate to global configuration.
-  return base::FeatureList::IsEnabled(
-      network::features::kOutOfProcessSystemDnsResolution);
+  return ContentBrowserClient::ShouldRunOutOfProcessSystemDnsResolution();
 }
 
 void ChromeContentBrowserClient::LogWebFeatureForCurrentPage(
diff --git a/chrome/browser/commerce/shopping_service_factory.cc b/chrome/browser/commerce/shopping_service_factory.cc
index 9888295..9f06983 100644
--- a/chrome/browser/commerce/shopping_service_factory.cc
+++ b/chrome/browser/commerce/shopping_service_factory.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/sync/sync_service_factory.h"
 #include "components/commerce/content/browser/commerce_tab_helper.h"
 #include "components/commerce/core/commerce_feature_list.h"
+#include "components/commerce/core/country_code_checker.h"
 #include "components/commerce/core/proto/commerce_subscription_db_content.pb.h"
 #include "components/commerce/core/proto/parcel_tracking_db_content.pb.h"
 #include "components/commerce/core/shopping_service.h"
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 8a86b407..d3c17517 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -1836,6 +1836,20 @@
             ContentSettingsPattern::FromURLNoWildcard(secondary_url));
 
   // Testing cases:
+  //   WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_SCHEMEFUL_SITE_SCOPE,
+  host_content_settings_map->SetContentSettingDefaultScope(
+      primary_url, secondary_url, ContentSettingsType::TPCD_SUPPORT,
+      CONTENT_SETTING_ALLOW);
+
+  settings = host_content_settings_map->GetSettingsForOneType(
+      ContentSettingsType::TPCD_SUPPORT);
+
+  EXPECT_EQ(settings[0].primary_pattern,
+            ContentSettingsPattern::FromURLNoWildcard(primary_url));
+  EXPECT_EQ(settings[0].secondary_pattern,
+            content_settings::URLToSchemefulSitePattern(secondary_url));
+
+  // Testing cases:
   //   WebsiteSettingsInfo::TOP_ORIGIN_WITH_RESOURCE_EXCEPTIONS_SCOPE,
   //   WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
   //   WebsiteSettingsInfo::TOP_ORIGIN_ONLY_SCOPE,
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h
index 8a53184..c717f266 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h
@@ -32,8 +32,7 @@
 // saved passwords and password exceptions (reading, adding, changing, removing,
 // import/export) and to notify listeners when these values have changed.
 class PasswordsPrivateDelegate
-    : public base::SupportsWeakPtr<PasswordsPrivateDelegate>,
-      public base::RefCounted<PasswordsPrivateDelegate> {
+    : public base::RefCounted<PasswordsPrivateDelegate> {
  public:
   using ImportResultsCallback =
       base::OnceCallback<void(const api::passwords_private::ImportResults&)>;
@@ -256,6 +255,8 @@
   virtual void ShowExportedFileInShell(content::WebContents* web_contents,
                                        std::string file_path) = 0;
 
+  virtual base::WeakPtr<PasswordsPrivateDelegate> AsWeakPtr() = 0;
+
  protected:
   virtual ~PasswordsPrivateDelegate() = default;
 
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h
index 49e0e0f..8fddc9c 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h
@@ -18,7 +18,7 @@
 namespace extensions {
 class PasswordsPrivateDelegate;
 
-// Wrapper class around PasswordsPrivateDelegate to control it's lifespan. If
+// Wrapper class around PasswordsPrivateDelegate to control its lifespan. If
 // the new PasswordManagerUI is enabled callers have to hold scoped_refptr of
 // PasswordsPrivateDelegate so the object can be released when no longer needed.
 // If the feature is disabled this class always holds a
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 8cf175f..ca17668 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
@@ -889,6 +889,11 @@
   platform_util::ShowItemInFolder(browser->profile(), path);
 }
 
+base::WeakPtr<PasswordsPrivateDelegate>
+PasswordsPrivateDelegateImpl::AsWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 password_manager::InsecureCredentialsManager*
 PasswordsPrivateDelegateImpl::GetInsecureCredentialsManager() {
   return password_check_delegate_.GetInsecureCredentialsManager();
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
index 435b251..831eb5b 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
@@ -132,6 +132,8 @@
   void ShowExportedFileInShell(content::WebContents* web_contents,
                                std::string file_path) override;
 
+  base::WeakPtr<PasswordsPrivateDelegate> AsWeakPtr() override;
+
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
   std::unique_ptr<device_reauth::DeviceAuthenticator> GetDeviceAuthenticator(
       content::WebContents* web_contents,
diff --git a/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc b/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
index 85a75f3b..47d4817 100644
--- a/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
+++ b/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
@@ -435,4 +435,9 @@
   exported_file_shown_in_shell_ = true;
 }
 
+base::WeakPtr<PasswordsPrivateDelegate>
+TestPasswordsPrivateDelegate::AsWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h b/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h
index c4c9825..5bc6f4f 100644
--- a/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h
+++ b/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_TEST_PASSWORDS_PRIVATE_DELEGATE_H_
 
 #include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
 #include "chrome/browser/profiles/profile.h"
@@ -95,6 +96,7 @@
   void ShowAddShortcutDialog(content::WebContents* web_contents) override;
   void ShowExportedFileInShell(content::WebContents* web_contents,
                                std::string file_path) override;
+  base::WeakPtr<PasswordsPrivateDelegate> AsWeakPtr() override;
 
   void SetProfile(Profile* profile);
   void SetOptedInForAccountStorage(bool opted_in);
@@ -195,6 +197,8 @@
 
   // used to track whether the exported file was shown in shell.
   bool exported_file_shown_in_shell_ = false;
+
+  base::WeakPtrFactory<TestPasswordsPrivateDelegate> weak_ptr_factory_{this};
 };
 }  // namespace extensions
 
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index 3d5386dd..8c0fc685 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -152,9 +152,7 @@
   }
 
  private:
-  class WillStartRequestObserverThrottle
-      : public content::NavigationThrottle,
-        public base::SupportsWeakPtr<WillStartRequestObserverThrottle> {
+  class WillStartRequestObserverThrottle : public content::NavigationThrottle {
    public:
     explicit WillStartRequestObserverThrottle(content::NavigationHandle* handle)
         : NavigationThrottle(handle) {}
@@ -169,6 +167,10 @@
       Resume();
     }
 
+    base::WeakPtr<WillStartRequestObserverThrottle> AsWeakPtr() {
+      return weak_ptr_factory_.GetWeakPtr();
+    }
+
    private:
     NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
       throttled_ = true;
@@ -176,6 +178,9 @@
     }
 
     bool throttled_ = false;
+
+    base::WeakPtrFactory<WillStartRequestObserverThrottle> weak_ptr_factory_{
+        this};
   };
 
   base::WeakPtr<WillStartRequestObserverThrottle> throttle_;
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index f298c96..e865b25 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -886,6 +886,8 @@
   // navigation as such contexts are trusted and do not have a concept of file
   // access.
   if (extension && url.SchemeIsFile() &&
+      // PDF viewer extension can navigate to file URLs.
+      extension->id() != extension_misc::kPdfExtensionId &&
       !util::AllowFileAccess(extension->id(), browser_context) &&
       base::FeatureList::IsEnabled(
           extensions_features::kRestrictFileURLNavigation) &&
diff --git a/chrome/browser/extensions/extension_tab_util_unittest.cc b/chrome/browser/extensions/extension_tab_util_unittest.cc
index 47c47560..424826a 100644
--- a/chrome/browser/extensions/extension_tab_util_unittest.cc
+++ b/chrome/browser/extensions/extension_tab_util_unittest.cc
@@ -205,6 +205,18 @@
   EXPECT_THAT(url, base::test::ValueIs(GURL(kFileURLWithEnterprisePolicy)));
 }
 
+TEST_F(ChromeExtensionNavigationTest, PrepareURLForNavigationWithPDFViewer) {
+  // Set ID for PDF viewer extension.
+  auto extension =
+      ExtensionBuilder("test").SetID(extension_misc::kPdfExtensionId).Build();
+
+  // File URLs are returned when the extension has access to file.
+  const std::string kFileURLWithPDFViewer("file:///etc/passwd");
+  auto url = ExtensionTabUtil::PrepareURLForNavigation(
+      kFileURLWithPDFViewer, extension.get(), browser_context());
+  EXPECT_THAT(url, base::test::ValueIs(GURL(kFileURLWithPDFViewer)));
+}
+
 TEST_F(ChromeExtensionNavigationTest, PrepareURLForNavigationOnDevtools) {
   const std::string kDevtoolsURL(
       "devtools://devtools/bundled/devtools_app.html");
diff --git a/chrome/browser/extensions/extension_view_host.cc b/chrome/browser/extensions/extension_view_host.cc
index d625aae..89d3bfa 100644
--- a/chrome/browser/extensions/extension_view_host.cc
+++ b/chrome/browser/extensions/extension_view_host.cc
@@ -75,12 +75,6 @@
     manager->SetDelegate(nullptr);
 }
 
-void ExtensionViewHost::SetAssociatedWebContents(
-    content::WebContents* web_contents) {
-  associated_web_contents_ =
-      web_contents ? web_contents->GetWeakPtr() : nullptr;
-}
-
 Browser* ExtensionViewHost::GetBrowser() {
   return browser_;
 }
@@ -243,13 +237,7 @@
   return browser_ ? browser_->extension_window_controller() : nullptr;
 }
 
-content::WebContents* ExtensionViewHost::GetAssociatedWebContents() const {
-  return associated_web_contents_.get();
-}
-
 content::WebContents* ExtensionViewHost::GetVisibleWebContents() const {
-  if (associated_web_contents_)
-    return associated_web_contents_.get();
   return (extension_host_type() == mojom::ViewType::kExtensionPopup)
              ? host_contents()
              : nullptr;
diff --git a/chrome/browser/extensions/extension_view_host.h b/chrome/browser/extensions/extension_view_host.h
index 599d068..fd758f6 100644
--- a/chrome/browser/extensions/extension_view_host.h
+++ b/chrome/browser/extensions/extension_view_host.h
@@ -8,14 +8,12 @@
 #include <memory>
 
 #include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_host_registry.h"
-#include "extensions/common/mojom/view_type.mojom.h"
 
 class Browser;
 
@@ -53,8 +51,6 @@
   void set_view(ExtensionView* view) { view_ = view; }
   ExtensionView* view() { return view_; }
 
-  void SetAssociatedWebContents(content::WebContents* web_contents);
-
   // Returns the browser associated with this ExtensionViewHost.
   virtual Browser* GetBrowser();
 
@@ -110,7 +106,6 @@
 
   // extensions::ExtensionFunctionDispatcher::Delegate
   WindowController* GetExtensionWindowController() const override;
-  content::WebContents* GetAssociatedWebContents() const override;
   content::WebContents* GetVisibleWebContents() const override;
 
   // ExtensionHostRegistry::Observer:
@@ -132,9 +127,6 @@
   // View that shows the rendered content in the UI.
   raw_ptr<ExtensionView, DanglingUntriaged> view_ = nullptr;
 
-  // The relevant WebContents associated with this ExtensionViewHost, if any.
-  base::WeakPtr<content::WebContents> associated_web_contents_;
-
   base::ScopedObservation<ExtensionHostRegistry,
                           ExtensionHostRegistry::Observer>
       host_registry_observation_{this};
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
index 3851ff2..d371e0e4 100644
--- a/chrome/browser/extensions/user_script_listener.cc
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -25,9 +25,7 @@
 
 namespace extensions {
 
-class UserScriptListener::Throttle
-    : public NavigationThrottle,
-      public base::SupportsWeakPtr<UserScriptListener::Throttle> {
+class UserScriptListener::Throttle : public NavigationThrottle {
  public:
   explicit Throttle(content::NavigationHandle* navigation_handle)
       : NavigationThrottle(navigation_handle) {}
@@ -58,9 +56,12 @@
     return "UserScriptListener::Throttle";
   }
 
+  base::WeakPtr<Throttle> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
+
  private:
   bool should_defer_ = true;
   bool did_defer_ = false;
+  base::WeakPtrFactory<Throttle> weak_ptr_factory_{this};
 };
 
 struct UserScriptListener::ProfileData {
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderListProperties.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderListProperties.java
index 2145428..354f0d6 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderListProperties.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderListProperties.java
@@ -61,13 +61,18 @@
     public static final PropertyModel.WritableIntPropertyKey STICKY_HEADER_MUTABLE_MARGIN_KEY =
             new PropertyModel.WritableIntPropertyKey();
 
+    /** Whether the view is shown in a narrow window on tablets. */
+    public static final PropertyModel.WritableBooleanPropertyKey IS_NARROW_WINDOW_ON_TABLET_KEY =
+            new PropertyModel.WritableBooleanPropertyKey();
+
     public static PropertyModel create(@Px int toolbarHeight) {
         return new PropertyModel
                 .Builder(IS_SECTION_ENABLED_KEY, SECTION_HEADERS_KEY, CURRENT_TAB_INDEX_KEY,
                         ON_TAB_SELECTED_CALLBACK_KEY, MENU_MODEL_LIST_KEY, MENU_DELEGATE_KEY,
                         IS_TAB_MODE_KEY, IS_LOGO_KEY, INDICATOR_VIEW_VISIBILITY_KEY,
                         EXPANDING_DRAWER_VIEW_KEY, TOOLBAR_HEIGHT_PX, STICKY_HEADER_VISIBLILITY_KEY,
-                        STICKY_HEADER_EXPANDING_DRAWER_VIEW_KEY, STICKY_HEADER_MUTABLE_MARGIN_KEY)
+                        STICKY_HEADER_EXPANDING_DRAWER_VIEW_KEY, STICKY_HEADER_MUTABLE_MARGIN_KEY,
+                        IS_NARROW_WINDOW_ON_TABLET_KEY)
                 .with(SECTION_HEADERS_KEY, new PropertyListModel<>())
                 .with(INDICATOR_VIEW_VISIBILITY_KEY, ViewVisibility.INVISIBLE)
                 .with(TOOLBAR_HEIGHT_PX, toolbarHeight)
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
index 152a0b8..e17a0ae3 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
@@ -192,14 +192,6 @@
             mTabListener = new SectionHeaderTabListener();
             mTabLayout.addOnTabSelectedListener(mTabListener);
             if (mIsSurfacePolishEnabled) {
-                ViewGroup.LayoutParams layoutParams = mTabLayout.getLayoutParams();
-                if (!mIsTablet) {
-                    layoutParams.width = LayoutParams.MATCH_PARENT;
-                } else {
-                    layoutParams.width = getResources().getDimensionPixelSize(
-                                                 R.dimen.feed_header_tab_layout_width_max)
-                            * 2;
-                }
                 mTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
                 mTabLayout.setBackgroundResource(
                         R.drawable.header_title_section_tab_background_polished);
@@ -651,4 +643,24 @@
      * Adjust the margin of the sticky header.
      */
     void updateStickyHeaderMargin(int marginValue) {}
+
+    /**
+     * Adjust the width of the TabLayout.
+     *
+     * @param isNarrowWindowOnTablet Whether the window that contains the view is a narrow one on
+     *     tablets.
+     */
+    void updateTabLayoutHeaderWidth(boolean isNarrowWindowOnTablet) {
+        if (mTabLayout == null) return;
+
+        assert mIsSurfacePolishEnabled;
+        MarginLayoutParams layoutParams = (MarginLayoutParams) mTabLayout.getLayoutParams();
+        if (!mIsTablet || isNarrowWindowOnTablet) {
+            layoutParams.width = LayoutParams.MATCH_PARENT;
+        } else {
+            layoutParams.width =
+                    getResources().getDimensionPixelSize(R.dimen.feed_header_tab_layout_width_max)
+                            * 2;
+        }
+    }
 }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewBinder.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewBinder.java
index 6ba6ee7..bc350de 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewBinder.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewBinder.java
@@ -57,6 +57,9 @@
         } else if (key == SectionHeaderListProperties.STICKY_HEADER_MUTABLE_MARGIN_KEY) {
             view.updateStickyHeaderMargin(
                     model.get(SectionHeaderListProperties.STICKY_HEADER_MUTABLE_MARGIN_KEY));
+        } else if (key == SectionHeaderListProperties.IS_NARROW_WINDOW_ON_TABLET_KEY) {
+            view.updateTabLayoutHeaderWidth(
+                    model.get(SectionHeaderListProperties.IS_NARROW_WINDOW_ON_TABLET_KEY));
         }
     }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 672f1f4..7d07286 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -765,6 +765,11 @@
     "expiry_milestone": 120
   },
   {
+    "name": "auxiliary-search-donation",
+    "owners": [ "gangwu", "chrome-mobile-search@google.com" ],
+    "expiry_milestone": 140
+  },
+  {
     "name": "avif-gainmap-hdr-images",
     "owners": [ "maryla@google.com", "avif-eng@google.com" ],
     "expiry_milestone": 130
@@ -3801,21 +3806,11 @@
     "expiry_milestone": 100
   },
   {
-    "name": "enable-vaapi-jpeg-image-decode-acceleration",
-    "owners": [ "andrescj", "chromeos-gfx@google.com" ],
-    "expiry_milestone": 100
-  },
-  {
     "name": "enable-vaapi-vp9-kSVC-encode-acceleration",
     "owners": [ "mcasas", "chromeos-gfx-video@google.com" ],
     "expiry_milestone": 100
   },
   {
-    "name": "enable-vaapi-webp-image-decode-acceleration",
-    "owners": [ "andrescj", "chromeos-gfx@google.com" ],
-    "expiry_milestone": 100
-  },
-  {
     "name": "enable-variable-refresh-rate",
     "owners": [ "aswolfers", "chromeos-gfx-compositor@google.com" ],
     "expiry_milestone": 125
@@ -4345,7 +4340,7 @@
   {
     "name": "feed-discofeed-endpoint",
     "owners": [ "//chrome/android/feed/OWNERS", "freedjm@chromium.org" ],
-    "expiry_milestone": 120
+    "expiry_milestone": 130
   },
   {
     "name": "feed-dynamic-colors",
@@ -4963,6 +4958,11 @@
     "expiry_milestone": 120
   },
   {
+    "name": "indexed-db-default-durability-relaxed",
+    "owners": [ "estade", "chrome-owp-storage@google.com" ],
+    "expiry_milestone": 125
+  },
+  {
     "name": "info-card-acknowledgement-tracking",
     "owners": [ "//chrome/android/feed/OWNERS", "jianli@chromium.org" ],
     "expiry_milestone": 120
@@ -5925,6 +5925,11 @@
     "expiry_milestone": 123
   },
   {
+    "name": "ntp-tab-resumption-module",
+    "owners": [ "mfacey", "romanarora" ],
+    "expiry_milestone": 130
+  },
+  {
     "name": "ntp-view-hierarchy-repair",
     "owners": [ "adamta", "sczs" ],
     "expiry_milestone": 115
@@ -8403,6 +8408,11 @@
     "expiry_milestone": 123
   },
   {
+    "name": "web-authentication-filter-google-passkeys",
+    "owners": [ "chrome-webauthn@google.com" ],
+    "expiry_milestone": 121
+  },
+  {
     "name": "web-authentication-permit-enterprise-attestation",
     "owners": [ "chrome-webauthn@google.com" ],
     // This flag lets end users enroll security keys with an enterprise that
@@ -8584,7 +8594,7 @@
   {
     "name": "windows11-mica-titlebar",
     "owners": [ "j@jloeffler.com", "pkasting" ],
-    "expiry_milestone": 120
+    "expiry_milestone": 140
   },
   {
     "name": "xsurface-metrics-reporting",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index eab192c..ffa71c8 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -115,6 +115,10 @@
     "reporting delays and noise. Only works if the Attribution Reporting API "
     "is already enabled.";
 
+const char kAuxiliarySearchDonationName[] = "Auxiliary Search Donation";
+const char kAuxiliarySearchDonationDescription[] =
+    "If enabled, override Auxiliary Search donation cap.";
+
 const char kBackgroundResourceFetchName[] = "Background Resource Fetch";
 const char kBackgroundResourceFetchDescription[] =
     "Process resource requests in a background thread inside Blink.";
@@ -2007,6 +2011,12 @@
 const char kIndexedDBCompressValuesWithSnappyDescription[] =
     "Compress IndexedDB values in the renderer process using Snappy.";
 
+const char kIndexedDBDefaultDurabilityRelaxed[] =
+    "IndexedDB transactions relaxed durability by default";
+const char kIndexedDBDefaultDurabilityRelaxedDescription[] =
+    "IDBTransaction \"readwrite\" transaction durability defaults to relaxed "
+    "when not specified";
+
 const char kInfobarScrollOptimizationName[] = "Infobar scroll optimiaztion";
 const char kInfobarScrollOptimizationDescription[] =
     "Optimize Infobar scroll on Android.";
@@ -3505,6 +3515,13 @@
     "Allows users to switch to checkpoint based wallpaper daily refresh "
     "feature.";
 
+const char kWebAuthnFilterGooglePasskeysName[] =
+    "Filter passkeys for google.com";
+const char kWebAuthnFilterGooglePasskeysDescription[] =
+    "When servicing a webauthn request for google.com, filter webauthn "
+    "credentials that do not match a user.id prefix identifying them as "
+    "passkeys, e.g. because they are used for autofill auth.";
+
 const char kWebBluetoothName[] = "Web Bluetooth";
 const char kWebBluetoothDescription[] =
     "Enables the Web Bluetooth API on platforms without official support";
@@ -4802,6 +4819,11 @@
     "Shows discounts on the visit tiles in the Journeys module when available "
     "on the New Tab Page.";
 
+const char kNtpTabResumptionModuleName[] =
+    "NTP Cross Device Tab Resumption Module";
+const char kNtpTabResumptionModuleDescription[] =
+    "Shows the Cross Device Tab Resumption Module on the New Tab Page.";
+
 const char kNtpMiddleSlotPromoDismissalName[] =
     "NTP Middle Slot Promo Dismissal";
 const char kNtpMiddleSlotPromoDismissalDescription[] =
@@ -6990,17 +7012,6 @@
 const char kUiSlowAnimationsName[] = "Slow UI animations";
 const char kUiSlowAnimationsDescription[] = "Makes all UI animations slow.";
 
-const char kVaapiJpegImageDecodeAccelerationName[] =
-    "VA-API JPEG decode acceleration for images";
-const char kVaapiJpegImageDecodeAccelerationDescription[] =
-    "Enable or disable decode acceleration of JPEG images (as opposed to camera"
-    " captures) using the VA-API.";
-
-const char kVaapiWebPImageDecodeAccelerationName[] =
-    "VA-API WebP decode acceleration for images";
-const char kVaapiWebPImageDecodeAccelerationDescription[] =
-    "Enable or disable decode acceleration of WebP images using the VA-API.";
-
 const char kVirtualKeyboardName[] = "Virtual Keyboard";
 const char kVirtualKeyboardDescription[] =
     "Always show virtual keyboard regardless of having a physical keyboard "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 9acdec91..b2057f4b 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -99,6 +99,9 @@
 extern const char kAppDeduplicationServiceFondueName[];
 extern const char kAppDeduplicationServiceFondueDescription[];
 
+extern const char kAuxiliarySearchDonationName[];
+extern const char kAuxiliarySearchDonationDescription[];
+
 extern const char kBackgroundResourceFetchName[];
 extern const char kBackgroundResourceFetchDescription[];
 
@@ -1153,6 +1156,9 @@
 extern const char kIndexedDBCompressValuesWithSnappy[];
 extern const char kIndexedDBCompressValuesWithSnappyDescription[];
 
+extern const char kIndexedDBDefaultDurabilityRelaxed[];
+extern const char kIndexedDBDefaultDurabilityRelaxedDescription[];
+
 extern const char kJapaneseOSSettingsName[];
 extern const char kJapaneseOSSettingsDescription[];
 
@@ -2036,6 +2042,9 @@
 extern const char kWallpaperRefreshRevampName[];
 extern const char kWallpaperRefreshRevampDescription[];
 
+extern const char kWebAuthnFilterGooglePasskeysName[];
+extern const char kWebAuthnFilterGooglePasskeysDescription[];
+
 extern const char kWebBluetoothName[];
 extern const char kWebBluetoothDescription[];
 
@@ -2790,6 +2799,9 @@
 extern const char kNtpDiscountsInHistoryClustersModuleName[];
 extern const char kNtpDiscountsInHistoryClustersModuleDescription[];
 
+extern const char kNtpTabResumptionModuleName[];
+extern const char kNtpTabResumptionModuleDescription[];
+
 extern const char kNtpMiddleSlotPromoDismissalName[];
 extern const char kNtpMiddleSlotPromoDismissalDescription[];
 
@@ -4019,12 +4031,6 @@
 extern const char kUseFakeDeviceForMediaStreamName[];
 extern const char kUseFakeDeviceForMediaStreamDescription[];
 
-extern const char kVaapiJpegImageDecodeAccelerationName[];
-extern const char kVaapiJpegImageDecodeAccelerationDescription[];
-
-extern const char kVaapiWebPImageDecodeAccelerationName[];
-extern const char kVaapiWebPImageDecodeAccelerationDescription[];
-
 extern const char kVirtualKeyboardName[];
 extern const char kVirtualKeyboardDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 531f2ca..a965f6e 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -178,6 +178,7 @@
     &kAndroidVisibleUrlTruncation,
     &kAnimatedImageDragShadow,
     &kAppMenuMobileSiteOption,
+    &kAuxiliarySearchDonation,
     &kAvoidSelectedTabFocusOnLayoutDoneShowing,
     &kBackGestureActivityTabProvider,
     &kBackGestureRefactorActivityAndroid,
@@ -507,6 +508,10 @@
              "AppMenuMobileSiteOption",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kAuxiliarySearchDonation,
+             "AuxiliarySearchDonation",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kBackgroundThreadPool,
              "BackgroundThreadPool",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index dde1407c..2fb76c27 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -8,6 +8,7 @@
 #include <jni.h>
 
 #include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
 
 namespace chrome {
 namespace android {
@@ -31,6 +32,7 @@
 BASE_DECLARE_FEATURE(kAndroidVisibleUrlTruncation);
 BASE_DECLARE_FEATURE(kAnimatedImageDragShadow);
 BASE_DECLARE_FEATURE(kAppMenuMobileSiteOption);
+BASE_DECLARE_FEATURE(kAuxiliarySearchDonation);
 BASE_DECLARE_FEATURE(kAvoidSelectedTabFocusOnLayoutDoneShowing);
 BASE_DECLARE_FEATURE(kBackGestureActivityTabProvider);
 BASE_DECLARE_FEATURE(kBackGestureRefactorActivityAndroid);
@@ -214,6 +216,17 @@
 BASE_DECLARE_FEATURE(kWebApkBackupAndRestoreBackend);
 BASE_DECLARE_FEATURE(kWebApkInstallService);
 
+// For FeatureParam, Alphabetical:
+constexpr base::FeatureParam<int> kAuxiliarySearchMaxBookmarksCountParam(
+    &kAuxiliarySearchDonation,
+    "auxiliary_search_max_donation_bookmark",
+    100);
+
+constexpr base::FeatureParam<int> kAuxiliarySearchMaxTabsCountParam(
+    &kAuxiliarySearchDonation,
+    "auxiliary_search_max_donation_tab",
+    100);
+
 }  // namespace android
 }  // namespace chrome
 
diff --git a/chrome/browser/media/webrtc/capture_policy_utils.cc b/chrome/browser/media/webrtc/capture_policy_utils.cc
index c637f9e..e0a57da 100644
--- a/chrome/browser/media/webrtc/capture_policy_utils.cc
+++ b/chrome/browser/media/webrtc/capture_policy_utils.cc
@@ -23,6 +23,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
+#include "media/base/media_switches.h"
 #include "third_party/blink/public/common/features_generated.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -80,8 +81,8 @@
   // properly on all platforms, and since it's not clear that we actually want
   // to support this anyway, turn it off for now.  Note that direct calls into
   // `GetAllowedCaptureLevel(..., PrefService)` will miss this check.
-  // TODO(crbug.com/1410382): Consider turning this back on.
-  if (PictureInPictureWindowManager::IsChildWebContents(
+  if (!base::FeatureList::IsEnabled(media::kDocumentPictureInPictureCapture) &&
+      PictureInPictureWindowManager::IsChildWebContents(
           capturer_web_contents)) {
     return AllowedScreenCaptureLevel::kDisallowed;
   }
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
index fcf8da6..47b72335 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
@@ -345,25 +345,21 @@
 }
 
 base::Value::Dict NearbySharePrivateCertificate::ToDictionary() const {
-  base::Value::Dict dict;
-
-  dict.Set(kVisibility, static_cast<int>(visibility_));
-  dict.Set(kNotBefore, base::TimeToValue(not_before_));
-  dict.Set(kNotAfter, base::TimeToValue(not_after_));
-
   std::vector<uint8_t> key_pair;
   key_pair_->ExportPrivateKey(&key_pair);
-  dict.Set(kKeyPair, BytesToEncodedString(key_pair));
 
-  dict.Set(kSecretKey, EncodeString(secret_key_->key()));
-  dict.Set(kMetadataEncryptionKey,
-           BytesToEncodedString(metadata_encryption_key_));
-  dict.Set(kId, BytesToEncodedString(id_));
-  dict.Set(kUnencryptedMetadata,
-           EncodeString(unencrypted_metadata_.SerializeAsString()));
-  dict.Set(kConsumedSalts, SaltsToString(consumed_salts_));
-
-  return dict;
+  return base::Value::Dict()
+      .Set(kVisibility, static_cast<int>(visibility_))
+      .Set(kNotBefore, base::TimeToValue(not_before_))
+      .Set(kNotAfter, base::TimeToValue(not_after_))
+      .Set(kKeyPair, BytesToEncodedString(key_pair))
+      .Set(kSecretKey, EncodeString(secret_key_->key()))
+      .Set(kMetadataEncryptionKey,
+           BytesToEncodedString(metadata_encryption_key_))
+      .Set(kId, BytesToEncodedString(id_))
+      .Set(kUnencryptedMetadata,
+           EncodeString(unencrypted_metadata_.SerializeAsString()))
+      .Set(kConsumedSalts, SaltsToString(consumed_salts_));
 }
 
 absl::optional<NearbySharePrivateCertificate>
diff --git a/chrome/browser/nearby_sharing/internal b/chrome/browser/nearby_sharing/internal
new file mode 160000
index 0000000..f4c4312
--- /dev/null
+++ b/chrome/browser/nearby_sharing/internal
@@ -0,0 +1 @@
+Subproject commit f4c4312a51a12bd060d3a012345e273a58f26601
diff --git a/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc b/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc
index a08c8bf..10d2c2d 100644
--- a/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc
+++ b/chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.cc
@@ -28,94 +28,89 @@
 
 base::Value::Dict ListPublicCertificatesRequestToReadableDictionary(
     const nearbyshare::proto::ListPublicCertificatesRequest& request) {
-  base::Value::Dict dict;
-  dict.Set("parent", request.parent());
-  dict.Set("page_size", request.page_size());
-  dict.Set("page_token", request.page_token());
-
   base::Value::List secret_ids_list;
   for (const auto& secret_id : request.secret_ids()) {
     secret_ids_list.Append(TruncateString(Encode(secret_id)));
   }
-  dict.Set("secret_ids", std::move(secret_ids_list));
-  return dict;
+
+  return base::Value::Dict()
+      .Set("parent", request.parent())
+      .Set("page_size", request.page_size())
+      .Set("page_token", request.page_token())
+      .Set("secret_ids", std::move(secret_ids_list));
 }
 
 base::Value::Dict ListPublicCertificatesResponseToReadableDictionary(
     const nearbyshare::proto::ListPublicCertificatesResponse& response) {
-  base::Value::Dict dict;
-  dict.Set("next_page_token", response.next_page_token());
-
   base::Value::List public_certificates_list;
   for (const auto& public_certificate : response.public_certificates()) {
     public_certificates_list.Append(
         PublicCertificateToReadableDictionary(public_certificate));
   }
-  dict.Set("public_certificates", std::move(public_certificates_list));
-  return dict;
+
+  return base::Value::Dict()
+      .Set("next_page_token", response.next_page_token())
+      .Set("public_certificates", std::move(public_certificates_list));
 }
 
 base::Value::Dict PublicCertificateToReadableDictionary(
     const nearbyshare::proto::PublicCertificate& certificate) {
-  base::Value::Dict dict;
-  dict.Set("secret_id", TruncateString(Encode(certificate.secret_id())));
-  dict.Set("secret_key", TruncateString(Encode(certificate.secret_key())));
-  dict.Set("public_key", TruncateString(Encode(certificate.public_key())));
-  dict.Set("start_time",
-           TimestampToReadableDictionary(certificate.start_time()));
-  dict.Set("end_time", TimestampToReadableDictionary(certificate.end_time()));
-  dict.Set("for_selected_contacts", certificate.for_selected_contacts());
-  dict.Set("metadata_encryption_key",
-           TruncateString(Encode(certificate.metadata_encryption_key())));
-  dict.Set("encrypted_metadata_bytes",
-           TruncateString(Encode(certificate.encrypted_metadata_bytes())));
-  dict.Set("metadata_encryption_key_tag",
-           TruncateString(Encode(certificate.metadata_encryption_key_tag())));
-  dict.Set("for_self_share", certificate.for_self_share());
-  return dict;
+  return base::Value::Dict()
+      .Set("secret_id", TruncateString(Encode(certificate.secret_id())))
+      .Set("secret_key", TruncateString(Encode(certificate.secret_key())))
+      .Set("public_key", TruncateString(Encode(certificate.public_key())))
+      .Set("start_time",
+           TimestampToReadableDictionary(certificate.start_time()))
+      .Set("end_time", TimestampToReadableDictionary(certificate.end_time()))
+      .Set("for_selected_contacts", certificate.for_selected_contacts())
+      .Set("metadata_encryption_key",
+           TruncateString(Encode(certificate.metadata_encryption_key())))
+      .Set("encrypted_metadata_bytes",
+           TruncateString(Encode(certificate.encrypted_metadata_bytes())))
+      .Set("metadata_encryption_key_tag",
+           TruncateString(Encode(certificate.metadata_encryption_key_tag())))
+      .Set("for_self_share", certificate.for_self_share());
 }
 
 base::Value::Dict TimestampToReadableDictionary(
     const ash::nearby::proto::Timestamp& timestamp) {
-  base::Value::Dict dict;
-  dict.Set("seconds", base::NumberToString(timestamp.seconds()));
-  dict.Set("nanos", base::NumberToString(timestamp.nanos()));
-  return dict;
+  return base::Value::Dict()
+      .Set("seconds", base::NumberToString(timestamp.seconds()))
+      .Set("nanos", base::NumberToString(timestamp.nanos()));
 }
 
 base::Value::Dict ListContactPeopleRequestToReadableDictionary(
     const nearbyshare::proto::ListContactPeopleRequest& request) {
-  base::Value::Dict dict;
-  dict.Set("page_size", request.page_size());
-  dict.Set("page_token", request.page_token());
-  return dict;
+  return base::Value::Dict()
+      .Set("page_size", request.page_size())
+      .Set("page_token", request.page_token());
 }
 
 base::Value::Dict ListContactPeopleResponseToReadableDictionary(
     const nearbyshare::proto::ListContactPeopleResponse& response) {
-  base::Value::Dict dict;
   base::Value::List contact_records_list;
   for (const auto& contact_record : response.contact_records()) {
     contact_records_list.Append(
         ContactRecordToReadableDictionary(contact_record));
   }
-  dict.Set("contact_records", std::move(contact_records_list));
-  dict.Set("next_page_token", response.next_page_token());
-  return dict;
+
+  return base::Value::Dict()
+      .Set("contact_records", std::move(contact_records_list))
+      .Set("next_page_token", response.next_page_token());
 }
 
 base::Value::Dict ContactRecordToReadableDictionary(
     const nearbyshare::proto::ContactRecord& contact_record) {
-  base::Value::Dict dict;
-  dict.Set("id", contact_record.id());
-  dict.Set("person_name", contact_record.person_name());
-  dict.Set("image_url", contact_record.image_url());
   base::Value::List identifiers_list;
   for (const auto& identifier : contact_record.identifiers()) {
     identifiers_list.Append(IdentifierToReadableDictionary(identifier));
   }
-  dict.Set("identifiers", std::move(identifiers_list));
-  return dict;
+
+  return base::Value::Dict()
+      .Set("id", contact_record.id())
+      .Set("person_name", contact_record.person_name())
+      .Set("image_url", contact_record.image_url())
+      .Set("identifiers", std::move(identifiers_list));
 }
 
 base::Value::Dict IdentifierToReadableDictionary(
@@ -133,69 +128,65 @@
 
 base::Value::Dict UpdateDeviceRequestToReadableDictionary(
     const nearbyshare::proto::UpdateDeviceRequest& request) {
-  base::Value::Dict dict;
-  dict.Set("device", DeviceToReadableDictionary(request.device()));
-  dict.Set("update_mask", FieldMaskToReadableDictionary(request.update_mask()));
-  return dict;
+  return base::Value::Dict()
+      .Set("device", DeviceToReadableDictionary(request.device()))
+      .Set("update_mask", FieldMaskToReadableDictionary(request.update_mask()));
 }
 
 base::Value::Dict DeviceToReadableDictionary(
     const nearbyshare::proto::Device& device) {
-  base::Value::Dict dict;
-  dict.Set("name", device.name());
-  dict.Set("display_name", device.display_name());
   base::Value::List contacts_list;
   for (const auto& contact : device.contacts()) {
     contacts_list.Append(ContactToReadableDictionary(contact));
   }
-  dict.Set("contacts", std::move(contacts_list));
+
   base::Value::List public_certificates_list;
   for (const auto& certificate : device.public_certificates()) {
     public_certificates_list.Append(
         PublicCertificateToReadableDictionary(certificate));
   }
-  dict.Set("public_certificates", std::move(public_certificates_list));
-  return dict;
+
+  return base::Value::Dict()
+      .Set("name", device.name())
+      .Set("display_name", device.display_name())
+      .Set("contacts", std::move(contacts_list))
+      .Set("public_certificates", std::move(public_certificates_list));
 }
 
 base::Value::Dict ContactToReadableDictionary(
     const nearbyshare::proto::Contact& contact) {
-  base::Value::Dict dict;
-  dict.Set("identifier", IdentifierToReadableDictionary(contact.identifier()));
-  dict.Set("is_selected", contact.is_selected());
-  return dict;
+  return base::Value::Dict()
+      .Set("identifier", IdentifierToReadableDictionary(contact.identifier()))
+      .Set("is_selected", contact.is_selected());
 }
 
 base::Value::Dict FieldMaskToReadableDictionary(
     const ash::nearby::proto::FieldMask& mask) {
-  base::Value::Dict dict;
   base::Value::List paths_list;
   for (const auto& path : mask.paths()) {
     paths_list.Append(path);
   }
-  dict.Set("paths", std::move(paths_list));
-  return dict;
+
+  return base::Value::Dict().Set("paths", std::move(paths_list));
 }
 
 base::Value::Dict UpdateDeviceResponseToReadableDictionary(
     const nearbyshare::proto::UpdateDeviceResponse& response) {
-  base::Value::Dict dict;
-  dict.Set("device", DeviceToReadableDictionary(response.device()));
-  dict.Set("person_name", response.person_name());
-  dict.Set("image_url", response.image_url());
-  dict.Set("image_token", response.image_token());
-  return dict;
+  return base::Value::Dict()
+      .Set("device", DeviceToReadableDictionary(response.device()))
+      .Set("person_name", response.person_name())
+      .Set("image_url", response.image_url())
+      .Set("image_token", response.image_token());
 }
 
 base::Value::Dict EncryptedMetadataToReadableDictionary(
     const nearbyshare::proto::EncryptedMetadata& data) {
-  base::Value::Dict dict;
-  dict.Set("device_name", data.device_name());
-  dict.Set("full_name", data.full_name());
-  dict.Set("icon_url", data.icon_url());
-  dict.Set("bluetooth_mac_address",
-           TruncateString(Encode(data.bluetooth_mac_address())));
-  dict.Set("obfuscated_gaia_id", data.obfuscated_gaia_id());
-  dict.Set("account_name", data.account_name());
-  return dict;
+  return base::Value::Dict()
+      .Set("device_name", data.device_name())
+      .Set("full_name", data.full_name())
+      .Set("icon_url", data.icon_url())
+      .Set("bluetooth_mac_address",
+           TruncateString(Encode(data.bluetooth_mac_address())))
+      .Set("obfuscated_gaia_id", data.obfuscated_gaia_id())
+      .Set("account_name", data.account_name());
 }
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 26f3634f..b82bde5 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1199,6 +1199,9 @@
   { key::kArcEnabled,
     arc::prefs::kArcEnabled,
     base::Value::Type::BOOLEAN },
+  { key::kUnaffiliatedDeviceArcAllowed,
+    arc::prefs::kUnaffiliatedDeviceArcAllowed,
+    base::Value::Type::BOOLEAN },
   { key::kReportArcStatusEnabled,
     prefs::kReportArcStatusEnabled,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index f1f36cf..51f94da 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -177,6 +177,7 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/tpcd/experiment/eligibility_service_factory.h"
 #include "chrome/browser/tpcd/metadata/updater_service_factory.h"
+#include "chrome/browser/tpcd/support/tpcd_support_service_factory.h"
 #include "chrome/browser/translate/translate_model_service_factory.h"
 #include "chrome/browser/translate/translate_ranker_factory.h"
 #include "chrome/browser/ui/cookie_controls/cookie_controls_service_factory.h"
@@ -1137,6 +1138,7 @@
   TopSitesFactory::GetInstance();
   tpcd::experiment::EligibilityServiceFactory::GetInstance();
   tpcd::metadata::UpdaterServiceFactory::GetInstance();
+  tpcd::support::TpcdSupportServiceFactory::GetInstance();
 #if !BUILDFLAG(IS_ANDROID)
   TrackingProtectionNoticeFactory::GetInstance();
 #endif
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index a6949fb..af0df45a 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -101,6 +101,7 @@
 #include "chrome/browser/ssl/stateful_ssl_host_state_delegate_factory.h"
 #include "chrome/browser/startup_data.h"
 #include "chrome/browser/storage/storage_notification_service_factory.h"
+#include "chrome/browser/tpcd/support/tpcd_support_service_factory.h"
 #include "chrome/browser/transition_manager/full_browser_transition_manager.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/webui/prefs_internals_source.h"
@@ -867,7 +868,15 @@
   }
 
   // Request an OriginTrialsControllerDelegate to ensure it is initialized.
+  // OriginTrialsControllerDelegate needs to be explicitly created here instead
+  // of using the common pattern for initializing with the profile (override
+  // OriginTrialsFactory::ServiceIsCreatedWithBrowserContext() to return true)
+  // as it depends on the default StoragePartition being initialized.
   GetOriginTrialsControllerDelegate();
+
+  // The TpcdSupportService must be created with the profile, but after the
+  // initialization of the OriginTrialsControllerDelegate, as it depends on it.
+  tpcd::support::TpcdSupportServiceFactory::GetForProfile(this);
 }
 
 base::FilePath ProfileImpl::last_selected_directory() {
diff --git a/chrome/browser/readaloud/android/BUILD.gn b/chrome/browser/readaloud/android/BUILD.gn
index cb01fbf13..9cd7e31 100644
--- a/chrome/browser/readaloud/android/BUILD.gn
+++ b/chrome/browser/readaloud/android/BUILD.gn
@@ -158,7 +158,6 @@
     "java/src/org/chromium/chrome/browser/readaloud/player/VisibilityState.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinator.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediator.java",
-    "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerProperties.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinator.java",
@@ -177,6 +176,7 @@
     "//third_party/android_deps:material_design_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_appcompat_appcompat_java",
+    "//third_party/androidx:androidx_interpolator_interpolator_java",
     "//ui/android:ui_java_resources",
     "//ui/android:ui_no_recycler_view_java",
   ]
@@ -188,6 +188,9 @@
   sources = [
     "java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java",
+    "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinatorUnitTest.java",
+    "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediatorUnitTest.java",
+    "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinatorUnitTest.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediatorUnitTest.java",
@@ -201,6 +204,7 @@
     "//chrome/browser/tab:java",
     "//components/browser_ui/bottomsheet/android:java",
     "//third_party/androidx:androidx_appcompat_appcompat_java",
+    "//third_party/androidx:androidx_interpolator_interpolator_java",
     "//third_party/androidx:androidx_test_core_java",
     "//third_party/androidx:androidx_test_ext_junit_java",
     "//third_party/junit:junit",
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
index accc49b2..2a8bf49 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
@@ -13,16 +13,16 @@
 import org.chromium.base.Log;
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.readaloud.player.PlayerCoordinator;
-import org.chromium.chrome.browser.readaloud.player.expanded.ExpandedPlayerCoordinator;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelTabObserver;
 import org.chromium.chrome.browser.translate.TranslateBridge;
-import org.chromium.chrome.modules.readaloud.ExpandedPlayer;
 import org.chromium.chrome.modules.readaloud.Playback;
 import org.chromium.chrome.modules.readaloud.PlaybackArgs;
+import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
 import org.chromium.chrome.modules.readaloud.Player;
 import org.chromium.chrome.modules.readaloud.ReadAloudPlaybackHooks;
@@ -35,13 +35,14 @@
 
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 
 /**
  * The main entrypoint component for Read Aloud feature. It's responsible for checking its
  * availability and triggering playback.
  */
-public class ReadAloudController implements Player.Observer, PlaybackListener {
+public class ReadAloudController implements Player.Observer, Player.Delegate, PlaybackListener {
     private static final String TAG = "ReadAloudController";
 
     private final ObservableSupplier<Profile> mProfileSupplier;
@@ -49,13 +50,14 @@
     private final Map<String, Boolean> mTimepointsSupportedMap = new HashMap<>();
     private final HashSet<String> mPendingRequests = new HashSet<>();
     private final TabModel mTabModel;
-    private final ExpandedPlayer mExpandedPlayer;
     private final PlayerCoordinator mPlayerCoordinator;
     @Nullable
     private static PlayerCoordinator sPlayerCoordinatorForTesting;
 
     private TabModelTabObserver mTabObserver;
 
+    private final BottomSheetController mBottomSheetController;
+
     private final ReadAloudReadabilityHooks mReadabilityHooks;
     @Nullable
     private static ReadAloudReadabilityHooks sReadabilityHooksForTesting;
@@ -122,11 +124,11 @@
         mReadabilityHooks = sReadabilityHooksForTesting != null
                 ? sReadabilityHooksForTesting
                 : new ReadAloudReadabilityHooksImpl(context, ReadAloudFeatures.getApiKeyOverride());
-        mExpandedPlayer = new ExpandedPlayerCoordinator(context, bottomSheetController);
-        mPlayerCoordinator = sPlayerCoordinatorForTesting != null
-                ? sPlayerCoordinatorForTesting
-                : new PlayerCoordinator(context, miniPlayerStub);
-
+        mBottomSheetController = bottomSheetController;
+        mPlayerCoordinator =
+                sPlayerCoordinatorForTesting != null
+                        ? sPlayerCoordinatorForTesting
+                        : new PlayerCoordinator(context, miniPlayerStub, this);
         if (mReadabilityHooks.isEnabled()) {
             mTabObserver =
                     new TabModelTabObserver(mTabModel) {
@@ -321,6 +323,57 @@
         }
     }
 
+    // Player.Delegate
+    @Override
+    public BottomSheetController getBottomSheetController() {
+        return mBottomSheetController;
+    }
+
+    @Override
+    public boolean isHighlightingSupported() {
+        // TODO: implement
+        return false;
+    }
+
+    @Override
+    public ObservableSupplierImpl<Boolean> getHighlightingEnabledSupplier() {
+        // TODO: implement
+        return new ObservableSupplierImpl<Boolean>();
+    }
+
+    @Override
+    public ObservableSupplier<List<PlaybackVoice>> getCurrentLanguageVoicesSupplier() {
+        // TODO: implement
+        return new ObservableSupplierImpl<List<PlaybackVoice>>();
+    }
+
+    @Override
+    public ObservableSupplier<String> getVoiceIdSupplier() {
+        // TODO: implement
+        return new ObservableSupplierImpl<String>();
+    }
+
+    @Override
+    public Map<String, String> getVoiceOverrides() {
+        // TODO: implement
+        return new HashMap<String, String>();
+    }
+
+    @Override
+    public void setVoiceOverride(PlaybackVoice voice) {
+        // TODO: implement
+    }
+
+    @Override
+    public void previewVoice(PlaybackVoice voice) {
+        // TODO: implement
+    }
+
+    @Override
+    public void navigateToPlayingTab() {
+        // TODO: implement
+    }
+
     // Player.Observer
     @Override
     public void onRequestClosePlayers() {
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java
index 38943a1..0c9c63c 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java
@@ -9,53 +9,55 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
+import org.chromium.chrome.browser.readaloud.player.expanded.ExpandedPlayerCoordinator;
 import org.chromium.chrome.browser.readaloud.player.mini.MiniPlayerCoordinator;
 import org.chromium.chrome.modules.readaloud.Playback;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
 import org.chromium.chrome.modules.readaloud.Player;
-import org.chromium.chrome.modules.readaloud.Player.Delegate;
-import org.chromium.chrome.modules.readaloud.Player.Observer;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /**
  * Class that controls and coordinates the mini and expanded player UI.
  *
- * The expanded player is a full-width bottom sheet that will completely obscure
- * the mini player if it's showing. Since showing or hiding the mini player
- * requires resizing web contents which is expensive and laggy, we will leave
- * the mini player on screen when the expanded player is shown.
+ * <p>The expanded player is a full-width bottom sheet that will completely obscure the mini player
+ * if it's showing. Since showing or hiding the mini player requires resizing web contents which is
+ * expensive and laggy, we will leave the mini player on screen when the expanded player is shown.
  *
- * States:
- * A. no players shown
- * B. mini player visible
- * C. expanded player open and mini player visible (behind expanded player)
+ * <p>States: A. no players shown B. mini player visible C. expanded player open and mini player
+ * visible (behind expanded player)
  */
 public class PlayerCoordinator implements Player {
     private static final String TAG = "ReadAloudPlayer";
-
     private final ObserverList<Observer> mObserverList;
     private final PlayerMediator mMediator;
+    private final Delegate mDelegate;
     private final MiniPlayerCoordinator mMiniPlayer;
-
-    // TODO(b/302567541): remove this constructor when Delegate is available.
-    public PlayerCoordinator(Context context, ViewStub miniPlayerStub) {
-        this(context, miniPlayerStub, null);
-    }
+    private final ExpandedPlayerCoordinator mExpandedPlayer;
+    private Playback mPlayback;
 
     public PlayerCoordinator(Context context, ViewStub miniPlayerStub, Delegate delegate) {
         // Note, context isn't used yet but will be needed by the expanded player.
         mObserverList = new ObserverList<Observer>();
         PropertyModel model = new PropertyModel.Builder(PlayerProperties.ALL_KEYS).build();
         mMiniPlayer = new MiniPlayerCoordinator(miniPlayerStub, model);
-        mMediator = new PlayerMediator(/* coordinator= */ this, model);
+        mExpandedPlayer = new ExpandedPlayerCoordinator(context, delegate, model);
+        mMediator = new PlayerMediator(/* coordinator= */ this, delegate, model);
+        mDelegate = delegate;
     }
 
     @VisibleForTesting
-    PlayerCoordinator(MiniPlayerCoordinator miniPlayer, PlayerMediator mediator) {
+    PlayerCoordinator(
+            MiniPlayerCoordinator miniPlayer,
+            PlayerMediator mediator,
+            Delegate delegate,
+            ExpandedPlayerCoordinator player) {
         mObserverList = new ObserverList<Observer>();
         mMiniPlayer = miniPlayer;
         mMediator = mediator;
+        mDelegate = delegate;
+        mExpandedPlayer = player;
     }
 
     @Override
@@ -72,6 +74,7 @@
     public void destroy() {
         dismissPlayers();
         mMediator.destroy();
+        mMiniPlayer.destroy();
     }
 
     @Override
@@ -91,6 +94,7 @@
     public void playbackFailed() {
         mMediator.setPlayback(null);
         mMediator.setPlaybackState(PlaybackListener.State.ERROR);
+        Log.e(TAG, "PlayerController.playbackFailed() UI changes not implemented.");
     }
 
     /** Show expanded player. */
@@ -105,7 +109,7 @@
         mMediator.setPlayback(null);
         mMediator.setPlaybackState(PlaybackListener.State.STOPPED);
         mMiniPlayer.dismiss(shouldAnimateMiniPlayer());
-        // TODO dismiss expanded player
+        mExpandedPlayer.dismiss();
     }
 
     /** To be called when the close button is clicked. */
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
index 40951f7..24a1de8 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
@@ -15,14 +15,17 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.readaloud.player.expanded.ExpandedPlayerCoordinator;
 import org.chromium.chrome.browser.readaloud.player.mini.MiniPlayerCoordinator;
 import org.chromium.chrome.browser.readaloud.player.mini.MiniPlayerLayout;
 import org.chromium.chrome.modules.readaloud.Playback;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
+import org.chromium.chrome.modules.readaloud.Player;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Unit tests for {@link PlayerCoordinator}. */
@@ -33,8 +36,8 @@
     private ViewStub mMiniPlayerViewStub;
     @Mock
     private MiniPlayerLayout mMiniPlayerLayout;
-    @Mock
-    private Playback mPlayback;
+    @Mock private MiniPlayerCoordinator mMiniPlayerCoordinator;
+    @Mock private Playback mPlayback;
     @Mock
     private PlayerCoordinator.Observer mObserver;
     @Mock
@@ -44,10 +47,14 @@
     private PlayerCoordinator mPlayerCoordinator;
     private PropertyModel mModel;
 
+    @Mock private Player.Delegate mDelegate;
+    @Mock private ExpandedPlayerCoordinator mExpandedPlayer;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mPlayerCoordinator = new PlayerCoordinator(mMiniPlayer, mMediator);
+        mPlayerCoordinator =
+                new PlayerCoordinator(mMiniPlayer, mMediator, mDelegate, mExpandedPlayer);
     }
 
     @Test
@@ -100,7 +107,8 @@
     @Test
     public void testCloseClicked() {
         doReturn(mMiniPlayerLayout).when(mMiniPlayerViewStub).inflate();
-        mPlayerCoordinator = new PlayerCoordinator(null, mMiniPlayerViewStub, null);
+        mPlayerCoordinator =
+                new PlayerCoordinator(mMiniPlayer, mMediator, mDelegate, mExpandedPlayer);
         mPlayerCoordinator.addObserver(mObserver);
         mPlayerCoordinator.closeClicked();
         verify(mObserver).onRequestClosePlayers();
@@ -118,7 +126,8 @@
         verify(mMediator).setPlayback(eq(null));
         verify(mMediator).setPlaybackState(eq(PlaybackListener.State.STOPPED));
         verify(mMediator).destroy();
-
+        verify(mMiniPlayer).dismiss(Mockito.anyBoolean());
+        verify(mExpandedPlayer).dismiss();
         verify(mObserver, never()).onRequestClosePlayers();
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java
index 60456e6f..e161dfd 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java
@@ -20,21 +20,28 @@
 /** Mediator class in charge of updating player UI property model. */
 class PlayerMediator implements InteractionHandler {
     private final PlayerCoordinator mCoordinator;
+    private final PlayerCoordinator.Delegate mDelegate;
     private final PropertyModel mModel;
-    private final PlaybackListener mPlaybackListener = new PlaybackListener() {
-        @Override
-        public void onPlaybackDataChanged(PlaybackData data) {
-            mModel.set(PlayerProperties.PLAYBACK_STATE, data.state());
-            float percent =
-                    (float) data.absolutePositionNanos() / (float) data.totalDurationNanos();
-            mModel.set(PlayerProperties.PROGRESS, percent);
-        }
-    };
+    private final PlaybackListener mPlaybackListener =
+            new PlaybackListener() {
+                @Override
+                public void onPlaybackDataChanged(PlaybackData data) {
+                    setPlaybackState(data.state());
+                    float percent =
+                            (float) data.absolutePositionNanos()
+                                    / (float) data.totalDurationNanos();
+                    mModel.set(PlayerProperties.PROGRESS, percent);
+                }
+            };
 
     private Playback mPlayback;
 
-    PlayerMediator(PlayerCoordinator coordinator, PropertyModel model) {
+    PlayerMediator(
+            PlayerCoordinator coordinator,
+            PlayerCoordinator.Delegate delegate,
+            PropertyModel model) {
         mCoordinator = coordinator;
+        mDelegate = delegate;
         mModel = model;
         mModel.set(PlayerProperties.INTERACTION_HANDLER, this);
     }
@@ -121,5 +128,7 @@
     public void onTranslateLanguageChange(String targetLanguage) {}
 
     @Override
-    public void onMiniPlayerExpandClick() {}
+    public void onMiniPlayerExpandClick() {
+        // TODO: implement expand
+    }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java
index a97341a..26575fd 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java
@@ -18,11 +18,20 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.modules.readaloud.Playback;
+import org.chromium.chrome.modules.readaloud.PlaybackArgs.PlaybackVoice;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
+import org.chromium.chrome.modules.readaloud.Player;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /** Unit tests for {@link PlayerMediator}. */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
@@ -85,6 +94,49 @@
     }
     private TestPlaybackData mPlaybackData;
 
+    private static class TestPlayer implements Player.Delegate {
+        @Override
+        public BottomSheetController getBottomSheetController() {
+            return null;
+        }
+
+        @Override
+        public boolean isHighlightingSupported() {
+            return true;
+        }
+
+        @Override
+        public ObservableSupplierImpl<Boolean> getHighlightingEnabledSupplier() {
+            return new ObservableSupplierImpl<Boolean>();
+        }
+
+        @Override
+        public ObservableSupplier<List<PlaybackVoice>> getCurrentLanguageVoicesSupplier() {
+            return new ObservableSupplierImpl<List<PlaybackVoice>>();
+        }
+
+        @Override
+        public ObservableSupplier<String> getVoiceIdSupplier() {
+            return new ObservableSupplierImpl<String>();
+        }
+
+        @Override
+        public Map<String, String> getVoiceOverrides() {
+            return new HashMap<String, String>();
+        }
+
+        @Override
+        public void setVoiceOverride(PlaybackVoice voice) {}
+
+        @Override
+        public void previewVoice(PlaybackVoice voice) {}
+
+        @Override
+        public void navigateToPlayingTab() {}
+    }
+
+    private TestPlayer mPlayer;
+
     private PlayerMediator mMediator;
 
     @Before
@@ -95,7 +147,7 @@
         doReturn(PUBLISHER).when(mPlaybackMetadata).publisher();
         mPlaybackData = new TestPlaybackData();
         mModel = new PropertyModel.Builder(PlayerProperties.ALL_KEYS).build();
-        mMediator = new PlayerMediator(mPlayerCoordinator, mModel);
+        mMediator = new PlayerMediator(mPlayerCoordinator, mPlayer, mModel);
     }
 
     @Test
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerProperties.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerProperties.java
index c2cc7913..c6aa559 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerProperties.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerProperties.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.readaloud.player;
 
+import org.chromium.chrome.browser.readaloud.player.mini.MiniPlayerMediator;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
 
@@ -12,6 +13,8 @@
     // VisibilityState
     public static final WritableObjectPropertyKey<Integer> MINI_PLAYER_VISIBILITY =
             new WritableObjectPropertyKey<>();
+    public static final WritableObjectPropertyKey<Integer> EXPANDED_PLAYER_VISIBILITY =
+            new WritableObjectPropertyKey<>();
     public static final WritableObjectPropertyKey<Boolean> MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES =
             new WritableObjectPropertyKey<>();
     public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
@@ -21,15 +24,21 @@
             new WritableObjectPropertyKey<>();
     public static final WritableObjectPropertyKey<Float> PROGRESS =
             new WritableObjectPropertyKey<>();
+    public static final WritableObjectPropertyKey<Float> SPEED = new WritableObjectPropertyKey<>();
     public static final WritableObjectPropertyKey<InteractionHandler> INTERACTION_HANDLER =
             new WritableObjectPropertyKey<>();
+    public static final WritableObjectPropertyKey<MiniPlayerMediator> MINI_PLAYER_MEDIATOR =
+            new WritableObjectPropertyKey<>();
     public static final PropertyKey[] ALL_KEYS = {
-            MINI_PLAYER_VISIBILITY, //
-            MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES, //
-            TITLE, //
-            PUBLISHER, //
-            PLAYBACK_STATE, //
-            PROGRESS, //
-            INTERACTION_HANDLER //
+        MINI_PLAYER_VISIBILITY, //
+        EXPANDED_PLAYER_VISIBILITY, //
+        MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES, //
+        TITLE, //
+        PUBLISHER, //
+        PLAYBACK_STATE, //
+        PROGRESS, //
+        MINI_PLAYER_MEDIATOR, //
+        SPEED, //
+        INTERACTION_HANDLER //
     };
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinator.java
index 3506689..0e1f1ec 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinator.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinator.java
@@ -6,87 +6,91 @@
 
 import android.content.Context;
 
-import org.chromium.base.ObserverList;
-import org.chromium.chrome.browser.readaloud.PlayerState;
-import org.chromium.chrome.modules.readaloud.ExpandedPlayer;
-import org.chromium.chrome.modules.readaloud.ExpandedPlayer.Observer;
-import org.chromium.chrome.modules.readaloud.Playback;
+import androidx.annotation.Nullable;
+
+import org.chromium.chrome.browser.readaloud.player.VisibilityState;
+import org.chromium.chrome.modules.readaloud.Player.Delegate;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
+import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
-public class ExpandedPlayerCoordinator implements ExpandedPlayer {
+public class ExpandedPlayerCoordinator {
     private final Context mContext;
-    private final BottomSheetController mBottomSheetController;
-    private final ObserverList<Observer> mObserverList;
-    private ExpandedPlayerSheetContent mSheetContent;
+    private final Delegate mDelegate;
+    private final BottomSheetObserver mBottomSheetObserver =
+            new EmptyBottomSheetObserver() {
+                private BottomSheetContent mTrackedContent;
+
+                @Override
+                public void onSheetContentChanged(@Nullable BottomSheetContent newContent) {
+                    // TODO: implement
+                }
+
+                @Override
+                public void onSheetOpened(@StateChangeReason int reason) {
+                    // TODO: implement
+                }
+
+                @Override
+                public void onSheetClosed(@StateChangeReason int reason) {
+                    // TODO: notify ExpandedPlayerSheetContent of sheet closed
+                }
+            };
     private PropertyModel mModel;
+    private ExpandedPlayerSheetContent mSheetContent;
     private PropertyModelChangeProcessor<PropertyModel, ExpandedPlayerSheetContent, PropertyKey>
             mModelChangeProcessor;
     private ExpandedPlayerMediator mMediator;
 
-    public ExpandedPlayerCoordinator(Context context, BottomSheetController bottomSheetController) {
+    public ExpandedPlayerCoordinator(Context context, Delegate delegate, PropertyModel model) {
         mContext = context;
-        mBottomSheetController = bottomSheetController;
-        mObserverList = new ObserverList<Observer>();
+        mDelegate = delegate;
+        mModel = model;
+        mDelegate.getBottomSheetController().addObserver(mBottomSheetObserver);
     }
 
-    @Override
-    public void addObserver(Observer observer) {
-        mObserverList.addObserver(observer);
-    }
-
-    @Override
-    public void removeObserver(Observer observer) {
-        mObserverList.removeObserver(observer);
-    }
-
-    @Override
-    public void show(Playback playback) {
-        assert playback != null;
+    public void show() {
         if (mSheetContent == null) {
-            mSheetContent = new ExpandedPlayerSheetContent(mContext, mBottomSheetController);
-            mModel =
-                    new PropertyModel.Builder(ExpandedPlayerProperties.ALL_KEYS)
-                            .with(ExpandedPlayerProperties.STATE_KEY, PlayerState.GONE)
-                            .build();
+            makeSheetContent();
             mModelChangeProcessor =
                     PropertyModelChangeProcessor.create(
                             mModel, mSheetContent, ExpandedPlayerViewBinder::bind);
-            mMediator =
-                    new ExpandedPlayerMediator(
-                            mBottomSheetController,
-                            mModel,
-                            new Observer() {
-                                @Override
-                                public void onCloseClicked() {
-                                    for (Observer observer : mObserverList) {
-                                        observer.onCloseClicked();
-                                    }
-                                }
-                            });
+            makeMediator();
         }
-        mMediator.show(playback);
+        mMediator.show();
     }
 
-    @Override
+    public void makeSheetContent() {
+        mSheetContent =
+                new ExpandedPlayerSheetContent(mContext, mDelegate.getBottomSheetController());
+    }
+
+    public void makeMediator() {
+        mMediator = new ExpandedPlayerMediator(mModel);
+    }
+
     public void dismiss() {
         if (mMediator != null) {
             mMediator.dismiss();
         }
     }
 
-    @Override
-    public @PlayerState int getState() {
+    public @VisibilityState int getVisibility() {
         if (mMediator == null) {
-            return PlayerState.GONE;
+            return VisibilityState.GONE;
         }
-        return mMediator.getState();
+        return mMediator.getVisibility();
     }
 
-    BottomSheetContent getSheetContentForTesting() {
-        return mSheetContent;
+    void setMediatorForTesting(ExpandedPlayerMediator mediator) {
+        mMediator = mediator;
+    }
+
+    void setSheetContentForTesting(ExpandedPlayerSheetContent sheetContent) {
+        mSheetContent = sheetContent;
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinatorUnitTest.java
index 2301389..4eb1f95 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerCoordinatorUnitTest.java
@@ -5,13 +5,15 @@
 package org.chromium.chrome.browser.readaloud.player.expanded;
 
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -19,13 +21,17 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.modules.readaloud.ExpandedPlayer.Observer;
+import org.chromium.chrome.browser.readaloud.player.PlayerCoordinator;
+import org.chromium.chrome.browser.readaloud.player.PlayerProperties;
+import org.chromium.chrome.browser.readaloud.player.VisibilityState;
 import org.chromium.chrome.modules.readaloud.Playback;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.ui.modelutil.PropertyModel;
 
 /** Unit tests for {@link ExpandedPlayerCoordinator}. */
 @RunWith(BaseRobolectricTestRunner.class)
@@ -33,49 +39,77 @@
 public class ExpandedPlayerCoordinatorUnitTest {
     @Mock private BottomSheetController mBottomSheetController;
     @Mock private Playback mPlayback;
-    @Mock private Observer mObserver;
-
+    @Mock private PlayerCoordinator.Delegate mDelegate;
+    private PropertyModel mModel;
+    @Mock private ExpandedPlayerMediator mMediator;
+    @Mock private ExpandedPlayerSheetContent mSheetContent;
     private ExpandedPlayerCoordinator mCoordinator;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mDelegate.getBottomSheetController()).thenReturn(mBottomSheetController);
+        mModel = new PropertyModel.Builder(PlayerProperties.ALL_KEYS).build();
         mCoordinator =
-                new ExpandedPlayerCoordinator(
-                        ApplicationProvider.getApplicationContext(), mBottomSheetController);
+                Mockito.spy(
+                        new ExpandedPlayerCoordinator(
+                                ApplicationProvider.getApplicationContext(), mDelegate, mModel));
+
+        doAnswer(
+                        invocation -> {
+                            mCoordinator.setSheetContentForTesting(mSheetContent);
+                            return null;
+                        })
+                .when(mCoordinator)
+                .makeSheetContent();
+        doNothing().when(mSheetContent).setSpeed(anyFloat());
+
+        doAnswer(
+                        invocation -> {
+                            mCoordinator.setMediatorForTesting(mMediator);
+                            when(mMediator.getVisibility()).thenReturn(VisibilityState.SHOWING);
+                            return null;
+                        })
+                .when(mCoordinator)
+                .makeMediator();
     }
 
     @Test
     public void testShowInflatesViewOnce() {
-        mCoordinator.show(mPlayback);
-        verify(mBottomSheetController, times(1)).requestShowContent(any(), eq(true));
+        mCoordinator.show();
+        verify(mCoordinator, times(1)).makeSheetContent();
 
         // Second show() shouldn't inflate the stub again.
-        reset(mBottomSheetController);
-        mCoordinator.show(mPlayback);
-        verify(mBottomSheetController, never()).requestShowContent(any(), anyBoolean());
+        reset(mCoordinator);
+        mCoordinator.show();
+        verify(mCoordinator, never()).makeSheetContent();
     }
 
     @Test
     public void testDismiss() {
-        mCoordinator.show(mPlayback);
+        mCoordinator.show();
         mCoordinator.dismiss();
-        verify(mBottomSheetController)
-                .hideContent(eq(mCoordinator.getSheetContentForTesting()), eq(true));
+        verify(mMediator, times(1)).dismiss();
     }
 
     @Test
-    public void testObserveClickClose() {
-        mCoordinator.addObserver(mObserver);
-        mCoordinator.show(mPlayback);
+    public void testGetVisibility() {
+        assertTrue(mCoordinator.getVisibility() == VisibilityState.GONE);
+        mCoordinator.show();
+        assertTrue(mCoordinator.getVisibility() == VisibilityState.SHOWING);
+    }
 
-        assertTrue(
-                mCoordinator
-                        .getSheetContentForTesting()
-                        .getContentView()
-                        .findViewById(R.id.readaloud_expanded_player_close_button)
-                        .performClick());
+    @Test
+    public void testBindVisibility() {
+        mCoordinator.show();
+        mModel.set(PlayerProperties.EXPANDED_PLAYER_VISIBILITY, VisibilityState.HIDING);
+        verify(mSheetContent).hide();
+    }
 
-        verify(mObserver, times(1)).onCloseClicked();
+    @Test
+    public void testBindSpeed() {
+        mCoordinator.show();
+        mModel.set(PlayerProperties.SPEED, 2f);
+        verify(mSheetContent).setSpeed(eq(2f));
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediator.java
index 7e098c7e..f61579e 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediator.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediator.java
@@ -4,70 +4,40 @@
 
 package org.chromium.chrome.browser.readaloud.player.expanded;
 
-import org.chromium.chrome.browser.readaloud.PlayerState;
-import org.chromium.chrome.modules.readaloud.ExpandedPlayer.Observer;
-import org.chromium.chrome.modules.readaloud.Playback;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
+import org.chromium.chrome.browser.readaloud.player.PlayerProperties;
+import org.chromium.chrome.browser.readaloud.player.VisibilityState;
 import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.ui.modelutil.PropertyModel;
 
-/** Mediator class responsible for controlling Read Aloud mini player. */
+/** Mediator class responsible for controlling Read Aloud expanded player. */
 public class ExpandedPlayerMediator extends EmptyBottomSheetObserver {
-    private final BottomSheetController mBottomSheetController;
     private final PropertyModel mModel;
-    private final Observer mObserver;
 
-    public ExpandedPlayerMediator(
-            BottomSheetController bottomSheetController, PropertyModel model, Observer observer) {
-        mBottomSheetController = bottomSheetController;
-        mBottomSheetController.addObserver(this);
+    public ExpandedPlayerMediator(PropertyModel model) {
         mModel = model;
-        mObserver = observer;
-        mModel.set(
-                ExpandedPlayerProperties.ON_CLOSE_CLICK_KEY,
-                (view) -> {
-                    mObserver.onCloseClicked();
-                });
     }
 
-    public void destroy() {
-        mBottomSheetController.removeObserver(this);
-    }
-
-    public void show(Playback playback) {
-        // TODO use playback
-        @PlayerState int state = getState();
-        if (state == PlayerState.SHOWING || state == PlayerState.VISIBLE) {
+    public void show() {
+        @VisibilityState int state = getVisibility();
+        if (state == VisibilityState.SHOWING || state == VisibilityState.VISIBLE) {
             return;
         }
-        setState(PlayerState.SHOWING);
+        setVisibility(VisibilityState.SHOWING);
     }
 
     public void dismiss() {
-        @PlayerState int state = getState();
-        if (state == PlayerState.GONE || state == PlayerState.HIDING) {
+        @VisibilityState int state = getVisibility();
+        if (state == VisibilityState.GONE || state == VisibilityState.HIDING) {
             return;
         }
-        setState(PlayerState.HIDING);
+        setVisibility(VisibilityState.HIDING);
     }
 
-    public @PlayerState int getState() {
-        return mModel.get(ExpandedPlayerProperties.STATE_KEY);
+    public @VisibilityState int getVisibility() {
+        return mModel.get(PlayerProperties.EXPANDED_PLAYER_VISIBILITY);
     }
 
-    // from EmptyBottomSheetObserver
-    @Override
-    public void onSheetOpened(@StateChangeReason int reason) {
-        setState(PlayerState.VISIBLE);
-    }
-
-    @Override
-    public void onSheetClosed(@StateChangeReason int reason) {
-        setState(PlayerState.GONE);
-    }
-
-    private void setState(@PlayerState int state) {
-        mModel.set(ExpandedPlayerProperties.STATE_KEY, state);
+    void setVisibility(@VisibilityState int state) {
+        mModel.set(PlayerProperties.EXPANDED_PLAYER_VISIBILITY, state);
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediatorUnitTest.java
index ed0d2b85..40d5980 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediatorUnitTest.java
@@ -9,7 +9,6 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import org.junit.Before;
@@ -21,8 +20,9 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.browser.readaloud.PlayerState;
-import org.chromium.chrome.modules.readaloud.ExpandedPlayer;
+import org.chromium.chrome.browser.readaloud.player.PlayerCoordinator;
+import org.chromium.chrome.browser.readaloud.player.PlayerProperties;
+import org.chromium.chrome.browser.readaloud.player.VisibilityState;
 import org.chromium.chrome.modules.readaloud.Playback;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -32,7 +32,7 @@
 @Config(manifest = Config.NONE)
 public class ExpandedPlayerMediatorUnitTest {
     @Mock private BottomSheetController mBottomSheetController;
-    @Mock private ExpandedPlayer.Observer mObserver;
+    @Mock private PlayerCoordinator.Delegate mDelegate;
     @Mock private Playback mPlayback;
 
     private PropertyModel mModel;
@@ -43,65 +43,55 @@
         MockitoAnnotations.initMocks(this);
         mModel =
                 Mockito.spy(
-                        new PropertyModel.Builder(ExpandedPlayerProperties.ALL_KEYS)
-                                .with(ExpandedPlayerProperties.STATE_KEY, PlayerState.GONE)
+                        new PropertyModel.Builder(PlayerProperties.ALL_KEYS)
+                                .with(
+                                        PlayerProperties.EXPANDED_PLAYER_VISIBILITY,
+                                        VisibilityState.GONE)
                                 .build());
 
-        mMediator = new ExpandedPlayerMediator(mBottomSheetController, mModel, mObserver);
-    }
-
-    @Test
-    public void testInitialStateAfterConstructMediator() {
-        verify(mBottomSheetController, times(1)).addObserver(eq(mMediator));
-        assertEquals(PlayerState.GONE, mMediator.getState());
-    }
-
-    @Test
-    public void testDestroy() {
-        mMediator.destroy();
-        verify(mBottomSheetController, times(1)).removeObserver(eq(mMediator));
+        mMediator = new ExpandedPlayerMediator(mModel);
     }
 
     @Test
     public void testShow() {
-        mMediator.show(mPlayback);
-        assertEquals(PlayerState.SHOWING, mMediator.getState());
+        mMediator.show();
+        assertEquals(VisibilityState.SHOWING, mMediator.getVisibility());
     }
 
     @Test
     public void testShowAlreadyShowing() {
-        mModel.set(ExpandedPlayerProperties.STATE_KEY, PlayerState.SHOWING);
+        mModel.set(PlayerProperties.EXPANDED_PLAYER_VISIBILITY, VisibilityState.SHOWING);
         reset(mModel);
-        mMediator.show(mPlayback);
-        assertEquals(PlayerState.SHOWING, mMediator.getState());
-        verify(mModel, never()).set(any(), any());
+        mMediator.show();
+        assertEquals(VisibilityState.SHOWING, mMediator.getVisibility());
+        verify(mModel, never()).set(eq(PlayerProperties.EXPANDED_PLAYER_VISIBILITY), any());
 
-        mModel.set(ExpandedPlayerProperties.STATE_KEY, PlayerState.VISIBLE);
+        mModel.set(PlayerProperties.EXPANDED_PLAYER_VISIBILITY, VisibilityState.VISIBLE);
         reset(mModel);
-        mMediator.show(mPlayback);
-        assertEquals(PlayerState.VISIBLE, mMediator.getState());
-        verify(mModel, never()).set(any(), any());
+        mMediator.show();
+        assertEquals(VisibilityState.VISIBLE, mMediator.getVisibility());
+        verify(mModel, never()).set(eq(PlayerProperties.EXPANDED_PLAYER_VISIBILITY), any());
     }
 
     @Test
     public void testDismissAlreadyHiding() {
-        mModel.set(ExpandedPlayerProperties.STATE_KEY, PlayerState.HIDING);
+        mModel.set(PlayerProperties.EXPANDED_PLAYER_VISIBILITY, VisibilityState.HIDING);
         reset(mModel);
         mMediator.dismiss();
-        assertEquals(PlayerState.HIDING, mMediator.getState());
+        assertEquals(VisibilityState.HIDING, mMediator.getVisibility());
         verify(mModel, never()).set(any(), any());
 
-        mModel.set(ExpandedPlayerProperties.STATE_KEY, PlayerState.GONE);
+        mModel.set(PlayerProperties.EXPANDED_PLAYER_VISIBILITY, VisibilityState.GONE);
         reset(mModel);
         mMediator.dismiss();
-        assertEquals(PlayerState.GONE, mMediator.getState());
+        assertEquals(VisibilityState.GONE, mMediator.getVisibility());
         verify(mModel, never()).set(any(), any());
     }
 
     @Test
     public void testDismiss() {
-        mMediator.show(mPlayback);
+        mMediator.show();
         mMediator.dismiss();
-        assertEquals(PlayerState.HIDING, mMediator.getState());
+        assertEquals(VisibilityState.HIDING, mMediator.getVisibility());
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerProperties.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerProperties.java
deleted file mode 100644
index c162b13..0000000
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerProperties.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.readaloud.player.expanded;
-
-import android.view.View;
-
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
-
-/** Keys for Read Aloud expanded player model properties. */
-public class ExpandedPlayerProperties {
-    public static final WritableObjectPropertyKey<Integer> STATE_KEY =
-            new WritableObjectPropertyKey<>();
-    public static final WritableObjectPropertyKey<Float> SPEED_KEY =
-            new WritableObjectPropertyKey<>();
-    public static final WritableObjectPropertyKey<View.OnClickListener> ON_CLOSE_CLICK_KEY =
-            new WritableObjectPropertyKey<>();
-    public static final PropertyKey[] ALL_KEYS = {STATE_KEY, SPEED_KEY, ON_CLOSE_CLICK_KEY};
-}
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
index dbc40f0..2f6e72c 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
@@ -12,8 +12,10 @@
 import android.widget.TextView;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Log;
+import org.chromium.chrome.browser.readaloud.player.InteractionHandler;
 import org.chromium.chrome.browser.readaloud.player.R;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
@@ -30,15 +32,22 @@
     private final BottomSheetController mBottomSheetController;
     private View mContentView;
 
-    // TODO remove hard-coded strings
-    @SuppressWarnings("SetTextI18n")
     public ExpandedPlayerSheetContent(
             Context context, BottomSheetController bottomSheetController) {
+        this(
+                context,
+                bottomSheetController,
+                LayoutInflater.from(context)
+                        .inflate(R.layout.readaloud_expanded_player_layout, null));
+    }
+
+    @SuppressWarnings("SetTextI18n")
+    @VisibleForTesting
+    ExpandedPlayerSheetContent(
+            Context context, BottomSheetController bottomSheetController, View contentView) {
         mContext = context;
         mBottomSheetController = bottomSheetController;
-        mContentView =
-                LayoutInflater.from(context)
-                        .inflate(R.layout.readaloud_expanded_player_layout, null);
+        mContentView = contentView;
         ((TextView) mContentView.findViewById(R.id.readaloud_expanded_player_title))
                 .setText("Page title");
         ((TextView) mContentView.findViewById(R.id.readaloud_expanded_player_publisher))
@@ -69,6 +78,14 @@
                 .setOnClickListener(onClick);
     }
 
+    void setInteractionHandler(InteractionHandler handler) {
+        setOnClickListener(R.id.readaloud_expanded_player_close_button, handler::onCloseClick);
+        setOnClickListener(R.id.readaloud_play_pause_button, handler::onPlayPauseClick);
+        setOnClickListener(R.id.readaloud_seek_back_button, handler::onSeekBackClick);
+        setOnClickListener(R.id.readaloud_seek_forward_button, handler::onSeekForwardClick);
+        setOnClickListener(R.id.readaloud_expanded_player_publisher, handler::onPublisherClick);
+    }
+
     @SuppressWarnings({"SetTextI18n", "DefaultLocale"})
     public void setSpeed(float speed) {
         TextView speedButton = (TextView) mContentView.findViewById(R.id.readaloud_playback_speed);
@@ -186,4 +203,13 @@
         // "Read Aloud player minimized."
         return R.string.readaloud_player_minimized;
     }
+
+    private void setOnClickListener(int id, Runnable onClick) {
+        mContentView
+                .findViewById(id)
+                .setOnClickListener(
+                        (view) -> {
+                            onClick.run();
+                        });
+    }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java
index 96212f1..cd9f0db9 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java
@@ -5,16 +5,19 @@
 package org.chromium.chrome.browser.readaloud.player.expanded;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.Activity;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.appcompat.app.AppCompatActivity;
 import androidx.test.core.app.ApplicationProvider;
 
 import org.junit.Before;
@@ -22,9 +25,12 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.readaloud.player.InteractionHandler;
+import org.chromium.chrome.browser.readaloud.player.R;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 
 /** Unit tests for {@link ExpandedPlayerSheetContent}. */
@@ -32,6 +38,7 @@
 @Config(manifest = Config.NONE)
 public class ExpandedPlayerSheetContentUnitTest {
     @Mock private BottomSheetController mBottomSheetController;
+    @Mock private InteractionHandler mInteractionHandler;
 
     private Context mContext;
     private Drawable mPlayDrawable;
@@ -41,6 +48,8 @@
     private ImageView mBackButton;
     private ImageView mForwardButton;
     private ImageView mPlayPauseButton;
+    private View mContentView;
+    private Activity mActivity;
 
     @Before
     public void setUp() {
@@ -48,12 +57,18 @@
         mContext = ApplicationProvider.getApplicationContext();
         mPlayDrawable = mContext.getDrawable(R.drawable.play_button);
         mPauseDrawable = mContext.getDrawable(R.drawable.pause_button);
-        mContent = new ExpandedPlayerSheetContent(mContext, mBottomSheetController);
-        final View contentView = mContent.getContentView();
-        mSpeedView = (TextView) contentView.findViewById(R.id.readaloud_playback_speed);
-        mBackButton = (ImageView) contentView.findViewById(R.id.readaloud_seek_back_button);
-        mForwardButton = (ImageView) contentView.findViewById(R.id.readaloud_seek_forward_button);
-        mPlayPauseButton = (ImageView) contentView.findViewById(R.id.readaloud_play_pause_button);
+        mActivity = Robolectric.buildActivity(AppCompatActivity.class).setup().get();
+        // Need to set theme before inflating layout.
+        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mContentView =
+                mActivity
+                        .getLayoutInflater()
+                        .inflate(R.layout.readaloud_expanded_player_layout, null);
+        mSpeedView = (TextView) mContentView.findViewById(R.id.readaloud_playback_speed);
+        mBackButton = (ImageView) mContentView.findViewById(R.id.readaloud_seek_back_button);
+        mForwardButton = (ImageView) mContentView.findViewById(R.id.readaloud_seek_forward_button);
+        mPlayPauseButton = (ImageView) mContentView.findViewById(R.id.readaloud_play_pause_button);
+        mContent = new ExpandedPlayerSheetContent(mContext, mBottomSheetController, mContentView);
     }
 
     @Test
@@ -65,6 +80,12 @@
     }
 
     @Test
+    public void testSetInteractionHandler() {
+        mContent.setInteractionHandler(mInteractionHandler);
+        assertTrue(mPlayPauseButton.performClick());
+    }
+
+    @Test
     public void testSetSpeed() {
         mContent.setSpeed(0.5f);
         assertEquals("0.5x", mSpeedView.getText());
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java
index 8e9aca8..28e18f97 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java
@@ -4,7 +4,8 @@
 
 package org.chromium.chrome.browser.readaloud.player.expanded;
 
-import org.chromium.chrome.browser.readaloud.PlayerState;
+import org.chromium.chrome.browser.readaloud.player.PlayerProperties;
+import org.chromium.chrome.browser.readaloud.player.VisibilityState;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -13,20 +14,24 @@
  * state.
  */
 public class ExpandedPlayerViewBinder {
-    /** Called by {@link PropertyModelChangeProcessor} each time the model is updated. */
+    /**
+     * Called by {@link PropertyModelChangeProcessor} on creation and each time the model is
+     * updated.
+     */
     public static void bind(
             PropertyModel model, ExpandedPlayerSheetContent content, PropertyKey key) {
-        if (key == ExpandedPlayerProperties.STATE_KEY) {
-            @PlayerState int state = model.get(ExpandedPlayerProperties.STATE_KEY);
-            if (state == PlayerState.SHOWING) {
+        if (key == PlayerProperties.EXPANDED_PLAYER_VISIBILITY) {
+            @VisibilityState int state = model.get(PlayerProperties.EXPANDED_PLAYER_VISIBILITY);
+            if (state == VisibilityState.SHOWING) {
                 content.show();
-            } else if (state == PlayerState.HIDING) {
+            } else if (state == VisibilityState.HIDING) {
                 content.hide();
             }
-        } else if (key == ExpandedPlayerProperties.SPEED_KEY) {
-            content.setSpeed(model.get(ExpandedPlayerProperties.SPEED_KEY));
-        } else if (key == ExpandedPlayerProperties.ON_CLOSE_CLICK_KEY) {
-            content.setCloseButtonHandler(model.get(ExpandedPlayerProperties.ON_CLOSE_CLICK_KEY));
+            // TODO: set title and publisher
+        } else if (key == PlayerProperties.SPEED) {
+            content.setSpeed(model.get(PlayerProperties.SPEED));
+        } else if (key == PlayerProperties.INTERACTION_HANDLER) {
+            content.setInteractionHandler(model.get(PlayerProperties.INTERACTION_HANDLER));
         }
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinator.java
index 983bde2..13de15f2 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinator.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinator.java
@@ -34,6 +34,12 @@
         mMediator = mediator;
     }
 
+    public void destroy() {
+        if (mLayout != null) {
+            mLayout.destroy();
+        }
+    }
+
     /**
      * Show the mini player if it isn't already showing.
      * @param animate True if the transition should be animated. If false, the mini player will
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinatorUnitTest.java
index 9db92e8..c98371f 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerCoordinatorUnitTest.java
@@ -55,6 +55,7 @@
     public void testViewInflated() {
         // Test the real constructor
         reset(mViewStub);
+        doReturn(mLayout).when(mViewStub).inflate();
         mCoordinator = new MiniPlayerCoordinator(mViewStub, mModel);
         verify(mViewStub).inflate();
     }
@@ -112,4 +113,13 @@
         mModel.set(PlayerProperties.PROGRESS, 0.5f);
         verify(mLayout).setProgress(eq(0.5f));
     }
+
+    @Test
+    public void testBindVisibility() {
+        mModel.set(PlayerProperties.MINI_PLAYER_VISIBILITY, VisibilityState.SHOWING);
+        verify(mLayout).updateVisibility(eq(VisibilityState.SHOWING));
+
+        mModel.set(PlayerProperties.MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES, true);
+        verify(mLayout).enableAnimations(eq(true));
+    }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java
index fef93634..9cc3343 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java
@@ -11,9 +11,13 @@
 import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.STOPPED;
 import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.UNKNOWN;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
@@ -21,10 +25,16 @@
 
 import org.chromium.chrome.browser.readaloud.player.InteractionHandler;
 import org.chromium.chrome.browser.readaloud.player.R;
+import org.chromium.chrome.browser.readaloud.player.VisibilityState;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
+import org.chromium.ui.interpolators.Interpolators;
 
 /** Convenience class for manipulating mini player UI layout. */
 public class MiniPlayerLayout extends LinearLayout {
+    private static final long SHOW_HIDE_DURATION_MS = 150L;
+    private static final Interpolator SHOW_HIDE_INTERPOLATOR =
+            Interpolators.FAST_OUT_SLOW_IN_INTERPOLATOR;
+
     private TextView mTitle;
     private TextView mPublisher;
     private ProgressBar mProgressBar;
@@ -36,10 +46,23 @@
     private LinearLayout mErrorLayout;
 
     private @PlaybackListener.State int mLastPlaybackState;
+    private boolean mEnableAnimations;
+    private InteractionHandler mInteractionHandler;
+    private int mHeightPx;
+    private ObjectAnimator mTranslationYAnimator;
+    private @VisibilityState int mFinalVisibility;
+    private boolean mPendingShowHideAnimation;
+    private MiniPlayerMediator mMediator;
+    private long mNextAnimationPlayTime;
 
     /** Constructor for inflating from XML. */
     public MiniPlayerLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mFinalVisibility = VisibilityState.GONE;
+    }
+
+    void destroy() {
+        destroyYTranslationAnimator();
     }
 
     @Override
@@ -55,6 +78,69 @@
         mErrorLayout = (LinearLayout) findViewById(R.id.error_layout);
 
         mLastPlaybackState = PlaybackListener.State.UNKNOWN;
+        mNextAnimationPlayTime = 0L;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        int height = getHeight();
+        if (height != 0) {
+            mHeightPx = height;
+        }
+
+        if (mPendingShowHideAnimation) {
+            runShowHideAnimation();
+            mPendingShowHideAnimation = false;
+        }
+    }
+
+    void updateVisibility(@VisibilityState int visibility) {
+        // If "showing" or "hiding", eventually the view will be "visible" or "gone".
+        if (visibility == VisibilityState.SHOWING) {
+            visibility = VisibilityState.VISIBLE;
+        } else if (visibility == VisibilityState.HIDING) {
+            visibility = VisibilityState.GONE;
+        }
+
+        // Stop now if no change is needed.
+        if (mFinalVisibility == visibility) {
+            return;
+        } else {
+            mFinalVisibility = visibility;
+        }
+
+        // If there's an animation running, it must be going in the wrong direction.
+        // Destroy it.
+        mNextAnimationPlayTime = 0L;
+        if (mTranslationYAnimator != null) {
+            // Record the old animation's progress so the new one can start from the same
+            // position rather than starting at fully shown or hidden.
+            mNextAnimationPlayTime =
+                    SHOW_HIDE_DURATION_MS - mTranslationYAnimator.getCurrentPlayTime();
+            destroyYTranslationAnimator();
+        }
+
+        // If animation is disabled, show or hide the view immediately and return.
+        if (!mEnableAnimations) {
+            setTranslationY(0);
+            setVisibility(mFinalVisibility == VisibilityState.VISIBLE ? View.VISIBLE : View.GONE);
+            notifyVisibilityChanged();
+            return;
+        }
+
+        // Otherwise kick off animations. Need to calculate view height at least once.
+        if (mHeightPx == 0) {
+            mPendingShowHideAnimation = true;
+            // Causes onLayout() to run.
+            setVisibility(View.INVISIBLE);
+        } else {
+            runShowHideAnimation();
+        }
+    }
+
+    void enableAnimations(boolean enable) {
+        mEnableAnimations = enable;
     }
 
     void setTitle(String title) {
@@ -74,11 +160,16 @@
     }
 
     void setInteractionHandler(InteractionHandler handler) {
+        mInteractionHandler = handler;
         setOnClickListener(R.id.close_button, handler::onCloseClick);
         setOnClickListener(R.id.mini_player_background, handler::onMiniPlayerExpandClick);
         setOnClickListener(R.id.play_button, handler::onPlayPauseClick);
     }
 
+    void setMediator(MiniPlayerMediator mediator) {
+        mMediator = mediator;
+    }
+
     void onPlaybackStateChanged(@PlaybackListener.State int state) {
         switch (state) {
             // UNKNOWN is currently the "reset" state and can be treated same as buffering.
@@ -137,4 +228,53 @@
     private void setOnClickListener(int id, Runnable handler) {
         findViewById(id).setOnClickListener((v) -> { handler.run(); });
     }
+
+    private void notifyVisibilityChanged() {
+        if (mMediator != null) {
+            mMediator.onVisibilityChanged(mFinalVisibility);
+        }
+    }
+
+    private void runShowHideAnimation() {
+        int startTranslationY = mHeightPx;
+        int endTranslationY = 0;
+        if (mFinalVisibility == VisibilityState.GONE) {
+            startTranslationY = 0;
+            endTranslationY = mHeightPx;
+        }
+
+        setTranslationY(startTranslationY);
+        // View starts out VISIBLE for both show and hide.
+        setVisibility(View.VISIBLE);
+
+        mTranslationYAnimator = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, endTranslationY);
+        mTranslationYAnimator.setDuration(SHOW_HIDE_DURATION_MS);
+        mTranslationYAnimator.setInterpolator(SHOW_HIDE_INTERPOLATOR);
+        mTranslationYAnimator.addListener(
+                new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        destroyYTranslationAnimator();
+                        if (mFinalVisibility == VisibilityState.GONE) {
+                            setVisibility(View.GONE);
+                        }
+                        notifyVisibilityChanged();
+                    }
+                });
+        // This call must come after setDuration().
+        mTranslationYAnimator.setCurrentPlayTime(mNextAnimationPlayTime);
+        mTranslationYAnimator.start();
+    }
+
+    private void destroyYTranslationAnimator() {
+        if (mTranslationYAnimator != null) {
+            mTranslationYAnimator.removeAllListeners();
+            mTranslationYAnimator.cancel();
+            mTranslationYAnimator = null;
+        }
+    }
+
+    ObjectAnimator getYTranslationAnimatorForTesting() {
+        return mTranslationYAnimator;
+    }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java
index 98dae7c..f434faf5 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java
@@ -4,11 +4,19 @@
 package org.chromium.chrome.browser.readaloud.player.mini;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
+import android.animation.ObjectAnimator;
 import android.app.Activity;
+import android.os.SystemClock;
 import android.view.View;
 import android.widget.ProgressBar;
 import android.widget.TextView;
@@ -22,21 +30,29 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowSystemClock;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.readaloud.player.InteractionHandler;
 import org.chromium.chrome.browser.readaloud.player.R;
+import org.chromium.chrome.browser.readaloud.player.VisibilityState;
 import org.chromium.chrome.modules.readaloud.PlaybackListener;
 
 /** Unit tests for {@link PlayerCoordinator}. */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+@Config(
+        manifest = Config.NONE,
+        shadows = {ShadowSystemClock.class})
 public class MiniPlayerLayoutUnitTest {
+    private static final float HEIGHT = 210f;
+    private static final long ANIMATION_DURATION_MS = 150L;
+    private static final int INITIAL_SYSTEM_TIME_MS = 1000;
     private final Activity mActivity;
     private final MiniPlayerLayout mLayout;
 
     @Mock
     private InteractionHandler mInteractionHandler;
+    @Mock private MiniPlayerMediator mMediator;
 
     public MiniPlayerLayoutUnitTest() {
         mActivity = Robolectric.buildActivity(AppCompatActivity.class).setup().get();
@@ -50,6 +66,8 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mLayout.setMediator(mMediator);
+        SystemClock.setCurrentTimeMillis(INITIAL_SYSTEM_TIME_MS);
     }
 
     @Test
@@ -152,4 +170,231 @@
         assertTrue(mLayout.findViewById(R.id.play_button).performClick());
         verify(mInteractionHandler).onPlayPauseClick();
     }
+
+    @Test
+    public void testShow() {
+        mLayout.enableAnimations(false);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+
+        // No animation, so state should immediately become VISIBLE.
+        assertEquals(View.VISIBLE, mLayout.getVisibility());
+        assertEquals(0f, mLayout.getTranslationY(), /* delta= */ 1e-6);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.VISIBLE));
+    }
+
+    @Test
+    public void testShow_alreadyShowing() {
+        // Show once.
+        mLayout.enableAnimations(false);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.VISIBLE));
+
+        // Showing again shouldn't have an effect.
+        reset(mMediator);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+        verify(mMediator, never()).onVisibilityChanged(anyInt());
+    }
+
+    @Test
+    public void testHide() {
+        mLayout.enableAnimations(false);
+
+        // Show.
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.VISIBLE));
+
+        // Hide.
+        mLayout.updateVisibility(VisibilityState.HIDING);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.GONE));
+        assertEquals(View.GONE, mLayout.getVisibility());
+        assertEquals(0f, mLayout.getTranslationY(), /* delta= */ 1e-6);
+    }
+
+    @Test
+    public void testHide_alreadyHiding() {
+        mLayout.enableAnimations(false);
+        assertEquals(View.GONE, mLayout.getVisibility());
+        // No effect yet since initial state is GONE.
+        mLayout.updateVisibility(VisibilityState.HIDING);
+        verify(mMediator, never()).onVisibilityChanged(anyInt());
+    }
+
+    @Test
+    public void testAnimatedShow() {
+        // Start show animation.
+        mLayout.enableAnimations(true);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+
+        // Visibility gets set from GONE to INVISIBLE to trigger layout.
+        assertEquals(View.INVISIBLE, mLayout.getVisibility());
+
+        // Pretend the layout step was triggered so the real height will be calculated.
+        mLayout.layout(0, 0, 0, (int) HEIGHT);
+        assertEquals((int) HEIGHT, mLayout.getHeight());
+
+        // Set up and run the animation.
+        // Start out visible and translated down by HEIGHT pixels.
+        assertEquals(View.VISIBLE, mLayout.getVisibility());
+        assertEquals(HEIGHT, mLayout.getTranslationY(), /* delta= */ 1e-6);
+
+        ObjectAnimator animator = mLayout.getYTranslationAnimatorForTesting();
+        assertNotNull(animator);
+        assertEquals(HEIGHT, (Float) animator.getAnimatedValue(), /* delta= */ 1e-6);
+        assertEquals(150L, animator.getDuration());
+
+        // Skip to the end.
+        animator.end();
+
+        // Translation is now 0, so the view is in its fully visible position.
+        assertEquals(0f, (Float) animator.getAnimatedValue(), /* delta= */ 1e-6);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.VISIBLE));
+    }
+
+    @Test
+    public void testAnimatedHide() {
+        mLayout.layout(0, 0, 0, (int) HEIGHT);
+        assertEquals((int) HEIGHT, mLayout.getHeight());
+
+        mLayout.enableAnimations(false);
+        mLayout.updateVisibility(VisibilityState.VISIBLE);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.VISIBLE));
+        reset(mMediator);
+
+        // Start hide animation.
+        mLayout.enableAnimations(true);
+        mLayout.updateVisibility(VisibilityState.HIDING);
+
+        // Start out visible and with no translation.
+        assertEquals(View.VISIBLE, mLayout.getVisibility());
+        assertEquals(0f, mLayout.getTranslationY(), /* delta= */ 1e-6);
+
+        ObjectAnimator animator = mLayout.getYTranslationAnimatorForTesting();
+        assertNotNull(animator);
+        assertEquals(0f, (Float) animator.getAnimatedValue(), /* delta= */ 1e-6);
+        assertEquals(150L, animator.getDuration());
+
+        // Skip to the end.
+        animator.end();
+
+        // Translation is now 0, so the view is in its fully visible position.
+        assertEquals(HEIGHT, (Float) animator.getAnimatedValue(), /* delta= */ 1e-6);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.GONE));
+    }
+
+    @Test
+    public void testAnimatedShowTwice() {
+        // Start show animation.
+        mLayout.enableAnimations(true);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+
+        // Pretend layout to set view height.
+        mLayout.layout(0, 0, 0, (int) HEIGHT);
+        assertEquals((int) HEIGHT, mLayout.getHeight());
+
+        // Animation should be started and not yet ended.
+        ObjectAnimator animator = mLayout.getYTranslationAnimatorForTesting();
+        assertTrue(animator.isStarted());
+
+        // Calling updateVisibility(SHOWING) again shouldn't interrupt the ongoing animation.
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+        assertEquals(animator, mLayout.getYTranslationAnimatorForTesting());
+        assertTrue(animator.isStarted());
+    }
+
+    @Test
+    public void testAnimatedHideDuringShow() {
+        // Start show animation.
+        mLayout.enableAnimations(true);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+
+        // Pretend layout to set view height.
+        mLayout.layout(0, 0, 0, (int) HEIGHT);
+        assertEquals((int) HEIGHT, mLayout.getHeight());
+
+        // Animation should be started and not yet ended.
+        ObjectAnimator animator = mLayout.getYTranslationAnimatorForTesting();
+        assertTrue(animator.isStarted());
+
+        // Pretend some time has passed.
+        long elapsedMs = 100L;
+        animator.setCurrentPlayTime(elapsedMs);
+
+        // Start hide animation while the show animation is still running.
+        mLayout.updateVisibility(VisibilityState.HIDING);
+
+        // There should be a new animator for hiding.
+        ObjectAnimator newAnimator = mLayout.getYTranslationAnimatorForTesting();
+        assertNotNull(newAnimator);
+        assertNotEquals(animator, newAnimator);
+        assertTrue(newAnimator.isStarted());
+
+        // The new animation should have started at (duration - 100) ms.
+        assertEquals((ANIMATION_DURATION_MS - elapsedMs), newAnimator.getCurrentPlayTime());
+    }
+
+    @Test
+    public void testDestroyCancelsAnimation() {
+        mLayout.layout(0, 0, 0, (int) HEIGHT);
+        assertEquals((int) HEIGHT, mLayout.getHeight());
+        mLayout.enableAnimations(true);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+
+        ObjectAnimator animator = mLayout.getYTranslationAnimatorForTesting();
+        assertTrue(animator.isStarted());
+
+        mLayout.destroy();
+        assertFalse(animator.isStarted());
+    }
+
+    @Test
+    public void testAnimatedShowHideShow() {
+        /// Show #1
+
+        // Start show animation.
+        mLayout.enableAnimations(true);
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+
+        // Pretend the layout step was triggered so the real height will be calculated.
+        mLayout.layout(0, 0, 0, (int) HEIGHT);
+        assertEquals((int) HEIGHT, mLayout.getHeight());
+
+        assertEquals(HEIGHT, mLayout.getTranslationY(), /* delta= */ 1e-6);
+
+        ObjectAnimator animator = mLayout.getYTranslationAnimatorForTesting();
+        assertNotNull(animator);
+        assertEquals(HEIGHT, (Float) animator.getAnimatedValue(), /* delta= */ 1e-6);
+        assertEquals(150L, animator.getDuration());
+
+        // Skip to the end.
+        animator.end();
+
+        // Translation is now 0, so the view is in its fully visible position.
+        assertEquals(0f, mLayout.getTranslationY(), /* delta= */ 1e-6);
+        verify(mMediator).onVisibilityChanged(eq(VisibilityState.VISIBLE));
+
+        /// Hide
+
+        mLayout.updateVisibility(VisibilityState.HIDING);
+        assertEquals(View.VISIBLE, mLayout.getVisibility());
+        assertEquals(0f, mLayout.getTranslationY(), /* delta= */ 1e-6);
+
+        animator = mLayout.getYTranslationAnimatorForTesting();
+        assertNotNull(animator);
+        assertEquals(0f, (Float) animator.getAnimatedValue(), /* delta= */ 1e-6);
+        assertEquals(150L, animator.getDuration());
+
+        animator.end();
+
+        assertEquals(HEIGHT, mLayout.getTranslationY(), /* delta= */ 1e-6);
+
+        /// Show #2
+
+        mLayout.updateVisibility(VisibilityState.SHOWING);
+
+        assertEquals(HEIGHT, mLayout.getTranslationY(), /* delta= */ 1e-6);
+
+        mLayout.getYTranslationAnimatorForTesting().end();
+
+        assertEquals(0f, mLayout.getTranslationY(), /* delta= */ 1e-6);
+    }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediator.java
index c1c258b2..55f9000 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediator.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediator.java
@@ -9,11 +9,12 @@
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Mediator class responsible for controlling Read Aloud mini player. */
-class MiniPlayerMediator {
+public class MiniPlayerMediator {
     private final PropertyModel mModel;
 
     MiniPlayerMediator(PropertyModel model) {
         mModel = model;
+        mModel.set(PlayerProperties.MINI_PLAYER_MEDIATOR, this);
     }
 
     @VisibilityState
@@ -22,14 +23,21 @@
     }
 
     void show(boolean animate) {
-        // TODO implement animation
         mModel.set(PlayerProperties.MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES, animate);
-        mModel.set(PlayerProperties.MINI_PLAYER_VISIBILITY, VisibilityState.VISIBLE);
+        mModel.set(PlayerProperties.MINI_PLAYER_VISIBILITY, VisibilityState.SHOWING);
     }
 
     void dismiss(boolean animate) {
-        // TODO implement animation
         mModel.set(PlayerProperties.MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES, animate);
-        mModel.set(PlayerProperties.MINI_PLAYER_VISIBILITY, VisibilityState.GONE);
+        mModel.set(PlayerProperties.MINI_PLAYER_VISIBILITY, VisibilityState.HIDING);
+    }
+
+    /**
+     * Called when the view visibility changes due to animation.
+     *
+     * @param newState New visibility.
+     */
+    public void onVisibilityChanged(@VisibilityState int newState) {
+        mModel.set(PlayerProperties.MINI_PLAYER_VISIBILITY, newState);
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediatorUnitTest.java
index 6fe0e403..0c70267 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediatorUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerMediatorUnitTest.java
@@ -30,11 +30,16 @@
     }
 
     @Test
+    public void testPlaceSelfInModel() {
+        assertEquals(mMediator, mModel.get(PlayerProperties.MINI_PLAYER_MEDIATOR));
+    }
+
+    @Test
     public void testShow() {
         mMediator.show(/*animate=*/false);
         assertEquals(false,
                 (boolean) mModel.get(PlayerProperties.MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES));
-        assertEquals(VisibilityState.VISIBLE, mMediator.getVisibility());
+        assertEquals(VisibilityState.SHOWING, mMediator.getVisibility());
     }
 
     @Test
@@ -42,6 +47,6 @@
         mMediator.dismiss(/*animate=*/false);
         assertEquals(false,
                 (boolean) mModel.get(PlayerProperties.MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES));
-        assertEquals(VisibilityState.GONE, mMediator.getVisibility());
+        assertEquals(VisibilityState.HIDING, mMediator.getVisibility());
     }
 }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerViewBinder.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerViewBinder.java
index 828a8db..789d230 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerViewBinder.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerViewBinder.java
@@ -4,10 +4,7 @@
 
 package org.chromium.chrome.browser.readaloud.player.mini;
 
-import android.view.View;
-
 import org.chromium.chrome.browser.readaloud.player.PlayerProperties;
-import org.chromium.chrome.browser.readaloud.player.VisibilityState;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -22,10 +19,14 @@
      */
     public static void bind(PropertyModel model, MiniPlayerLayout view, PropertyKey key) {
         if (key == PlayerProperties.MINI_PLAYER_VISIBILITY) {
-            view.setVisibility(
-                    model.get(PlayerProperties.MINI_PLAYER_VISIBILITY) == VisibilityState.VISIBLE
-                            ? View.VISIBLE
-                            : View.GONE);
+            view.updateVisibility(model.get(PlayerProperties.MINI_PLAYER_VISIBILITY));
+
+        } else if (key == PlayerProperties.MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES) {
+            view.enableAnimations(
+                    model.get(PlayerProperties.MINI_PLAYER_ANIMATE_VISIBILITY_CHANGES));
+
+        } else if (key == PlayerProperties.MINI_PLAYER_MEDIATOR) {
+            view.setMediator(model.get(PlayerProperties.MINI_PLAYER_MEDIATOR));
 
         } else if (key == PlayerProperties.TITLE) {
             view.setTitle(model.get(PlayerProperties.TITLE));
diff --git a/chrome/browser/resources/ash/settings/BUILD.gn b/chrome/browser/resources/ash/settings/BUILD.gn
index dec09e0..1bdee19 100644
--- a/chrome/browser/resources/ash/settings/BUILD.gn
+++ b/chrome/browser/resources/ash/settings/BUILD.gn
@@ -469,7 +469,7 @@
     "//chrome/browser/ui/webui/ash/settings/search/mojom:mojom_ts__generator",
     "//chrome/browser/ui/webui/settings/ash/display_settings:mojom_ts__generator",
     "//chromeos/ash/components/audio/public/mojom:mojom_ts__generator",
-    "//chromeos/ash/components/drivefs/mojom:pin_manager_types_ts__generator",
+    "//chromeos/ash/components/drivefs/mojom:pinning_manager_types_ts__generator",
     "//ui/events/ash/mojom:mojom_ts__generator",
   ]
   mojo_files = [
@@ -487,7 +487,7 @@
     "$root_gen_dir/chrome/browser/ui/webui/ash/settings/search/mojom/user_action_recorder.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/ui/webui/settings/ash/display_settings/display_settings_provider.mojom-webui.ts",
     "$root_gen_dir/chromeos/ash/components/audio/public/mojom/cros_audio_config.mojom-webui.ts",
-    "$root_gen_dir/chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom-webui.ts",
+    "$root_gen_dir/chromeos/ash/components/drivefs/mojom/pinning_manager_types.mojom-webui.ts",
     "$root_gen_dir/ui/events/ash/mojom/extended_fkeys_modifier.mojom-webui.ts",
     "$root_gen_dir/ui/events/ash/mojom/modifier_key.mojom-webui.ts",
     "$root_gen_dir/ui/events/ash/mojom/simulate_right_click_modifier.mojom-webui.ts",
diff --git a/chrome/browser/resources/ash/settings/os_files_page/google_drive_browser_proxy.ts b/chrome/browser/resources/ash/settings/os_files_page/google_drive_browser_proxy.ts
index 7ee1a48..0dd0a1b6 100644
--- a/chrome/browser/resources/ash/settings/os_files_page/google_drive_browser_proxy.ts
+++ b/chrome/browser/resources/ash/settings/os_files_page/google_drive_browser_proxy.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {PageCallbackRouter, PageHandlerFactory, PageHandlerRemote, PageRemote, Status} from '../mojom-webui/google_drive_handler.mojom-webui.js';
-import {Stage} from '../mojom-webui/pin_manager_types.mojom-webui.js';
+import {Stage} from '../mojom-webui/pinning_manager_types.mojom-webui.js';
 
 // Communicates with the GoogleDrivePageHandler in the browser process.
 class GoogleDriveBrowserProxy {
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/input_page.html b/chrome/browser/resources/ash/settings/os_languages_page/input_page.html
index 12c80d8c..264875d 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/input_page.html
+++ b/chrome/browser/resources/ash/settings/os_languages_page/input_page.html
@@ -164,7 +164,8 @@
           </div>
         </div>
         <template is="dom-if"
-            if="[[shouldShowSpinner_(item, languagePacksInSettingsEnabled_)]]">
+            if="[[shouldShowSpinner_(item, languagePacksInSettingsEnabled_,
+                  languages.inputMethods.imeLanguagePackStatus.*)]]">
           <paper-spinner-lite alt="TO BE TRANSLATED: Loading" active>
           </paper-spinner-lite>
         </template>
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts b/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
index 397d1264..013bbd4 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
+++ b/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
@@ -630,9 +630,11 @@
     }
   }
 
-  private shouldShowSpinner_(_item: chrome.languageSettingsPrivate.InputMethod):
+  private shouldShowSpinner_(item: chrome.languageSettingsPrivate.InputMethod):
       boolean {
-    return this.languagePacksInSettingsEnabled_;
+    return this.languagePacksInSettingsEnabled_ &&
+        this.languageHelper.getImeLanguagePackStatus(item.id) ===
+        chrome.inputMethodPrivate.LanguagePackStatus.IN_PROGRESS;
   }
 }
 
diff --git a/chrome/browser/resources/ash/settings/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/ash/settings/os_settings_menu/os_settings_menu.html
index a15e656..d72d36b 100644
--- a/chrome/browser/resources/ash/settings/os_settings_menu/os_settings_menu.html
+++ b/chrome/browser/resources/ash/settings/os_settings_menu/os_settings_menu.html
@@ -9,6 +9,11 @@
     padding-top: 8px;
   }
 
+  :host-context(body.revamp-wayfinding-enabled):host {
+    padding-inline-end: 8px;
+    padding-inline-start: 16px;
+  }
+
   :host * {
     -webkit-tap-highlight-color: transparent;
   }
@@ -75,6 +80,16 @@
 
   #topMenu > os-settings-menu-item {
     margin-bottom: 8px;
+  }
+
+  :host-context(body:not(.revamp-wayfinding-enabled))
+      #topMenu > os-settings-menu-item {
+    margin-inline-end: 2px;
+  }
+
+  :host-context(body:not(.revamp-wayfinding-enabled))
+      #advancedSubmenu > os-settings-menu-item {
+    margin-bottom: 8px;
     margin-inline-end: 2px;
   }
 
diff --git a/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html b/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html
index c23f5c9..8cdabfa 100644
--- a/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html
+++ b/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html
@@ -15,6 +15,10 @@
     --cr-toolbar-padding-top: 8px;
   }
 
+  :host-context(body.revamp-wayfinding-enabled):host {
+    --settings-menu-width: 280px;
+  }
+
   os-toolbar {
     /* TODO(hsuregan): update for dark mode when needed. */
     min-height: 56px;
@@ -63,6 +67,17 @@
     width: var(--settings-menu-width);
   }
 
+  :host-context(body.revamp-wayfinding-enabled) #left os-settings-menu {
+    background-color: var(--cros-sys-surface3);
+    border-start-end-radius: 20px;
+  }
+
+  @media (prefers-color-scheme: dark) {
+    :host-context(body.revamp-wayfinding-enabled) #left os-settings-menu {
+      background-color: var(--cros-sys-surface2);
+    }
+  }
+
   #main {
     flex-basis: var(--settings-main-basis);
   }
diff --git a/chrome/browser/resources/ash/settings/parental_controls_page/parental_controls_settings_card.html b/chrome/browser/resources/ash/settings/parental_controls_page/parental_controls_settings_card.html
index 3c5d5f76..2c5c3b6a 100644
--- a/chrome/browser/resources/ash/settings/parental_controls_page/parental_controls_settings_card.html
+++ b/chrome/browser/resources/ash/settings/parental_controls_page/parental_controls_settings_card.html
@@ -23,14 +23,13 @@
         <div class="secondary" id="subLabel" aria-hidden="true">
           [[getSetupLabelText_(online_)]]
         </div>
-        <div class="separator"></div>
-        <cr-button id="setupButton" on-click="handleSetupButtonClick_"
-            disabled$="[[!online_]]" aria-labelledby="label"
-            aria-describedby="subLabel"
-            aria-roledescription="$i18n{parentalControlsSetUpButtonRole}">
-          $i18n{parentalControlsSetUpButtonLabel}
-        </cr-button>
       </div>
+      <cr-button id="setupButton" on-click="handleSetupButtonClick_"
+          disabled$="[[!online_]]" aria-labelledby="label"
+          aria-describedby="subLabel"
+          aria-roledescription="$i18n{parentalControlsSetUpButtonRole}">
+        $i18n{parentalControlsSetUpButtonLabel}
+      </cr-button>
     </template>
   </div>
 </settings-card>
diff --git a/chrome/browser/resources/chromeos/BUILD.gn b/chrome/browser/resources/chromeos/BUILD.gn
index 2c0a7ae5..8f27eb2 100644
--- a/chrome/browser/resources/chromeos/BUILD.gn
+++ b/chrome/browser/resources/chromeos/BUILD.gn
@@ -44,6 +44,7 @@
     "sensor_info:resources",
     "supervision:resources",
     "vc_tray_tester:resources",
+    "web_app_install:resources",
   ]
 }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/BUILD.gn
index 1b43b862..73f3a2b 100644
--- a/chrome/browser/resources/chromeos/accessibility/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/BUILD.gn
@@ -30,7 +30,9 @@
       ":select_to_speak_guest_manifest",
       ":select_to_speak_manifest",
       ":switch_access_guest_manifest",
+      ":switch_access_guest_manifest_v3",
       ":switch_access_manifest",
+      ":switch_access_manifest_v3",
       "accessibility_common:build",
       "enhanced_network_tts:build",
       "select_to_speak:build",
@@ -93,19 +95,36 @@
   is_guest_manifest = true
 }
 
+switch_access_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVWTYdXNGhIG6FJKIhaohRRrYYGwg9cR2jea2NRBSEg+T7E3EvUyFy0ouez0N0omeSAL/xlvQtCjZJ72eCqDBgON/49SRtUdLS5TQ2U9cHYcIwI86llKMqqws6uMSwlWXldyNwKx5LVT1nR0+x3J744E2mymCSip2Y+NrGEA2yCUFL8D+O/uS+d5pVFb3NNjPTVbNOlhIs5ZUVX3FBij86ILivoSfRZMIZqK7MU8XDT1zolpFPiSYvDh1Qivwqar0pVYmNbCSjEgbGIuQh7zMaMdHC1HtvjbI20XFzWHyP/cW2YKszlfqawH+kdHSp4ANIjc7GCAjGJNxm33iMNwcFAgMBAAECggEAL47YakkzjZheKp3U6mAGDSAXHV6BQrkBY1yPXGstq7B/DZzy4RrF3QOkDf2jys8dCUXTg7YjrhqVqXuNdmmphvmGq8dxnFDeDxb6wZWE3GdlUzfYK77rdGp2cVuYtMhI05LwOmPSN/bDXk9eK4bDhTTy+lgomOH/aYcntXkEpIfVQ1kVs7RLvBs3tF3QfsL7t+aqphUlbyVRxCzogK3EDnLD0NODrydx5xB2UMKcxrQD8mVl8IhyBUeluWmcqVkIv7z9C9Y6s9HgcQdxsxhClymAsXtjkZVyP/xst9iwIxOyTijffcqbQOPtB9w1d7GWUrdpwCys0TveJslU7zo6jQKBgQD3VOJSiJuENck71q2Sg4yP0ytBNWVO7xLeTDc6OPEuhqtennWYFeprdplL8aejHqPFiNi7L2QVguP1JDLWPPu+RHHsZDtvG+stssE9Z+oVzBowDJZO1EvBH7nvqgxFz4utoDIrQmkbCcsBqOqwv1i7UdJ0DPIofZE/u0G8wONriwKBgQDc02xS5HZ8ysxEdhL9dC8FSvd12lHocEuBML5ufCkK4SUo8EFeg8k+2UVwd0xXwFNv3nKRPfr/yOQ0CRlKTo3IXXj4Uie+ww3j1jWIMPzC5Oo7IUHRd69KfLvG5N9byGv4wdsPKsXsGrUlvP4meD1U9fujxJdE9RC9evZss33prwKBgAQE7BydPbG7UgbX6UAtRRZ9PwGzRW8v8WWNZYRbsoeoBpbmClErYgDXD4ytY6UB9XVbUPJRxdWXp+6u5OiYWxrvb86AnnqiwIKgmgVOb/5kr7RCMBsd1hFQW6wqXkKwKbvrk4UiciTPVu4y+YVfxqhcnwflwfWofLjFaT8Q/2EbAoGANkdtr+5iRYhfr1BKmKwvRqDHtNtGGNlJZecCWAwC1p7C0I5FsyK3m9AyJlPcmxE2MSA/jv3qLWdG2JeH9ODcLuzy6C7hgB1X07H6lJBeANXd0Uz6ba96kdeZHGlzkY7xI0MbQl4kKkXiUvVijzgs8y5HfVi8SgHm7HxGCDASehcCgYEAnw1yu4eaWqsq7ECyjEBM7sQcMVGypiG3VupzLKA75iPkg/E+peUZyDRg7LPCiX/UcW22bliUw1ASRzY+thuVlGWC2CPah95Z4m+H4cJVSEEqKUbYRGfsDlDIJNxPihGvhoTniKZwvpUacbAhop7rbiAVGx+RJ+tFG8P56AbvBVE="
+
 manifest("switch_access_manifest") {
   input_file = "switch_access_manifest.json.jinja2"
   output_file = "$accessibility_out_dir/switch_access_manifest.json"
-  key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVWTYdXNGhIG6FJKIhaohRRrYYGwg9cR2jea2NRBSEg+T7E3EvUyFy0ouez0N0omeSAL/xlvQtCjZJ72eCqDBgON/49SRtUdLS5TQ2U9cHYcIwI86llKMqqws6uMSwlWXldyNwKx5LVT1nR0+x3J744E2mymCSip2Y+NrGEA2yCUFL8D+O/uS+d5pVFb3NNjPTVbNOlhIs5ZUVX3FBij86ILivoSfRZMIZqK7MU8XDT1zolpFPiSYvDh1Qivwqar0pVYmNbCSjEgbGIuQh7zMaMdHC1HtvjbI20XFzWHyP/cW2YKszlfqawH+kdHSp4ANIjc7GCAjGJNxm33iMNwcFAgMBAAECggEAL47YakkzjZheKp3U6mAGDSAXHV6BQrkBY1yPXGstq7B/DZzy4RrF3QOkDf2jys8dCUXTg7YjrhqVqXuNdmmphvmGq8dxnFDeDxb6wZWE3GdlUzfYK77rdGp2cVuYtMhI05LwOmPSN/bDXk9eK4bDhTTy+lgomOH/aYcntXkEpIfVQ1kVs7RLvBs3tF3QfsL7t+aqphUlbyVRxCzogK3EDnLD0NODrydx5xB2UMKcxrQD8mVl8IhyBUeluWmcqVkIv7z9C9Y6s9HgcQdxsxhClymAsXtjkZVyP/xst9iwIxOyTijffcqbQOPtB9w1d7GWUrdpwCys0TveJslU7zo6jQKBgQD3VOJSiJuENck71q2Sg4yP0ytBNWVO7xLeTDc6OPEuhqtennWYFeprdplL8aejHqPFiNi7L2QVguP1JDLWPPu+RHHsZDtvG+stssE9Z+oVzBowDJZO1EvBH7nvqgxFz4utoDIrQmkbCcsBqOqwv1i7UdJ0DPIofZE/u0G8wONriwKBgQDc02xS5HZ8ysxEdhL9dC8FSvd12lHocEuBML5ufCkK4SUo8EFeg8k+2UVwd0xXwFNv3nKRPfr/yOQ0CRlKTo3IXXj4Uie+ww3j1jWIMPzC5Oo7IUHRd69KfLvG5N9byGv4wdsPKsXsGrUlvP4meD1U9fujxJdE9RC9evZss33prwKBgAQE7BydPbG7UgbX6UAtRRZ9PwGzRW8v8WWNZYRbsoeoBpbmClErYgDXD4ytY6UB9XVbUPJRxdWXp+6u5OiYWxrvb86AnnqiwIKgmgVOb/5kr7RCMBsd1hFQW6wqXkKwKbvrk4UiciTPVu4y+YVfxqhcnwflwfWofLjFaT8Q/2EbAoGANkdtr+5iRYhfr1BKmKwvRqDHtNtGGNlJZecCWAwC1p7C0I5FsyK3m9AyJlPcmxE2MSA/jv3qLWdG2JeH9ODcLuzy6C7hgB1X07H6lJBeANXd0Uz6ba96kdeZHGlzkY7xI0MbQl4kKkXiUvVijzgs8y5HfVi8SgHm7HxGCDASehcCgYEAnw1yu4eaWqsq7ECyjEBM7sQcMVGypiG3VupzLKA75iPkg/E+peUZyDRg7LPCiX/UcW22bliUw1ASRzY+thuVlGWC2CPah95Z4m+H4cJVSEEqKUbYRGfsDlDIJNxPihGvhoTniKZwvpUacbAhop7rbiAVGx+RJ+tFG8P56AbvBVE="
+  key = "$switch_access_key"
+}
+
+manifest("switch_access_manifest_v3") {
+  input_file = "switch_access_manifest.json.jinja2"
+  output_file = "$accessibility_out_dir/switch_access_manifest_v3.json"
+  key = "$switch_access_key"
+  is_manifest_v3 = true
 }
 
 manifest("switch_access_guest_manifest") {
   input_file = "switch_access_manifest.json.jinja2"
   output_file = "$accessibility_out_dir/switch_access_manifest_guest.json"
-  key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVWTYdXNGhIG6FJKIhaohRRrYYGwg9cR2jea2NRBSEg+T7E3EvUyFy0ouez0N0omeSAL/xlvQtCjZJ72eCqDBgON/49SRtUdLS5TQ2U9cHYcIwI86llKMqqws6uMSwlWXldyNwKx5LVT1nR0+x3J744E2mymCSip2Y+NrGEA2yCUFL8D+O/uS+d5pVFb3NNjPTVbNOlhIs5ZUVX3FBij86ILivoSfRZMIZqK7MU8XDT1zolpFPiSYvDh1Qivwqar0pVYmNbCSjEgbGIuQh7zMaMdHC1HtvjbI20XFzWHyP/cW2YKszlfqawH+kdHSp4ANIjc7GCAjGJNxm33iMNwcFAgMBAAECggEAL47YakkzjZheKp3U6mAGDSAXHV6BQrkBY1yPXGstq7B/DZzy4RrF3QOkDf2jys8dCUXTg7YjrhqVqXuNdmmphvmGq8dxnFDeDxb6wZWE3GdlUzfYK77rdGp2cVuYtMhI05LwOmPSN/bDXk9eK4bDhTTy+lgomOH/aYcntXkEpIfVQ1kVs7RLvBs3tF3QfsL7t+aqphUlbyVRxCzogK3EDnLD0NODrydx5xB2UMKcxrQD8mVl8IhyBUeluWmcqVkIv7z9C9Y6s9HgcQdxsxhClymAsXtjkZVyP/xst9iwIxOyTijffcqbQOPtB9w1d7GWUrdpwCys0TveJslU7zo6jQKBgQD3VOJSiJuENck71q2Sg4yP0ytBNWVO7xLeTDc6OPEuhqtennWYFeprdplL8aejHqPFiNi7L2QVguP1JDLWPPu+RHHsZDtvG+stssE9Z+oVzBowDJZO1EvBH7nvqgxFz4utoDIrQmkbCcsBqOqwv1i7UdJ0DPIofZE/u0G8wONriwKBgQDc02xS5HZ8ysxEdhL9dC8FSvd12lHocEuBML5ufCkK4SUo8EFeg8k+2UVwd0xXwFNv3nKRPfr/yOQ0CRlKTo3IXXj4Uie+ww3j1jWIMPzC5Oo7IUHRd69KfLvG5N9byGv4wdsPKsXsGrUlvP4meD1U9fujxJdE9RC9evZss33prwKBgAQE7BydPbG7UgbX6UAtRRZ9PwGzRW8v8WWNZYRbsoeoBpbmClErYgDXD4ytY6UB9XVbUPJRxdWXp+6u5OiYWxrvb86AnnqiwIKgmgVOb/5kr7RCMBsd1hFQW6wqXkKwKbvrk4UiciTPVu4y+YVfxqhcnwflwfWofLjFaT8Q/2EbAoGANkdtr+5iRYhfr1BKmKwvRqDHtNtGGNlJZecCWAwC1p7C0I5FsyK3m9AyJlPcmxE2MSA/jv3qLWdG2JeH9ODcLuzy6C7hgB1X07H6lJBeANXd0Uz6ba96kdeZHGlzkY7xI0MbQl4kKkXiUvVijzgs8y5HfVi8SgHm7HxGCDASehcCgYEAnw1yu4eaWqsq7ECyjEBM7sQcMVGypiG3VupzLKA75iPkg/E+peUZyDRg7LPCiX/UcW22bliUw1ASRzY+thuVlGWC2CPah95Z4m+H4cJVSEEqKUbYRGfsDlDIJNxPihGvhoTniKZwvpUacbAhop7rbiAVGx+RJ+tFG8P56AbvBVE="
+  key = "$switch_access_key"
   is_guest_manifest = true
 }
 
+manifest("switch_access_guest_manifest_v3") {
+  input_file = "switch_access_manifest.json.jinja2"
+  output_file = "$accessibility_out_dir/switch_access_manifest_guest_v3.json"
+  key = "$switch_access_key"
+  is_guest_manifest = true
+  is_manifest_v3 = true
+}
+
 accessibility_strings("accessibility_strings") {
   out_dir = accessibility_out_dir
 }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
index 361e536..d9ed4c0 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -156,9 +156,6 @@
   "learn_mode/learn_mode.js",
   "log_page/log.js",
   "log_page/log_loader.js",
-  "options/bluetooth_braille_display_manager.js",
-  "options/bluetooth_braille_display_ui.js",
-  "options/options.js",
   "panel/i_search_ui.js",
   "panel/menu_manager.js",
   "panel/panel.js",
@@ -194,7 +191,6 @@
   deps = [
     ":chromevox_background_script",
     ":chromevox_copied_files",
-    ":chromevox_options_script",
     ":chromevox_panel_script",
     ":chromevox_phonetic_dictionaries_js",
     "//chrome/browser/resources/chromeos/accessibility/braille_ime:braille_ime_manifest",
@@ -204,7 +200,6 @@
 }
 
 chromevox_background_script_loader_file = "background/loader.js"
-chromevox_options_script_loader_file = "options/options_loader.js"
 chromevox_panel_script_loader_file = "panel/panel_loader.js"
 
 # Instead of setting up one copy target for each subdirectory, use a script
@@ -233,10 +228,6 @@
     "learn_mode/learn_mode.html",
     "log_page/log.css",
     "log_page/log.html",
-    "options/checked.png",
-    "options/options.css",
-    "options/options.html",
-    "options/unchecked.png",
     "panel/panel.css",
     "panel/panel.html",
     "tutorial/practice_areas/jump_commands.html",
@@ -306,11 +297,6 @@
 
 # TODO once these loaders are all empty, we will need to re-work the entry points.
 
-compress_js("chromevox_options_script") {
-  sources = [ chromevox_options_script_loader_file ]
-  output_file = "$chromevox_out_dir/chromeVoxChromeOptionsScript.js"
-}
-
 compress_js("chromevox_background_script") {
   sources = [ chromevox_background_script_loader_file ]
   output_file = "$chromevox_out_dir/chromeVoxChromeBackgroundScript.js"
@@ -440,9 +426,6 @@
       "common/locale_output_helper_test.js",
       "common/settings_manager_test.js",
       "learn_mode/learn_mode_test.js",
-      "options/bluetooth_braille_display_manager_test.js",
-      "options/bluetooth_braille_display_ui_test.js",
-      "options/options_test.js",
       "panel/menu_manager_test.js",
       "panel/panel_test.js",
       "panel/panel_test_base.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager.js
deleted file mode 100644
index bd5c0b4..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager.js
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Abstracts away the details of chrome.bluetooth,
- * chrome.bluetoothPrivate, and chrome.brailleDisplayPrivate for a UI component
- * to interact with a bluetooth braille display.
- */
-import {SettingsManager} from '../common/settings_manager.js';
-
-/** @interface */
-export class BluetoothBrailleDisplayListener {
-  /**
-   * @param {!Array<chrome.bluetooth.Device>} displays
-   */
-  onDisplayListChanged(displays) {}
-
-  /**
-   * Called when a pincode is requested and a response can be made by calling
-   * BluetoothBrailleDisplayManager.finishPairing.
-   * @param {!chrome.bluetooth.Device} display
-   */
-  onPincodeRequested(display) {}
-}
-
-
-/**
- * Manages interaction with the bluetooth and braille subsystems in Chrome.
- * A caller can use this class by doing:
- * let manager = new BluetoothBrailleDisplayManager();
- * manager.addListener(listenerObject); // listenerObject receives updates on
- *                                     // important events in bluetooth.
- * manager.start();  // Starts bluetooth discovery.
- * manager.connect(); // Connects to a discovered device received in the
- *                   // listenerObject.
- * manager.finishPairing(); // If a pairing request is sent to the
- *                          // listenerObject, this is how a caller can respond.
- * manager.stop(); // Stops discovery, but persists connections.
- */
-export class BluetoothBrailleDisplayManager {
-  constructor() {
-    /** @private {!Array<BluetoothBrailleDisplayListener>} */
-    this.listeners_ = [];
-
-    /**
-     * This list of braille display names was taken from other services that
-     * utilize Brltty (e.g. BrailleBack).
-     * @private {!Array<string|RegExp>}
-     */
-    this.displayNamePrefixes_ = [
-      'Actilino ALO',
-      'Activator AC4',
-      'Active Braille AB',
-      'Active Star AS',
-      'ALVA BC',
-      'APEX',
-      'APH Chameleon',
-      'APH Mantis',
-      'Basic Braille BB',
-      'Basic Braille Plus BP',
-      'BAUM Conny',
-      'Baum PocketVario',
-      'Baum SuperVario',
-      'Baum SVario',
-      'BrailleConnect',
-      'BrailleEDGE',
-      'BrailleMe',
-      'BMpk',
-      'BMsmart',
-      'BM32',
-      'BrailleNote Touch',
-      'BrailleSense',
-      'Braille Star',
-      'Braillex',
-      'Brailliant BI',
-      'Brailliant 14',
-      'Brailliant 80',
-      'Braillino BL',
-      'B2G',
-      'Conny',
-      'Easy Braille EBR',
-      'EL12-',
-      'Esys-',
-      'Focus',
-      'Humanware BrailleOne',
-      'HWG Brailliant',
-      'MB248',
-      'NLS eReader',
-      'Orbit Reader',
-      'Pronto!',
-      'Refreshabraille',
-      'SmartBeetle',
-      'SuperVario',
-      'TSM',
-      'VarioConnect',
-      'VarioUltra',
-    ];
-
-    /**
-     * The display explicitly preferred by a caller via connect. Only one such
-     * display exists at a time.
-     * @private {?string}
-     */
-    this.preferredDisplayAddress_ = /** @type {?string} */ (
-        SettingsManager.get('preferredBrailleDisplayAddress'));
-
-    /**
-     * Tracks whether the preferred display is connected.
-     * @private {boolean|null|undefined}
-     */
-    this.preferredDisplayConnected_;
-
-    chrome.bluetooth.onDeviceAdded.addListener(
-        this.handleDevicesChanged.bind(this));
-    chrome.bluetooth.onDeviceChanged.addListener(
-        this.handleDevicesChanged.bind(this));
-    chrome.bluetooth.onDeviceRemoved.addListener(
-        this.handleDevicesChanged.bind(this));
-    chrome.bluetoothPrivate.onPairing.addListener(
-        this.handlePairing.bind(this));
-  }
-
-  /**
-   * Adds a new listener.
-   * @param {BluetoothBrailleDisplayListener} listener
-   */
-  addListener(listener) {
-    this.listeners_.push(listener);
-  }
-
-  /**
-   * Starts discovering bluetooth devices.
-   */
-  start() {
-    chrome.bluetooth.startDiscovery();
-
-    // Pick up any devices already in the system including previously paired,
-    // but out of range displays.
-    this.handleDevicesChanged();
-  }
-
-  /**
-   * Stops discovering bluetooth devices.
-   */
-  stop() {
-    chrome.bluetooth.stopDiscovery();
-  }
-
-  /**
-   * Connects to the given display.
-   *@param{!chrome.bluetooth.Device} display
-   */
-  connect(display) {
-    if (this.preferredDisplayAddress_ === display.address ||
-        !this.preferredDisplayAddress_) {
-      this.connectInternal(display);
-    } else {
-      chrome.bluetoothPrivate.disconnectAll(
-          this.preferredDisplayAddress_, () => this.connectInternal(display));
-    }
-  }
-
-  /**
-   * @param{!chrome.bluetooth.Device} display
-   * @protected *
-   */
-  connectInternal(display) {
-    this.preferredDisplayAddress_ = display.address;
-    SettingsManager.set('preferredBrailleDisplayAddress', display.address);
-    if (!display.connected) {
-      chrome.bluetoothPrivate.connect(display.address, result => {
-        if (!display.paired) {
-          chrome.bluetoothPrivate.pair(display.address);
-        }
-      });
-      return;
-    }
-
-    if (!display.paired) {
-      chrome.bluetoothPrivate.pair(display.address);
-    }
-  }
-
-  /**
-   * Disconnects the given display and clears it from Brltty.
-   * @param{!chrome.bluetooth.Device} display
-   */
-  disconnect(display) {
-    chrome.bluetoothPrivate.disconnectAll(display.address);
-    chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress('');
-  }
-
-  /**
-   * Forgets the given display.
-   * @param {!chrome.bluetooth.Device} display
-   */
-  forget(display) {
-    chrome.bluetoothPrivate.forgetDevice(display.address);
-    chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress('');
-  }
-
-  /**
-   *  Finishes pairing in response to
-   * BluetoothBrailleDisplayListener.onPincodeRequested.
-   * @param{!chrome.bluetooth.Device} display
-   * @param{string} pincode *
-   */
-  finishPairing(display, pincode) {
-    chrome.bluetoothPrivate.setPairingResponse(
-        {response: 'confirm', device: display, pincode}, () => {});
-  }
-
-  /**
-   * @param{ chrome.bluetooth.Device=} opt_device
-   * @protected
-   */
-  handleDevicesChanged(opt_device) {
-    chrome.bluetooth.getDevices(devices => {
-      const displayList = devices.filter(device => {
-        return this.displayNamePrefixes_.some(name => {
-          return device.name && device.name.search(name) === 0;
-        });
-      });
-      if (displayList.length === 0) {
-        return;
-      }
-      if (opt_device && !displayList.find(i => i.name === opt_device.name)) {
-        return;
-      }
-
-      displayList.forEach(display => {
-        if (this.preferredDisplayAddress_ === display.address) {
-          this.handlePreferredDisplayConnectionStateChanged(display);
-        }
-      });
-      this.listeners_.forEach(
-          listener => listener.onDisplayListChanged(displayList));
-    });
-  }
-
-  /**
-   * @param{chrome.bluetoothPrivate.PairingEvent} pairingEvent
-   * @protected
-   */
-  handlePairing(pairingEvent) {
-    if (pairingEvent.pairing ===
-        chrome.bluetoothPrivate.PairingEventType.REQUEST_PINCODE) {
-      this.listeners_.forEach(
-          listener => listener.onPincodeRequested(pairingEvent.device));
-    }
-  }
-
-  /**
-   * @param{chrome.bluetooth.Device} display
-   * @protected
-   */
-  handlePreferredDisplayConnectionStateChanged(display) {
-    if (display.connected === this.preferredDisplayConnected_) {
-      return;
-    }
-
-    this.preferredDisplayConnected_ = display.connected;
-
-    // We do not clear the address seen by Brltty unless the caller explicitly
-    // disconnects or forgets the display via the public methods of this
-    // class.
-    if (display.connected) {
-      chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress(
-          display.address);
-    }
-  }
-}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager_test.js
deleted file mode 100644
index 084feed..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager_test.js
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Include test fixture.
-GEN_INCLUDE(['../testing/chromevox_e2e_test_base.js']);
-GEN_INCLUDE(['../testing/fake_objects.js']);
-
-/**
- * A fake BluetoothBraileDisplayManagerListener.
- */
-class FakeBluetoothBrailleDisplayManagerListener {
-  constructor() {
-    this.displays = [];
-    this.wasPincodeRequested = false;
-  }
-
-  onDisplayListChanged(displays) {
-    this.displays = displays;
-  }
-
-  onPincodeRequested(displays) {
-    this.wasPincodeRequested = true;
-  }
-}
-
-
-/**
- * Test fixture.
- */
-ChromeVoxBluetoothBrailleDisplayManagerWebUITest =
-    class extends ChromeVoxE2ETest {
-  /** @override */
-  async setUpDeferred() {
-    await super.setUpDeferred();
-
-    await Promise.all([
-      // Alphabetical based on file path.
-      importModule(
-          'BluetoothBrailleDisplayManager',
-          '/chromevox/options/bluetooth_braille_display_manager.js'),
-      importModule('LocalStorage', '/common/local_storage.js'),
-      importModule('SettingsManager', '/chromevox/common/settings_manager.js'),
-    ]);
-  }
-};
-
-ChromeVoxBluetoothBrailleDisplayManagerWebUITest.prototype.isAsync = true;
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest', 'Connect', function() {
-      let connectCalled = false;
-      chrome.bluetoothPrivate.connect = (result, callback) => {
-        connectCalled = true;
-        callback();
-      };
-      chrome.bluetoothPrivate.disconnectAll = assertNotReached;
-      chrome.bluetoothPrivate.pair = this.newCallback();
-      const manager = new BluetoothBrailleDisplayManager();
-      manager.connect({address: 'abcd', connected: false, paired: false});
-      assertTrue(connectCalled);
-    });
-
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest', 'ConnectAlreadyPaired',
-    function() {
-      chrome.bluetoothPrivate.connect = this.newCallback();
-      chrome.bluetoothPrivate.disconnectAll = assertNotReached;
-      chrome.bluetoothPrivate.pair = assertNotReached;
-      const manager = new BluetoothBrailleDisplayManager();
-      manager.connect({address: 'abcd', connected: false, paired: true});
-    });
-
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest',
-    'ConnectAlreadyConnectedNotPaired', function() {
-      chrome.bluetoothPrivate.connect = assertNotReached;
-      chrome.bluetoothPrivate.disconnectAll = assertNotReached;
-      chrome.bluetoothPrivate.pair = this.newCallback();
-      const manager = new BluetoothBrailleDisplayManager();
-      manager.connect({address: 'abcd', connected: true, paired: false});
-    });
-
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest',
-    'DisconnectPreviousPreferredOnConnectNewPreferred', function() {
-      chrome.bluetoothPrivate.connect = this.newCallback(address => {
-        assertEquals('abcd', address);
-      });
-      chrome.bluetoothPrivate.disconnectAll =
-          this.newCallback((address, callback) => {
-            assertEquals('1234', address);
-            callback();
-          });
-      SettingsManager.set('preferredBrailleDisplayAddress', '1234');
-      const manager = new BluetoothBrailleDisplayManager();
-      manager.connect({address: 'abcd', connected: false, paired: false});
-    });
-
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest', 'ReconnectPreferred',
-    function() {
-      chrome.bluetoothPrivate.connect = this.newCallback();
-      chrome.bluetoothPrivate.disconnectAll = assertNotReached;
-      SettingsManager.set('preferredBrailleDisplayAddress', 'abcd');
-      const manager = new BluetoothBrailleDisplayManager();
-      manager.connect({address: 'abcd', connected: false, paired: false});
-    });
-
-AX_TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest', 'Listener', function() {
-      const manager = new BluetoothBrailleDisplayManager();
-      const listener = new FakeBluetoothBrailleDisplayManagerListener();
-      manager.addListener(listener);
-      let devices = [];
-      chrome.bluetooth.getDevices = callback => callback(devices);
-
-      // No devices have been added, removed, or changed.
-      manager.handleDevicesChanged();
-      assertEquals(0, listener.displays.length);
-
-      // A recognized braille display was added.
-      devices = [{name: 'Focus 40 BT', address: '1234'}];
-      manager.handleDevicesChanged();
-      assertEquals(1, listener.displays.length);
-      assertEquals('Focus 40 BT', listener.displays[0].name);
-
-      // An unrecognized device was added.
-      devices = [
-        {name: 'Focus 40 BT', address: '1234'},
-        {name: 'headphones', address: '4321'},
-      ];
-      manager.handleDevicesChanged();
-      assertEquals(1, listener.displays.length);
-      assertEquals('Focus 40 BT', listener.displays[0].name);
-
-      // A named variant of Focus 40 BT was added.
-      devices = [
-        {name: 'Focus 40 BT', address: '1234'},
-        {name: 'Focus 40 BT rev 123', address: '4321'},
-      ];
-      manager.handleDevicesChanged();
-      assertEquals(2, listener.displays.length);
-      assertEquals('Focus 40 BT', listener.displays[0].name);
-      assertEquals('Focus 40 BT rev 123', listener.displays[1].name);
-    });
-
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest',
-    'ConnectPreferredTriggersBrlttyUpdate', function() {
-      chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-          this.newCallback(address => {
-            assertEquals('abcd', address);
-          });
-
-      SettingsManager.set('preferredBrailleDisplayAddress', 'abcd');
-      const manager = new BluetoothBrailleDisplayManager();
-      let devices = [];
-      chrome.bluetooth.getDevices = callback => callback(devices);
-
-      // No devices.
-      manager.handleDevicesChanged();
-
-      // A different device.
-      devices = [{name: 'Headhpones', address: '1234', connected: true}];
-      manager.handleDevicesChanged();
-
-      // A focus, but different address.
-      devices = [{name: 'Focus 40 BT', address: '1234', connected: true}];
-      manager.handleDevicesChanged();
-
-      // Finally, a device that is both connected and is our preferred device.
-      devices = [{name: 'Focus 40 BT', address: 'abcd', connected: true}];
-      manager.handleDevicesChanged();
-    });
-
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest',
-    'ForgetPreferredTriggersBrlttyUpdate', function() {
-      chrome.bluetoothPrivate.forgetDevice = this.newCallback();
-      chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-          this.newCallback(address => {
-            assertEquals('', address);
-          });
-
-      const manager = new BluetoothBrailleDisplayManager();
-
-      // Forget the preferred device. Note there is no requirement that this
-      // device be preferred.
-      manager.forget('abcd');
-    });
-
-TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayManagerWebUITest',
-    'DisconnectPreferredTriggersBrlttyUpdate', function() {
-      chrome.bluetoothPrivate.disconnectAll = this.newCallback();
-      chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-          this.newCallback(address => {
-            assertEquals('', address);
-          });
-
-      const manager = new BluetoothBrailleDisplayManager();
-
-      // Disconnect the preferred device. Note there is no requirement that this
-      // device be preferred.
-      manager.disconnect('abcd');
-    });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui.js
deleted file mode 100644
index 2e385c90..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui.js
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2018 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 widget that exposes UI for interacting with a list of braille
- * displays.
- */
-
-import {Msgs} from '../common/msgs.js';
-
-import {BluetoothBrailleDisplayListener, BluetoothBrailleDisplayManager} from './bluetooth_braille_display_manager.js';
-
-/**
- * A widget used for interacting with bluetooth braille displays.
- * @implements {BluetoothBrailleDisplayListener}
- */
-export class BluetoothBrailleDisplayUI {
-  constructor() {
-    /** @private {!BluetoothBrailleDisplayManager} */
-    this.manager_ = new BluetoothBrailleDisplayManager();
-
-    this.manager_.addListener(this);
-
-    /** @private {Element} */
-    this.root_;
-
-    /** @private {Element} */
-    this.displaySelect_;
-
-    /** @private {Element} */
-    this.controls_;
-
-    /** @private {string|undefined} */
-    this.selectedAndConnectedDisplayAddress_;
-  }
-
-  /**
-   * Attaches this widget to |element|.
-   * @param {!Element} element
-   */
-  attach(element) {
-    this.manager_.start();
-    const container = document.createElement('div');
-    element.appendChild(container);
-    this.root_ = container;
-
-    const title = document.createElement('h2');
-    title.textContent = Msgs.getMsg('options_bluetooth_braille_display_title');
-    container.appendChild(title);
-    const controls = document.createElement('div');
-    container.appendChild(controls);
-    this.controls_ = controls;
-    controls.className = 'option';
-
-    const selectLabel = document.createElement('span');
-    controls.appendChild(selectLabel);
-    selectLabel.id = 'bluetoothBrailleSelectLabel';
-    selectLabel.textContent =
-        Msgs.getMsg('options_bluetooth_braille_display_select_label');
-
-    const displaySelect = document.createElement('select');
-    this.displaySelect_ = displaySelect;
-    controls.appendChild(displaySelect);
-    displaySelect.setAttribute(
-        'aria-labelledby', 'bluetoothBrailleSelectLabel');
-    displaySelect.addEventListener('change', evt => {
-      this.updateControls_();
-    });
-
-    const connectOrDisconnect = document.createElement('button');
-    controls.appendChild(connectOrDisconnect);
-    connectOrDisconnect.id = 'connectOrDisconnect';
-    connectOrDisconnect.disabled = true;
-    connectOrDisconnect.textContent =
-        Msgs.getMsg('options_bluetooth_braille_display_connect');
-
-    const forget = document.createElement('button');
-    controls.appendChild(forget);
-    forget.id = 'forget';
-    forget.textContent =
-        Msgs.getMsg('options_bluetooth_braille_display_forget');
-    forget.disabled = true;
-  }
-
-  /**
-   * Detaches the rendered widget.
-   */
-  detach() {
-    this.manager_.stop();
-
-    if (this.root_) {
-      this.root_.remove();
-      this.root_ = null;
-    }
-  }
-
-  /** @override */
-  onDisplayListChanged(displays) {
-    if (!this.displaySelect_) {
-      throw 'Expected attach to have been called.';
-    }
-
-    // Remove any displays that were removed.
-    for (let i = 0; i < this.displaySelect_.children.length; i++) {
-      const domDisplay = this.displaySelect_.children[i];
-      if (!displays.find(display => domDisplay.id === display.address)) {
-        domDisplay.remove();
-      }
-    }
-
-    displays.forEach(display => {
-      // Check if the element already exists.
-      let displayContainer =
-          this.displaySelect_.querySelector('#' + CSS.escape(display.address));
-
-      // If the display already exists, no further processing is needed.
-      if (displayContainer) {
-        return;
-      }
-
-      displayContainer = document.createElement('option');
-      this.displaySelect_.appendChild(displayContainer);
-      displayContainer.id = display.address;
-      const name = document.createElement('span');
-      displayContainer.appendChild(name);
-      name.textContent = display.name;
-    });
-    this.updateControls_();
-  }
-
-  /** @override */
-  onPincodeRequested(display) {
-    this.controls_.hidden = true;
-    let form = document.createElement('form');
-    this.controls_.parentElement.insertBefore(form, this.controls_);
-
-    // Create the text field and its label.
-    const label = document.createElement('label');
-    form.appendChild(label);
-    label.id = 'pincodeLabel';
-    label.textContent =
-        Msgs.getMsg('options_bluetooth_braille_display_pincode_label');
-    label.for = 'pincode';
-    const pincodeField = document.createElement('input');
-    pincodeField.id = 'pincode';
-    pincodeField.type = 'text';
-    pincodeField.setAttribute('aria-labelledby', 'pincodeLabel');
-    form.appendChild(pincodeField);
-
-    let timeoutId = -1;
-    form.addEventListener('submit', evt => {
-      if (timeoutId) {
-        clearTimeout(timeoutId);
-      }
-
-      if (pincodeField.value) {
-        this.manager_.finishPairing(display, pincodeField.value);
-      }
-
-      this.controls_.hidden = false;
-      form.remove();
-      form = null;
-      evt.preventDefault();
-      evt.stopPropagation();
-      this.displaySelect_.focus();
-    });
-
-    // Also, schedule a 60 second timeout for pincode entry.
-    timeoutId = setTimeout(() => {
-      form.remove();
-      this.controls_.hidden = false;
-      this.displaySelect_.focus();
-    }, 60000);
-
-    document.body.blur();
-    pincodeField.focus();
-  }
-
-  /**
-   * @private
-   */
-  updateControls_() {
-    // Only update controls if there is a selected display.
-    const sel = this.displaySelect_.options[this.displaySelect_.selectedIndex];
-    if (!sel) {
-      this.selectedAndConnectedDisplayAddress_ = undefined;
-      return;
-    }
-
-    chrome.bluetooth.getDevice(sel.id, display => {
-      // Record metrics if the display is connected for the first time either
-      // via a click of the Connect button or re-connection by selection via the
-      // select.
-      if (display.connected) {
-        if (this.selectedAndConnectedDisplayAddress_ !== sel.id) {
-          this.selectedAndConnectedDisplayAddress_ = sel.id;
-          chrome.metricsPrivate.recordUserAction(
-              BluetoothBrailleDisplayUI.CONNECTED_METRIC_NAME_);
-        }
-      } else {
-        // The display is no longer connected.
-        if (this.selectedAndConnectedDisplayAddress_ === sel.id) {
-          this.selectedAndConnectedDisplayAddress_ = undefined;
-        }
-      }
-
-      const connectOrDisconnect =
-          this.controls_.querySelector('#connectOrDisconnect');
-      connectOrDisconnect.disabled = display.connecting;
-      this.displaySelect_.disabled = display.connecting;
-      connectOrDisconnect.textContent = Msgs.getMsg(
-          display.connecting ?
-              'options_bluetooth_braille_display_connecting' :
-              (display.connected ?
-                   'options_bluetooth_braille_display_disconnect' :
-                   'options_bluetooth_braille_display_connect'));
-      connectOrDisconnect.onclick = function(savedDisplay, evt) {
-        if (savedDisplay.connected) {
-          this.manager_.disconnect(savedDisplay);
-        } else {
-          this.manager_.connect(savedDisplay);
-        }
-      }.bind(this, display);
-
-      const forget = this.controls_.querySelector('#forget');
-      forget.disabled = !display.paired || display.connecting;
-      forget.onclick = function(savedDisplay) {
-        this.manager_.forget(savedDisplay);
-      }.bind(this, display);
-    });
-  }
-}
-
-
-/** @private {string} */
-BluetoothBrailleDisplayUI.CONNECTED_METRIC_NAME_ =
-    'Accessibility.ChromeVox.BluetoothBrailleDisplayConnectedButtonClick';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui_test.js
deleted file mode 100644
index e379948..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui_test.js
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Include test fixture.
-GEN_INCLUDE(['../testing/chromevox_e2e_test_base.js']);
-GEN_INCLUDE(['../testing/fake_objects.js']);
-
-/** Test fixture. */
-ChromeVoxBluetoothBrailleDisplayUITest = class extends ChromeVoxE2ETest {
-  /** @override */
-  async setUpDeferred() {
-    await super.setUpDeferred();
-
-    // Alphabetical based on file path.
-    await importModule(
-        'BluetoothBrailleDisplayUI',
-        '/chromevox/options/bluetooth_braille_display_ui.js');
-  }
-
-  /** Label of the select. @type {string} */
-  get selectLabel() {
-    return 'Select a bluetooth braille display';
-  }
-
-  /**
-   * Builds an expected stringified version of the widget, inserting static
-   * expected content as needed.
-   * @param {string} controls The expected controls block.
-   * @return {string} The final expectation.
-   */
-  buildUIExpectation(controls) {
-    return `
-        <div>
-          <h2>Bluetooth Braille Display</h2>
-          <div class="option">
-            <span id="bluetoothBrailleSelectLabel">${this.selectLabel}</span>
-            ${controls}
-          </div>
-        </div>`;
-  }
-};
-
-AX_TEST_F('ChromeVoxBluetoothBrailleDisplayUITest', 'NoDisplays', function() {
-  const ui = new BluetoothBrailleDisplayUI();
-  ui.attach(document.body);
-  assertEqualsDOM(
-      this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel"></select>
-                <button id="connectOrDisconnect" disabled="">Connect</button>
-                <button id="forget" disabled="">Forget</button>`),
-      document.body.children[0]);
-});
-
-AX_TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayUITest',
-    'ControlStateUpdatesNotConnectedOrPaired', function() {
-      const ui = new BluetoothBrailleDisplayUI();
-      ui.attach(document.body);
-
-      let displays = [];
-
-      // Fake out getDevice using |display| as the backing source which changes
-      // below.
-      chrome.bluetooth.getDevice = (address, callback) => {
-        const display = displays.find(display => display.address === address);
-        assertNotNullNorUndefined(display);
-        callback(display);
-      };
-
-      // One display; it automatically gets selected.
-      // Not connected, not paired.
-      displays = [{name: 'Focus 40 BT', address: 'abcd1234'}];
-      ui.onDisplayListChanged(displays);
-      assertEqualsDOM(
-          this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel">
-                <option id="abcd1234"><span>Focus 40 BT</span></option>
-              </select>
-              <button id="connectOrDisconnect">Connect</button>
-              <button id="forget" disabled="">Forget</button>`),
-          document.body.children[0]);
-      ui.detach();
-    });
-
-AX_TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayUITest',
-    'ControlStateUpdatesPairedNotConnected', function() {
-      const ui = new BluetoothBrailleDisplayUI();
-      ui.attach(document.body);
-
-      const display = [];
-
-      // Fake out getDevice using |display| as the backing source which changes
-      // below.
-      chrome.bluetooth.getDevice = (address, callback) => {
-        const display = displays.find(display => display.address === address);
-        assertNotNullNorUndefined(display);
-        callback(display);
-      };
-
-      // One display; paired, but not connected.
-      displays = [{name: 'Focus 40 BT', address: 'abcd1234', paired: true}];
-      ui.onDisplayListChanged(displays);
-      assertEqualsDOM(
-          this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel">
-                <option id="abcd1234"><span>Focus 40 BT</span></option>
-              </select>
-              <button id="connectOrDisconnect">Connect</button>
-              <button id="forget">Forget</button>`),
-          document.body.children[0]);
-
-      // Added one display; not paired, not connected.
-      displays = [
-        {name: 'Focus 40 BT', address: 'abcd1234', paired: true},
-        {name: 'Focus 40 BT rev 2', address: '4321dcba'},
-      ];
-      ui.onDisplayListChanged(displays);
-      assertEqualsDOM(
-          this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel">
-                <option id="abcd1234"><span>Focus 40 BT</span></option>
-                <option id="4321dcba"><span>Focus 40 BT rev 2</span></option>
-              </select>
-              <button id="connectOrDisconnect">Connect</button>
-              <button id="forget">Forget</button>`),
-          document.body.children[0]);
-
-      // Our selected display is connecting.
-      displays[0].connecting = true;
-      ui.onDisplayListChanged(displays);
-      assertEqualsDOM(
-          this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel" disabled="">
-                <option id="abcd1234"><span>Focus 40 BT</span></option>
-                <option id="4321dcba"><span>Focus 40 BT rev 2</span></option>
-              </select>
-              <button id="connectOrDisconnect" disabled="">Connecting</button>
-              <button id="forget" disabled="">Forget</button>`),
-          document.body.children[0]);
-
-      // Our selected display connected.
-      displays[0].connecting = false;
-      displays[0].connected = true;
-      ui.onDisplayListChanged(displays);
-      assertEqualsDOM(
-          this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel">
-                <option id="abcd1234"><span>Focus 40 BT</span></option>
-                <option id="4321dcba"><span>Focus 40 BT rev 2</span></option>
-              </select>
-              <button id="connectOrDisconnect">Disconnect</button>
-              <button id="forget">Forget</button>`),
-          document.body.children[0]);
-
-      // The user picks the second display.
-      // The manager has to ask for the device details.
-      const select = document.body.querySelector('select');
-      select.selectedIndex = 1;
-      const changeEvt = document.createEvent('HTMLEvents');
-      changeEvt.initEvent('change');
-      select.dispatchEvent(changeEvt);
-      // The controls update based on the newly selected display.
-      assertEqualsDOM(
-          this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel">
-                <option id="abcd1234"><span>Focus 40 BT</span></option>
-                <option id="4321dcba"><span>Focus 40 BT rev 2</span></option>
-              </select>
-              <button id="connectOrDisconnect">Connect</button>
-              <button id="forget" disabled="">Forget</button>`),
-          document.body.children[0]);
-    });
-
-AX_TEST_F(
-    'ChromeVoxBluetoothBrailleDisplayUITest', 'PincodeRequest', function() {
-      const ui = new BluetoothBrailleDisplayUI();
-      ui.attach(document.body);
-
-      // Trigger pincode screen.
-      ui.onPincodeRequested();
-      assertEqualsDOM(
-          `
-          <div>
-            <h2>Bluetooth Braille Display</h2>
-            <form>
-              <label id="pincodeLabel">Please enter a pin</label>
-              <input id="pincode" type="text" aria-labelledby="pincodeLabel">
-            </form>
-            <div class="option" hidden="">
-              <span id="bluetoothBrailleSelectLabel">${this.selectLabel}</span>
-              <select aria-labelledby="bluetoothBrailleSelectLabel"></select>
-              <button id="connectOrDisconnect" disabled="">Connect</button>
-              <button id="forget" disabled="">Forget</button>
-            </div>
-          </div>`,
-          document.body.children[0]);
-      ui.detach();
-    });
-
-TEST_F('ChromeVoxBluetoothBrailleDisplayUITest', 'ClickControls', function() {
-  const ui = new BluetoothBrailleDisplayUI();
-  ui.attach(document.body);
-
-  let displays = [];
-
-  // Fake out getDevice using |display| as the backing source which changes
-  // below.
-  chrome.bluetooth.getDevice = (address, callback) => {
-    const display = displays.find(display => display.address === address);
-    assertNotNullNorUndefined(display);
-    callback(display);
-  };
-
-  // One display; paired, but not connected.
-  displays = [{name: 'VarioUltra', address: 'abcd1234', paired: true}];
-  ui.onDisplayListChanged(displays);
-  assertEqualsDOM(
-      this.buildUIExpectation(`
-              <select aria-labelledby="bluetoothBrailleSelectLabel">
-                <option id="abcd1234"><span>VarioUltra</span></option>
-              </select>
-              <button id="connectOrDisconnect">Connect</button>
-              <button id="forget">Forget</button>`),
-      document.body.children[0]);
-
-  // Click the connect button. Only connect should be called.
-  chrome.bluetoothPrivate.connect = this.newCallback();
-  chrome.bluetoothPrivate.disconnectAll = assertNotReached;
-  document.getElementById('connectOrDisconnect').onclick();
-
-  // Now, update the state to be connected.
-  displays[0].connected = true;
-  ui.onDisplayListChanged(displays);
-
-  // Click the disconnect button.
-  chrome.bluetoothPrivate.connect = assertNotReached;
-  chrome.bluetoothPrivate.disconnectAll = this.newCallback();
-  chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-      this.newCallback();
-  document.getElementById('connectOrDisconnect').onclick();
-
-  // Click the forget button.
-  chrome.bluetoothPrivate.forgetDevice = this.newCallback();
-  chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-      this.newCallback();
-  document.getElementById('forget').onclick();
-});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/checked.png b/chrome/browser/resources/chromeos/accessibility/chromevox/options/checked.png
deleted file mode 100644
index 0bf9877..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/checked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.css b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.css
deleted file mode 100644
index 3816f4ca..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.css
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Copyright 2017 The Chromium Authors
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-body {
-    margin: 0 0 20px 0;
-    padding: 0;
-}
-
-body,
-button,
-input,
-select {
-    background-color: rgb(241, 241, 241);
-}
-
-h1 {
-    background: rgb(247, 152, 58);
-    color: white;
-    display: block;
-    font-size: 16px;
-    height: 56px;
-    line-height: 56px;
-    text-align: center;
-    width: 100%;
-}
-
-h2 {
-    color: rgb(97, 97, 97);
-    font-size: 13px;
-    height: 15px;
-    margin-top: 21px;
-}
-
-.container {
-    margin: auto;
-    width: 646px;
-}
-
-.option {
-    background-color: #fff;
-    border: 1px solid #ddd;
-    font-size: 13px;
-    line-height: 60px;
-    min-height: 60px;
-    padding: 0 20px;
-    vertical-align: middle;
-    width: 646px;
-}
-
-.option input[type='checkbox'] {
-    -webkit-appearance: none;
-    background-color: #fff;
-    background-image: url(unchecked.png);
-    background-position: center center;
-    background-repeat: no-repeat;
-    border: 0;
-    float: right;
-    height: 60px;
-    margin: 0;
-    padding: 0;
-    width: 40px;
-}
-
-#developerLog {
-  padding: 0;
-  width: 686px;
-}
-
-.option .developerLog {
-  height: 60px;
-  padding-inline-end: 0;
-  width: 666px;
-}
-
-.option .sub-description {
-  color: rgb(95, 99, 104);
-  display: block;
-}
-
-.option .developer-option-icon-button {
-  height: 60px;
-  padding: 0 20px;
-}
-
-.option input[type='checkbox']:checked {
-    background-image: url(checked.png);
-}
-
-#show-log-label {
-  flex: 1;
-}
-
-.option select {
-    background-color: #fff;
-    border-color: #ddd;
-    border-width: 0 0 1px 0;
-    height: 20px;
-    line-height: 60px;
-    margin: 20px 0;
-    padding: 0;
-}
-
-.option input {
-    background-color: #fff;
-    border-color: #ddd;
-    border-width: 0 0 2px 0;
-    outline: none;
-}
-
-.option input:focus {
-    border-color: rgb(0, 0, 255);
-}
-
-.option button {
-    background-color: #ddd;
-    border-width: 0;
-    font-weight: bold;
-    height: 30px;
-    margin-inline-start: 20px;
-    padding: 0 20px;
-}
-
-.option-eventstream {
-    background-color: #fff;
-    border: 1px solid #ddd;
-    font-size: 13px;
-    line-height: 30px;
-    min-height: 30px;
-    padding: 0 20px;
-    vertical-align: middle;
-    width: 646px;
-}
-
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.html b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.html
deleted file mode 100644
index 14d00561..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.html
+++ /dev/null
@@ -1,617 +0,0 @@
-<!--
-Copyright 2014 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<html>
-
-<head>
-<title class="i18n" msgid="options_page_title">ChromeVox Options</title>
-<link rel="stylesheet" type="text/css" href="options.css">
-
-<script type="text/javascript" src="../closure/base.js"></script>
-<script type="text/javascript" src="../deps.js"></script>
-<script type="text/javascript" src="options_loader.js"></script>
-<script type="text/javascript" src="../chromeVoxChromeOptionsScript.js">
-</script>
-<script type="module" src="options.js"></script>
-
-<script type="module"
-    src="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js">
-</script>
-<script type="module"
-    src="chrome://resources/cr_elements/cr_link_row/cr_link_row.js"></script>
-</head>
-
-<body>
-  <!--
-    The "with dev msgs" in the title helps when debugging problems
-    with the message replacer.
-  -->
-  <h1 class="i18n" msgid="options_page_title">ChromeVox (with dev msgs)</h1>
-
-  <div class="container">
-
-  <p id="version"></p>
-
-  <div class="option">
-    <label id="verboseDescriptionsLabel" class="i18n"
-          msgid="options_verbosity_verbose">
-      Enable verbose descriptions.
-    </label>
-      <input id="useVerboseMode" type="checkbox" class="checkbox pref"
-             name="useVerboseMode" aria-labelledby="verboseDescriptionsLabel">
-  </div>
-
-  <div class="option">
-    <label id="readPageLabel" class="i18n" msgid="options_auto_read">
-      Automatically read a page after it finishes loading.
-    </label>
-    <input id="autoRead" type="checkbox" class="checkbox pref"
-             name="autoRead" aria-labelledby="readPageLabel">
-  </div>
-
-  <div class="option">
-    <label id="speakMouseTextLabel" class="i18n" msgid="options_speak_mouse">
-      Speak text under the mouse.
-    </label>
-    <input id="speakTextUnderMouse" type="checkbox" class="checkbox pref"
-             name="speakTextUnderMouse" aria-labelledby="speakMouseTextLabel">
-  </div>
-
-  <div class="option" id="usePitchChangesOption">
-    <label id="usePitchChangesLabel" class="i18n"
-          msgid="options_use_pitch_changes_checkbox_label">
-          Change pitch when speaking element types and formatted text
-    </label>
-    <input id="usePitchChanges" type="checkbox"
-             class="checkbox pref" name="usePitchChanges"
-             aria-labelledby="usePitchChangesLabel">
-  </div>
-
-  <div class="option" id="capitalStrategyOption">
-    <label id="capitalStrategyLabel" class="i18n"
-          msgid="options_capital_strategy_select_label">
-      When reading capitals:
-    </label>
-    <select id="capitalStrategy" class="pref"
-          aria-labelledby="capitalStrategyLabel">
-      <option id="announceCapitals" class="i18n"
-            msgid="options_announce_capitals">
-        Speak "cap" before letter
-      </option>
-      <option id="increasePitch" class="i18n" msgid="options_increase_pitch">
-        Increase pitch
-      </option>
-    </select>
-  </div>
-
-  <div class="option" id="numberReadingStyleOption">
-    <label id="numberReadingStyleLabel" class="i18n"
-          msgid="options_number_reading_style_select_label">
-      Read numbers as:
-    </label>
-    <select id="numberReadingStyle" class="pref"
-          aria-labelledby="numberReadingStyleLabel">
-      <option id="asWords" class="i18n"
-            msgid="options_number_reading_style_words">
-        Words
-      </option>
-      <option id="asDigits" class="i18n"
-              msgid="options_number_reading_style_digits">
-        Digits
-      </option>
-    </select>
-  </div>
-
-  <div class="option" id="punctuationEchoOption">
-    <label id="punctuationEchoLabel" class="i18n"
-          msgid="options_punctuation_echo_select_label">
-      Punctuation echo:
-    </label>
-    <select id="punctuationEcho" class="pref"
-          aria-labelledby="punctuationEchoLabel">
-      <option id="none" class="i18n"
-            msgid="options_punctuation_echo_none">
-        None
-      </option>
-      <option id="some" class="i18n"
-              msgid="options_punctuation_echo_some">
-        Some
-      </option>
-      <option id="all" class="i18n"
-              msgid="options_punctuation_echo_all">
-        All
-      </option>
-    </select>
-  </div>
-
-  <div class="option">
-    <label id="announceDownloadsLabel" class="i18n"
-          msgid="options_announce_download">
-      Announce download notifications.
-    </label>
-    <input id="announceDownloadNotifications" type="checkbox"
-             class="checkbox pref" name="announceDownloadNotifications"
-             aria-labelledby="announceDownloadsLabel">
-  </div>
-
-  <div class="option">
-    <label id="smartStickyModeLabel" class="i18n"
-          msgid="options_smart_sticky_mode">
-      Turn off sticky mode when editing text (Smart Sticky Mode)
-    </label>
-    <input id="smartStickyMode" type="checkbox"
-             class="checkbox pref" name="smartStickyMode"
-             aria-labelledby="smartStickyModeLabel">
-  </div>
-
-  <h2 class="i18n description" msgid="options_audio_description"
-      id="audioDescription">
-    When playing audio
-  </h2>
-
-  <div class="option">
-    <select id="audioStrategy" class="pref" aria-labelledby="audioDescription">
-      <option id="audioNormal" class="i18n" msgid="options_audio_normal">
-        play at normal volume even if ChromeVox is speaking
-      </option>
-      <option id="audioDuck" class="i18n" msgid="options_audio_duck">
-        play at lower volume when ChromeVox is speaking
-      </option>
-      <option id="audioSuspend" class="i18n" msgid="options_audio_suspend">
-        pause playback when ChromeVox is speaking
-      </option>
-    </select>
-  </div>
-
-  <h2 class="i18n" msgid="options_voices">Voices</h2>
-  <div class="option">
-    <span class="i18n description" msgid="options_voices_description"
-          id="voices_description">
-      Select current voice:
-    </span>
-    <select id="voices" aria-labelledby="voices_description"></select>
-  </div>
-
-  <div class="option" id="languageSwitchingOption">
-    <label id="voiceSwitchingLabel" class="i18n"
-          msgid="options_lang_switching_checkbox_label">
-      Automatically switch ChromeVox voice based on language
-    </label>
-    <input id="languageSwitching" type="checkbox"
-             class="checkbox pref" name="languageSwitching"
-             aria-labelledby="voiceSwitchingLabel">
-  </div>
-
-  <div class="option">
-    <label>
-      <cr-link-row id="openTtsSettings"
-          using-slotted-label external embedded button-aria-description="">
-        <span slot="label" class="i18n" msgid="show_tts_settings"></span>
-        <span slot="sub-label" class="i18n sub-description"
-            msgid="options_show_tts_settings"></span>
-      </cr-link-row>
-    </label>
-  </div>
-
-  <div id="richTextIndicationOption">
-    <h2 class="i18n" msgid="options_rich_text_header">Formatting</h2>
-    <div class="option">
-      <label id="textStylingLabel" class="i18n"
-            msgid="options_rich_text_checkbox_label">
-        Announce text styling
-      </label>
-      <input id="announceRichTextAttributes" type="checkbox"
-             class="checkbox pref" name="announceRichTextAttributes"
-             aria-labelledby="textStylingLabel">
-    </div>
-  </div>
-
-  <h2 class="chromeos i18n" msgid="options_braille">Braille</h2>
-  <div class="chromeos option">
-    <span class="i18n description" msgid="options_braille_description_6"
-          id="braille_description_6">
-      Select a 6-dot braille table:
-    </span>
-    <select id="brailleTable6" aria-labelledby="braille_description_6"></select>
-  </div>
-  <div class="chromeos option">
-    <span class="i18n description" msgid="options_braille_description_8"
-          id="braille_description_8">
-      Select an 8-dot braille table:
-    </span>
-    <select id="brailleTable8" aria-labelledby="braille_description_8"></select>
-  </div>
-  <div class="chromeos option">
-    <button id="brailleTableType"></button><span>&nbsp;</span>
-  </div>
-  <div class="chromeos option">
-    <label>
-      <input id="brailleWordWrap" type="checkbox" class="checkbox pref"
-             name="brailleWordWrap">
-      <span class="i18n" msgid="options_braille_word_wrap">
-        Enable word wrap
-      </span>
-    </label>
-  </div>
-  <div class="option">
-    <label id="menuBrailleCommandsLabel" class="i18n"
-          msgid="options_menu_braille_commands">
-      Show braille commands in ChromeVox menus
-    </label>
-    <input id="menuBrailleCommands" type="checkbox"
-             class="checkbox pref" name="menuBrailleCommands"
-             aria-labelledby="menuBrailleCommandsLabel">
-  </div>
-
-  <div id="bluetoothBraille"></div>
-
-  <h2 class="i18n" msgid="options_virtual_braille_display">
-    Virtual Braille Display
-  </h2>
-  <p class="i18n" msgid="options_virtual_braille_display_details">
-    Simulates the output of a refreshable braille display
-    in the ChromeVox panel at the top of the screen.
-  </p>
-  <div class="option">
-  <label>
-    <span class="i18n description" msgid="options_virtual_braille_display_rows"
-          id="virtual_braille_display_rows_description">
-      Lines:
-    </span>
-    <input type="number" min="1" id="virtual_braille_display_rows_input">
-  </label>
-  </div>
-  <div class="option">
-  <label>
-    <span class="i18n description"
-          msgid="options_virtual_braille_display_columns"
-          id="virtual_braille_display_columns_description">
-      Cells in each line:
-    </span>
-    <input type="number" min="1" id="virtual_braille_display_columns_input">
-  </label>
-  </div>
-  <div class="option">
-    <span id="currentDisplayStyle"></span>
-    <button id="changeDisplayStyle"></button>
-  </div>
-
-  <h2 class="i18n" msgid="options_developer_options" id="developerDescription">
-    Developer Options
-  </h2>
-  <div class="chromeos option" id="developerLog">
-    <label>
-      <cr-expand-button class="developer-option-icon-button"
-          id="chromeVoxDeveloperOptions" name="chromeVoxDeveloperOptions">
-        <span class="i18n" msgid="options_developer_options"
-              id="developer-options-label">
-          Enable developer options
-        </span>
-      </cr-expand-button>
-    </label>
-  </div>
-  <div class="option" id="developerSpeechLogging" hidden>
-    <label>
-      <input id="enableSpeechLogging" type="checkbox"
-             class="checkbox pref logging" name="enableSpeechLogging">
-      <span class="i18n" msgid="options_developer_speech_logging">
-        Enable speech logging
-      </span>
-    </label>
-  </div>
-  <div class="option" id="developerEarconLogging" hidden>
-    <label>
-      <input id="enableEarconLogging" type="checkbox"
-             class="checkbox pref logging" name="enableEarconLogging">
-      <span class="i18n" msgid="options_developer_earcon_logging">
-        Enable earcon logging
-      </span>
-    </label>
-  </div>
-  <div class="option" id="developerBrailleLogging" hidden>
-    <label>
-      <input id="enableBrailleLogging" type="checkbox"
-             class="checkbox pref logging" name="enableBrailleLogging">
-      <span class="i18n" msgid="options_developer_braille_logging">
-        Enable braille logging
-      </span>
-    </label>
-  </div>
-  <div class="option" id="developerEventStream" hidden>
-    <label>
-      <input id="enableEventStreamLogging" type="checkbox"
-             class="checkbox pref logging" name="enableEventStreamLogging">
-      <span class="i18n" msgid="options_event_stream_logging">
-        Enable event stream logging
-      </span>
-    </label>
-    <button id="toggleEventStreamFilters"></button>
-  </div>
-  <div class="option" id="showDeveloperLog" hidden>
-    <label>
-      <cr-link-row class="developer-option-icon-button" id="openDeveloperLog"
-          using-slotted-label external embedded>
-        <span slot="label" class="i18n" msgid="options_show_log"></span>
-        <span slot="sub-label" class="i18n sub-description"
-            msgid="options_show_log_key"></span>
-      </cr-link-row>
-    </label>
-  </div>
-
-  <div id="eventStreamFilters" hidden>
-    <div class="option">
-      <button id="enableAllEventStreamFilters" class="i18n"
-          msgid="options_enable_all_event_stream_filters"></button>
-      <button id="disableAllEventStreamFilters" class="i18n"
-          msgid="options_disable_all_event_stream_filters"></button>
-    </div>
-    <label><div class="option-eventstream">
-      <input name="activedescendantchanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>activedescendantchanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="alert" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>alert</span>
-    </div></label>
-    <!-- TODO(crbug.com/1464633) Fully remove ariaAttributeChangedDeprecated
-         starting in 122, because although it was removed in 118, it is still
-         present in earlier versions of LaCros. -->
-    <label><div class="option-eventstream">
-      <input name="ariaAttributeChangedDeprecated" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>ariaAttributeChangedDeprecated</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="autocorrectionOccured" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>autocorrectionOccured</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="blur" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>blur</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="checkedStateChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>checkedStateChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="childrenChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>childrenChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="clicked" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>clicked</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="documentSelectionChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>documentSelectionChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="documentTitleChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>documentTitleChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="expandedChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>expandedChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="focus" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>focus</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="focusContext" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>focusContext</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="imageFrameUpdated" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>imageFrameUpdated</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="hide" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>hide</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="hitTestResult" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>hitTestResult</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="hover" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>hover</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="invalidStatusChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>invalidStatusChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="layoutComplete" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>layoutComplete</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="liveRegionCreated" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>liveRegionCreated</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="liveRegionChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>liveRegionChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="loadComplete" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>loadComplete</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="locationChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>locationChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="mediaStartedPlaying" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>mediaStartedPlaying</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="mediaStoppedPlaying" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>mediaStoppedPlaying</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="menuEnd" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>menuEnd</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="menuItemSelected" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>menuItemSelected</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="menuListValueChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>menuListValueChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="menuPopupEnd" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>menuPopupEnd</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="menuPopupStart" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>menuPopupStart</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="menuStart" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>menuStart</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="mouseCanceled" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>mouseCanceled</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="mouseDragged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>mouseDragged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="mouseMoved" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>mouseMoved</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="mousePressed" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>mousePressed</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="mouseReleased" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>mouseReleased</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="rowCollapsed" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>rowCollapsed</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="rowCountChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>rowCountChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="rowExpanded" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>rowExpanded</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="scrollPositionChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>scrollPositionChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="scrolledToAnchor" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>scrolledToAnchor</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="selectedChildrenChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>selectedChildrenChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="selection" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>selection</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="selectionAdd" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>selectionAdd</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="selectionRemove" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>selectionRemove</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="show" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>show</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="stateChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>stateChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="textChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>textChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="textSelectionChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>textSelectionChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="treeChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>treeChanged</span>
-    </div></label>
-    <label><div class="option-eventstream">
-      <input name="valueInTextFieldChanged" type="checkbox"
-             class="checkbox pref eventstream">
-      <span>valueInTextFieldChanged</span>
-    </div></label>
-  </div>
-  </div>
-
-  <div id="status" role="live" aria-live="assertive">
-  </div>
-
-  </div>
-
-</body>
-</html>
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
deleted file mode 100644
index 9389d73..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
+++ /dev/null
@@ -1,537 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview ChromeVox options page.
- */
-import {constants} from '../../common/constants.js';
-import {LocalStorage} from '../../common/local_storage.js';
-import {BackgroundBridge} from '../common/background_bridge.js';
-import {BrailleTable} from '../common/braille/braille_table.js';
-import {Msgs} from '../common/msgs.js';
-import {PanelCommand, PanelCommandType} from '../common/panel_command.js';
-import {SettingsManager} from '../common/settings_manager.js';
-import {PunctuationEchoes, TtsSettings} from '../common/tts_types.js';
-
-import {BluetoothBrailleDisplayUI} from './bluetooth_braille_display_ui.js';
-
-/** @const {string} */
-const GOOGLE_TTS_EXTENSION_ID = 'gjjabgpgjpampikjhjpfhneeoapjbjaf';
-
-/** @const {string} */
-const ESPEAK_TTS_EXTENSION_ID = 'dakbfdmgjiabojdgbiljlhgjbokobjpg';
-
-/**
- * Class to manage the options page.
- */
-export class OptionsPage {
-  /**
-   * Initialize the options page by setting the current value of all prefs, and
-   * adding event listeners.
-   * @this {OptionsPage}
-   */
-  static async init() {
-    await LocalStorage.init();
-    await SettingsManager.init();
-    OptionsPage.populateVoicesSelect();
-    BrailleTable.getAll(function(tables) {
-      /** @type {!Array<BrailleTable.Table>} */
-      OptionsPage.brailleTables = tables;
-      OptionsPage.populateBrailleTablesSelect();
-    });
-
-    $('brailleWordWrap').checked = SettingsManager.get('brailleWordWrap');
-    $('virtual_braille_display_rows_input').value =
-        SettingsManager.get('virtualBrailleRows');
-    $('virtual_braille_display_columns_input').value =
-        SettingsManager.get('virtualBrailleColumns');
-
-    const changeToInterleave =
-        Msgs.getMsg('options_change_current_display_style_interleave');
-    const changeToSideBySide =
-        Msgs.getMsg('options_change_current_display_style_side_by_side');
-    const currentlyDisplayingInterleave =
-        Msgs.getMsg('options_current_display_style_interleave');
-    const currentlyDisplayingSideBySide =
-        Msgs.getMsg('options_current_display_style_side_by_side');
-    $('changeDisplayStyle').textContent =
-        SettingsManager.get('brailleSideBySide') ? changeToInterleave :
-                                                   changeToSideBySide;
-    $('currentDisplayStyle').textContent =
-        SettingsManager.get('brailleSideBySide') ?
-        currentlyDisplayingSideBySide :
-        currentlyDisplayingInterleave;
-
-    const showEventStreamFilters =
-        Msgs.getMsg('options_show_event_stream_filters');
-    const hideEventStreamFilters =
-        Msgs.getMsg('options_hide_event_stream_filters');
-    $('toggleEventStreamFilters').textContent = showEventStreamFilters;
-    OptionsPage.disableEventStreamFilterCheckBoxes(
-        !SettingsManager.getBoolean('enableEventStreamLogging'));
-
-    if (SettingsManager.get('audioStrategy')) {
-      for (let i = 0, opt; opt = $('audioStrategy').options[i]; i++) {
-        if (opt.id === SettingsManager.get('audioStrategy')) {
-          opt.setAttribute('selected', '');
-        }
-      }
-    }
-    if (SettingsManager.getString('capitalStrategy')) {
-      for (let i = 0, opt; opt = $('capitalStrategy').options[i]; ++i) {
-        if (opt.id === SettingsManager.getString('capitalStrategy')) {
-          opt.setAttribute('selected', '');
-        }
-      }
-    }
-
-    if (SettingsManager.get('numberReadingStyle')) {
-      for (let i = 0, opt; opt = $('numberReadingStyle').options[i]; ++i) {
-        if (opt.id === SettingsManager.get('numberReadingStyle')) {
-          opt.setAttribute('selected', '');
-        }
-      }
-    }
-
-    if (SettingsManager.get(TtsSettings.PUNCTUATION_ECHO)) {
-      const currentPunctuationEcho =
-          PunctuationEchoes[SettingsManager.getNumber(
-              TtsSettings.PUNCTUATION_ECHO)];
-      for (let i = 0, opt; opt = $('punctuationEcho').options[i]; ++i) {
-        if (opt.id === currentPunctuationEcho.name) {
-          opt.setAttribute('selected', '');
-        }
-      }
-    }
-
-    $('toggleEventStreamFilters').addEventListener('click', function(evt) {
-      if ($('eventStreamFilters').hidden) {
-        $('eventStreamFilters').hidden = false;
-        $('toggleEventStreamFilters').textContent = hideEventStreamFilters;
-      } else {
-        $('eventStreamFilters').hidden = true;
-        $('toggleEventStreamFilters').textContent = showEventStreamFilters;
-      }
-    });
-
-    $('openTtsSettings').addEventListener('click', evt => {
-      chrome.accessibilityPrivate.openSettingsSubpage(
-          'manageAccessibility/tts');
-    });
-
-    $('enableAllEventStreamFilters').addEventListener('click', () => {
-      OptionsPage.setAllEventStreamLoggingFilters(true);
-    });
-    $('disableAllEventStreamFilters').addEventListener('click', () => {
-      OptionsPage.setAllEventStreamLoggingFilters(false);
-    });
-
-    $('chromeVoxDeveloperOptions').addEventListener('expanded-changed', () => {
-      const hidden = !$('chromeVoxDeveloperOptions')['expanded'];
-      $('developerSpeechLogging').hidden = hidden;
-      $('developerEarconLogging').hidden = hidden;
-      $('developerBrailleLogging').hidden = hidden;
-      $('developerEventStream').hidden = hidden;
-      $('showDeveloperLog').hidden = hidden;
-    });
-
-    $('openDeveloperLog').addEventListener('click', function(evt) {
-      const logPage = {url: 'chromevox/log_page/log.html'};
-      chrome.tabs.create(logPage);
-    });
-
-    Msgs.addTranslatedMessagesToDom(document);
-    OptionsPage.hidePlatformSpecifics();
-
-    await OptionsPage.update();
-
-    document.addEventListener('change', OptionsPage.eventListener, false);
-    document.addEventListener('click', OptionsPage.eventListener, false);
-    document.addEventListener('keydown', OptionsPage.eventListener, false);
-
-    SettingsManager.addListenerForKey(
-        'speakTextUnderMouse',
-        enabled => chrome.accessibilityPrivate.enableMouseEvents(enabled));
-
-    const clearVirtualDisplay = function() {
-      const groups = [];
-      const sizeOfDisplay =
-          parseInt($('virtual_braille_display_rows_input').innerHTML, 10) *
-          parseInt($('virtual_braille_display_columns_input').innerHTML, 10);
-      for (let i = 0; i < sizeOfDisplay; i++) {
-        groups.push(['X', 'X']);
-      }
-      (new PanelCommand(PanelCommandType.UPDATE_BRAILLE, {groups})).send();
-    };
-
-    $('changeDisplayStyle').addEventListener('click', function(evt) {
-      const sideBySide = SettingsManager.get('brailleSideBySide');
-      SettingsManager.set('brailleSideBySide', !sideBySide);
-      $('changeDisplayStyle').textContent =
-          sideBySide ? changeToInterleave : changeToSideBySide;
-      $('currentDisplayStyle').textContent = sideBySide ?
-          currentlyDisplayingSideBySide :
-          currentlyDisplayingInterleave;
-      clearVirtualDisplay();
-    }, true);
-
-    handleNumericalInputPref(
-        'virtual_braille_display_rows_input', 'virtualBrailleRows');
-    handleNumericalInputPref(
-        'virtual_braille_display_columns_input', 'virtualBrailleColumns');
-
-    /** @type {!BluetoothBrailleDisplayUI} */
-    OptionsPage.bluetoothBrailleDisplayUI = new BluetoothBrailleDisplayUI();
-
-    const bluetoothBraille = $('bluetoothBraille');
-    if (bluetoothBraille) {
-      OptionsPage.bluetoothBrailleDisplayUI.attach(bluetoothBraille);
-    }
-
-    $('usePitchChanges').addEventListener('click', evt => {
-      // The capitalStrategy pref depends on the value of usePitchChanges.
-      // When usePitchChanges is toggled, we should update the preference value
-      // and options for capitalStrategy.
-      const checked = evt.target.checked;
-      if (!checked) {
-        $('announceCapitals').selected = true;
-        $('increasePitch').selected = false;
-        $('increasePitch').disabled = true;
-        SettingsManager.set(
-            'capitalStrategyBackup',
-            SettingsManager.getString('capitalStrategy'));
-        BackgroundBridge.ChromeVoxPrefs.setPref(
-            'capitalStrategy', 'announceCapitals');
-      } else {
-        $('increasePitch').disabled = false;
-        const capitalStrategyBackup =
-            SettingsManager.getString('capitalStrategyBackup');
-        if (capitalStrategyBackup) {
-          // Restore original capitalStrategy setting.
-          $('announceCapitals').selected =
-              (capitalStrategyBackup === 'announceCapitals');
-          $('increasePitch').selected =
-              (capitalStrategyBackup === 'increasePitch');
-          BackgroundBridge.ChromeVoxPrefs.setPref(
-              'capitalStrategy', capitalStrategyBackup);
-        }
-      }
-    });
-  }
-
-  /**
-   * Update the value of controls to match the current preferences.
-   * This happens if the user presses a key in a tab that changes a
-   * pref.
-   */
-  static async update() {
-    const prefs = await BackgroundBridge.ChromeVoxPrefs.getPrefs();
-    for (const key in prefs) {
-      // TODO(rshearer): 'active' is a pref, but there's no place in the
-      // options page to specify whether you want ChromeVox active.
-      const elements = document.querySelectorAll('*[name="' + key + '"]');
-      for (let i = 0; i < elements.length; i++) {
-        OptionsPage.setValue(elements[i], prefs[key]);
-      }
-    }
-  }
-
-  /**
-   * Populates the voices select with options.
-   */
-  static async populateVoicesSelect() {
-    const select = $('voices');
-
-    async function setVoiceList() {
-      const selectedVoice =
-          await BackgroundBridge.TtsBackground.getCurrentVoice();
-      const addVoiceOption = (visibleVoiceName, voiceName) => {
-        const option = document.createElement('option');
-        option.voiceName = voiceName;
-        option.innerText = visibleVoiceName;
-        if (selectedVoice === voiceName) {
-          option.setAttribute('selected', '');
-        }
-        select.add(option);
-      };
-      chrome.tts.getVoices(function(voices) {
-        select.innerHTML = '';
-        // TODO(plundblad): voiceName can actually be omitted in the TTS engine.
-        // We should generate a name in that case.
-        voices.forEach(voice => voice.voiceName = voice.voiceName || '');
-        voices.sort(function(a, b) {
-          // Prefer Google tts voices over all others.
-          if (a.extensionId === GOOGLE_TTS_EXTENSION_ID &&
-              b.extensionId !== GOOGLE_TTS_EXTENSION_ID) {
-            return -1;
-          }
-
-          // Next, prefer Espeak tts voices.
-          if (a.extensionId === ESPEAK_TTS_EXTENSION_ID &&
-              b.extensionId !== ESPEAK_TTS_EXTENSION_ID) {
-            return -1;
-          }
-
-          // Finally, prefer local over remote voices.
-          if (!a['remote'] && b['remote']) {
-            return -1;
-          }
-
-          return 0;
-        });
-        addVoiceOption(Msgs.getMsg('system_voice'), constants.SYSTEM_VOICE);
-        voices.forEach(
-            voice => addVoiceOption(voice.voiceName, voice.voiceName));
-      });
-    }
-
-    window.speechSynthesis.onvoiceschanged = setVoiceList;
-    await setVoiceList();
-
-    select.addEventListener('change', function(evt) {
-      const selIndex = select.selectedIndex;
-      const sel = select.options[selIndex];
-      SettingsManager.set('voiceName', sel.voiceName);
-    }, true);
-  }
-
-  /**
-   * Populates the braille select control.
-   */
-  static populateBrailleTablesSelect() {
-    const tables = OptionsPage.brailleTables;
-    const populateSelect = function(node, dots) {
-      const activeTable = SettingsManager.get(node.id) ||
-          SettingsManager.getString('brailleTable');
-      // Gather the display names and sort them according to locale.
-      const items = [];
-      for (let i = 0, table; table = tables[i]; i++) {
-        if (table.dots !== dots) {
-          continue;
-        }
-        const displayName = BrailleTable.getDisplayName(table);
-
-        // Ignore tables that don't have a display name.
-        if (displayName) {
-          items.push({id: table.id, name: displayName});
-        }
-      }
-      items.sort(function(a, b) {
-        return a.id.localeCompare(b.id);
-      });
-      for (let i = 0, item; item = items[i]; ++i) {
-        const elem = document.createElement('option');
-        elem.id = item.id;
-        elem.textContent = item.name;
-        if (item.id === activeTable) {
-          elem.setAttribute('selected', '');
-        }
-        node.appendChild(elem);
-      }
-    };
-    const select6 = $('brailleTable6');
-    const select8 = $('brailleTable8');
-    populateSelect(select6, '6');
-    populateSelect(select8, '8');
-
-    const handleBrailleSelect = function(node) {
-      return function(evt) {
-        const selIndex = node.selectedIndex;
-        const sel = node.options[selIndex];
-        SettingsManager.set('brailleTable', sel.id);
-        SettingsManager.set(node.id, sel.id);
-      };
-    };
-
-    select6.addEventListener('change', handleBrailleSelect(select6), true);
-    select8.addEventListener('change', handleBrailleSelect(select8), true);
-
-    const tableTypeButton = $('brailleTableType');
-    const updateTableType = function(setFocus) {
-      const currentTableType =
-          SettingsManager.getString('brailleTableType') || 'brailleTable6';
-      if (currentTableType === 'brailleTable6') {
-        select6.parentElement.style.display = 'block';
-        select8.parentElement.style.display = 'none';
-        if (setFocus) {
-          select6.focus();
-        }
-        SettingsManager.set(
-            'brailleTable', SettingsManager.getString('brailleTable6'));
-        SettingsManager.set('brailleTableType', 'brailleTable6');
-        tableTypeButton.textContent =
-            Msgs.getMsg('options_braille_table_type_6');
-      } else {
-        select6.parentElement.style.display = 'none';
-        select8.parentElement.style.display = 'block';
-        if (setFocus) {
-          select8.focus();
-        }
-        SettingsManager.set(
-            'brailleTable', SettingsManager.getString('brailleTable8'));
-        SettingsManager.set('brailleTableType', 'brailleTable8');
-        tableTypeButton.textContent =
-            Msgs.getMsg('options_braille_table_type_8');
-      }
-    };
-    updateTableType(false);
-
-    tableTypeButton.addEventListener('click', function(evt) {
-      const oldTableType = SettingsManager.getString('brailleTableType');
-      SettingsManager.set(
-          'brailleTableType',
-          oldTableType === 'brailleTable6' ? 'brailleTable8' : 'brailleTable6');
-      updateTableType(true);
-    }, true);
-  }
-
-  /**
-   * Set the html element for a preference to match the given value.
-   * @param {Element} element The HTML control.
-   * @param {*} value The new value.
-   */
-  static setValue(element, value) {
-    if (element.tagName === 'INPUT' && element.type === 'checkbox') {
-      element.checked = value;
-    } else if (element.tagName === 'INPUT' && element.type === 'radio') {
-      element.checked = (String(element.value) === value);
-    } else {
-      element.value = value;
-    }
-  }
-
-  /**
-   * Disable event stream logging filter check boxes.
-   * Check boxes should be disabled when event stream logging is disabled.
-   * @param {boolean} disable
-   */
-  static disableEventStreamFilterCheckBoxes(disable) {
-    const filters = document.querySelectorAll('.option-eventstream > input');
-    for (let i = 0; i < filters.length; i++) {
-      filters[i].disabled = disable;
-    }
-  }
-
-  /**
-   * Set all event stream logging filter to on or off.
-   * @param {boolean} enabled
-   */
-  static setAllEventStreamLoggingFilters(enabled) {
-    for (const checkbox of document.querySelectorAll(
-             '.option-eventstream > input')) {
-      if (checkbox.checked !== enabled) {
-        OptionsPage.setEventStreamFilter(checkbox.name, enabled);
-      }
-    }
-  }
-
-  /**
-   * Set the specified event logging filter to on or off.
-   * @param {string} name
-   * @param {boolean} enabled
-   */
-  static setEventStreamFilter(name, enabled) {
-    BackgroundBridge.ChromeVoxPrefs.setPref(name, enabled);
-
-    // TODO(accessibility): the below cast needs to be validated.
-    BackgroundBridge.EventStreamLogger.notifyEventStreamFilterChanged(
-        /** @type {chrome.automation.EventType} */ (name), enabled);
-  }
-
-  /**
-   * Event listener, called when an event occurs in the page that might
-   * affect one of the preference controls.
-   * @param {Event} event The event.
-   * @return {boolean} True if the default action should occur.
-   */
-  static eventListener(event) {
-    setTimeout(function() {
-      const target = event.target;
-      if (target.id === 'brailleWordWrap') {
-        SettingsManager.set(target.id, target.checked);
-      } else if (target.className.indexOf('logging') !== -1) {
-        BackgroundBridge.ChromeVoxPrefs.setLoggingPrefs(
-            target.name, target.checked);
-        if (target.name === 'enableEventStreamLogging') {
-          OptionsPage.disableEventStreamFilterCheckBoxes(!target.checked);
-        }
-      } else if (target.className.indexOf('eventstream') !== -1) {
-        OptionsPage.setEventStreamFilter(target.name, target.checked);
-      } else if (target.id === 'punctuationEcho') {
-        const selectedPunctuationEcho = target.options[target.selectedIndex].id;
-        const punctuationEcho = PunctuationEchoes.findIndex(
-            echo => echo.name === selectedPunctuationEcho);
-        BackgroundBridge.TtsBackground.updatePunctuationEcho(punctuationEcho);
-      } else if (target.classList.contains('pref')) {
-        if (target.tagName === 'INPUT' && target.type === 'checkbox') {
-          BackgroundBridge.ChromeVoxPrefs.setPref(target.name, target.checked);
-        } else if (target.tagName === 'INPUT' && target.type === 'radio') {
-          const key = target.name;
-          const elements = document.querySelectorAll('*[name="' + key + '"]');
-          for (let i = 0; i < elements.length; i++) {
-            if (elements[i].checked) {
-              BackgroundBridge.ChromeVoxPrefs.setPref(
-                  target.name, elements[i].value);
-            }
-          }
-        } else if (target.tagName === 'SELECT') {
-          const selIndex = target.selectedIndex;
-          const sel = target.options[selIndex];
-          const value = sel ? sel.id : 'audioNormal';
-          BackgroundBridge.ChromeVoxPrefs.setPref(target.id, value);
-        }
-      }
-    }, 0);
-    return true;
-  }
-
-  /**
-   * Hides all elements not matching the current platform.
-   */
-  static hidePlatformSpecifics() {}
-}
-
-/**
- * Adds event listeners to input boxes to update settings values and make sure
- * that the input is a positive nonempty number between 1 and 99.
- * @param {string} id Id of the input box.
- * @param {string} pref Preference key in SettingsManager to access and modify.
- */
-const handleNumericalInputPref = function(id, pref) {
-  $(id).addEventListener('input', function(evt) {
-    if ($(id).value === '') {
-      return;
-    }
-
-    const numericalValue = parseInt($(id).value, 10);
-    if (numericalValue < 1 || numericalValue > 99) {
-      $(id).value = SettingsManager.get(pref);
-    } else {
-      SettingsManager.set(pref, numericalValue);
-    }
-  }, true);
-
-  $(id).addEventListener('focusout', function(evt) {
-    if ($(id).value === '') {
-      $(id).value = SettingsManager.get(pref);
-    }
-  }, true);
-};
-
-document.addEventListener('DOMContentLoaded', async function() {
-  await OptionsPage.init();
-}, false);
-
-window.addEventListener('beforeunload', function(e) {
-  OptionsPage.bluetoothBrailleDisplayUI.detach();
-});
-
-/**
- * Shortcut for document.getElementById.
- * @param {string} id of the element.
- * @return {Element} with the id.
- */
-function $(id) {
-  return document.getElementById(id);
-}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js
deleted file mode 100644
index 25d6697..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Loads the options script.
- */
-
-goog.require('goog.i18n.MessageFormat');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js
deleted file mode 100644
index 4a513e27..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Include test fixture.
-GEN_INCLUDE([
-  '../testing/chromevox_e2e_test_base.js',
-]);
-
-/**
- * Test fixture for ChromeVox options page.
- */
-ChromeVoxOptionsTest = class extends ChromeVoxE2ETest {
-  constructor() {
-    super();
-    globalThis.EventType = chrome.automation.EventType;
-    globalThis.RoleType = chrome.automation.RoleType;
-    globalThis.press = this.press;
-  }
-
-  /** @override */
-  async setUpDeferred() {
-    await super.setUpDeferred();
-
-    await Promise.all([
-      // Alphabetical based on file path.
-      importModule(
-          'CommandHandlerInterface',
-          '/chromevox/background/input/command_handler_interface.js'),
-      importModule('TtsSettings', '/chromevox/common/tts_types.js'),
-      importModule('AsyncUtil', '/common/async_util.js'),
-      importModule('EventGenerator', '/common/event_generator.js'),
-      importModule('KeyCode', '/common/key_code.js'),
-      importModule('LocalStorage', '/common/local_storage.js'),
-      importModule('SettingsManager', '/chromevox/common/settings_manager.js'),
-    ]);
-  }
-
-  async loadOptionsPage() {
-    return new Promise(async resolve => {
-      const mockFeedback = this.createMockFeedback();
-      const desktop = await AsyncUtil.getDesktop();
-      desktop.addEventListener(
-          EventType.LOAD_COMPLETE, evt => {
-            if (evt.target.docUrl.indexOf('options/options.html') === -1 ||
-                !evt.target.docLoaded) {
-              return;
-            }
-
-            mockFeedback.expectSpeech('ChromeVox Options');
-            resolve([mockFeedback, evt]);
-          });
-      CommandHandlerInterface.instance.onCommand('showOptionsPage');
-    });
-  }
-
-  press(keyCode, modifiers) {
-    return function() {
-      EventGenerator.sendKeyPress(keyCode, modifiers);
-    };
-  }
-};
-
-// TODO(crbug.com/1318133): Test times out flakily.
-AX_TEST_F(
-    'ChromeVoxOptionsTest', 'DISABLED_NumberReadingStyleSelect',
-    async function() {
-      const [mockFeedback, evt] = await this.loadOptionsPage();
-      const numberStyleSelect = evt.target.find({
-        role: RoleType.POP_UP_BUTTON,
-        attributes: {name: 'Read numbers as:'},
-      });
-      assertNotNullNorUndefined(numberStyleSelect);
-      mockFeedback.call(numberStyleSelect.focus.bind(numberStyleSelect))
-          .expectSpeech('Read numbers as:', 'Words', 'Collapsed')
-          .call(numberStyleSelect.doDefault.bind(numberStyleSelect))
-          .expectSpeech('Expanded')
-
-          // Before selecting the menu option.
-          .call(() => {
-            assertEquals('asWords', SettingsManager.get('numberReadingStyle'));
-          })
-
-          .call(press(KeyCode.DOWN))
-          .expectSpeech('Digits', 'List item', ' 2 of 2 ')
-          .call(press(KeyCode.RETURN))
-          .expectSpeech('Digits', 'Collapsed')
-          .call(() => {
-            assertEquals('asDigits', SettingsManager.get('numberReadingStyle'));
-          });
-
-      await mockFeedback.replay();
-    });
-
-// TODO(crbug.com/1128926, crbug.com/1172387):
-// Test times out flakily.
-AX_TEST_F(
-    'ChromeVoxOptionsTest', 'DISABLED_PunctuationEchoSelect', async function() {
-      const [mockFeedback, evt] = await this.loadOptionsPage();
-      const PUNCTUATION_ECHO_NONE = '0';
-      const PUNCTUATION_ECHO_SOME = '1';
-      const PUNCTUATION_ECHO_ALL = '2';
-      const punctuationEchoSelect = evt.target.find({
-        role: RoleType.POP_UP_BUTTON,
-        attributes: {name: 'Punctuation echo:'},
-      });
-      assertNotNullNorUndefined(punctuationEchoSelect);
-      mockFeedback.call(punctuationEchoSelect.focus.bind(punctuationEchoSelect))
-          .expectSpeech('Punctuation echo:', 'None', 'Collapsed')
-          .call(punctuationEchoSelect.doDefault.bind(punctuationEchoSelect))
-          .expectSpeech('Expanded')
-
-          // Before selecting the menu option.
-          .call(() => {
-            assertEquals(
-                PUNCTUATION_ECHO_NONE,
-                SettingsManager.get(TtsSettings.PUNCTUATION_ECHO));
-          })
-
-          .call(press(KeyCode.DOWN))
-          .expectSpeech('Some', 'List item', ' 2 of 3 ')
-          .call(press(KeyCode.RETURN))
-          .expectSpeech('Some', 'Collapsed')
-          .call(() => {
-            assertEquals(
-                PUNCTUATION_ECHO_SOME,
-                SettingsManager.get(TtsSettings.PUNCTUATION_ECHO));
-          })
-
-          .call(press(KeyCode.DOWN))
-          .expectSpeech('All', ' 3 of 3 ')
-          .call(() => {
-            assertEquals(
-                PUNCTUATION_ECHO_ALL,
-                SettingsManager.get(TtsSettings.PUNCTUATION_ECHO));
-          });
-
-      await mockFeedback.replay();
-    });
-
-// TODO(crbug.com/1128926, crbug.com/1172387):
-// Test times out flakily.
-AX_TEST_F('ChromeVoxOptionsTest', 'DISABLED_SmartStickyMode', async function() {
-  const [mockFeedback, evt] = await this.loadOptionsPage();
-  const smartStickyModeCheckbox = evt.target.find({
-    role: RoleType.CHECK_BOX,
-    attributes:
-        {name: 'Turn off sticky mode when editing text (Smart Sticky Mode)'},
-  });
-  assertNotNullNorUndefined(smartStickyModeCheckbox);
-  mockFeedback.call(smartStickyModeCheckbox.focus.bind(smartStickyModeCheckbox))
-      .expectSpeech(
-          'Turn off sticky mode when editing text (Smart Sticky Mode)',
-          'Check box', 'Checked')
-      .call(() => {
-        assertEquals('true', SettingsManager.get('smartStickyMode'));
-      })
-      .call(smartStickyModeCheckbox.doDefault.bind(smartStickyModeCheckbox))
-      .expectSpeech(
-          'Turn off sticky mode when editing text (Smart Sticky Mode)',
-          'Check box', 'Not checked')
-      .call(() => {
-        assertEquals('false', SettingsManager.get('smartStickyMode'));
-      });
-
-  await mockFeedback.replay();
-});
-
-// TODO(crbug.com/1169396, crbug.com/1172387):
-// Test times out or crashes flakily.
-AX_TEST_F('ChromeVoxOptionsTest', 'DISABLED_UsePitchChanges', async function() {
-  const [mockFeedback, evt] = await this.loadOptionsPage();
-  const pitchChangesCheckbox = evt.target.find({
-    role: RoleType.CHECK_BOX,
-    attributes: {
-      name: 'Change pitch when speaking element types and quoted, ' +
-          'deleted, bolded, parenthesized, or capitalized text.',
-    },
-  });
-  const capitalStrategySelect = evt.target.find({
-    role: RoleType.POP_UP_BUTTON,
-    attributes: {name: 'When reading capitals:'},
-  });
-  assertNotNullNorUndefined(pitchChangesCheckbox);
-  assertNotNullNorUndefined(capitalStrategySelect);
-
-  // Assert initial pref values.
-  assertTrue(SettingsManager.getBoolean('usePitchChanges'));
-  assertEquals('increasePitch', SettingsManager.getString('capitalStrategy'));
-
-  mockFeedback.call(pitchChangesCheckbox.focus.bind(pitchChangesCheckbox))
-      .expectSpeech(
-          'Change pitch when speaking element types and quoted, ' +
-              'deleted, bolded, parenthesized, or capitalized text.',
-          'Check box', 'Checked')
-      .call(pitchChangesCheckbox.doDefault.bind(pitchChangesCheckbox))
-      .expectSpeech(
-          'Change pitch when speaking element types and quoted, ' +
-              'deleted, bolded, parenthesized, or capitalized text.',
-          'Check box', 'Not checked')
-      .call(() => {
-        assertFalse(SettingsManager.getBoolean('usePitchChanges'));
-        // Toggling usePitchChanges affects capitalStrategy. Ensure that
-        // the preference has been changed and that the 'Increase pitch'
-        // option is hidden.
-        assertEquals(
-            'announceCapitals', SettingsManager.getString('capitalStrategy'));
-
-        // Open the menu first in order to assert this.
-        // const increasePitchOption = evt.target.find({
-        //  role: RoleType.MENU_LIST_OPTION,
-        //  attributes: {name: 'Increase pitch'}
-        //});
-        // assertNotNullNorUndefined(increasePitchOption);
-        // assertTrue(increasePitchOption.state.invisible);
-      })
-      .call(capitalStrategySelect.focus.bind(capitalStrategySelect))
-      .expectSpeech(
-          'When reading capitals:', 'Speak "cap" before letter', 'Collapsed')
-      .call(pitchChangesCheckbox.doDefault.bind(pitchChangesCheckbox))
-      .expectSpeech(
-          'Change pitch when speaking element types and quoted, ' +
-              'deleted, bolded, parenthesized, or capitalized text.',
-          'Check box', 'Checked')
-      .call(() => {
-        assertTrue(SettingsManager.getBoolean('usePitchChanges'));
-        // Ensure that the capitalStrategy preference is restored to its
-        // initial setting and that the 'Increase pitch' option is visible
-        // again.
-        assertEquals(
-            'increasePitch', SettingsManager.getString('capitalStrategy'));
-
-        // Open the menu first in order to assert this.
-        // const increasePitchOption = evt.target.find({
-        //  role: RoleType.MENU_LIST_OPTION,
-        //  attributes: {name: 'Increase pitch'}
-        //});
-        // assertNotNullNorUndefined(increasePitchOption);
-        // assertEquals(undefined, increasePitchOption.state.invisible);
-      })
-      .call(capitalStrategySelect.focus.bind(capitalStrategySelect))
-      .expectSpeech('When reading capitals:', 'Increase pitch', 'Collapsed');
-  await mockFeedback.replay();
-});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/unchecked.png b/chrome/browser/resources/chromeos/accessibility/chromevox/options/unchecked.png
deleted file mode 100644
index a2d04ee5..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/unchecked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/tools/generate_manifest.py b/chrome/browser/resources/chromeos/accessibility/chromevox/tools/generate_manifest.py
index c54b1df..978224c 100755
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/tools/generate_manifest.py
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/tools/generate_manifest.py
@@ -63,6 +63,12 @@
       metavar='NUM',
       help='Whether to generate a guest mode capable manifest')
   parser.add_option(
+      '--is_manifest_v3',
+      default='0',
+      action='store',
+      metavar='NUM',
+      help='Whether to generate a manifest using manifest version 3')
+  parser.add_option(
       '--is_js_compressed',
       default='1',
       action='store',
diff --git a/chrome/browser/resources/chromeos/accessibility/common/flags.js b/chrome/browser/resources/chromeos/accessibility/common/flags.js
index 7795b99..2457ad2c 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/flags.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/flags.js
@@ -8,6 +8,7 @@
 export const FlagName = {
   CHROMEVOX_Q1_FAST_TRACK: 'enable-chromevox-q1-fast-track-features',
   MAGNIFIER_DEBUG_DRAW_RECT: 'enable-magnifier-debug-draw-rect',
+  MANIFEST_V3: 'enable-experimental-accessibility-manifest-v3',
   SWITCH_ACCESS_TEXT: 'enable-experimental-accessibility-switch-access-text',
 };
 
diff --git a/chrome/browser/resources/chromeos/accessibility/manifest.gni b/chrome/browser/resources/chromeos/accessibility/manifest.gni
index afabcfd..5b44aef 100644
--- a/chrome/browser/resources/chromeos/accessibility/manifest.gni
+++ b/chrome/browser/resources/chromeos/accessibility/manifest.gni
@@ -25,6 +25,9 @@
     if (defined(invoker.is_guest_manifest) && invoker.is_guest_manifest) {
       args += [ "--is_guest_manifest=1" ]
     }
+    if (defined(invoker.is_manifest_v3) && invoker.is_manifest_v3) {
+      args += [ "--is_manifest_v3=1" ]
+    }
     args += rebase_path(sources, root_build_dir)
   }
 }
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2
index 0a077ee5..b5cb5a8b 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2
@@ -2,16 +2,24 @@
 {% if key is defined %}
   "key": "{{key}}",
 {% endif %}
+{% if is_manifest_v3 == '1' %}
+  "manifest_version": 3,
+  "background": {
+    "service_worker": "switch_access/switch_access_loader.js",
+    "type": "module"
+  },
+{% else %}
   "manifest_version": 2,
+  "background": {
+    "page": "switch_access/background.html"
+  },
+{% endif %}
   "name": "__MSG_SWITCH_ACCESS_NAME__",
   "version": "{{set_version}}",
   "description": "__MSG_SWITCH_ACCESS_DESCRIPTION__",
 {% if is_guest_manifest == '1' %}
   "incognito": "split",
 {% endif %}
-  "background": {
-    "page": "switch_access/background.html"
-  },
   "permissions": [
     "accessibilityPrivate",
     "clipboard",
diff --git a/chrome/browser/resources/chromeos/quickoffice b/chrome/browser/resources/chromeos/quickoffice
index 79e797d..23bde34 160000
--- a/chrome/browser/resources/chromeos/quickoffice
+++ b/chrome/browser/resources/chromeos/quickoffice
@@ -1 +1 @@
-Subproject commit 79e797d69d4675a2f0ef916dbb65457fe9485fc9
+Subproject commit 23bde3495989fbc0112213613d2498030be51417
diff --git a/chrome/browser/resources/chromeos/web_app_install/BUILD.gn b/chrome/browser/resources/chromeos/web_app_install/BUILD.gn
new file mode 100644
index 0000000..200cb3c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/web_app_install/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2023 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ui/webui/resources/tools/build_webui.gni")
+
+build_webui("build") {
+  grd_prefix = "web_app_install"
+
+  static_files = [ "main.html" ]
+  web_component_files = [ "web_app_install_dialog.ts" ]
+
+  html_to_wrapper_template = "native"
+
+  ts_deps = [
+    "//ui/webui/resources/cr_elements:build_ts",
+    "//ui/webui/resources/js:build_ts",
+  ]
+}
diff --git a/chrome/browser/resources/chromeos/web_app_install/OWNERS b/chrome/browser/resources/chromeos/web_app_install/OWNERS
new file mode 100644
index 0000000..290ee25
--- /dev/null
+++ b/chrome/browser/resources/chromeos/web_app_install/OWNERS
@@ -0,0 +1 @@
+alancutter@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/web_app_install/main.html b/chrome/browser/resources/chromeos/web_app_install/main.html
new file mode 100644
index 0000000..c07d1f0
--- /dev/null
+++ b/chrome/browser/resources/chromeos/web_app_install/main.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+  <head>
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+    <link rel="stylesheet"
+      href="chrome://resources/chromeos/colors/cros_styles.css">
+    <style>
+      body {
+        background-color: var(--cros-bg-color-elevation-3);
+      }
+    </style>
+    <script type="module" src="web_app_install_dialog.js"></script>
+  </head>
+  <body>
+    <web-app-install-dialog></web-app-install-dialog>
+  </body>
+</html>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/web_app_install/web_app_install_dialog.html b/chrome/browser/resources/chromeos/web_app_install/web_app_install_dialog.html
new file mode 100644
index 0000000..b0801c9d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/web_app_install/web_app_install_dialog.html
@@ -0,0 +1,9 @@
+<cr-dialog id="dialog">
+  <div slot="title">Install app</div>
+  <div slot="body">
+    Body
+  </div>
+  <!-- TODO(crbug.com/1488697): Add app details (name, icon, url, description,
+                                screenshots). -->
+  <!-- TODO(crbug.com/1488697): Add install and cancel buttons. -->
+</cr-dialog>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/web_app_install/web_app_install_dialog.ts b/chrome/browser/resources/chromeos/web_app_install/web_app_install_dialog.ts
new file mode 100644
index 0000000..26a3de2
--- /dev/null
+++ b/chrome/browser/resources/chromeos/web_app_install/web_app_install_dialog.ts
@@ -0,0 +1,32 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {getTemplate} from './web_app_install_dialog.html.js';
+
+/**
+ * @fileoverview
+ * 'web-app-install-dialog' defines the UI for the ChromeOS web app install
+ * dialog.
+ */
+
+class WebAppInstallDialogElement extends HTMLElement {
+  static get is() {
+    return 'web-app-install-dialog';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  constructor() {
+    super();
+    const template = document.createElement('template');
+    template.innerHTML = WebAppInstallDialogElement.template as string;
+    const fragment = template.content.cloneNode(true);
+    this.attachShadow({mode: 'open'}).appendChild(fragment);
+  }
+}
+
+customElements.define(
+    WebAppInstallDialogElement.is, WebAppInstallDialogElement);
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html
index 1ad1ab8..6f5f2d7 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html
+++ b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html
@@ -1,6 +1,6 @@
 <style include="cr-icons cr-shared-style">
   :host {
-    background: var(--color-new-tab-page-module-item-background);
+    background-color: var(--color-new-tab-page-module-background);
     border-radius: var(--ntp-module-item-border-radius);
     display: flex;
     flex-direction: column;
@@ -9,7 +9,7 @@
 
   :host([suggestion-chip-header-enabled_]),
   :host([suggestion-chip-header-enabled_]) ntp-module-header-v2 {
-    background: transparent;
+    background-color: inherit;
     border: none;
   }
 
diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.html b/chrome/browser/resources/settings/privacy_page/cookies_page.html
index d25830a..6b42dbca 100644
--- a/chrome/browser/resources/settings/privacy_page/cookies_page.html
+++ b/chrome/browser/resources/settings/privacy_page/cookies_page.html
@@ -129,6 +129,8 @@
             $i18n{trackingProtectionThirdPartyCookiesToggleSubLabel}"
           learn-more-url="
             $i18n{trackingProtectionThirdPartyCookiesLearnMoreUrl}"
+          learn-more-aria-label="
+            $i18n{trackingProtectionThirdPartyCookiesLearnMoreAriaLabel}"
           on-settings-boolean-control-change="onBlockAll3pcToggleChanged_"
           icon="settings:visibility-off">
       </settings-toggle-button>
diff --git a/chrome/browser/resources/settings_shared/controls/settings_toggle_button.html b/chrome/browser/resources/settings_shared/controls/settings_toggle_button.html
index 532bcddf..b797e234 100644
--- a/chrome/browser/resources/settings_shared/controls/settings_toggle_button.html
+++ b/chrome/browser/resources/settings_shared/controls/settings_toggle_button.html
@@ -78,10 +78,13 @@
       </span>
       <template is="dom-if" if="[[learnMoreUrl]]">
         <a id="learn-more" href="[[learnMoreUrl]]" target="_blank"
-            aria-labelledby="sub-label-text learn-more"
+            aria-labelledby$="[[getLearnMoreAriaLabelledBy_(learnMoreAriaLabel)]]"
             on-click="onLearnMoreClick_">
           $i18n{learnMore}
         </a>
+        <span id="learn-more-aria-label" aria-hidden="true" hidden>
+          [[learnMoreAriaLabel]]
+        </span>
       </template>
       <template is="dom-if" if="[[subLabelWithLink]]">
         <div id="sub-label-text-with-link"
diff --git a/chrome/browser/resources/settings_shared/controls/settings_toggle_button.ts b/chrome/browser/resources/settings_shared/controls/settings_toggle_button.ts
index 127e1ee1..b6fc74e 100644
--- a/chrome/browser/resources/settings_shared/controls/settings_toggle_button.ts
+++ b/chrome/browser/resources/settings_shared/controls/settings_toggle_button.ts
@@ -82,6 +82,11 @@
         reflectToAttribute: true,
       },
 
+      learnMoreAriaLabel: {
+        type: String,
+        value: '',
+      },
+
       icon: String,
 
       subLabelIcon: String,
@@ -99,6 +104,7 @@
   ariaShowSublabel: boolean;
   elideLabel: boolean;
   icon: string;
+  learnMoreAriaLabel: string;
   learnMoreUrl: string;
   subLabelWithLink: string;
   subLabelIcon: string;
@@ -133,6 +139,11 @@
     return this.ariaLabel || this.label;
   }
 
+  private getLearnMoreAriaLabelledBy_(): string {
+    return this.learnMoreAriaLabel ? 'learn-more-aria-label' :
+                                     'sub-label-text learn-more';
+  }
+
   private onDisableOrPrefChange_() {
     this.toggleAttribute('effectively-disabled_', this.controlDisabled());
   }
diff --git a/chrome/browser/resources/side_panel/commerce/history_graph.ts b/chrome/browser/resources/side_panel/commerce/history_graph.ts
index d3646a9..fdace06 100644
--- a/chrome/browser/resources/side_panel/commerce/history_graph.ts
+++ b/chrome/browser/resources/side_panel/commerce/history_graph.ts
@@ -285,9 +285,16 @@
       return Math.max(max, value.price);
     }, this.points[0].price);
 
-    // Ensure the line is in the middle of the graph.
-    minPrice = Math.max(minPrice - 1, 0);
-    maxPrice = maxPrice + 1;
+    // To ensure that the Y-axis doesn't reflect trivial changes and that the
+    // line is in the middle of the graph, apply a padding max(median price /
+    // 10, $1) to the minPrice and maxPrice.
+    const medianPrice = ([...this.points].sort(
+        (a, b) => a.price - b.price))[Math.floor(this.points.length / 2)]
+                            .price;
+    const padding = Math.max(medianPrice / 10, 1);
+    minPrice = Math.max(minPrice - padding, 0);
+    maxPrice = maxPrice + padding;
+
     const valueRange = maxPrice - minPrice;
     let tickInterval = valueRange / (TICK_COUNT_Y - 1);
 
diff --git a/chrome/browser/resources/side_panel/customize_chrome/combobox/customize_chrome_combobox.ts b/chrome/browser/resources/side_panel/customize_chrome/combobox/customize_chrome_combobox.ts
index 0a6a9cd..6b1b0c5 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/combobox/customize_chrome_combobox.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/combobox/customize_chrome_combobox.ts
@@ -96,6 +96,48 @@
   }
 
   private onKeydown_(e: KeyboardEvent) {
+    if (this.expanded_) {
+      this.onKeydownExpandedState_(e);
+    } else {
+      this.onKeydownCollapsedState_(e);
+    }
+  }
+
+  private onKeydownCollapsedState_(e: KeyboardEvent) {
+    if (!['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter', 'Space'].includes(
+            e.key)) {
+      return;
+    }
+
+    e.preventDefault();
+    e.stopPropagation();
+
+    this.expanded_ = true;
+    if (this.highlightedElement_) {
+      // If an item is already highlighted, nothing to do.
+      return;
+    }
+
+    // Highlight the first item for most keys, unless the key is ArrowUp/End.
+    let elementToHighlight = this.highlightableElements_[0];
+    if (e.key === 'ArrowUp' || e.key === 'End') {
+      elementToHighlight =
+          this.highlightableElements_[this.highlightableElements_.length - 1];
+    }
+
+    if (elementToHighlight) {
+      this.highlightElement_(elementToHighlight);
+    }
+  }
+
+  private onKeydownExpandedState_(e: KeyboardEvent) {
+    if (e.key === 'Escape') {
+      e.preventDefault();
+      e.stopPropagation();
+      this.expanded_ = false;
+      return;
+    }
+
     if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key)) {
       return;
     }
@@ -127,9 +169,7 @@
       index = 0;
     }
 
-    if (this.expanded_) {
-      this.highlightElement_(this.highlightableElements_[index]!);
-    }
+    this.highlightElement_(this.highlightableElements_[index]!);
   }
 }
 
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc
index f81a8046..2ebeef5b 100644
--- a/chrome/browser/themes/theme_service_unittest.cc
+++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -35,6 +35,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/color/color_mixers.h"
 #include "components/supervised_user/core/common/buildflags.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/test_utils.h"
@@ -231,7 +232,9 @@
       ui::LinuxUi::SetInstance(linux_ui);
 #endif  // BUILDFLAG(IS_LINUX)
 
-      // Add the Chrome ColorMixers after native ColorMixers.
+      // Add the components and Chrome ColorMixers after native ColorMixers.
+      ui::ColorProviderManager::Get().AppendColorProviderInitializer(
+          base::BindRepeating(color::AddComponentsColorMixers));
       ui::ColorProviderManager::Get().AppendColorProviderInitializer(
           base::BindRepeating(AddChromeColorMixers));
 
diff --git a/chrome/browser/tpcd/support/DEPS b/chrome/browser/tpcd/support/DEPS
new file mode 100644
index 0000000..e721398
--- /dev/null
+++ b/chrome/browser/tpcd/support/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/origin_trials/browser",
+]
diff --git a/chrome/browser/tpcd/support/tpcd_support_browsertest.cc b/chrome/browser/tpcd/support/tpcd_support_browsertest.cc
index 00387b9..5fd71bb 100644
--- a/chrome/browser/tpcd/support/tpcd_support_browsertest.cc
+++ b/chrome/browser/tpcd/support/tpcd_support_browsertest.cc
@@ -11,6 +11,7 @@
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/content_settings/core/common/features.h"
 #include "components/content_settings/core/common/pref_names.h"
@@ -35,12 +36,26 @@
 using content::URLLoaderInterceptor;
 using content::WebContents;
 
+namespace tpcd::support {
 namespace {
 
 const char kTestTokenPublicKey[] =
     "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=,fMS4mpO6buLQ/QMd+zJmxzty/"
     "VQ6B1EUZqoCU04zoRU=";
 
+const char kTrialEnabledDomain[] = "example.test";
+const char kTrialEnabledIframePath[] = "origin-trial-iframe";
+const char kEmbeddedScriptPagePath[] =
+    "tpcd/page_with_cross_site_tpcd_support_ot.html";
+// Origin Trials token for `kTrialEnabledSite` generated with:
+// tools/origin_trials/generate_token.py --expire-days 5000
+// https://example.test Tpcd
+const char kTrialToken[] =
+    "A1F5vUG256mdaDWxcpAddjWWg7LdOPuoEBswgFVy8b3j0ejT56eJ+e+"
+    "IBocST6j2C8nYcnDm6gkd5O7M3FMo4AIAAABPeyJvcmlnaW4iOiAiaHR0cHM6Ly"
+    "9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiVHBjZCIsICJleHBpcnkiO"
+    "iAyMTI0MzA4MDY1fQ==";
+
 class ContentSettingChangeObserver : public content_settings::Observer {
  public:
   explicit ContentSettingChangeObserver(
@@ -110,7 +125,7 @@
         net::EmbeddedTestServer::TYPE_HTTPS);
     https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
     https_server_->AddDefaultHandlers(
-        base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+        base::FilePath(FILE_PATH_LITERAL("chrome/test/data/")));
     ASSERT_TRUE(https_server_->Start());
 
     // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
@@ -147,136 +162,135 @@
   }
 
   bool OnRequest(content::URLLoaderInterceptor::RequestParams* params) {
-    if (params->url_request.url == kEnrolledSiteWithToken) {
-      // Origin Trials key generated with:
-      //
-      // tools/origin_trials/generate_token.py --expire-days 5000
-      // --is-third-party https://example.test Tpcd
-      //
-      // Note that you can't have an origin trial token with expiry more than
-      // 2^31-1 seconds past the epoch, so (for instance) --expire-days 10000
-      // would not have generated a valid token.
+    std::string path = params->url_request.url.path().substr(1);
+
+    if (path.find("tpcd/") == 0) {
       content::URLLoaderInterceptor::WriteResponse(
-          base::ReplaceStringPlaceholders(
-              "HTTP/1.1 200 OK\n"
-              "Content-type: text/html\n"
-              "Origin-Trial: $1\n\n",
-              {"A1F5vUG256mdaDWxcpAddjWWg7LdOPuoEBswgFVy8b3j0ejT56eJ+e+"
-               "IBocST6j2C8nYcnDm6gkd5O7M3FMo4AIAAABPeyJvcmlnaW4iOiAiaHR0cHM6Ly"
-               "9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiVHBjZCIsICJleHBpcnkiO"
-               "iAyMTI0MzA4MDY1fQ=="},
-              /*offsets=*/nullptr),
-          /*body=*/"", params->client.get());
+          base::StrCat(
+              {"chrome/test/data/", params->url_request.url.path_piece()}),
+          params->client.get());
       return true;
     }
-    return false;
+
+    if (params->url_request.url.host() != kTrialEnabledDomain) {
+      return false;
+    }
+
+    std::string headers =
+        "HTTP/1.1 200 OK\n"
+        "Content-type: text/html\n";
+
+    if (path == kTrialEnabledIframePath) {
+      base::StrAppend(&headers, {"Origin-Trial: ", kTrialToken, "\n"});
+    }
+
+    content::URLLoaderInterceptor::WriteResponse(headers,
+                                                 /*body=*/"",
+                                                 params->client.get());
+    return true;
   }
 
   base::test::ScopedFeatureList features_;
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
   std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_;
-  const GURL kEnrolledSiteWithToken{"https://example.test/with-token"};
+  const GURL kTrialEnabledSite{base::StrCat({"https://", kTrialEnabledDomain})};
 };
 
 IN_PROC_BROWSER_TEST_F(TpcdSupportBrowserTest,
-                       ThirdPartyIframeEnrolledAfterResponse) {
+                       EnabledAfterThirdPartyIframeResponse) {
   content::WebContents* web_contents = GetActiveWebContents();
   GURL embedding_site =
       embedded_test_server()->GetURL("a.test", "/iframe_blank.html");
 
-  // Verify the enrolled site does not have cookie access as a third-party.
+  // Verify `kTrialEnabledSite` does not have cookie access as a third-party.
   content_settings::CookieSettings* settings =
       CookieSettingsFactory::GetForProfile(GetProfile()).get();
-  EXPECT_EQ(
-      settings->GetCookieSetting(kEnrolledSiteWithToken, GURL(), {}, nullptr),
-      CONTENT_SETTING_BLOCK);
-  EXPECT_EQ(settings->GetCookieSetting(kEnrolledSiteWithToken, embedding_site,
-                                       {}, nullptr),
+  EXPECT_EQ(settings->GetCookieSetting(kTrialEnabledSite, GURL(), {}, nullptr),
+            CONTENT_SETTING_BLOCK);
+  EXPECT_EQ(settings->GetCookieSetting(kTrialEnabledSite, embedding_site, {},
+                                       nullptr),
             CONTENT_SETTING_BLOCK);
 
-  // Navigate the top-level page to |embedding_site| and update it to have an
-  // iframe pointing to the enrolled site.
+  // Navigate the top-level page to `embedding_site` and update it to have an
+  // `kTrialEnabledSite` iframe that returns the origin trial token in it's HTTP
+  // response headers.
   ASSERT_TRUE(content::NavigateToURL(web_contents, embedding_site));
   const std::string kIframeId = "test";  // defined in iframe_blank.html
   {
     ContentSettingChangeObserver setting_observer(
-        web_contents->GetBrowserContext(), kEnrolledSiteWithToken,
-        embedding_site, ContentSettingsType::TPCD_SUPPORT);
+        web_contents->GetBrowserContext(), kTrialEnabledSite, embedding_site,
+        ContentSettingsType::TPCD_SUPPORT);
 
-    ASSERT_TRUE(content::NavigateIframeToURL(web_contents, kIframeId,
-                                             kEnrolledSiteWithToken));
+    GURL iframe_url = GURL(kTrialEnabledSite.spec() + kTrialEnabledIframePath);
+    ASSERT_TRUE(
+        content::NavigateIframeToURL(web_contents, kIframeId, iframe_url));
     setting_observer.Wait();
   }
 
-  // Check that the enrolled site now has access to cookies as a third-party
-  // when embedded by |embedding_site|.
-  EXPECT_EQ(settings->GetCookieSetting(kEnrolledSiteWithToken, embedding_site,
+  // Check that `kTrialEnabledSite` now has access to cookies as a third-party
+  // when embedded by `embedding_site`.
+  EXPECT_EQ(settings->GetCookieSetting(kTrialEnabledSite, embedding_site, {},
+                                       nullptr),
+            CONTENT_SETTING_ALLOW);
+
+  // TODO (crbug.com/1466156): Actually attempt to read cookies for
+  // `kTrialEnabledSite` as a third-party.
+
+  // Check cookie access for `kTrialEnabledSite` with a different path and port
+  // (since it's generated by `https_server_`).
+  GURL enabled_site_diff_path =
+      GURL(kTrialEnabledSite.spec() + "/iframe_blank.html");
+
+  EXPECT_EQ(settings->GetCookieSetting(enabled_site_diff_path, embedding_site,
                                        {}, nullptr),
             CONTENT_SETTING_ALLOW);
 
-  // TODO (crbug.com/1466156): Actually attempt to read the enrolled site's
-  // cookie as a third-party.
-
-  // Check cookie access for |enrolled_site| with a different path and port
-  // (since it's generated by |https_server|).
-  GURL enrolled_site_diff_path = https_server_->GetURL(
-      kEnrolledSiteWithToken.host(), "/iframe_blank.html");
-
-  EXPECT_EQ(settings->GetCookieSetting(enrolled_site_diff_path, embedding_site,
-                                       {}, nullptr),
-            CONTENT_SETTING_ALLOW);
-
-  // Verify that a subsequent load of a resource from the enrolled site on the
-  // embedding site without the token (|enrolled_site_diff_path|) un-enrolls it.
+  // Verify that a subsequent load of a resource from `kTrialEnabledSite` on the
+  // embedding site without the token (`enabled_site_diff_path`) removes the
+  // `TPCD_SUPPORT` content setting for it it.
   {
     ContentSettingChangeObserver setting_observer(
-        web_contents->GetBrowserContext(), enrolled_site_diff_path,
+        web_contents->GetBrowserContext(), enabled_site_diff_path,
         embedding_site, ContentSettingsType::TPCD_SUPPORT);
     ASSERT_TRUE(content::NavigateIframeToURL(web_contents, kIframeId,
-                                             enrolled_site_diff_path));
+                                             enabled_site_diff_path));
     setting_observer.Wait();
   }
 
-  // Verify the enrolled site no longer has cookie access.
-  EXPECT_EQ(settings->GetCookieSetting(kEnrolledSiteWithToken, embedding_site,
+  // Verify `kTrialEnabledSite` no longer has cookie access.
+  EXPECT_EQ(settings->GetCookieSetting(kTrialEnabledSite, embedding_site, {},
+                                       nullptr),
+            CONTENT_SETTING_BLOCK);
+  EXPECT_EQ(settings->GetCookieSetting(enabled_site_diff_path, embedding_site,
                                        {}, nullptr),
             CONTENT_SETTING_BLOCK);
 }
 
-IN_PROC_BROWSER_TEST_F(TpcdSupportBrowserTest,
-                       EnrolledUsingDifferentSubDomain) {
+IN_PROC_BROWSER_TEST_F(TpcdSupportBrowserTest, EnabledAfterMetaTagAppend) {
   content::WebContents* web_contents = GetActiveWebContents();
-  GURL embedding_site =
-      embedded_test_server()->GetURL("a.test", "/iframe_blank.html");
+  GURL embedding_site{
+      base::StrCat({"https://a.test/", kEmbeddedScriptPagePath})};
 
-  // Navigate the top-level page to |embedding_site| and update it to have an
-  // iframe pointing to the enrolled site.
-  ASSERT_TRUE(content::NavigateToURL(web_contents, embedding_site));
-  const std::string kIframeId = "test";  // defined in iframe_blank.html
+  // Navigate to a page with an embedded script (sourced from
+  // `kTrialEnabledSite`), that enables the trial for `kTrialEnabledSite` by
+  // appending a meta tag containing `kTrialEnabledSite`'s third-party origin
+  // trial token to the head of the page.
   {
     ContentSettingChangeObserver setting_observer(
-        web_contents->GetBrowserContext(), kEnrolledSiteWithToken,
-        embedding_site, ContentSettingsType::TPCD_SUPPORT);
+        web_contents->GetBrowserContext(), kTrialEnabledSite, embedding_site,
+        ContentSettingsType::TPCD_SUPPORT);
 
-    ASSERT_TRUE(content::NavigateIframeToURL(web_contents, kIframeId,
-                                             kEnrolledSiteWithToken));
+    ASSERT_TRUE(content::NavigateToURL(web_contents, embedding_site));
     setting_observer.Wait();
   }
 
-  // Verify that the enrolled site now has access to cookies as a third-party
-  // when embedded by |embedding_site|.
+  // Verify that `kTrialEnabledSite` now has access to cookies as a third-party
+  // when embedded by `embedding_site`.
   content_settings::CookieSettings* settings =
       CookieSettingsFactory::GetForProfile(GetProfile()).get();
-  EXPECT_EQ(settings->GetCookieSetting(kEnrolledSiteWithToken, embedding_site,
-                                       {}, nullptr),
-            CONTENT_SETTING_ALLOW);
-
-  // Check cookie access for a subdomain on |enrolled_site|.
-  GURL enrolled_site_subdomain = https_server_->GetURL(
-      "sub." + kEnrolledSiteWithToken.host(), "/iframe_blank.html");
-  EXPECT_EQ(settings->GetCookieSetting(enrolled_site_subdomain, embedding_site,
-                                       {}, nullptr),
+  EXPECT_EQ(settings->GetCookieSetting(kTrialEnabledSite, embedding_site, {},
+                                       nullptr),
             CONTENT_SETTING_ALLOW);
 }
 
-// TODO(crbug.com/1466156): add test case(s) for tokens sent during redirects.
+}  // namespace tpcd::support
diff --git a/chrome/browser/tpcd/support/tpcd_support_manager.cc b/chrome/browser/tpcd/support/tpcd_support_manager.cc
deleted file mode 100644
index bfc8433..0000000
--- a/chrome/browser/tpcd/support/tpcd_support_manager.cc
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/tpcd/support/tpcd_support_manager.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/functional/callback_helpers.h"
-#include "chrome/browser/content_settings/host_content_settings_map_factory.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"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/origin_trials_controller_delegate.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/common/content_features.h"
-#include "services/network/public/mojom/cookie_manager.mojom.h"
-
-/* static */
-void TpcdSupportManager::MaybeCreateForWebContents(
-    content::WebContents* web_contents) {
-  if (!base::FeatureList::IsEnabled(features::kPersistentOriginTrials)) {
-    return;
-  }
-
-  // TODO (crbug.com/1466156): condition creation on the type of profile
-  // associated with the WebContents.
-  TpcdSupportManager::CreateForWebContents(
-      web_contents,
-      std::make_unique<TpcdSupportDelegate>(web_contents->GetBrowserContext()));
-}
-
-TpcdSupportManager::TpcdSupportManager(
-    content::WebContents* web_contents,
-    std::unique_ptr<TpcdSupportDelegate> delegate)
-    : content::WebContentsObserver(web_contents),
-      content::WebContentsUserData<TpcdSupportManager>(*web_contents),
-      delegate_(std::move(delegate)) {}
-
-TpcdSupportManager::~TpcdSupportManager() = default;
-
-void TpcdSupportDelegate::Update3pcdSupportSettings(
-    const url::Origin& request_origin,
-    const url::Origin& partition_origin,
-    bool enrolled) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  HostContentSettingsMap* settings_map =
-      HostContentSettingsMapFactory::GetForProfile(browser_context_);
-  CHECK(settings_map);
-
-  const GURL request_site_as_url = net::SchemefulSite(request_origin).GetURL();
-  const GURL partition_site_as_url =
-      net::SchemefulSite(partition_origin).GetURL();
-
-  // Check for an existing enrollment setting for the pair.
-  content_settings::SettingInfo info;
-  bool existing_setting = (settings_map->GetContentSetting(
-                               request_site_as_url, partition_site_as_url,
-                               ContentSettingsType::TPCD_SUPPORT,
-                               &info) == CONTENT_SETTING_ALLOW) &&
-                          !info.primary_pattern.MatchesAllHosts() &&
-                          !info.secondary_pattern.MatchesAllHosts();
-  // If the enrollment status matches existing settings, there is no need to
-  // update |settings_map|.
-  if (enrolled == existing_setting) {
-    return;
-  }
-
-  if (enrolled) {
-    settings_map->SetContentSettingDefaultScope(
-        request_site_as_url, partition_site_as_url,
-        ContentSettingsType::TPCD_SUPPORT, CONTENT_SETTING_ALLOW);
-  } else {
-    ContentSettingsPattern primary_site_pattern =
-        ContentSettingsPattern::CreateBuilder()
-            ->WithScheme(request_site_as_url.scheme())
-            ->WithDomainWildcard()
-            ->WithHost(request_site_as_url.host())
-            ->WithPathWildcard()
-            ->WithPortWildcard()
-            ->Build();
-    ContentSettingsPattern secondary_site_pattern =
-        ContentSettingsPattern::CreateBuilder()
-            ->WithScheme(partition_site_as_url.scheme())
-            ->WithDomainWildcard()
-            ->WithHost(partition_site_as_url.host())
-            ->WithPathWildcard()
-            ->WithPortWildcard()
-            ->Build();
-
-    // Remove settings for expired/unused pairs to avoid memory bloat.
-    auto matches_pair =
-        [&](const ContentSettingPatternSource& setting) -> bool {
-      return (setting.primary_pattern == primary_site_pattern) &&
-             (setting.secondary_pattern == secondary_site_pattern);
-    };
-
-    settings_map->ClearSettingsForOneTypeWithPredicate(
-        ContentSettingsType::TPCD_SUPPORT, matches_pair);
-  }
-
-  ContentSettingsForOneType enrollments =
-      settings_map->GetSettingsForOneType(ContentSettingsType::TPCD_SUPPORT);
-
-  browser_context_->GetDefaultStoragePartition()
-      ->GetCookieManagerForBrowserProcess()
-      ->SetContentSettings(ContentSettingsType::TPCD_SUPPORT,
-                           std::move(enrollments), base::NullCallback());
-}
-
-// Persistent Origin Trials can only be checked on the UI thread.
-void TpcdSupportManager::Check3pcdTrialOnUiThread(
-    ContentSettingUpdateCallback done_callback,
-    const url::Origin& request_origin,
-    const url::Origin& partition_origin) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  content::OriginTrialsControllerDelegate* trial_delegate =
-      WebContentsObserver::web_contents()
-          ->GetBrowserContext()
-          ->GetOriginTrialsControllerDelegate();
-  if (!trial_delegate) {
-    return;
-  }
-
-  bool enrolled = trial_delegate->IsFeaturePersistedForOrigin(
-      request_origin, partition_origin, blink::mojom::OriginTrialFeature::kTpcd,
-      base::Time::Now());
-
-  std::move(done_callback)
-      .Run(std::move(request_origin), std::move(partition_origin), enrolled);
-}
-
-void TpcdSupportManager::Check3pcdTrialAsync(
-    ContentSettingUpdateCallback done_callback,
-    const url::Origin& request_origin,
-    const url::Origin& partition_origin) {
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(&TpcdSupportManager::Check3pcdTrialOnUiThread,
-                     weak_factory_.GetWeakPtr(), std::move(done_callback),
-                     std::move(request_origin), std::move(partition_origin)));
-}
-
-void TpcdSupportManager::Update3pcdSupportSettings(
-    const url::Origin& request_origin,
-    const url::Origin& partition_origin,
-    bool enrolled) {
-  delegate_->Update3pcdSupportSettings(request_origin, partition_origin,
-                                       enrolled);
-}
-
-void TpcdSupportManager::OnNavigationResponse(
-    content::NavigationHandle* navigation_handle) {
-  // Navigations in the outermost main frame should not be considered.
-  if (navigation_handle->IsInOutermostMainFrame()) {
-    return;
-  }
-
-  url::Origin request_origin = url::Origin::Create(navigation_handle->GetURL());
-  url::Origin partition_origin = WebContentsObserver::web_contents()
-                                     ->GetPrimaryMainFrame()
-                                     ->GetLastCommittedOrigin();
-
-  if (request_origin.opaque() || partition_origin.opaque()) {
-    return;
-  }
-
-  Check3pcdTrialAsync(
-      base::BindOnce(&TpcdSupportManager::Update3pcdSupportSettings,
-                     weak_factory_.GetWeakPtr()),
-      std::move(request_origin), std::move(partition_origin));
-}
-
-void TpcdSupportManager::DidRedirectNavigation(
-    content::NavigationHandle* navigation_handle) {
-  OnNavigationResponse(navigation_handle);
-}
-
-void TpcdSupportManager::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  OnNavigationResponse(navigation_handle);
-}
-
-WEB_CONTENTS_USER_DATA_KEY_IMPL(TpcdSupportManager);
diff --git a/chrome/browser/tpcd/support/tpcd_support_manager.h b/chrome/browser/tpcd/support/tpcd_support_manager.h
deleted file mode 100644
index 2e7c0d6..0000000
--- a/chrome/browser/tpcd/support/tpcd_support_manager.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_MANAGER_H_
-#define CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_MANAGER_H_
-
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-class TpcdSupportDelegate {
- public:
-  explicit TpcdSupportDelegate(content::BrowserContext* browser_context)
-      : browser_context_(browser_context) {}
-
-  virtual ~TpcdSupportDelegate() = default;
-  // Updates ContentSettingsForOneType::TPCD_SUPPORT to reflect
-  // |origin|'s enrollment status (when embedded by |partition_origin|).
-  void Update3pcdSupportSettings(const url::Origin& origin,
-                                 const url::Origin& partition_origin,
-                                 bool enrolled);
-
- private:
-  raw_ptr<content::BrowserContext> browser_context_;
-};
-
-// Observes a WebContents to detect changes in enrollment and
-// update TPCD_SUPPORT content settings appropriately.
-class TpcdSupportManager
-    : public content::WebContentsObserver,
-      public content::WebContentsUserData<TpcdSupportManager> {
- public:
-  using ContentSettingUpdateCallback =
-      base::OnceCallback<void(const url::Origin& request_origin,
-                              const url::Origin& partition_origin,
-                              bool enrolled)>;
-
-  static void MaybeCreateForWebContents(content::WebContents* web_contents);
-
-  ~TpcdSupportManager() override;
-  TpcdSupportManager(const TpcdSupportManager&) = delete;
-  TpcdSupportManager& operator=(const TpcdSupportManager&) = delete;
-
- private:
-  // So WebContentsUserData::CreateForWebContents() can call the constructor.
-  friend class content::WebContentsUserData<TpcdSupportManager>;
-
-  explicit TpcdSupportManager(content::WebContents* web_contents,
-                              std::unique_ptr<TpcdSupportDelegate> delegate);
-
-  // Updates ContentSettingsForOneType::TPCD_SUPPORT to reflect
-  // |origin|'s enrollment status (when embedded by |partition_origin|).
-  void Update3pcdSupportSettings(const url::Origin& origin,
-                                 const url::Origin& partition_origin,
-                                 bool enrolled);
-  void Check3pcdTrialOnUiThread(ContentSettingUpdateCallback done_callback,
-                                const url::Origin& request_origin,
-                                const url::Origin& partition_origin);
-  // Post a call to the UI thread to check the enrollment status of
-  // |request_origin| (when embedded by |partition_origin|).
-  void Check3pcdTrialAsync(ContentSettingUpdateCallback done_callback,
-                           const url::Origin& request_origin,
-                           const url::Origin& partition_origin);
-
-  void OnNavigationResponse(content::NavigationHandle* navigation_handle);
-
-  // WebContentsObserver overrides:
-  void DidRedirectNavigation(
-      content::NavigationHandle* navigation_handle) override;
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override;
-
-  std::unique_ptr<TpcdSupportDelegate> delegate_;
-  base::WeakPtrFactory<TpcdSupportManager> weak_factory_{this};
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
-};
-
-#endif  // CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_MANAGER_H_
diff --git a/chrome/browser/tpcd/support/tpcd_support_service.cc b/chrome/browser/tpcd/support/tpcd_support_service.cc
new file mode 100644
index 0000000..0e752e5e3
--- /dev/null
+++ b/chrome/browser/tpcd/support/tpcd_support_service.cc
@@ -0,0 +1,131 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/tpcd/support/tpcd_support_service.h"
+
+#include "base/functional/callback_helpers.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.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"
+#include "components/content_settings/core/common/content_settings_utils.h"
+#include "components/origin_trials/browser/origin_trials.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace tpcd::support {
+namespace {
+
+const char kTrialName[] = "Tpcd";
+}  // namespace
+
+TpcdSupportService::TpcdSupportService(content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {
+  ot_controller_ = browser_context->GetOriginTrialsControllerDelegate();
+
+  if (ot_controller_) {
+    ot_controller_->AddObserver(this);
+  }
+}
+
+TpcdSupportService::~TpcdSupportService() = default;
+
+void TpcdSupportService::Shutdown() {
+  if (ot_controller_) {
+    ot_controller_->RemoveObserver(this);
+  }
+
+  ot_controller_ = nullptr;
+  browser_context_ = nullptr;
+}
+
+void TpcdSupportService::Update3pcdSupportSettings(
+    const url::Origin& request_origin,
+    const std::string& partition_site,
+    bool enabled) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  HostContentSettingsMap* settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser_context_);
+  CHECK(settings_map);
+
+  const GURL request_site_as_url = net::SchemefulSite(request_origin).GetURL();
+  const GURL partition_site_as_url = GURL(partition_site);
+
+  // Check for an existing `TPCD_SUPPORT` setting that allows the pair.
+  content_settings::SettingInfo existing_setting_info;
+  bool setting_exists =
+      (settings_map->GetContentSetting(
+           request_site_as_url, partition_site_as_url,
+           ContentSettingsType::TPCD_SUPPORT,
+           &existing_setting_info) == CONTENT_SETTING_ALLOW) &&
+      !existing_setting_info.primary_pattern.MatchesAllHosts() &&
+      !existing_setting_info.secondary_pattern.MatchesAllHosts();
+
+  // If the trial status matches existing settings, there is no need to
+  // update `settings_map`.
+  if (enabled == setting_exists) {
+    return;
+  }
+
+  if (enabled) {
+    settings_map->SetContentSettingDefaultScope(
+        request_site_as_url, partition_site_as_url,
+        ContentSettingsType::TPCD_SUPPORT, CONTENT_SETTING_ALLOW);
+  } else {
+    CHECK(setting_exists);
+
+    // Remove settings for expired/unused pairs to avoid memory bloat.
+    auto matches_pair =
+        [&](const ContentSettingPatternSource& setting) -> bool {
+      return (setting.primary_pattern ==
+              existing_setting_info.primary_pattern) &&
+             (setting.secondary_pattern ==
+              existing_setting_info.secondary_pattern);
+    };
+
+    settings_map->ClearSettingsForOneTypeWithPredicate(
+        ContentSettingsType::TPCD_SUPPORT, matches_pair);
+  }
+
+  ContentSettingsForOneType tpcd_support_settings =
+      settings_map->GetSettingsForOneType(ContentSettingsType::TPCD_SUPPORT);
+
+  browser_context_->GetDefaultStoragePartition()
+      ->GetCookieManagerForBrowserProcess()
+      ->SetContentSettings(ContentSettingsType::TPCD_SUPPORT,
+                           std::move(tpcd_support_settings),
+                           base::NullCallback());
+}
+
+void TpcdSupportService::ClearTpcdSupportSettings() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  HostContentSettingsMap* settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser_context_);
+  CHECK(settings_map);
+
+  settings_map->ClearSettingsForOneType(ContentSettingsType::TPCD_SUPPORT);
+}
+
+void TpcdSupportService::OnStatusChanged(const url::Origin& origin,
+                                         const std::string& partition_site,
+                                         bool enabled) {
+  Update3pcdSupportSettings(origin, partition_site, enabled);
+}
+
+void TpcdSupportService::OnPersistedTokensCleared() {
+  ClearTpcdSupportSettings();
+};
+
+std::string TpcdSupportService::trial_name() {
+  return kTrialName;
+}
+
+}  // namespace tpcd::support
diff --git a/chrome/browser/tpcd/support/tpcd_support_service.h b/chrome/browser/tpcd/support/tpcd_support_service.h
new file mode 100644
index 0000000..a6e3077
--- /dev/null
+++ b/chrome/browser/tpcd/support/tpcd_support_service.h
@@ -0,0 +1,53 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_SERVICE_H_
+#define CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_SERVICE_H_
+
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/origin_trials_controller_delegate.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace tpcd::support {
+
+// A profile-keyed service that maintains TPCD_SUPPORT content settings based on
+// the state of the associated origin trial for a given
+// `origin`-`partition_site` pair.
+class TpcdSupportService
+    : public content::OriginTrialsControllerDelegate::Observer,
+      public KeyedService {
+ public:
+  explicit TpcdSupportService(content::BrowserContext* browser_context);
+  ~TpcdSupportService() override;
+  TpcdSupportService(const TpcdSupportService&) = delete;
+  TpcdSupportService& operator=(const TpcdSupportService&) = delete;
+
+  // KeyedService overrides:
+  void Shutdown() override;
+
+ private:
+  // Updates ContentSettingsForOneType::TPCD_SUPPORT to reflect
+  // the status of the trial for `origin` (when embedded by `partition_site`).
+  void Update3pcdSupportSettings(const url::Origin& origin,
+                                 const std::string& partition_site,
+                                 bool enabled);
+  void ClearTpcdSupportSettings();
+
+  // content::OriginTrialsControllerDelegate::Observer overrides:
+  void OnStatusChanged(const url::Origin& origin,
+                       const std::string& partition_site,
+                       bool enabled) override;
+  void OnPersistedTokensCleared() override;
+  std::string trial_name() override;
+
+  raw_ptr<content::OriginTrialsControllerDelegate> ot_controller_;
+  raw_ptr<content::BrowserContext> browser_context_;
+};
+
+}  // namespace tpcd::support
+
+#endif  // CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_SERVICE_H_
diff --git a/chrome/browser/tpcd/support/tpcd_support_service_factory.cc b/chrome/browser/tpcd/support/tpcd_support_service_factory.cc
new file mode 100644
index 0000000..4854c9a
--- /dev/null
+++ b/chrome/browser/tpcd/support/tpcd_support_service_factory.cc
@@ -0,0 +1,61 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/tpcd/support/tpcd_support_service_factory.h"
+
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/origin_trials/origin_trials_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tpcd/support/tpcd_support_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_features.h"
+#include "net/base/features.h"
+
+namespace tpcd::support {
+
+// static
+TpcdSupportServiceFactory* TpcdSupportServiceFactory::GetInstance() {
+  static base::NoDestructor<TpcdSupportServiceFactory> factory;
+  return factory.get();
+}
+
+// static
+TpcdSupportService* TpcdSupportServiceFactory::GetForProfile(Profile* profile) {
+  return static_cast<TpcdSupportService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+ProfileSelections TpcdSupportServiceFactory::CreateProfileSelections() {
+  if (!base::FeatureList::IsEnabled(net::features::kTpcdSupportSettings) ||
+      !base::FeatureList::IsEnabled(features::kPersistentOriginTrials)) {
+    return ProfileSelections::BuildNoProfilesSelected();
+  }
+
+  return ProfileSelections::Builder()
+      .WithRegular(ProfileSelection::kOriginalOnly)
+      .WithGuest(ProfileSelection::kOwnInstance)
+      // The Following will be completely unselected as users do not "browse"
+      // within this profiles.
+      .WithSystem(ProfileSelection::kNone)
+      .WithAshInternals(ProfileSelection::kNone)
+      .Build();
+}
+
+TpcdSupportServiceFactory::TpcdSupportServiceFactory()
+    : ProfileKeyedServiceFactory("TpcdSupportService",
+                                 CreateProfileSelections()) {
+  DependsOn(OriginTrialsFactory::GetInstance());
+  DependsOn(HostContentSettingsMapFactory::GetInstance());
+}
+
+TpcdSupportServiceFactory::~TpcdSupportServiceFactory() = default;
+
+KeyedService* TpcdSupportServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return new TpcdSupportService(context);
+}
+
+}  // namespace tpcd::support
diff --git a/chrome/browser/tpcd/support/tpcd_support_service_factory.h b/chrome/browser/tpcd/support/tpcd_support_service_factory.h
new file mode 100644
index 0000000..cc2a7802
--- /dev/null
+++ b/chrome/browser/tpcd/support/tpcd_support_service_factory.h
@@ -0,0 +1,43 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace tpcd::support {
+class TpcdSupportService;
+
+class TpcdSupportServiceFactory : public ProfileKeyedServiceFactory {
+ public:
+  static TpcdSupportServiceFactory* GetInstance();
+  static TpcdSupportService* GetForProfile(Profile* profile);
+  static ProfileSelections CreateProfileSelections();
+
+  TpcdSupportServiceFactory(const TpcdSupportServiceFactory&) = delete;
+  TpcdSupportServiceFactory& operator=(const TpcdSupportServiceFactory&) =
+      delete;
+  TpcdSupportServiceFactory(TpcdSupportServiceFactory&&) = delete;
+  TpcdSupportServiceFactory& operator=(TpcdSupportServiceFactory&&) = delete;
+
+ private:
+  friend class base::NoDestructor<TpcdSupportServiceFactory>;
+
+  TpcdSupportServiceFactory();
+  ~TpcdSupportServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+}  // namespace tpcd::support
+
+#endif  // CHROME_BROWSER_TPCD_SUPPORT_TPCD_SUPPORT_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 8a685ecb..e075ecec 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1481,7 +1481,6 @@
       "tabs/saved_tab_groups/saved_tab_group_web_contents_listener.cc",
       "tabs/saved_tab_groups/saved_tab_group_web_contents_listener.h",
       "tabs/supports_handles.h",
-      "tabs/tab.h",
       "tabs/tab_change_type.h",
       "tabs/tab_group.cc",
       "tabs/tab_group.h",
@@ -1494,6 +1493,8 @@
       "tabs/tab_menu_model.h",
       "tabs/tab_menu_model_factory.cc",
       "tabs/tab_menu_model_factory.h",
+      "tabs/tab_model.cc",
+      "tabs/tab_model.h",
       "tabs/tab_network_state.cc",
       "tabs/tab_network_state.h",
       "tabs/tab_renderer_data.cc",
@@ -1579,8 +1580,6 @@
       "user_notes/user_notes_controller.h",
       "views/eye_dropper/eye_dropper.cc",
       "views/eye_dropper/eye_dropper.h",
-      "views/eye_dropper/eye_dropper_view.cc",
-      "views/eye_dropper/eye_dropper_view.h",
       "webui/access_code_cast/access_code_cast_dialog.cc",
       "webui/access_code_cast/access_code_cast_dialog.h",
       "webui/access_code_cast/access_code_cast_handler.cc",
@@ -3285,6 +3284,16 @@
       "webui/ash/settings/pages/files/one_drive_page_handler.h",
       "webui/ash/settings/pages/files/one_drive_page_handler_factory.cc",
       "webui/ash/settings/pages/files/one_drive_page_handler_factory.h",
+      "webui/ash/settings/pages/internet/internet_handler.cc",
+      "webui/ash/settings/pages/internet/internet_handler.h",
+      "webui/ash/settings/pages/internet/internet_section.cc",
+      "webui/ash/settings/pages/internet/internet_section.h",
+      "webui/ash/settings/pages/kerberos/kerberos_accounts_handler.cc",
+      "webui/ash/settings/pages/kerberos/kerberos_accounts_handler.h",
+      "webui/ash/settings/pages/kerberos/kerberos_section.cc",
+      "webui/ash/settings/pages/kerberos/kerberos_section.h",
+      "webui/ash/settings/pages/languages/languages_section.cc",
+      "webui/ash/settings/pages/languages/languages_section.h",
       "webui/ash/settings/pages/people/account_manager_ui_handler.cc",
       "webui/ash/settings/pages/people/account_manager_ui_handler.h",
       "webui/ash/settings/pages/people/fingerprint_handler.cc",
@@ -3336,6 +3345,10 @@
       "webui/ash/vc_tray_tester/vc_tray_tester_ui.h",
       "webui/ash/vm/vm_ui.cc",
       "webui/ash/vm/vm_ui.h",
+      "webui/ash/web_app_install/web_app_install_dialog.cc",
+      "webui/ash/web_app_install/web_app_install_dialog.h",
+      "webui/ash/web_app_install/web_app_install_ui.cc",
+      "webui/ash/web_app_install/web_app_install_ui.h",
       "webui/chromeos/chrome_url_disabled/chrome_url_disabled_ui.cc",
       "webui/chromeos/chrome_url_disabled/chrome_url_disabled_ui.h",
       "webui/extensions/ash/kiosk_apps_handler.cc",
@@ -3370,16 +3383,6 @@
       "webui/settings/ash/display_settings/display_settings_provider.h",
       "webui/settings/ash/hierarchy.cc",
       "webui/settings/ash/hierarchy.h",
-      "webui/settings/ash/internet_handler.cc",
-      "webui/settings/ash/internet_handler.h",
-      "webui/settings/ash/internet_section.cc",
-      "webui/settings/ash/internet_section.h",
-      "webui/settings/ash/kerberos_accounts_handler.cc",
-      "webui/settings/ash/kerberos_accounts_handler.h",
-      "webui/settings/ash/kerberos_section.cc",
-      "webui/settings/ash/kerberos_section.h",
-      "webui/settings/ash/languages_section.cc",
-      "webui/settings/ash/languages_section.h",
       "webui/settings/ash/main_section.cc",
       "webui/settings/ash/main_section.h",
       "webui/settings/ash/metrics_consent_handler.cc",
@@ -3836,6 +3839,7 @@
       "startup/silent_sync_enabler.h",
       "views/chrome_browser_main_extra_parts_views_lacros.cc",
       "views/chrome_browser_main_extra_parts_views_lacros.h",
+      "views/eye_dropper/eye_dropper_lacros.cc",
       "views/frame/browser_frame_lacros.cc",
       "views/frame/browser_frame_lacros.h",
       "views/frame/desktop_browser_frame_lacros.cc",
@@ -6189,7 +6193,7 @@
       "views/apps/shaped_app_window_targeter.cc",
       "views/apps/shaped_app_window_targeter.h",
       "views/dropdown_bar_host_aura.cc",
-      "views/eye_dropper/eye_dropper_view_aura.cc",
+      "views/eye_dropper/eye_dropper_aura.cc",
       "views/renderer_context_menu/render_view_context_menu_views.cc",
       "views/renderer_context_menu/render_view_context_menu_views.h",
       "views/tab_contents/chrome_web_contents_view_delegate_views.cc",
@@ -6199,6 +6203,7 @@
       "window_sizer/window_sizer_aura.cc",
     ]
     deps += [
+      "//components/eye_dropper",
       "//ui/aura",
       "//ui/wm",
     ]
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 739f6bb..3f99ebc 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -212,6 +212,8 @@
 #if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/browser/apps/intent_helper/supported_links_infobar_delegate.h"
 #include "chromeos/ui/wm/features.h"
+#else
+#include "chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h"
 #endif
 
 #if BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)
@@ -1993,6 +1995,8 @@
 #if BUILDFLAG(IS_CHROMEOS)
   apps::SupportedLinksInfoBarDelegate::RemoveSupportedLinksInfoBar(
       web_contents);
+#else
+  apps::EnableLinkCapturingInfoBarDelegate::RemoveInfoBar(web_contents);
 #endif
   target_browser->window()->Show();
   return target_browser;
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm
index d4fe79e6..370825f 100644
--- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm
+++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm
@@ -222,17 +222,12 @@
                                    colorProvider:color_provider
                           useWithPopUpButtonCell:NO];
 
-  gfx::Point params_position(params_.x, params_.y);
-  // TODO(dfried): this is almost certainly wrong; let's fix it.
-  [menu_controller_delegate_ setAnchorRect:gfx::Rect(params_position, {1, 1})];
-
   // Synthesize an event for the click, as there is no certainty that
   // [NSApp currentEvent] will return a valid event.
   NSEvent* currentEvent = [NSApp currentEvent];
   NSWindow* window = [parent_view_ window];
   NSPoint position =
-      NSMakePoint(params_position.x(),
-                  NSHeight([parent_view_ bounds]) - params_position.y());
+      NSMakePoint(params_.x, NSHeight(parent_view_.bounds) - params_.y);
   position = [parent_view_ convertPoint:position toView:nil];
   NSTimeInterval eventTime = [currentEvent timestamp];
   NSEvent* clickEvent = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
diff --git a/chrome/browser/ui/color/BUILD.gn b/chrome/browser/ui/color/BUILD.gn
index e2cdfed7..6cdc9f0 100644
--- a/chrome/browser/ui/color/BUILD.gn
+++ b/chrome/browser/ui/color/BUILD.gn
@@ -9,6 +9,7 @@
 
   public_deps = [
     "//chrome/browser:theme_properties",
+    "//components/color:color_headers",
     "//ui/color:color_headers",
   ]
 }
@@ -94,6 +95,7 @@
       ":color_headers",
       ":mixers",
       "//chrome/browser",
+      "//components/color",
       "//ui/color:mixers",
     ]
 
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h
index 63c1c3d..a1aadf5 100644
--- a/chrome/browser/ui/color/chrome_color_id.h
+++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_COLOR_CHROME_COLOR_ID_H_
 
 #include "chrome/browser/themes/theme_properties.h"
+#include "components/color/color_id.h"
 #include "ui/color/color_id.h"
 
 // TODO(pkasting): Add the rest of the colors.
@@ -106,11 +107,6 @@
   E_CPONLY(kColorExtensionMenuPinButtonIconDisabled) \
   E_CPONLY(kColorExtensionsMenuHighlightedBackground) \
   E_CPONLY(kColorExtensionsToolbarControlsBackground) \
-  /* Eyedropper colors. */ \
-  E_CPONLY(kColorEyedropperBoundary) \
-  E_CPONLY(kColorEyedropperCentralPixelInnerRing) \
-  E_CPONLY(kColorEyedropperCentralPixelOuterRing) \
-  E_CPONLY(kColorEyedropperGrid) \
   /* Feature Promo bubble colors. */ \
   E_CPONLY(kColorFeaturePromoBubbleBackground) \
   E_CPONLY(kColorFeaturePromoBubbleButtonBorder) \
@@ -754,7 +750,7 @@
 #include "ui/color/color_id_macros.inc"
 
 enum ChromeColorIds : ui::ColorId {
-  kChromeColorsStart = ui::kUiColorsEnd,
+  kChromeColorsStart = color::kComponentsColorsEnd,
 
   CHROME_COLOR_IDS
 
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc
index 865582f0..a5585a00 100644
--- a/chrome/browser/ui/color/chrome_color_mixer.cc
+++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -227,10 +227,6 @@
       ui::kColorSysNeutralContainer};
   mixer[kColorExtensionsToolbarControlsBackground] = {
       kColorToolbarBackgroundSubtleEmphasis};
-  mixer[kColorEyedropperBoundary] = {SK_ColorDKGRAY};
-  mixer[kColorEyedropperCentralPixelInnerRing] = {SK_ColorBLACK};
-  mixer[kColorEyedropperCentralPixelOuterRing] = {SK_ColorWHITE};
-  mixer[kColorEyedropperGrid] = {SK_ColorGRAY};
   mixer[kColorFeaturePromoBubbleBackground] = {gfx::kGoogleBlue700};
   mixer[kColorFeaturePromoBubbleButtonBorder] = {gfx::kGoogleGrey300};
   mixer[kColorFeaturePromoBubbleCloseButtonInkDrop] = {gfx::kGoogleBlue300};
diff --git a/chrome/browser/ui/color/new_tab_page_color_mixer.cc b/chrome/browser/ui/color/new_tab_page_color_mixer.cc
index 96aa545d..e9957a4 100644
--- a/chrome/browser/ui/color/new_tab_page_color_mixer.cc
+++ b/chrome/browser/ui/color/new_tab_page_color_mixer.cc
@@ -156,12 +156,11 @@
   if (base::FeatureList::IsEnabled(ntp_features::kNtpModulesRedesigned)) {
     mixer[kColorNewTabPageModuleBackground] = SelectBasedOnWhiteInput(
         {kColorNewTabPageBackground}, gfx::kGoogleGrey100,
-        kColorNewTabPageBackground);
-    mixer[kColorNewTabPageModuleItemBackground] = element_background_color;
+        element_background_color);
   } else {
     mixer[kColorNewTabPageModuleBackground] = element_background_color;
-    mixer[kColorNewTabPageModuleItemBackground] = {kColorNewTabPageBackground};
   }
+  mixer[kColorNewTabPageModuleItemBackground] = {kColorNewTabPageBackground};
 
   mixer[kColorNewTabPageHistoryClustersModuleItemBackground] =
       SelectBasedOnWhiteInput(element_background_color, gfx::kGoogleGrey100,
diff --git a/chrome/browser/ui/color/tools/dump_colors.cc b/chrome/browser/ui/color/tools/dump_colors.cc
index 385be61..6ad9ee4 100644
--- a/chrome/browser/ui/color/tools/dump_colors.cc
+++ b/chrome/browser/ui/color/tools/dump_colors.cc
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/color/chrome_color_mixers.h"
+#include "components/color/color_mixers.h"
 #include "ui/color/color_mixers.h"
 #include "ui/color/color_provider.h"
 #include "ui/color/color_provider_utils.h"
@@ -52,6 +53,7 @@
     key.color_mode = color_mode;
     key.contrast_mode = contrast_mode;
     ui::AddColorMixers(provider, key);
+    color::AddComponentsColorMixers(provider, key);
     AddChromeColorMixers(provider, key);
     provider->GenerateColorMap();
   };
diff --git a/chrome/browser/ui/intent_picker_tab_helper.cc b/chrome/browser/ui/intent_picker_tab_helper.cc
index 6f42c55..109b2f4 100644
--- a/chrome/browser/ui/intent_picker_tab_helper.cc
+++ b/chrome/browser/ui/intent_picker_tab_helper.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/functional/bind.h"
+#include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
@@ -346,8 +347,9 @@
   browser->window()->UpdatePageActionIcon(PageActionIconType::kIntentPicker);
 
   icon_resolved_after_last_navigation_ = true;
-  if (icon_update_closure_)
-    std::move(icon_update_closure_).Run();
+  if (icon_update_closure_for_testing_) {
+    std::move(icon_update_closure_for_testing_).Run();
+  }
 }
 
 void IntentPickerTabHelper::ShowIntentPickerOrLaunchAppImpl(
@@ -436,7 +438,7 @@
     std::move(callback).Run();
     return;
   }
-  icon_update_closure_ = std::move(callback);
+  icon_update_closure_for_testing_ = std::move(callback);
 }
 
 void IntentPickerTabHelper::DidStartNavigation(
diff --git a/chrome/browser/ui/intent_picker_tab_helper.h b/chrome/browser/ui/intent_picker_tab_helper.h
index 1c7a974..6de91a1 100644
--- a/chrome/browser/ui/intent_picker_tab_helper.h
+++ b/chrome/browser/ui/intent_picker_tab_helper.h
@@ -146,7 +146,7 @@
   bool current_app_is_preferred_ = false;
   ui::ImageModel current_app_icon_;
 
-  base::OnceClosure icon_update_closure_;
+  base::OnceClosure icon_update_closure_for_testing_;
 
   base::ScopedObservation<web_app::WebAppInstallManager,
                           web_app::WebAppInstallManagerObserver>
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index b930203..ed316a8 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -84,7 +84,6 @@
 #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
 #include "chrome/browser/tab_contents/navigation_metrics_recorder.h"
 #include "chrome/browser/tpcd/heuristics/opener_heuristic_tab_helper.h"
-#include "chrome/browser/tpcd/support/tpcd_support_manager.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/trusted_vault/trusted_vault_encryption_keys_tab_helper.h"
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
@@ -374,7 +373,6 @@
   CoreTabHelper::CreateForWebContents(web_contents);
   DIPSWebContentsObserver::MaybeCreateForWebContents(web_contents);
   ExternalProtocolObserver::CreateForWebContents(web_contents);
-  TpcdSupportManager::MaybeCreateForWebContents(web_contents);
   favicon::CreateContentFaviconDriverForWebContents(web_contents);
   FileSystemAccessPermissionRequestManager::CreateForWebContents(web_contents);
   FileSystemAccessTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/tabs/tab.h b/chrome/browser/ui/tabs/tab.h
deleted file mode 100644
index 35896ae..0000000
--- a/chrome/browser/ui/tabs/tab.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_TABS_TAB_H_
-#define CHROME_BROWSER_UI_TABS_TAB_H_
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "components/tab_groups/tab_group_id.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-template <typename TContents>
-class TabBase {
- public:
-  explicit TabBase(std::unique_ptr<TContents> contents)
-      : contents_(std::move(contents)) {}
-
-  TabBase(const TabBase&) = delete;
-  TabBase& operator=(const TabBase&) = delete;
-
-  TContents* contents() const { return contents_.get(); }
-  TContents* opener() const { return opener_; }
-  bool reset_opener_on_active_tab_change() const {
-    return reset_opener_on_active_tab_change_;
-  }
-  bool pinned() const { return pinned_; }
-  bool blocked() const { return blocked_; }
-  absl::optional<tab_groups::TabGroupId> group() const { return group_; }
-
-  void set_contents(std::unique_ptr<TContents> contents) {
-    contents_ = contents;
-  }
-  void set_opener(TContents* opener) { opener_ = opener; }
-  void set_reset_opener_on_active_tab_change(
-      bool reset_opener_on_active_tab_change) {
-    reset_opener_on_active_tab_change_ = reset_opener_on_active_tab_change;
-  }
-  void set_pinned(bool pinned) { pinned_ = pinned; }
-  void set_blocked(bool blocked) { blocked_ = blocked; }
-  void set_group(absl::optional<tab_groups::TabGroupId> group) {
-    group_ = group;
-  }
-
-  std::unique_ptr<TContents> ReplaceContents(
-      std::unique_ptr<TContents> contents) {
-    contents_.swap(contents);
-    return contents;
-  }
-
- private:
-  std::unique_ptr<TContents> contents_;
-  raw_ptr<TContents> opener_ = nullptr;
-  bool reset_opener_on_active_tab_change_ = false;
-  bool pinned_ = false;
-  bool blocked_ = false;
-  absl::optional<tab_groups::TabGroupId> group_ = absl::nullopt;
-};
-
-#endif  // CHROME_BROWSER_UI_TABS_TAB_H_
diff --git a/chrome/browser/ui/tabs/tab_model.cc b/chrome/browser/ui/tabs/tab_model.cc
new file mode 100644
index 0000000..d269f53
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_model.cc
@@ -0,0 +1,19 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/tabs/tab_model.h"
+
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
+
+TabModel::TabModel(std::unique_ptr<content::WebContents> contents)
+    : contents_(std::move(contents)) {}
+
+TabModel::~TabModel() = default;
+
+void TabModel::WriteIntoTrace(perfetto::TracedValue context) const {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("web_contents", contents());
+  dict.Add("pinned", pinned());
+  dict.Add("blocked", blocked());
+}
diff --git a/chrome/browser/ui/tabs/tab_model.h b/chrome/browser/ui/tabs/tab_model.h
new file mode 100644
index 0000000..96c1789f
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_model.h
@@ -0,0 +1,64 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_TABS_TAB_MODEL_H_
+#define CHROME_BROWSER_UI_TABS_TAB_MODEL_H_
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "components/tab_groups/tab_group_id.h"
+#include "content/public/browser/web_contents.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
+
+class TabModel {
+ public:
+  explicit TabModel(std::unique_ptr<content::WebContents> contents);
+  ~TabModel();
+
+  TabModel(const TabModel&) = delete;
+  TabModel& operator=(const TabModel&) = delete;
+
+  content::WebContents* contents() const { return contents_.get(); }
+  content::WebContents* opener() const { return opener_; }
+  bool reset_opener_on_active_tab_change() const {
+    return reset_opener_on_active_tab_change_;
+  }
+  bool pinned() const { return pinned_; }
+  bool blocked() const { return blocked_; }
+  absl::optional<tab_groups::TabGroupId> group() const { return group_; }
+
+  void set_contents(std::unique_ptr<content::WebContents> contents) {
+    contents_ = std::move(contents);
+  }
+  void set_opener(content::WebContents* opener) { opener_ = opener; }
+  void set_reset_opener_on_active_tab_change(
+      bool reset_opener_on_active_tab_change) {
+    reset_opener_on_active_tab_change_ = reset_opener_on_active_tab_change;
+  }
+  void set_pinned(bool pinned) { pinned_ = pinned; }
+  void set_blocked(bool blocked) { blocked_ = blocked; }
+  void set_group(absl::optional<tab_groups::TabGroupId> group) {
+    group_ = group;
+  }
+
+  void WriteIntoTrace(perfetto::TracedValue context) const;
+
+  std::unique_ptr<content::WebContents> ReplaceContents(
+      std::unique_ptr<content::WebContents> contents) {
+    contents_.swap(contents);
+    return contents;
+  }
+
+ private:
+  std::unique_ptr<content::WebContents> contents_;
+  raw_ptr<content::WebContents> opener_ = nullptr;
+  bool reset_opener_on_active_tab_change_ = false;
+  bool pinned_ = false;
+  bool blocked_ = false;
+  absl::optional<tab_groups::TabGroupId> group_ = absl::nullopt;
+};
+
+#endif  // CHROME_BROWSER_UI_TABS_TAB_MODEL_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index b868a4e..b6ba491 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -39,10 +39,10 @@
 #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
-#include "chrome/browser/ui/tabs/tab.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
+#include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
@@ -216,34 +216,6 @@
 DetachedWebContents::~DetachedWebContents() = default;
 DetachedWebContents::DetachedWebContents(DetachedWebContents&&) = default;
 
-///////////////////////////////////////////////////////////////////////////////
-// Tab
-
-// An object to own a WebContents that is in a tabstrip, as well as other
-// various properties it has.
-class TabStripModel::Tab : public TabBase<content::WebContents> {
- public:
-  explicit Tab(std::unique_ptr<content::WebContents> content)
-      : TabBase<content::WebContents>(std::move(content)) {}
-
-  // Changes the WebContents that this Tab tracks.
-  std::unique_ptr<content::WebContents> ReplaceWebContents(
-      std::unique_ptr<content::WebContents> contents);
-  WebContents* web_contents() { return contents(); }
-
-  void WriteIntoTrace(perfetto::TracedValue context) const {
-    auto dict = std::move(context).WriteDictionary();
-    dict.Add("web_contents", contents());
-    dict.Add("pinned", pinned());
-    dict.Add("blocked", blocked());
-  }
-};
-
-std::unique_ptr<content::WebContents> TabStripModel::Tab::ReplaceWebContents(
-    std::unique_ptr<content::WebContents> contents) {
-  return ReplaceContents(std::move(contents));
-}
-
 // Holds all state necessary to send notifications for detached tabs.
 struct TabStripModel::DetachNotifications {
   DetachNotifications(WebContents* initially_active_web_contents,
@@ -356,7 +328,7 @@
   TabStripSelectionChange selection(GetActiveWebContents(), selection_model_);
   WebContents* raw_new_contents = new_contents.get();
   std::unique_ptr<WebContents> old_contents =
-      contents_data_[index]->ReplaceWebContents(std::move(new_contents));
+      contents_data_[index]->ReplaceContents(std::move(new_contents));
 
   // When the active WebContents is replaced send out a selection notification
   // too. We do this as nearly all observers need to treat a replacement of the
@@ -430,7 +402,7 @@
 
   for (auto& observer : observers_) {
     observer.OnTabWillBeRemoved(
-        contents_data_[index_at_time_of_removal]->web_contents(),
+        contents_data_[index_at_time_of_removal]->contents(),
         index_at_time_of_removal);
   }
 
@@ -449,7 +421,7 @@
 
   UngroupTab(index_at_time_of_removal);
 
-  std::unique_ptr<Tab> old_data =
+  std::unique_ptr<TabModel> old_data =
       std::move(contents_data_[index_at_time_of_removal]);
   contents_data_.erase(contents_data_.begin() + index_at_time_of_removal);
 
@@ -476,7 +448,7 @@
     }
   }
 
-  auto owned_contents = old_data->ReplaceWebContents(nullptr);
+  auto owned_contents = old_data->ReplaceContents(nullptr);
   auto* contents = owned_contents.get();
   return std::make_unique<DetachedWebContents>(
       index_before_any_removals, index_at_time_of_removal,
@@ -499,8 +471,8 @@
 
   TabStripModelChange::Remove remove;
   for (auto& dwc : notifications->detached_web_contents) {
-    remove.contents.push_back({dwc->contents, dwc->index_before_any_removals,
-                               dwc->remove_reason, dwc->id});
+    remove.contents.emplace_back(dwc->contents, dwc->index_before_any_removals,
+                                 dwc->remove_reason, dwc->id);
   }
   TabStripModelChange change(std::move(remove));
 
@@ -645,8 +617,9 @@
 
 int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const {
   for (size_t i = 0; i < contents_data_.size(); ++i) {
-    if (contents_data_[i]->web_contents() == contents)
+    if (contents_data_[i]->contents() == contents) {
       return i;
+    }
   }
   return kNoTab;
 }
@@ -708,8 +681,9 @@
 
 bool TabStripModel::TabsAreLoading() const {
   for (const auto& data : contents_data_) {
-    if (data->web_contents()->IsLoading())
+    if (data->contents()->IsLoading()) {
       return true;
+    }
   }
 
   return false;
@@ -748,7 +722,7 @@
         continue;
       break;
     }
-    opener_and_descendants.insert(contents_data_[i]->web_contents());
+    opener_and_descendants.insert(contents_data_[i]->contents());
     last_index = i;
   }
   return last_index;
@@ -779,8 +753,7 @@
     return;
   contents_data_[index]->set_blocked(blocked);
   for (auto& observer : observers_)
-    observer.TabBlockedStateChanged(contents_data_[index]->web_contents(),
-                                    index);
+    observer.TabBlockedStateChanged(contents_data_[index]->contents(), index);
 }
 
 int TabStripModel::SetTabPinned(int index, bool pinned) {
@@ -1828,7 +1801,8 @@
   // since the old contents and the new contents will be the same...
   WebContents* active_contents = GetActiveWebContents();
   WebContents* raw_contents = contents.get();
-  std::unique_ptr<Tab> data = std::make_unique<Tab>(std::move(contents));
+  std::unique_ptr<TabModel> data =
+      std::make_unique<TabModel>(std::move(contents));
   data->set_pinned(pin);
   if ((add_types & ADD_INHERIT_OPENER) && active_contents) {
     if (active) {
@@ -2013,7 +1987,7 @@
 WebContents* TabStripModel::GetWebContentsAtImpl(int index) const {
   CHECK(ContainsIndex(index))
       << "Failed to find: " << index << " in: " << count() << " entries.";
-  return contents_data_[index]->web_contents();
+  return contents_data_[index]->contents();
 }
 
 TabStripSelectionChange TabStripModel::SetSelection(
@@ -2154,8 +2128,8 @@
 
   CHECK_LT(index, static_cast<int>(contents_data_.size()));
   CHECK_LT(to_position, static_cast<int>(contents_data_.size()));
-  std::unique_ptr<Tab> moved_data = std::move(contents_data_[index]);
-  WebContents* web_contents = moved_data->web_contents();
+  std::unique_ptr<TabModel> moved_data = std::move(contents_data_[index]);
+  WebContents* web_contents = moved_data->contents();
   contents_data_.erase(contents_data_.begin() + index);
   contents_data_.insert(contents_data_.begin() + to_position,
                         std::move(moved_data));
@@ -2218,7 +2192,7 @@
   if (!group_model_)
     return;
 
-  DCHECK(!base::Contains(contents_data_, new_group, &Tab::group));
+  DCHECK(!base::Contains(contents_data_, new_group, &TabModel::group));
   group_model_->AddTabGroup(new_group, absl::nullopt);
 
   // Find a destination for the first tab that's not pinned or inside another
@@ -2387,8 +2361,8 @@
   // Update the tab.
   contents_data_[index]->set_group(absl::nullopt);
   for (auto& observer : observers_) {
-    observer.TabGroupedStateChanged(
-        absl::nullopt, contents_data_[index]->web_contents(), index);
+    observer.TabGroupedStateChanged(absl::nullopt,
+                                    contents_data_[index]->contents(), index);
   }
 
   // Update the group model.
@@ -2415,8 +2389,8 @@
   }
   contents_data_[index]->set_group(group);
   for (auto& observer : observers_) {
-    observer.TabGroupedStateChanged(
-        group, contents_data_[index]->web_contents(), index);
+    observer.TabGroupedStateChanged(group, contents_data_[index]->contents(),
+                                    index);
   }
 
   group_model_->GetTabGroup(group)->AddTab();
@@ -2474,7 +2448,7 @@
   }
 
   for (auto& observer : observers_) {
-    observer.TabPinnedStateChanged(this, contents_data_[index]->web_contents(),
+    observer.TabPinnedStateChanged(this, contents_data_[index]->contents(),
                                    index);
   }
 
@@ -2564,15 +2538,15 @@
       continue;
 
     // Ensure a tab isn't its own opener.
-    data->set_opener(new_opener == data->web_contents() ? nullptr : new_opener);
+    data->set_opener(new_opener == data->contents() ? nullptr : new_opener);
   }
 
   // Sanity check that none of the tabs' openers refer |old_contents| or
   // themselves.
   DCHECK(!base::ranges::any_of(
-      contents_data_, [old_contents](const std::unique_ptr<Tab>& data) {
+      contents_data_, [old_contents](const std::unique_ptr<TabModel>& data) {
         return data->opener() == old_contents ||
-               data->opener() == data->web_contents();
+               data->opener() == data->contents();
       }));
 }
 
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 2158fa7..19eeb03 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -40,6 +40,7 @@
 class TabGroupModel;
 class TabStripModelDelegate;
 class TabStripModelObserver;
+class TabModel;
 
 namespace content {
 class WebContents;
@@ -583,7 +584,6 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(TabStripModelTest, GetIndicesClosedByCommand);
 
-  class Tab;
   struct DetachNotifications;
 
   // Perform tasks associated with changes to the model. Change the Active Index
@@ -805,7 +805,7 @@
 
   // The WebContents data currently hosted within this TabStripModel. This must
   // be kept in sync with |selection_model_|.
-  std::vector<std::unique_ptr<Tab>> contents_data_;
+  std::vector<std::unique_ptr<TabModel>> contents_data_;
 
   // The model for tab groups hosted within this TabStripModel.
   std::unique_ptr<TabGroupModel> group_model_;
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc
index 3fd92db..61b8e72 100644
--- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc
@@ -18,7 +18,7 @@
 #include "components/autofill/core/browser/data_model/autofill_offer_data.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
-#include "components/commerce/core/commerce_utils.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc
index 2dae61f..eb5e780 100644
--- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc
@@ -27,7 +27,7 @@
 #include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/autofill/core/browser/ui/payments/payments_bubble_closed_reasons.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
-#include "components/commerce/core/commerce_utils.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/mock_shopping_service.h"
 #include "components/commerce/core/test_utils.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc
index 5b843ad..84dd42c 100644
--- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc
@@ -11,7 +11,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/core/browser/data_model/autofill_offer_data.h"
 #include "components/autofill/core/browser/payments/offer_notification_options.h"
-#include "components/commerce/core/commerce_utils.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "content/public/test/browser_test.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_icon_view_interactive_uitest.cc
index 8b94606..f6095c1 100644
--- a/chrome/browser/ui/views/autofill/payments/offer_notification_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_icon_view_interactive_uitest.cc
@@ -13,7 +13,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "components/autofill/core/common/autofill_clock.h"
-#include "components/commerce/core/commerce_utils.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/mock_shopping_service.h"
 #include "components/commerce/core/test_utils.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
diff --git a/chrome/browser/ui/views/enable_link_capturing_infobar_browsertest.cc b/chrome/browser/ui/views/enable_link_capturing_infobar_browsertest.cc
new file mode 100644
index 0000000..3c53d454
--- /dev/null
+++ b/chrome/browser/ui/views/enable_link_capturing_infobar_browsertest.cc
@@ -0,0 +1,493 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <tuple>
+
+#include "base/functional/callback_forward.h"
+#include "base/ranges/algorithm.h"
+#include "base/test/metrics/user_action_tester.h"
+#include "base/test/test_future.h"
+#include "chrome/browser/apps/app_service/app_registry_cache_waiter.h"
+#include "chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h"
+#include "chrome/browser/apps/link_capturing/intent_picker_info.h"
+#include "chrome/browser/apps/link_capturing/link_capturing_features.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/intent_picker_tab_helper.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/page_action/page_action_icon_view.h"
+#include "chrome/browser/ui/views/page_action/page_action_icon_view_observer.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/ui/web_applications/test/web_app_navigation_browsertest.h"
+#include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registry_update.h"
+#include "chrome/browser/web_applications/web_app_sync_bridge.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/infobars/content/content_infobar_manager.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "components/infobars/core/infobar.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/test/button_test_api.h"
+#include "ui/views/widget/any_widget_observer.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace web_app {
+namespace {
+
+content::WebContents* GetActiveWebContents(Browser* browser) {
+  return browser->tab_strip_model()->GetActiveWebContents();
+}
+
+// TODO(dmurph): Remove this after all of the updating to the launch page action
+// view and we can know that updating is synchronous. https://crbug.com/1491258
+class OneOffIconObserver : public PageActionIconViewObserver {
+ public:
+  explicit OneOffIconObserver(base::OnceClosure on_shown)
+      : on_shown_(std::move(on_shown)) {}
+
+  void OnPageActionIconViewShown(PageActionIconView* view) override {
+    std::move(on_shown_).Run();
+    view->RemovePageIconViewObserver(this);
+  }
+
+ private:
+  base::OnceClosure on_shown_;
+};
+
+class EnableLinkCapturingInfobarBrowserTest
+    : public WebAppNavigationBrowserTest {
+ public:
+  EnableLinkCapturingInfobarBrowserTest() {
+    feature_list_.InitAndEnableFeature(
+        apps::features::kDesktopPWAsLinkCapturing);
+  }
+
+  PageActionIconView* GetIntentPickerIcon() {
+    return BrowserView::GetBrowserViewForBrowser(browser())
+        ->toolbar_button_provider()
+        ->GetPageActionIconView(PageActionIconType::kIntentPicker);
+  }
+
+  // Returns [app_id, in_scope_url]
+  std::tuple<AppId, GURL> InstallTestApp() {
+    GURL start_url = embedded_test_server()->GetURL("/web_apps/basic.html");
+    GURL in_scope_url = embedded_test_server()->GetURL("/web_apps/page1.html");
+
+    AppId app_id =
+        InstallWebAppFromPageAndCloseAppBrowser(browser(), start_url);
+    apps::AppReadinessWaiter(profile(), app_id).Await();
+    return {app_id, in_scope_url};
+  }
+
+  // Returns [outer app_id, inner app_id, inner app in_scope_url]
+  std::tuple<AppId, AppId, GURL> InstallOuterAppAndInnerApp() {
+    GURL outer_start_url =
+        embedded_test_server()->GetURL("/web_apps/nesting/index.html");
+    GURL inner_start_url =
+        embedded_test_server()->GetURL("/web_apps/nesting/nested/index.html");
+    GURL inner_in_scope_url =
+        embedded_test_server()->GetURL("/web_apps/nesting/nested/page1.html");
+
+    // The inner app must be installed first so that it is installable.
+    AppId inner_app_id =
+        InstallWebAppFromPageAndCloseAppBrowser(browser(), inner_start_url);
+    apps::AppReadinessWaiter(profile(), inner_app_id).Await();
+    AppId outer_app_id =
+        InstallWebAppFromPageAndCloseAppBrowser(browser(), outer_start_url);
+    apps::AppReadinessWaiter(profile(), outer_app_id).Await();
+    return {outer_app_id, inner_app_id, inner_in_scope_url};
+  }
+
+  void NavigateViaLinkClick(Browser* browser,
+                            const GURL& url,
+                            LinkTarget link_target = LinkTarget::SELF) {
+    ClickLinkAndWait(GetActiveWebContents(browser), url, link_target,
+                     std::string());
+  }
+
+  infobars::InfoBar* GetLinkCapturingInfoBar(Browser* browser) {
+    return GetLinkCapturingInfoBar(GetActiveWebContents(browser));
+  }
+
+  infobars::InfoBar* GetLinkCapturingInfoBar(
+      content::WebContents* web_contents) {
+    return apps::EnableLinkCapturingInfoBarDelegate::FindInfoBar(web_contents);
+  }
+
+  void TurnOnLinkCapturing(webapps::AppId app_id) {
+    ScopedRegistryUpdate update = provider().sync_bridge_unsafe().BeginUpdate();
+    WebApp* app = update->UpdateApp(app_id);
+    CHECK(app);
+    app->SetIsUserSelectedAppForSupportedLinks(true);
+  }
+
+  testing::AssertionResult ClickIntentPickerAndWaitForBubble() {
+    base::test::TestFuture<void> future;
+    auto* tab_helper =
+        IntentPickerTabHelper::FromWebContents(GetActiveWebContents(browser()));
+    tab_helper->SetIconUpdateCallbackForTesting(
+        future.GetCallback(), /*include_latest_navigation=*/true);
+    if (!future.Wait()) {
+      return testing::AssertionFailure()
+             << "Intent picker app did not resolve an applicable app.";
+    }
+
+    PageActionIconView* intent_picker_icon = GetIntentPickerIcon();
+    if (!intent_picker_icon) {
+      return testing::AssertionFailure()
+             << "Intent picker icon does not exist.";
+    }
+    if (!intent_picker_icon->GetVisible()) {
+      base::test::TestFuture<void> icon_visible;
+      OneOffIconObserver observer(icon_visible.GetCallback());
+      intent_picker_icon->AddPageIconViewObserver(&observer);
+      if (!icon_visible.Wait()) {
+        return testing::AssertionFailure()
+               << "Intent picker icon never became visible.";
+      }
+    }
+    EXPECT_TRUE(intent_picker_icon->GetVisible());
+
+    views::NamedWidgetShownWaiter intent_picker_bubble_shown(
+        views::test::AnyWidgetTestPasskey{},
+        IntentPickerBubbleView::kViewClassName);
+    views::test::ButtonTestApi test_api(intent_picker_icon);
+    test_api.NotifyClick(ui::MouseEvent(
+        ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
+        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+
+    if (!intent_picker_bubble_shown.WaitIfNeededAndGet()) {
+      return testing::AssertionFailure()
+             << "Intent picker bubble did not appear after click.";
+    }
+    CHECK(intent_picker_bubble());
+    return testing::AssertionSuccess();
+  }
+
+  IntentPickerBubbleView* intent_picker_bubble() {
+    return IntentPickerBubbleView::intent_picker_bubble();
+  }
+
+  views::Button* GetIntentPickerButtonAtIndex(size_t index) {
+    CHECK(intent_picker_bubble());
+    auto children =
+        intent_picker_bubble()
+            ->GetViewByID(IntentPickerBubbleView::ViewId::kItemContainer)
+            ->children();
+    CHECK_LT(index, children.size());
+    return static_cast<views::Button*>(children[index]);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest,
+                       InfoBarShowsOnIntentPickerLaunch) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [_, in_scope_url] = InstallTestApp();
+
+  NavigateViaLinkClick(browser(), in_scope_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  ui_test_utils::BrowserChangeObserver browser_added_waiter(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  intent_picker_bubble()->AcceptDialog();
+  Browser* app_browser = browser_added_waiter.Wait();
+  ASSERT_TRUE(app_browser);
+
+  EXPECT_NE(GetLinkCapturingInfoBar(app_browser), nullptr);
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest,
+                       EnableLinkCapturingThroughInfoBar) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [app_id, in_scope_url] = InstallTestApp();
+
+  NavigateViaLinkClick(browser(), in_scope_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  Browser* app_browser;
+  {
+    ui_test_utils::BrowserChangeObserver browser_added_waiter(
+        nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+    intent_picker_bubble()->AcceptDialog();
+    app_browser = browser_added_waiter.Wait();
+    ASSERT_TRUE(app_browser);
+  }
+  infobars::InfoBar* infobar = GetLinkCapturingInfoBar(app_browser);
+  ASSERT_TRUE(infobar);
+
+  base::UserActionTester user_action_tester;
+  // Because there is no testing utility for info bars, manually accept &
+  // remove.
+  EXPECT_TRUE(
+      static_cast<ConfirmInfoBarDelegate*>(infobar->delegate())->Accept());
+  infobar->RemoveSelf();
+  provider().command_manager().AwaitAllCommandsCompleteForTesting();
+
+  EXPECT_EQ(
+      1, user_action_tester.GetActionCount("LinkCapturingAcceptedFromInfoBar"));
+
+  EXPECT_EQ(app_id,
+            provider().registrar_unsafe().FindAppThatCapturesLinksInScope(
+                in_scope_url));
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest,
+                       InfoBarNotShownOnLinkCapturingEnabled) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [app_id, in_scope_url] = InstallTestApp();
+  TurnOnLinkCapturing(app_id);
+
+  ui_test_utils::NavigateToURL(browser(), in_scope_url);
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  ui_test_utils::BrowserChangeObserver browser_added_waiter(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  intent_picker_bubble()->AcceptDialog();
+  Browser* app_browser = browser_added_waiter.Wait();
+  ASSERT_TRUE(app_browser);
+
+  EXPECT_EQ(GetLinkCapturingInfoBar(app_browser), nullptr);
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest,
+                       RecordUserActionCancelled) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [_, in_scope_url] = InstallTestApp();
+
+  NavigateViaLinkClick(browser(), in_scope_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  ui_test_utils::BrowserChangeObserver browser_added_waiter(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  intent_picker_bubble()->AcceptDialog();
+  Browser* app_browser = browser_added_waiter.Wait();
+  ASSERT_TRUE(app_browser);
+
+  infobars::InfoBar* infobar = GetLinkCapturingInfoBar(app_browser);
+  ASSERT_TRUE(infobar);
+
+  base::UserActionTester user_action_tester;
+  // Because there is no testing utility for info bars, manually cancel &
+  // remove.
+  EXPECT_TRUE(
+      static_cast<ConfirmInfoBarDelegate*>(infobar->delegate())->Cancel());
+  infobar->RemoveSelf();
+  provider().command_manager().AwaitAllCommandsCompleteForTesting();
+
+  EXPECT_EQ(1, user_action_tester.GetActionCount(
+                   "LinkCapturingCancelledFromInfoBar"));
+
+  EXPECT_EQ(absl::nullopt,
+            provider().registrar_unsafe().FindAppThatCapturesLinksInScope(
+                in_scope_url));
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest,
+                       RecordUserActionIgnored) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [_, in_scope_url] = InstallTestApp();
+
+  NavigateViaLinkClick(browser(), in_scope_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  ui_test_utils::BrowserChangeObserver browser_added_waiter(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  intent_picker_bubble()->AcceptDialog();
+  Browser* app_browser = browser_added_waiter.Wait();
+  ASSERT_TRUE(app_browser);
+
+  infobars::InfoBar* infobar = GetLinkCapturingInfoBar(app_browser);
+  ASSERT_TRUE(infobar);
+
+  base::UserActionTester user_action_tester;
+
+  CloseBrowserSynchronously(app_browser);
+  provider().command_manager().AwaitAllCommandsCompleteForTesting();
+
+  EXPECT_EQ(
+      1, user_action_tester.GetActionCount("LinkCapturingIgnoredFromInfoBar"));
+
+  EXPECT_EQ(absl::nullopt,
+            provider().registrar_unsafe().FindAppThatCapturesLinksInScope(
+                in_scope_url));
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest, AppLaunched) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [app_id, in_scope_url] = InstallTestApp();
+
+  NavigateViaLinkClick(browser(), in_scope_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  Browser* app_browser;
+  {
+    ui_test_utils::BrowserChangeObserver browser_added_waiter(
+        nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+    intent_picker_bubble()->AcceptDialog();
+    app_browser = browser_added_waiter.Wait();
+    ASSERT_TRUE(app_browser);
+  }
+
+  infobars::InfoBar* infobar = GetLinkCapturingInfoBar(app_browser);
+  ASSERT_TRUE(infobar);
+  base::UserActionTester user_action_tester;
+  EXPECT_TRUE(
+      static_cast<ConfirmInfoBarDelegate*>(infobar->delegate())->Accept());
+  // Because there is no testing utility for info bars, manually remove.
+  infobar->RemoveSelf();
+  provider().command_manager().AwaitAllCommandsCompleteForTesting();
+
+  CloseBrowserSynchronously(app_browser);
+  provider().command_manager().AwaitAllCommandsCompleteForTesting();
+
+  content::TestNavigationObserver observer =
+      content::TestNavigationObserver(GURL(url::kAboutBlankURL));
+  observer.StartWatchingNewWebContents();
+  chrome::AddTabAt(browser(), GURL(url::kAboutBlankURL), /*index=*/-1,
+                   /*foreground=*/true);
+  observer.Wait();
+  {
+    ui_test_utils::BrowserChangeObserver browser_added_waiter(
+        nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+    NavigateViaLinkClick(browser(), in_scope_url);
+    app_browser = browser_added_waiter.Wait();
+    ASSERT_TRUE(app_browser);
+    EXPECT_TRUE(AppBrowserController::IsForWebApp(app_browser, app_id));
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest, BarRemoved) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [_, in_scope_url] = InstallTestApp();
+
+  NavigateViaLinkClick(browser(), in_scope_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  ui_test_utils::BrowserChangeObserver browser_added_waiter(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  intent_picker_bubble()->AcceptDialog();
+  Browser* app_browser = browser_added_waiter.Wait();
+  ASSERT_TRUE(app_browser);
+
+  // The web_contents here is moving to `browser()`, and `app_browser` will be
+  // invalidated, so grab a WeakPtr here.
+  base::WeakPtr<content::WebContents> web_contents =
+      GetActiveWebContents(app_browser)->GetWeakPtr();
+
+  EXPECT_TRUE(GetLinkCapturingInfoBar(web_contents.get()));
+
+  // Note: this will close & invalidate app_browser.
+  Browser* tabbed_browser = chrome::OpenInChrome(app_browser);
+
+  ASSERT_TRUE(web_contents);
+  EXPECT_EQ(web_contents.get(), GetActiveWebContents(tabbed_browser));
+  EXPECT_FALSE(GetLinkCapturingInfoBar(web_contents.get()));
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest,
+                       InfoBarHiddenAfterDismissals) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [_, in_scope_url] = InstallTestApp();
+
+  // Dismiss the infobar twice.
+  for (int i = 0; i < 2; ++i) {
+    NavigateViaLinkClick(browser(), in_scope_url);
+
+    ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+    ui_test_utils::BrowserChangeObserver browser_added_waiter(
+        nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+    intent_picker_bubble()->AcceptDialog();
+    Browser* app_browser = browser_added_waiter.Wait();
+    ASSERT_TRUE(app_browser);
+
+    infobars::InfoBar* infobar = GetLinkCapturingInfoBar(app_browser);
+    ASSERT_TRUE(infobar);
+
+    base::UserActionTester user_action_tester;
+    EXPECT_TRUE(
+        static_cast<ConfirmInfoBarDelegate*>(infobar->delegate())->Cancel());
+    // Because there is no testing utility for info bars, manually remove.
+    infobar->RemoveSelf();
+    provider().command_manager().AwaitAllCommandsCompleteForTesting();
+
+    EXPECT_EQ(1, user_action_tester.GetActionCount(
+                     "LinkCapturingCancelledFromInfoBar"));
+
+    EXPECT_EQ(absl::nullopt,
+              provider().registrar_unsafe().FindAppThatCapturesLinksInScope(
+                  in_scope_url));
+    CloseBrowserSynchronously(app_browser);
+  }
+
+  // Now, the infobar will not show up.
+  NavigateViaLinkClick(browser(), in_scope_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  ui_test_utils::BrowserChangeObserver browser_added_waiter(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  intent_picker_bubble()->AcceptDialog();
+  Browser* app_browser = browser_added_waiter.Wait();
+  ASSERT_TRUE(app_browser);
+
+  infobars::InfoBar* infobar = GetLinkCapturingInfoBar(app_browser);
+  EXPECT_FALSE(infobar);
+}
+
+IN_PROC_BROWSER_TEST_F(EnableLinkCapturingInfobarBrowserTest,
+                       OuterAppNoInfoBar) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const auto [outer_app_id, inner_app_id, inner_app_scoped_url] =
+      InstallOuterAppAndInnerApp();
+
+  NavigateViaLinkClick(browser(), inner_app_scoped_url);
+
+  ASSERT_TRUE(ClickIntentPickerAndWaitForBubble());
+
+  // The app list is currently not deterministically ordered, so find the
+  // correct item and select that.
+  const auto& app_infos = intent_picker_bubble()->app_info_for_testing();
+  auto it = base::ranges::find(app_infos, outer_app_id,
+                               &apps::IntentPickerAppInfo::launch_name);
+  ASSERT_NE(it, app_infos.end());
+  size_t index = it - app_infos.begin();
+
+  ui_test_utils::BrowserChangeObserver browser_added_waiter(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+  views::test::ButtonTestApi test_api(GetIntentPickerButtonAtIndex(index));
+  test_api.NotifyClick(ui::MouseEvent(
+      ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
+      ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+  intent_picker_bubble()->AcceptDialog();
+
+  Browser* app_browser = browser_added_waiter.Wait();
+
+  ASSERT_TRUE(app_browser);
+  EXPECT_TRUE(AppBrowserController::IsWebApp(app_browser));
+  EXPECT_TRUE(AppBrowserController::IsForWebApp(app_browser, outer_app_id));
+  EXPECT_FALSE(GetLinkCapturingInfoBar(app_browser));
+}
+
+}  // namespace
+}  // namespace web_app
diff --git a/chrome/browser/ui/views/eye_dropper/DEPS b/chrome/browser/ui/views/eye_dropper/DEPS
index e566fc70..eb4319e1 100644
--- a/chrome/browser/ui/views/eye_dropper/DEPS
+++ b/chrome/browser/ui/views/eye_dropper/DEPS
@@ -1,3 +1,3 @@
 include_rules = [
-  "+third_party/webrtc",
+  "+components/eye_dropper",
 ]
diff --git a/chrome/browser/ui/views/eye_dropper/OWNERS b/chrome/browser/ui/views/eye_dropper/OWNERS
index 932bb4b0..cc8e0ec 100644
--- a/chrome/browser/ui/views/eye_dropper/OWNERS
+++ b/chrome/browser/ui/views/eye_dropper/OWNERS
@@ -1,2 +1,3 @@
 sajos@microsoft.com
+joelhockey@chromium.org
 pkasting@chromium.org
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_aura.cc b/chrome/browser/ui/views/eye_dropper/eye_dropper_aura.cc
new file mode 100644
index 0000000..faf60f88
--- /dev/null
+++ b/chrome/browser/ui/views/eye_dropper/eye_dropper_aura.cc
@@ -0,0 +1,37 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "build/build_config.h"
+#include "chrome/browser/ui/color/chrome_color_id.h"
+#include "components/eye_dropper/eye_dropper_view.h"
+#include "content/public/browser/eye_dropper.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/base/ui_base_features.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ui/aura/window.h"
+#endif
+
+std::unique_ptr<content::EyeDropper> ShowEyeDropper(
+    content::RenderFrameHost* frame,
+    content::EyeDropperListener* listener) {
+  if (!features::IsEyeDropperEnabled() || !frame->GetView()->HasFocus()) {
+    return nullptr;
+  }
+
+  auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
+  auto* parent = web_contents->GetNativeView();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // Parent on a top-level container to allow moving between displays.
+  parent =
+      parent->GetRootWindow()->GetChildById(ash::kShellWindowId_MenuContainer);
+#endif
+  return std::make_unique<eye_dropper::EyeDropperView>(
+      parent, web_contents->GetNativeView(), listener);
+}
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_browsertest.cc b/chrome/browser/ui/views/eye_dropper/eye_dropper_browsertest.cc
index 071d2e67..591dbd3 100644
--- a/chrome/browser/ui/views/eye_dropper/eye_dropper_browsertest.cc
+++ b/chrome/browser/ui/views/eye_dropper/eye_dropper_browsertest.cc
@@ -20,7 +20,7 @@
 
 // TODO(crbug.com/1448244): enable this test on all supported platforms.
 #if BUILDFLAG(IS_WIN)
-#include "chrome/browser/ui/views/eye_dropper/eye_dropper_view.h"
+#include "components/eye_dropper/eye_dropper_view.h"
 #endif
 
 class EyeDropperBrowserTest : public UiBrowserTest,
@@ -51,7 +51,8 @@
       return false;
 
     views::Widget* widget =
-        static_cast<EyeDropperView*>(eye_dropper_.get())->GetWidget();
+        static_cast<eye_dropper::EyeDropperView*>(eye_dropper_.get())
+            ->GetWidget();
     auto* test_info = testing::UnitTest::GetInstance()->current_test_info();
     const std::string screenshot_name =
         base::StrCat({test_info->test_case_name(), "_", test_info->name()});
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_lacros.cc b/chrome/browser/ui/views/eye_dropper/eye_dropper_lacros.cc
new file mode 100644
index 0000000..68fbe4a
--- /dev/null
+++ b/chrome/browser/ui/views/eye_dropper/eye_dropper_lacros.cc
@@ -0,0 +1,57 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "chromeos/crosapi/mojom/eye_dropper.mojom.h"
+#include "chromeos/lacros/lacros_service.h"
+#include "content/public/browser/eye_dropper.h"
+#include "content/public/browser/eye_dropper_listener.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "ui/base/ui_base_features.h"
+
+namespace {
+
+class SystemEyeDropper : public crosapi::mojom::EyeDropperListener,
+                         public content::EyeDropper {
+ public:
+  explicit SystemEyeDropper(content::EyeDropperListener* listener)
+      : listener_(listener) {
+    chromeos::LacrosService::Get()
+        ->GetRemote<crosapi::mojom::EyeDropper>()
+        ->ShowEyeDropper(receiver.BindNewPipeAndPassRemoteWithVersion());
+  }
+
+  SystemEyeDropper(const SystemEyeDropper&) = delete;
+  SystemEyeDropper& operator=(const SystemEyeDropper&) = delete;
+
+  ~SystemEyeDropper() override = default;
+
+ private:
+  void ColorSelected(SkColor color) override {
+    listener_->ColorSelected(color);
+  }
+
+  void ColorSelectionCanceled() override {
+    listener_->ColorSelectionCanceled();
+  }
+
+  raw_ptr<content::EyeDropperListener> listener_;
+  mojo::Receiver<crosapi::mojom::EyeDropperListener> receiver{this};
+};
+
+}  // namespace
+
+std::unique_ptr<content::EyeDropper> ShowEyeDropper(
+    content::RenderFrameHost* frame,
+    content::EyeDropperListener* listener) {
+  if (!features::IsEyeDropperEnabled() || !frame->GetView()->HasFocus() ||
+      !chromeos::LacrosService::Get()
+           ->IsSupported<crosapi::mojom::EyeDropper>()) {
+    return nullptr;
+  }
+  return std::make_unique<SystemEyeDropper>(listener);
+}
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura_browsertest.cc b/chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura_browsertest.cc
index 5e2d884..47d2ec9 100644
--- a/chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura_browsertest.cc
+++ b/chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura_browsertest.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 "chrome/browser/ui/views/eye_dropper/eye_dropper_view.h"
-
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/eye_dropper/eye_dropper_view.h"
 #include "content/public/browser/eye_dropper.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
index 166f5ee..71aea4a 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -189,7 +189,7 @@
     frame_header_ = CreateFrameHeader();
   }
 
-  if (AppIsBorderlessPwa()) {
+  if (AppIsPwaWithBorderlessDisplayMode()) {
     UpdateBorderlessModeEnabled();
   }
 
@@ -438,10 +438,10 @@
       browser_view()->IsBorderlessModeEnabled());
 }
 
-bool BrowserNonClientFrameViewChromeOS::AppIsBorderlessPwa() const {
+bool BrowserNonClientFrameViewChromeOS::AppIsPwaWithBorderlessDisplayMode()
+    const {
   return browser_view()->GetIsWebAppType() &&
-         browser_view()->AppUsesBorderlessMode() &&
-         browser_view()->IsBorderlessModeEnabled();
+         browser_view()->AppUsesBorderlessMode();
 }
 
 void BrowserNonClientFrameViewChromeOS::Layout() {
@@ -462,7 +462,7 @@
     LayoutProfileIndicator();
   }
 
-  if (AppIsBorderlessPwa()) {
+  if (AppIsPwaWithBorderlessDisplayMode()) {
     UpdateBorderlessModeEnabled();
   }
 
@@ -924,7 +924,9 @@
   const bool immersive =
       browser_view()->immersive_mode_controller()->IsEnabled();
   const bool tab_strip_visible = browser_view()->GetTabStripVisible();
-  const int inset = (tab_strip_visible || immersive || AppIsBorderlessPwa())
+  const int inset = (tab_strip_visible || immersive ||
+                     (AppIsPwaWithBorderlessDisplayMode() &&
+                      browser_view()->IsBorderlessModeEnabled()))
                         ? 0
                         : GetTopInset(/*restored=*/false);
   frame()->GetNativeWindow()->SetProperty(aura::client::kTopViewInset, inset);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
index f3aba8fa..a772754 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
@@ -135,7 +135,10 @@
   FRIEND_TEST_ALL_PREFIXES(ImmersiveModeBrowserViewTestNoWebUiTabStrip,
                            ImmersiveFullscreen);
 
-  bool AppIsBorderlessPwa() const;
+  // App is a PWA and has borderless in its manifest. This doesn't yet mean
+  // that the `window-management` permission has been granted and borderless
+  // mode would be activated.
+  bool AppIsPwaWithBorderlessDisplayMode() const;
 
   // Returns true if `GetShowCaptionButtonsWhenNotInOverview()` returns true
   // and this browser window is not showing in overview.
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
index 16b8975..1311e940 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -99,7 +99,7 @@
   std::unique_ptr<TabSearchContainer> tab_search_container;
   if (browser && browser->is_type_normal()) {
     tab_search_container = std::make_unique<TabSearchContainer>(
-        tab_strip_->controller(), render_tab_search_before_tab_strip_);
+        tab_strip_->controller(), render_tab_search_before_tab_strip_, this);
     tab_search_container->SetProperty(views::kCrossAxisAlignmentKey,
                                       views::LayoutAlignment::kCenter);
   }
diff --git a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
index bb3bbc8..3a4024f 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
@@ -232,9 +232,8 @@
 
 // Verify that we can open the ReadingMode side panel from the 3dot -> More
 // tools context menu.
-// TODO(dljames): Figure out why this is flaking.
 IN_PROC_BROWSER_TEST_F(PinnedSidePanelInteractiveTest,
-                       DISABLED_OpenReadingModeSidePanel) {
+                       OpenReadingModeSidePanel) {
   SidePanelUtil::GetSidePanelCoordinatorForBrowser(browser())
       ->SetNoDelaysForTesting(true);
 
@@ -243,6 +242,7 @@
                   SelectMenuItem(AppMenuModel::kMoreToolsMenuItem),
                   SelectMenuItem(ToolsMenuModel::kReadingModeMenuItem),
                   WatchSidePanelSelection(), WaitForShow(kSidePanelElementId),
+                  FlushEvents(),
                   WaitForSidePanelSelection(SidePanelEntryId::kReadAnything),
                   // Click on the close button to dismiss the side panel.
                   PressButton(kSidePanelCloseButtonElementId),
diff --git a/chrome/browser/ui/views/tabs/tab_organization_button.cc b/chrome/browser/ui/views/tabs/tab_organization_button.cc
index 6a055b3..cd82324 100644
--- a/chrome/browser/ui/views/tabs/tab_organization_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_organization_button.cc
@@ -9,14 +9,21 @@
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/compositor/layer.h"
+#include "ui/views/animation/ink_drop.h"
+#include "ui/views/controls/highlight_path_generator.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/view_class_properties.h"
 
 namespace {
 constexpr int kTabOrganizeCornerRadius = 10;
 constexpr int kTabOrganizeFlatCornerRadius = 2;
-constexpr int kTabOrganizeInsetsWidth = 20;
+constexpr int kTabOrganizeLabelMargin = 10;
+constexpr int kTabOrganizeCloseButtonMargin = 8;
+constexpr int kTabOrganizeCloseButtonSize = 16;
 }
 
 TabOrganizationButton::TabOrganizationButton(
@@ -30,6 +37,11 @@
           l10n_util::GetStringUTF16(IDS_TAB_ORGANIZE),
           flat_edge),
       pressed_callback_(std::move(pressed_callback)) {
+  auto* const layout_manager =
+      SetLayoutManager(std::make_unique<views::BoxLayout>());
+  layout_manager->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kEnd);
+
   SetProperty(views::kElementIdentifierKey, kTabOrganizationButtonElementId);
 
   SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_ORGANIZE));
@@ -37,6 +49,10 @@
   SetLabelStyle(views::style::STYLE_BODY_3_EMPHASIS);
   label()->SetElideBehavior(gfx::ElideBehavior::NO_ELIDE);
 
+  const gfx::Insets label_margin =
+      gfx::Insets().set_left(kTabOrganizeLabelMargin);
+  label()->SetProperty(views::kMarginsKey, label_margin);
+
   UpdateForegroundFrameActiveColorId(kColorNewTabButtonForegroundFrameActive);
   UpdateForegroundFrameInactiveColorId(
       kColorNewTabButtonForegroundFrameInactive);
@@ -46,6 +62,10 @@
 
   set_paint_transparent_for_custom_image_theme(false);
 
+  SetCloseButton(base::BindRepeating(&TabOrganizationButton::ClosePressed,
+                                     base::Unretained(this)));
+  layout_manager->SetFlexForView(close_button_, 1);
+
   UpdateColors();
 }
 
@@ -57,8 +77,7 @@
 }
 
 gfx::Size TabOrganizationButton::CalculatePreferredSize() const {
-  const int full_width =
-      LabelButton::CalculatePreferredSize().width() + kTabOrganizeInsetsWidth;
+  const int full_width = GetLayoutManager()->GetPreferredSize(this).width();
   const int width = full_width * width_factor_;
   const int height = TabStripControlButton::CalculatePreferredSize().height();
   return gfx::Size(width, height);
@@ -73,6 +92,10 @@
   pressed_callback_.Run(event);
 }
 
+void TabOrganizationButton::ClosePressed(const ui::Event& event) {
+  pressed_callback_.Run(event);
+}
+
 int TabOrganizationButton::GetCornerRadius() const {
   return kTabOrganizeCornerRadius;
 }
@@ -81,5 +104,46 @@
   return kTabOrganizeFlatCornerRadius;
 }
 
+void TabOrganizationButton::SetCloseButton(
+    views::LabelButton::PressedCallback pressed_callback) {
+  auto close_button =
+      std::make_unique<views::LabelButton>(std::move(pressed_callback));
+  close_button->SetTooltipText(
+      l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_ORGANIZE_CLOSE));
+
+  const ui::ImageModel icon_image_model = ui::ImageModel::FromVectorIcon(
+      vector_icons::kCloseChromeRefreshIcon,
+      kColorNewTabButtonForegroundFrameActive, kTabOrganizeCloseButtonSize);
+
+  close_button->SetImageModel(views::Button::STATE_NORMAL, icon_image_model);
+  close_button->SetImageModel(views::Button::STATE_HOVERED, icon_image_model);
+  close_button->SetImageModel(views::Button::STATE_PRESSED, icon_image_model);
+
+  close_button->SetPaintToLayer();
+  close_button->layer()->SetFillsBoundsOpaquely(false);
+
+  views::InkDrop::Get(close_button.get())
+      ->SetMode(views::InkDropHost::InkDropMode::ON);
+  views::InkDrop::Get(close_button.get())->SetHighlightOpacity(0.16f);
+  views::InkDrop::Get(close_button.get())->SetVisibleOpacity(0.14f);
+  views::InkDrop::Get(close_button.get())
+      ->SetBaseColorId(kColorNewTabButtonForegroundFrameActive);
+
+  auto ink_drop_highlight_path =
+      std::make_unique<views::CircleHighlightPathGenerator>(gfx::Insets());
+  views::HighlightPathGenerator::Install(close_button.get(),
+                                         std::move(ink_drop_highlight_path));
+
+  close_button->SetPreferredSize(
+      gfx::Size(kTabOrganizeCloseButtonSize, kTabOrganizeCloseButtonSize));
+  close_button->SetBorder(nullptr);
+
+  const gfx::Insets margin = gfx::Insets().set_left_right(
+      kTabOrganizeCloseButtonMargin, kTabOrganizeCloseButtonMargin);
+  close_button->SetProperty(views::kMarginsKey, margin);
+
+  close_button_ = AddChildView(std::move(close_button));
+}
+
 BEGIN_METADATA(TabOrganizationButton, TabStripControlButton)
 END_METADATA
diff --git a/chrome/browser/ui/views/tabs/tab_organization_button.h b/chrome/browser/ui/views/tabs/tab_organization_button.h
index 6300fc1..01a1730 100644
--- a/chrome/browser/ui/views/tabs/tab_organization_button.h
+++ b/chrome/browser/ui/views/tabs/tab_organization_button.h
@@ -31,6 +31,7 @@
   gfx::Size CalculatePreferredSize() const override;
 
   void ButtonPressed(const ui::Event& event);
+  void ClosePressed(const ui::Event& event);
 
  protected:
   // TabStripControlButton:
@@ -38,10 +39,13 @@
   int GetFlatCornerRadius() const override;
 
  private:
+  void SetCloseButton(PressedCallback callback);
+
   // Preferred width multiplier, between 0-1. Used to animate button size.
   float width_factor_ = 0;
   raw_ptr<TabOrganizationSession, DanglingUntriaged> session_ = nullptr;
   PressedCallback pressed_callback_;
+  raw_ptr<views::LabelButton> close_button_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_ORGANIZATION_BUTTON_H_
diff --git a/chrome/browser/ui/views/tabs/tab_search_container.cc b/chrome/browser/ui/views/tabs/tab_search_container.cc
index 65f45e81..b35eedc 100644
--- a/chrome/browser/ui/views/tabs/tab_search_container.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_container.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/layout/flex_layout.h"
+#include "ui/views/mouse_watcher.h"
+#include "ui/views/mouse_watcher_view_host.h"
 #include "ui/views/view_class_properties.h"
 
 namespace {
@@ -28,8 +30,15 @@
 }  // namespace
 
 TabSearchContainer::TabSearchContainer(TabStripController* tab_strip_controller,
-                                       bool before_tab_strip)
-    : AnimationDelegateViews(this) {
+                                       bool before_tab_strip,
+                                       View* locked_expansion_view)
+    : AnimationDelegateViews(this),
+      locked_expansion_view_(locked_expansion_view) {
+  mouse_watcher_ = std::make_unique<views::MouseWatcher>(
+      std::make_unique<views::MouseWatcherViewHost>(locked_expansion_view,
+                                                    gfx::Insets()),
+      this);
+
   std::unique_ptr<TabSearchButton> tab_search_button =
       std::make_unique<TabSearchButton>(
           tab_strip_controller, features::IsTabOrganization()
@@ -81,6 +90,42 @@
 }
 
 void TabSearchContainer::ShowTabOrganization() {
+  if (locked_expansion_view_->IsMouseHovered()) {
+    SetLockedExpansionMode(LockedExpansionMode::kWillShow);
+  }
+  if (locked_expansion_mode_ == LockedExpansionMode::kNone) {
+    ExecuteShowTabOrganization();
+  }
+}
+
+void TabSearchContainer::HideTabOrganization() {
+  if (locked_expansion_view_->IsMouseHovered()) {
+    SetLockedExpansionMode(LockedExpansionMode::kWillHide);
+  }
+  if (locked_expansion_mode_ == LockedExpansionMode::kNone) {
+    ExecuteHideTabOrganization();
+  }
+}
+
+void TabSearchContainer::SetLockedExpansionModeForTesting(
+    LockedExpansionMode mode) {
+  SetLockedExpansionMode(mode);
+}
+
+void TabSearchContainer::SetLockedExpansionMode(LockedExpansionMode mode) {
+  if (mode == LockedExpansionMode::kNone) {
+    if (locked_expansion_mode_ == LockedExpansionMode::kWillShow) {
+      ExecuteShowTabOrganization();
+    } else if (locked_expansion_mode_ == LockedExpansionMode::kWillHide) {
+      ExecuteHideTabOrganization();
+    }
+  } else {
+    mouse_watcher_->Start(GetWidget()->GetNativeWindow());
+  }
+  locked_expansion_mode_ = mode;
+}
+
+void TabSearchContainer::ExecuteShowTabOrganization() {
   expansion_animation_.Show();
 
   const base::TimeDelta delta = base::Seconds(16);
@@ -88,10 +133,14 @@
                                      &TabSearchContainer::HideTabOrganization);
 }
 
-void TabSearchContainer::HideTabOrganization() {
+void TabSearchContainer::ExecuteHideTabOrganization() {
   expansion_animation_.Hide();
 }
 
+void TabSearchContainer::MouseMovedOutOfHost() {
+  SetLockedExpansionMode(LockedExpansionMode::kNone);
+}
+
 void TabSearchContainer::AnimationCanceled(const gfx::Animation* animation) {
   ApplyAnimationValue(animation->GetCurrentValue());
 }
diff --git a/chrome/browser/ui/views/tabs/tab_search_container.h b/chrome/browser/ui/views/tabs/tab_search_container.h
index 9e881572..e38e5f82c 100644
--- a/chrome/browser/ui/views/tabs/tab_search_container.h
+++ b/chrome/browser/ui/views/tabs/tab_search_container.h
@@ -12,6 +12,7 @@
 #include "ui/gfx/animation/animation.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/views/animation/animation_delegate_views.h"
+#include "ui/views/mouse_watcher.h"
 #include "ui/views/view.h"
 
 enum class Edge;
@@ -20,13 +21,21 @@
 class TabSearchButton;
 class TabStripController;
 
+enum class LockedExpansionMode {
+  kNone = 0,
+  kWillShow,
+  kWillHide,
+};
+
 class TabSearchContainer : public views::View,
                            public views::AnimationDelegateViews,
-                           public TabOrganizationObserver {
+                           public TabOrganizationObserver,
+                           public views::MouseWatcherListener {
  public:
   METADATA_HEADER(TabSearchContainer);
   TabSearchContainer(TabStripController* tab_strip_controller,
-                     bool before_tab_strip);
+                     bool before_tab_strip,
+                     View* locked_expansion_view);
   TabSearchContainer(const TabSearchContainer&) = delete;
   TabSearchContainer& operator=(const TabSearchContainer&) = delete;
   ~TabSearchContainer() override;
@@ -46,6 +55,10 @@
 
   void ShowTabOrganization();
   void HideTabOrganization();
+  void SetLockedExpansionModeForTesting(LockedExpansionMode mode);
+
+  // views::MouseWatcherListener:
+  void MouseMovedOutOfHost() override;
 
   // views::AnimationDelegateViews
   void AnimationCanceled(const gfx::Animation* animation) override;
@@ -56,8 +69,15 @@
   void OnToggleActionUIState(const Browser* browser, bool should_show) override;
 
  private:
+  void SetLockedExpansionMode(LockedExpansionMode mode);
+  void ExecuteShowTabOrganization();
+  void ExecuteHideTabOrganization();
   void ApplyAnimationValue(float value);
 
+  // View where, if the mouse is currently over its bounds, the expansion state
+  // will not change. Changes will be staged until after the mouse exits the
+  // bounds of this View.
+  raw_ptr<View, DanglingUntriaged> locked_expansion_view_;
   raw_ptr<TabOrganizationButton, DanglingUntriaged> tab_organization_button_ =
       nullptr;
   raw_ptr<TabSearchButton, DanglingUntriaged> tab_search_button_ = nullptr;
@@ -69,6 +89,14 @@
 
   // Timer for hiding tab_organization_button_ after show.
   base::OneShotTimer hide_tab_organization_timer_;
+
+  // When locked, the container is unable to change its expanded state. Changes
+  // will be staged until after this is unlocked.
+  LockedExpansionMode locked_expansion_mode_ = LockedExpansionMode::kNone;
+
+  // MouseWatcher is used to lock and unlock the expansion state of this
+  // container.
+  std::unique_ptr<views::MouseWatcher> mouse_watcher_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_SEARCH_CONTAINER_H_
diff --git a/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc b/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc
index fffd1cf..254f455 100644
--- a/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc
@@ -17,6 +17,7 @@
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_base_features.h"
+#include "ui/events/test/event_generator.h"
 
 class TabSearchContainerBrowserTest : public InProcessBrowserTest {
  public:
@@ -62,3 +63,40 @@
       nullptr,
       tab_search_container()->tab_organization_button()->session_for_testing());
 }
+
+IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, DelaysShow) {
+  ASSERT_FALSE(
+      tab_search_container()->expansion_animation_for_testing()->IsShowing());
+
+  tab_search_container()->SetLockedExpansionModeForTesting(
+      LockedExpansionMode::kWillShow);
+  tab_search_container()->ShowTabOrganization();
+
+  ASSERT_FALSE(
+      tab_search_container()->expansion_animation_for_testing()->IsShowing());
+
+  tab_search_container()->SetLockedExpansionModeForTesting(
+      LockedExpansionMode::kNone);
+
+  ASSERT_TRUE(
+      tab_search_container()->expansion_animation_for_testing()->IsShowing());
+}
+
+IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, DelaysHide) {
+  tab_search_container()->expansion_animation_for_testing()->Reset(1);
+  ASSERT_FALSE(
+      tab_search_container()->expansion_animation_for_testing()->IsClosing());
+
+  tab_search_container()->SetLockedExpansionModeForTesting(
+      LockedExpansionMode::kWillHide);
+  tab_search_container()->HideTabOrganization();
+
+  ASSERT_FALSE(
+      tab_search_container()->expansion_animation_for_testing()->IsClosing());
+
+  tab_search_container()->SetLockedExpansionModeForTesting(
+      LockedExpansionMode::kNone);
+
+  ASSERT_TRUE(
+      tab_search_container()->expansion_animation_for_testing()->IsClosing());
+}
diff --git a/chrome/browser/ui/views/tabs/tab_search_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_search_container_unittest.cc
index 36e38f8..fe39031 100644
--- a/chrome/browser/ui/views/tabs/tab_search_container_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_container_unittest.cc
@@ -37,15 +37,17 @@
 
     tab_strip_controller_ =
         std::make_unique<FakeBaseTabStripControllerWithProfile>();
-    container_before_tab_strip_ =
-        std::make_unique<TabSearchContainer>(tab_strip_controller_.get(), true);
+    locked_expansion_view_ = std::make_unique<views::View>();
+    container_before_tab_strip_ = std::make_unique<TabSearchContainer>(
+        tab_strip_controller_.get(), true, locked_expansion_view_.get());
     container_after_tab_strip_ = std::make_unique<TabSearchContainer>(
-        tab_strip_controller_.get(), false);
+        tab_strip_controller_.get(), false, locked_expansion_view_.get());
   }
 
  protected:
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<TabStripController> tab_strip_controller_;
+  std::unique_ptr<views::View> locked_expansion_view_;
   std::unique_ptr<TabSearchContainer> container_before_tab_strip_;
   std::unique_ptr<TabSearchContainer> container_after_tab_strip_;
 };
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
index 0e6c44e..35f0c35 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
@@ -281,8 +281,14 @@
       NavigateWebContents(kWebContentsId, url3),
       // Show the context menu.
       MoveMouseTo(kToolbarBackButtonElementId), ClickMouse(ui_controls::RIGHT),
+      Log("Logging to probe crbug.com/1489499. Waiting for back button menu."),
       WaitForShow(kToolbarBackButtonMenuElementId),
+      // Don't try to send an event to the menu before it's fully shown.
+      FlushEvents(),
       // Dismiss the context menu by clicking on it.
-      MoveMouseTo(kToolbarBackButtonMenuElementId), ClickMouse(),
-      WaitForHide(kToolbarBackButtonMenuElementId));
+      Log("Moving mouse to menu."),
+      MoveMouseTo(kToolbarBackButtonMenuElementId),
+      Log("Clicking mouse to dismiss."), ClickMouse(),
+      Log("Waiting for menu to dismiss."),
+      WaitForHide(kToolbarBackButtonMenuElementId), Log("Menu dismissed."));
 }
diff --git a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
index 50a6ee7..73ecb1f 100644
--- a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
+++ b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
@@ -101,9 +101,11 @@
 #include "chrome/browser/ui/webui/ash/sys_internals/sys_internals_ui.h"
 #include "chrome/browser/ui/webui/ash/vc_tray_tester/vc_tray_tester_ui.h"
 #include "chrome/browser/ui/webui/ash/vm/vm_ui.h"
+#include "chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.h"
 #include "chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h"
 #include "chrome/browser/ui/webui/settings/ash/os_settings_ui.h"
+#include "chromeos/constants/chromeos_features.h"
 #if !defined(OFFICIAL_BUILD)
 #include "ash/webui/sample_system_web_app_ui/sample_system_web_app_ui.h"
 #if !defined(USE_REAL_DBUS_CLIENTS)
@@ -319,6 +321,11 @@
       std::make_unique<UrgentPasswordExpiryNotificationUIConfig>());
   map.AddWebUIConfig(std::make_unique<VcTrayTesterUIConfig>());
   map.AddWebUIConfig(std::make_unique<VmUIConfig>());
+  if (base::FeatureList::IsEnabled(
+          chromeos::features::kCrosWebAppInstallDialog)) {
+    map.AddWebUIConfig(
+        std::make_unique<web_app_install::WebAppInstallDialogUIConfig>());
+  }
 #if !defined(OFFICIAL_BUILD)
   map.AddWebUIConfig(std::make_unique<SampleSystemWebAppUIConfig>());
   map.AddWebUIConfig(std::make_unique<StatusAreaInternalsUIConfig>());
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.cc
index edc2dfd..d5dd1f0 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.cc
@@ -11,15 +11,23 @@
 
 CloudOpenMetrics::CloudOpenMetrics(CloudProvider cloud_provider)
     : cloud_provider_(cloud_provider),
+      one_drive_open_error_(kOneDriveErrorMetricName),
       task_result_(cloud_provider_ == CloudProvider::kGoogleDrive
                        ? kGoogleDriveTaskResultMetricName
                        : kOneDriveTaskResultMetricName),
       transfer_required_(cloud_provider_ == CloudProvider::kGoogleDrive
                              ? kDriveTransferRequiredMetric
-                             : kOneDriveTransferRequiredMetric) {}
+                             : kOneDriveTransferRequiredMetric),
+      upload_result_(cloud_provider_ == CloudProvider::kGoogleDrive
+                         ? kGoogleDriveUploadResultMetricName
+                         : kOneDriveUploadResultMetricName) {}
 
 CloudOpenMetrics::~CloudOpenMetrics() = default;
 
+void CloudOpenMetrics::LogOneDriveOpenError(OfficeOneDriveOpenErrors value) {
+  one_drive_open_error_.Log(value);
+}
+
 void CloudOpenMetrics::LogTaskResult(OfficeTaskResult value) {
   task_result_.Log(value);
 }
@@ -28,6 +36,10 @@
   transfer_required_.Log(value);
 }
 
+void CloudOpenMetrics::LogUploadResult(OfficeFilesUploadResult value) {
+  upload_result_.Log(value);
+}
+
 base::SafeRef<CloudOpenMetrics> CloudOpenMetrics::GetSafeRef() const {
   return weak_ptr_factory_.GetSafeRef();
 }
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.h b/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.h
index 7680e1f..989b124 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.h
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_open_metrics.h
@@ -28,12 +28,18 @@
   CloudOpenMetrics(const CloudOpenMetrics&&) = delete;
   CloudOpenMetrics& operator=(CloudOpenMetrics&&) = delete;
 
+  // Log the `value` for the OneDriveOpenError metric.
+  void LogOneDriveOpenError(OfficeOneDriveOpenErrors value);
+
   // Log the `value` for the TaskResult metric.
   void LogTaskResult(OfficeTaskResult value);
 
   // Log the `value` for the TransferRequired metric.
   void LogTransferRequired(OfficeFilesTransferRequired value);
 
+  // Log the `value` for the UploadResult metric.
+  void LogUploadResult(OfficeFilesUploadResult value);
+
   base::SafeRef<CloudOpenMetrics> GetSafeRef() const;
 
   // For testing.
@@ -78,8 +84,10 @@
   };
 
   CloudProvider cloud_provider_;
+  Metric<OfficeOneDriveOpenErrors> one_drive_open_error_;
   Metric<OfficeTaskResult> task_result_;
   Metric<OfficeFilesTransferRequired> transfer_required_;
+  Metric<OfficeFilesUploadResult> upload_result_;
   base::WeakPtrFactory<CloudOpenMetrics> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
index 8b56957..b2b6350 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
@@ -875,7 +875,7 @@
 void CloudOpenTask::LogOneDriveOpenResultUMA(
     OfficeTaskResult success_task_result,
     OfficeOneDriveOpenErrors open_result) {
-  UMA_HISTOGRAM_ENUMERATION(kOneDriveErrorMetricName, open_result);
+  cloud_open_metrics_->LogOneDriveOpenError(open_result);
   cloud_open_metrics_->LogTaskResult(open_result ==
                                              OfficeOneDriveOpenErrors::kSuccess
                                          ? success_task_result
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
index 7f1a5a3..fcc6f31 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
@@ -250,7 +250,7 @@
 void DriveUploadHandler::OnEndUpload(
     base::expected<GURL, std::string> hosted_url,
     OfficeFilesUploadResult result_metric) {
-  UMA_HISTOGRAM_ENUMERATION(kGoogleDriveUploadResultMetricName, result_metric);
+  cloud_open_metrics_->LogUploadResult(result_metric);
   // TODO (b/243095484) Define error behavior on invalid hosted URL.
   observed_relative_drive_path_.clear();
   // Stop suppressing Drive events for the observed file.
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc
index c55977f..2341e88d 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc
@@ -156,7 +156,7 @@
 void OneDriveUploadHandler::OnEndUpload(
     base::expected<storage::FileSystemURL, std::string> url,
     OfficeFilesUploadResult result_metric) {
-  UMA_HISTOGRAM_ENUMERATION(kOneDriveUploadResultMetricName, result_metric);
+  cloud_open_metrics_->LogUploadResult(result_metric);
   if (url.has_value()) {
     // Resolve notifications.
     if (notification_manager_) {
diff --git a/chrome/browser/ui/webui/ash/drive_internals_ui.cc b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
index 79858f0..7875487a 100644
--- a/chrome/browser/ui/webui/ash/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
@@ -41,7 +41,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/services/file_util/public/cpp/zip_file_creator.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "components/download/content/public/all_download_item_notifier.h"
 #include "components/download/public/common/download_item.h"
 #include "components/drive/drive_notification_manager.h"
@@ -67,7 +67,7 @@
 using content::BrowserThread;
 using drive::DriveIntegrationService;
 using drive::prefs::kDriveFsBulkPinningEnabled;
-using drivefs::pinning::PinManager;
+using drivefs::pinning::PinningManager;
 
 constexpr char kKey[] = "key";
 constexpr char kValue[] = "value";
@@ -598,7 +598,7 @@
         "updateBulkPinning",
         Value(GetPrefs()->GetBoolean(kDriveFsBulkPinningEnabled)));
 
-    if (PinManager* const manager = service->GetPinManager()) {
+    if (PinningManager* const manager = service->GetPinningManager()) {
       OnBulkPinProgress(manager->GetProgress());
     }
   }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.cc b/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.cc
index 584d887a..6b2c748c 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #include "chrome/browser/ash/drive/file_system_util.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/files/mojom/google_drive_handler.mojom.h"
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/text/bytes_formatting.h"
@@ -19,7 +19,7 @@
 namespace {
 
 using drive::DriveIntegrationService;
-using drivefs::pinning::PinManager;
+using drivefs::pinning::PinningManager;
 using drivefs::pinning::Progress;
 
 google_drive::mojom::StatusPtr CreateStatusPtr(const Progress& progress) {
@@ -55,14 +55,14 @@
 GoogleDrivePageHandler::~GoogleDrivePageHandler() = default;
 
 void GoogleDrivePageHandler::CalculateRequiredSpace() {
-  PinManager* const pin_manager = GetPinManager();
-  if (!pin_manager) {
+  PinningManager* const pinning_manager = GetPinningManager();
+  if (!pinning_manager) {
     page_->OnServiceUnavailable();
     return;
   }
 
-  NotifyProgress(pin_manager->GetProgress());
-  if (!pin_manager->CalculateRequiredSpace()) {
+  NotifyProgress(pinning_manager->GetProgress());
+  if (!pinning_manager->CalculateRequiredSpace()) {
     page_->OnServiceUnavailable();
     return;
   }
@@ -78,13 +78,13 @@
   return service && service->IsMounted() ? service : nullptr;
 }
 
-PinManager* GoogleDrivePageHandler::GetPinManager() {
+PinningManager* GoogleDrivePageHandler::GetPinningManager() {
   DriveIntegrationService* const service = GetDriveService();
-  return service ? service->GetPinManager() : nullptr;
+  return service ? service->GetPinningManager() : nullptr;
 }
 
 void GoogleDrivePageHandler::OnBulkPinProgress(const Progress& progress) {
-  if (!GetPinManager()) {
+  if (!GetPinningManager()) {
     page_->OnServiceUnavailable();
     return;
   }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.h b/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.h
index ae3ec89..1dcc527 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.h
+++ b/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_page_handler.h
@@ -50,7 +50,7 @@
   void OnClearPinnedFiles(ClearPinnedFilesCallback callback,
                           drive::FileError error);
 
-  drivefs::pinning::PinManager* GetPinManager();
+  drivefs::pinning::PinningManager* GetPinningManager();
   drive::DriveIntegrationService* GetDriveService();
   const raw_ptr<Profile> profile_;
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/mojom/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/files/mojom/BUILD.gn
index e140c15..fe6eaefab 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/files/mojom/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/files/mojom/BUILD.gn
@@ -17,7 +17,7 @@
   use_typescript_sources = true
 
   public_deps = [
-    "//chromeos/ash/components/drivefs/mojom:pin_manager_types",
+    "//chromeos/ash/components/drivefs/mojom:pinning_manager_types",
     "//mojo/public/mojom/base",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/mojom/google_drive_handler.mojom b/chrome/browser/ui/webui/ash/settings/pages/files/mojom/google_drive_handler.mojom
index 2a48e8c..d88a3731 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/files/mojom/google_drive_handler.mojom
+++ b/chrome/browser/ui/webui/ash/settings/pages/files/mojom/google_drive_handler.mojom
@@ -4,7 +4,7 @@
 
 module ash.settings.google_drive.mojom;
 
-import "chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom";
+import "chromeos/ash/components/drivefs/mojom/pinning_manager_types.mojom";
 
 // Contains the current status of the underlying pin manager as it progress
 // through the various stages.
@@ -18,7 +18,7 @@
   string free_space;
 
   // The current stage the pin manager is going through.
-  drivefs.pin_manager_types.mojom.Stage stage;
+  drivefs.pinning_manager_types.mojom.Stage stage;
 
   // The number of listed files during the `kListingFiles` stage.
   uint64 listed_files;
diff --git a/chrome/browser/ui/webui/settings/ash/internet_handler.cc b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.cc
similarity index 96%
rename from chrome/browser/ui/webui/settings/ash/internet_handler.cc
rename to chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.cc
index 2c99520..a1ddbe6 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_handler.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.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 "chrome/browser/ui/webui/settings/ash/internet_handler.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.h"
 
 #include <memory>
 #include <vector>
@@ -67,13 +67,15 @@
   gms_core_notifications_state_tracker_ =
       tether_service ? tether_service->GetGmsCoreNotificationsStateTracker()
                      : nullptr;
-  if (gms_core_notifications_state_tracker_)
+  if (gms_core_notifications_state_tracker_) {
     gms_core_notifications_state_tracker_->AddObserver(this);
+  }
 }
 
 InternetHandler::~InternetHandler() {
-  if (gms_core_notifications_state_tracker_)
+  if (gms_core_notifications_state_tracker_) {
     gms_core_notifications_state_tracker_->RemoveObserver(this);
+  }
 }
 
 void InternetHandler::RegisterMessages() {
@@ -255,12 +257,14 @@
 }
 
 void InternetHandler::SendGmsCoreNotificationsDisabledDeviceNames() {
-  if (!IsJavascriptAllowed())
+  if (!IsJavascriptAllowed()) {
     return;
+  }
 
   base::Value::List device_names_value;
-  for (const auto& device_name : device_names_without_notifications_)
+  for (const auto& device_name : device_names_without_notifications_) {
     device_names_value.Append(device_name.Clone());
+  }
 
   FireWebUIListener(kSendGmsCoreNotificationsDisabledDeviceNames,
                     device_names_value);
@@ -273,8 +277,9 @@
 void InternetHandler::SetGmsCoreNotificationsStateTrackerForTesting(
     tether::GmsCoreNotificationsStateTracker*
         gms_core_notifications_state_tracker) {
-  if (gms_core_notifications_state_tracker_)
+  if (gms_core_notifications_state_tracker_) {
     gms_core_notifications_state_tracker_->RemoveObserver(this);
+  }
 
   gms_core_notifications_state_tracker_ = gms_core_notifications_state_tracker;
   gms_core_notifications_state_tracker_->AddObserver(this);
diff --git a/chrome/browser/ui/webui/settings/ash/internet_handler.h b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.h
similarity index 89%
rename from chrome/browser/ui/webui/settings/ash/internet_handler.h
rename to chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.h
index 5c67ac3..cd5335d6e 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_handler.h
+++ b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.h
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_INTERNET_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_INTERNET_HANDLER_H_
-
-#include <memory>
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_INTERNET_INTERNET_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_INTERNET_INTERNET_HANDLER_H_
 
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
@@ -71,4 +69,4 @@
 
 }  // namespace ash::settings
 
-#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_INTERNET_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_INTERNET_INTERNET_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/ash/internet_handler_unittest.cc b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler_unittest.cc
similarity index 97%
rename from chrome/browser/ui/webui/settings/ash/internet_handler_unittest.cc
rename to chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler_unittest.cc
index 9d17a08..e68cc98a7 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_handler_unittest.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/settings/ash/internet_handler.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.h"
 
 #include <memory>
 
@@ -74,8 +74,9 @@
     EXPECT_EQ(kSendDeviceNamesMessageType, last_call_data->arg1()->GetString());
 
     std::vector<std::string> actual_device_names;
-    for (const auto& device_name_value : last_call_data->arg2()->GetList())
+    for (const auto& device_name_value : last_call_data->arg2()->GetList()) {
       actual_device_names.push_back(device_name_value.GetString());
+    }
     EXPECT_EQ(expected_device_names, actual_device_names);
   }
 
diff --git a/chrome/browser/ui/webui/settings/ash/internet_section.cc b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.cc
similarity index 98%
rename from chrome/browser/ui/webui/settings/ash/internet_section.cc
rename to chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.cc
index 040391c..a091b82 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.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 "chrome/browser/ui/webui/settings/ash/internet_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.h"
 
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/hotspot_config_service.h"
@@ -16,9 +16,9 @@
 #include "base/no_destructor.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/ui/webui/ash/cellular_setup/cellular_setup_localized_strings_provider.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/internet/internet_handler.h"
 #include "chrome/browser/ui/webui/ash/settings/search/search_tag_registry.h"
 #include "chrome/browser/ui/webui/extension_control_handler.h"
-#include "chrome/browser/ui/webui/settings/ash/internet_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/url_constants.h"
@@ -657,8 +657,9 @@
 }
 
 bool AllowAddESim(const network_config::mojom::GlobalPolicyPtr& global_policy) {
-  if (HermesManagerClient::Get()->GetAvailableEuiccs().size() == 0)
+  if (HermesManagerClient::Get()->GetAvailableEuiccs().size() == 0) {
     return false;
+  }
 
   return !global_policy->allow_only_policy_cellular_networks;
 }
@@ -666,8 +667,9 @@
 absl::optional<std::string> GetCellularActiveSimIccid(
     const network_config::mojom::DeviceStatePropertiesPtr& device) {
   for (const auto& sim_info : *device->sim_infos) {
-    if (sim_info->is_primary)
+    if (sim_info->is_primary) {
       return sim_info->iccid;
+    }
   }
   return absl::nullopt;
 }
@@ -1314,20 +1316,25 @@
   std::string modified_url =
       OsSettingsSection::ModifySearchResultUrl(type, id, url_to_modify);
 
-  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kEthernetDetails))
+  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kEthernetDetails)) {
     return GetDetailsSubpageUrl(modified_url, *connected_ethernet_guid_);
+  }
 
-  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kWifiDetails))
+  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kWifiDetails)) {
     return GetDetailsSubpageUrl(modified_url, *connected_wifi_guid_);
+  }
 
-  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kCellularDetails))
+  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kCellularDetails)) {
     return GetDetailsSubpageUrl(modified_url, *active_cellular_guid_);
+  }
 
-  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kTetherDetails))
+  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kTetherDetails)) {
     return GetDetailsSubpageUrl(modified_url, *connected_tether_guid_);
+  }
 
-  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kVpnDetails))
+  if (IsPartOfDetailsSubpage(type, id, mojom::Subpage::kVpnDetails)) {
     return GetDetailsSubpageUrl(modified_url, *connected_vpn_guid_);
+  }
 
   // Use default implementation.
   return modified_url;
@@ -1419,10 +1426,11 @@
     switch (device->type) {
       case NetworkType::kWiFi:
         updater.AddSearchTags(GetWifiSearchConcepts());
-        if (device->device_state == DeviceStateType::kEnabled)
+        if (device->device_state == DeviceStateType::kEnabled) {
           updater.AddSearchTags(GetWifiOnSearchConcepts());
-        else if (device->device_state == DeviceStateType::kDisabled)
+        } else if (device->device_state == DeviceStateType::kDisabled) {
           updater.AddSearchTags(GetWifiOffSearchConcepts());
+        }
         break;
 
       case NetworkType::kCellular:
@@ -1443,10 +1451,11 @@
 
       case NetworkType::kTether:
         updater.AddSearchTags(GetInstantTetheringSearchConcepts());
-        if (device->device_state == DeviceStateType::kEnabled)
+        if (device->device_state == DeviceStateType::kEnabled) {
           updater.AddSearchTags(GetInstantTetheringOnSearchConcepts());
-        else if (device->device_state == DeviceStateType::kDisabled)
+        } else if (device->device_state == DeviceStateType::kDisabled) {
           updater.AddSearchTags(GetInstantTetheringOffSearchConcepts());
+        }
         break;
 
       case NetworkType::kEthernet:
@@ -1516,8 +1525,9 @@
       }
     }
 
-    if (!IsConnected(network->connection_state))
+    if (!IsConnected(network->connection_state)) {
       continue;
+    }
 
     switch (network->type) {
       case NetworkType::kEthernet:
@@ -1528,16 +1538,20 @@
       case NetworkType::kWiFi:
         connected_wifi_guid_ = network->guid;
         updater.AddSearchTags(GetWifiConnectedSearchConcepts());
-        if (base::FeatureList::IsEnabled(::features::kMeteredShowToggle))
+        if (base::FeatureList::IsEnabled(::features::kMeteredShowToggle)) {
           updater.AddSearchTags(GetWifiMeteredSearchConcepts());
-        if (base::FeatureList::IsEnabled(::features::kShowHiddenNetworkToggle))
+        }
+        if (base::FeatureList::IsEnabled(
+                ::features::kShowHiddenNetworkToggle)) {
           updater.AddSearchTags(GetWifiHiddenSearchConcepts());
+        }
         break;
 
       case NetworkType::kCellular:
         updater.AddSearchTags(GetCellularConnectedSearchConcepts());
-        if (base::FeatureList::IsEnabled(::features::kMeteredShowToggle))
+        if (base::FeatureList::IsEnabled(::features::kMeteredShowToggle)) {
           updater.AddSearchTags(GetCellularMeteredSearchConcepts());
+        }
         break;
 
       case NetworkType::kTether:
diff --git a/chrome/browser/ui/webui/settings/ash/internet_section.h b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.h
similarity index 93%
rename from chrome/browser/ui/webui/settings/ash/internet_section.h
rename to chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.h
index 02a7c19c6..e32c8d6 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_section.h
+++ b/chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_INTERNET_SECTION_H_
-#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_INTERNET_SECTION_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_INTERNET_INTERNET_SECTION_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_INTERNET_INTERNET_SECTION_H_
 
 #include <string>
 #include <vector>
@@ -101,4 +101,4 @@
 
 }  // namespace ash::settings
 
-#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_INTERNET_SECTION_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_INTERNET_INTERNET_SECTION_H_
diff --git a/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.cc b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.cc
similarity index 98%
rename from chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.cc
rename to chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.cc
index 36617c9..234f541 100644
--- a/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.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 "chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.h"
 
 #include <string>
 #include <utility>
@@ -194,8 +194,9 @@
 KerberosAccountsHandler::CreateIfKerberosEnabled(Profile* profile) {
   KerberosCredentialsManager* kerberos_credentials_manager =
       KerberosCredentialsManagerFactory::GetExisting(profile);
-  if (!IsKerberosEnabled(kerberos_credentials_manager))
+  if (!IsKerberosEnabled(kerberos_credentials_manager)) {
     return nullptr;
+  }
   return base::WrapUnique(
       new KerberosAccountsHandler(kerberos_credentials_manager));
 }
diff --git a/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.h b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.h
similarity index 93%
rename from chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.h
rename to chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.h
index 2b8e169f..cbe5a1b69 100644
--- a/chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.h
+++ b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_KERBEROS_ACCOUNTS_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_KERBEROS_ACCOUNTS_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_KERBEROS_KERBEROS_ACCOUNTS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_KERBEROS_KERBEROS_ACCOUNTS_HANDLER_H_
 
 #include <memory>
 #include <string>
@@ -107,4 +107,4 @@
 
 }  // namespace ash::settings
 
-#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_KERBEROS_ACCOUNTS_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_KERBEROS_KERBEROS_ACCOUNTS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/ash/kerberos_section.cc b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.cc
similarity index 96%
rename from chrome/browser/ui/webui/settings/ash/kerberos_section.cc
rename to chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.cc
index b54c11a..4308aef 100644
--- a/chrome/browser/ui/webui/settings/ash/kerberos_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/settings/ash/kerberos_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.h"
 
 #include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_accounts_handler.h"
 #include "chrome/browser/ui/webui/ash/settings/search/search_tag_registry.h"
-#include "chrome/browser/ui/webui/settings/ash/kerberos_accounts_handler.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -86,8 +86,9 @@
 }
 
 KerberosSection::~KerberosSection() {
-  if (kerberos_credentials_manager_)
+  if (kerberos_credentials_manager_) {
     kerberos_credentials_manager_->RemoveObserver(this);
+  }
 }
 
 void KerberosSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
diff --git a/chrome/browser/ui/webui/settings/ash/kerberos_section.h b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.h
similarity index 87%
rename from chrome/browser/ui/webui/settings/ash/kerberos_section.h
rename to chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.h
index 8c59843..fe47dc5 100644
--- a/chrome/browser/ui/webui/settings/ash/kerberos_section.h
+++ b/chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_KERBEROS_SECTION_H_
-#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_KERBEROS_SECTION_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_KERBEROS_KERBEROS_SECTION_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_KERBEROS_KERBEROS_SECTION_H_
 
 #include "base/memory/raw_ptr.h"
 #include "base/values.h"
@@ -54,4 +54,4 @@
 
 }  // namespace ash::settings
 
-#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_KERBEROS_SECTION_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_KERBEROS_KERBEROS_SECTION_H_
diff --git a/chrome/browser/ui/webui/settings/ash/languages_section.cc b/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.cc
similarity index 98%
rename from chrome/browser/ui/webui/settings/ash/languages_section.cc
rename to chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.cc
index 16b3d05..75c5e911 100644
--- a/chrome/browser/ui/webui/settings/ash/languages_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.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 "chrome/browser/ui/webui/settings/ash/languages_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h"
 
 #include "ash/constants/ash_features.h"
 #include "ash/webui/settings/public/constants/routes.mojom-forward.h"
diff --git a/chrome/browser/ui/webui/settings/ash/languages_section.h b/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h
similarity index 85%
rename from chrome/browser/ui/webui/settings/ash/languages_section.h
rename to chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h
index a3bbb068..a695377 100644
--- a/chrome/browser/ui/webui/settings/ash/languages_section.h
+++ b/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_LANGUAGES_SECTION_H_
-#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_LANGUAGES_SECTION_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_LANGUAGES_LANGUAGES_SECTION_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_LANGUAGES_LANGUAGES_SECTION_H_
 
 #include "base/memory/raw_ptr.h"
 #include "base/values.h"
@@ -44,4 +44,4 @@
 
 }  // namespace ash::settings
 
-#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_LANGUAGES_SECTION_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_LANGUAGES_LANGUAGES_SECTION_H_
diff --git a/chrome/browser/ui/webui/ash/web_app_install/OWNERS b/chrome/browser/ui/webui/ash/web_app_install/OWNERS
new file mode 100644
index 0000000..290ee25
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/web_app_install/OWNERS
@@ -0,0 +1 @@
+alancutter@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/ash/web_app_install/web_app_install_dialog.cc b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_dialog.cc
new file mode 100644
index 0000000..5ceffcc
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_dialog.cc
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/ash/web_app_install/web_app_install_dialog.h"
+
+#include "chrome/common/webui_url_constants.h"
+#include "chromeos/constants/chromeos_features.h"
+
+namespace ash::web_app_install {
+
+// static
+bool WebAppInstallDialog::Show() {
+  CHECK(base::FeatureList::IsEnabled(
+      chromeos::features::kCrosWebAppInstallDialog));
+  // Allow no more than one upload dialog at a time.
+  if (SystemWebDialogDelegate::HasInstance(
+          GURL(chrome::kChromeUIWebAppInstallDialogURL))) {
+    return false;
+  }
+
+  // The pointer is managed by an instance of `views::WebDialogView` and removed
+  // in `SystemWebDialogDelegate::OnDialogClosed`.
+  WebAppInstallDialog* dialog = new WebAppInstallDialog();
+  dialog->ShowSystemDialog();
+  return true;
+}
+
+WebAppInstallDialog::WebAppInstallDialog()
+    : SystemWebDialogDelegate(GURL(chrome::kChromeUIWebAppInstallDialogURL),
+                              std::u16string() /* title */) {}
+
+WebAppInstallDialog::~WebAppInstallDialog() = default;
+
+bool WebAppInstallDialog::ShouldShowCloseButton() const {
+  return false;
+}
+
+}  // namespace ash::web_app_install
diff --git a/chrome/browser/ui/webui/ash/web_app_install/web_app_install_dialog.h b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_dialog.h
new file mode 100644
index 0000000..89c3972
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_dialog.h
@@ -0,0 +1,30 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_WEB_APP_INSTALL_WEB_APP_INSTALL_DIALOG_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_WEB_APP_INSTALL_WEB_APP_INSTALL_DIALOG_H_
+
+#include "chrome/browser/ui/webui/ash/system_web_dialog_delegate.h"
+
+namespace ash::web_app_install {
+
+// Defines the web dialog used for installing a web app.
+class WebAppInstallDialog : public SystemWebDialogDelegate {
+ public:
+  WebAppInstallDialog(const WebAppInstallDialog&) = delete;
+  WebAppInstallDialog& operator=(const WebAppInstallDialog&) = delete;
+
+  // Creates and shows a new dialog for installing a web app. Returns true
+  // if a new dialog has been effectively created.
+  static bool Show();
+
+ protected:
+  WebAppInstallDialog();
+  ~WebAppInstallDialog() override;
+  bool ShouldShowCloseButton() const override;
+};
+
+}  // namespace ash::web_app_install
+
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_WEB_APP_INSTALL_WEB_APP_INSTALL_DIALOG_H_
diff --git a/chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.cc b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.cc
new file mode 100644
index 0000000..0d3ee2af
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.cc
@@ -0,0 +1,42 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.h"
+
+#include "base/feature_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/webui_util.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/web_app_install_resources.h"
+#include "chrome/grit/web_app_install_resources_map.h"
+#include "chromeos/constants/chromeos_features.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/common/url_constants.h"
+
+namespace ash::web_app_install {
+
+WebAppInstallDialogUI::WebAppInstallDialogUI(content::WebUI* web_ui)
+    : ui::WebDialogUI(web_ui) {
+  content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
+      Profile::FromWebUI(web_ui), chrome::kChromeUIWebAppInstallDialogHost);
+  webui::SetupWebUIDataSource(
+      source,
+      base::make_span(kWebAppInstallResources, kWebAppInstallResourcesSize),
+      IDR_WEB_APP_INSTALL_MAIN_HTML);
+}
+
+WebAppInstallDialogUI::~WebAppInstallDialogUI() = default;
+
+bool WebAppInstallDialogUIConfig::IsWebUIEnabled(
+    content::BrowserContext* browser_context) {
+  return base::FeatureList::IsEnabled(
+      chromeos::features::kCrosWebAppInstallDialog);
+}
+
+WebAppInstallDialogUIConfig::WebAppInstallDialogUIConfig()
+    : DefaultWebUIConfig(content::kChromeUIScheme,
+                         chrome::kChromeUIWebAppInstallDialogHost) {}
+
+}  // namespace ash::web_app_install
diff --git a/chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.h b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.h
new file mode 100644
index 0000000..435e031
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/web_app_install/web_app_install_ui.h
@@ -0,0 +1,34 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_WEB_APP_INSTALL_WEB_APP_INSTALL_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_WEB_APP_INSTALL_WEB_APP_INSTALL_UI_H_
+
+#include "content/public/browser/webui_config.h"
+#include "ui/web_dialogs/web_dialog_ui.h"
+
+namespace ash::web_app_install {
+
+// The WebUI for chrome://web-app-install-dialog, used for confirming web app
+// installation.
+class WebAppInstallDialogUI : public ui::WebDialogUI {
+ public:
+  explicit WebAppInstallDialogUI(content::WebUI* web_ui);
+  WebAppInstallDialogUI(const WebAppInstallDialogUI&) = delete;
+  WebAppInstallDialogUI& operator=(const WebAppInstallDialogUI&) = delete;
+  ~WebAppInstallDialogUI() override;
+};
+
+// WebUIConfig for chrome://web-app-install-dialog
+class WebAppInstallDialogUIConfig
+    : public content::DefaultWebUIConfig<WebAppInstallDialogUI> {
+ public:
+  WebAppInstallDialogUIConfig();
+
+  bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
+};
+
+}  // namespace ash::web_app_install
+
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_WEB_APP_INSTALL_WEB_APP_INSTALL_UI_H_
diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc b/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc
index 974ef54..214364b 100644
--- a/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc
+++ b/chrome/browser/ui/webui/settings/ash/os_settings_sections.cc
@@ -16,12 +16,12 @@
 #include "chrome/browser/ui/webui/ash/settings/pages/date_time/date_time_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/device/device_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/files/files_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/internet/internet_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/kerberos/kerberos_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/people/people_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/printing/printing_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/search/search_section.h"
-#include "chrome/browser/ui/webui/settings/ash/internet_section.h"
-#include "chrome/browser/ui/webui/settings/ash/kerberos_section.h"
-#include "chrome/browser/ui/webui/settings/ash/languages_section.h"
 #include "chrome/browser/ui/webui/settings/ash/main_section.h"
 #include "chrome/browser/ui/webui/settings/ash/multidevice_section.h"
 #include "chrome/browser/ui/webui/settings/ash/personalization_section.h"
diff --git a/chrome/browser/ui/webui/settings/ash/system_preferences_section.cc b/chrome/browser/ui/webui/settings/ash/system_preferences_section.cc
index 3c52db2..669cffdf 100644
--- a/chrome/browser/ui/webui/settings/ash/system_preferences_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/system_preferences_section.cc
@@ -6,11 +6,11 @@
 
 #include "chrome/browser/ui/webui/ash/settings/pages/date_time/date_time_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/files/files_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/power/power_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/search/search_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/storage/storage_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/system_preferences/startup_section.h"
-#include "chrome/browser/ui/webui/settings/ash/languages_section.h"
 #include "chrome/browser/ui/webui/settings/ash/reset_section.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/ash/system_preferences_section.h b/chrome/browser/ui/webui/settings/ash/system_preferences_section.h
index 9e54ce5..8f624a7 100644
--- a/chrome/browser/ui/webui/settings/ash/system_preferences_section.h
+++ b/chrome/browser/ui/webui/settings/ash/system_preferences_section.h
@@ -8,11 +8,11 @@
 #include "base/values.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/date_time/date_time_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/files/files_section.h"
+#include "chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/power/power_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/search/search_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/storage/storage_section.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/system_preferences/startup_section.h"
-#include "chrome/browser/ui/webui/settings/ash/languages_section.h"
 #include "chrome/browser/ui/webui/settings/ash/os_settings_section.h"
 #include "chrome/browser/ui/webui/settings/ash/reset_section.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 55782dbc..fc224ce 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -2607,6 +2607,8 @@
      IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_TOGGLE_LABEL},
     {"trackingProtectionThirdPartyCookiesToggleSubLabel",
      IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_TOGGLE_SUB_LABEL},
+    {"trackingProtectionThirdPartyCookiesLearnMoreAriaLabel",
+     IDS_SETTINGS_TRACKING_PROTECTION_THIRD_PARTY_COOKIES_LEARN_MORE_ARIA_LABEL},
     {"trackingProtectionDoNotTrackToggleSubLabel",
      IDS_SETTINGS_TRACKING_PROTECTION_DO_NOT_TRACK_TOGGLE_SUB_LABEL},
     {"trackingProtectionSitesAllowedCookiesTitle",
@@ -3280,7 +3282,9 @@
       "trackingProtectionBulletTwoDescription",
       l10n_util::GetStringFUTF16(
           IDS_SETTINGS_TRACKING_PROTECTION_BULLET_TWO_DESCRIPTION,
-          base::ASCIIToUTF16(chrome::kUserBypassHelpCenterURL)));
+          base::ASCIIToUTF16(chrome::kUserBypassHelpCenterURL),
+          l10n_util::GetStringUTF16(
+              IDS_SETTINGS_TRACKING_PROTECTION_BULLET_TWO_LEARN_MORE_ARIA_LABEL)));
   html_source->AddString("trackingProtectionThirdPartyCookiesLearnMoreUrl",
                          chrome::kManage3pcHelpCenterURL);
 
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom
index 3e46e7f6..fbe322f3 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom
@@ -88,6 +88,15 @@
   kModules,
 };
 
+struct DescriptorA {
+  string category;
+  array<string> labels;
+};
+
+struct Descriptors {
+  array<DescriptorA> descriptor_a;
+};
+
 // Used by the WebUI page to bootstrap bidirectional communication.
 interface CustomizeChromePageHandlerFactory {
   // The WebUI calls this method when the page is first initialized.
@@ -153,18 +162,21 @@
 
   // Searches NTP wallpaper for `query`. Returns true if search was successful.
   SearchWallpaper(string query) => (bool success);
+
+  // Searches for NTP descriptors.
+  GetDescriptors() => (Descriptors? descriptors);
 };
 
 // WebUI-side handler for requests from the browser.
 interface CustomizeChromePage {
-   // Sets available modules and their associated properties such as id, name,
-   // enabled status, visibility and managed state.
-   SetModulesSettings(array<ModuleSettings> modules_settings, bool managed,
-       bool visible);
+  // Sets available modules and their associated properties such as id, name,
+  // enabled status, visibility and managed state.
+  SetModulesSettings(array<ModuleSettings> modules_settings, bool managed,
+      bool visible);
   // Sets the visibility of NTP tiles and whether custom links are enabled.
   SetMostVisitedSettings(bool custom_links_enabled, bool visible);
-   // Sets the current theme.
-   SetTheme(Theme theme);
+  // Sets the current theme.
+  SetTheme(Theme theme);
   // Scrolls side panel to |section|. Possibly a response to a call to
   // |CustomizeChromePageHandler.UpdateScrollToSection()|.
   ScrollToSection(CustomizeChromeSection section);
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc
index 63690c7..c9158d5 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc
@@ -41,6 +41,8 @@
 #include "extensions/common/extension.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/color/color_provider.h"
@@ -222,6 +224,71 @@
   }
 }
 
+void CustomizeChromePageHandler::OnDescriptorsRetrieved(
+    std::unique_ptr<std::string> response_body) {
+  if (!response_body) {
+    // Network errors (i.e. the server did not provide a response).
+    DVLOG(1) << "Request failed with error: " << simple_url_loader_->NetError();
+    std::move(get_descriptors_callback_).Run(nullptr);
+    return;
+  }
+
+  std::string response;
+  response.swap(*response_body);
+  // The response may start with . Ignore this.
+  const char kXSSIResponsePreamble[] = ")]}'";
+  if (base::StartsWith(response, kXSSIResponsePreamble,
+                       base::CompareCase::SENSITIVE)) {
+    response = response.substr(strlen(kXSSIResponsePreamble));
+  }
+  data_decoder::DataDecoder::ParseJsonIsolated(
+      response,
+      base::BindOnce(&CustomizeChromePageHandler::OnDescriptorsJsonParsed,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CustomizeChromePageHandler::OnDescriptorsJsonParsed(
+    data_decoder::DataDecoder::ValueOrError result) {
+  if (!result.has_value() || !result->is_dict()) {
+    DVLOG(1) << "Parsing JSON failed: " << result.error();
+    std::move(get_descriptors_callback_).Run(nullptr);
+    return;
+  }
+
+  const base::Value::List* descriptor_a =
+      result->GetDict().FindList("descriptor_a");
+  if (!descriptor_a) {
+    DVLOG(1) << "Parsing JSON failed: " << result.error();
+    std::move(get_descriptors_callback_).Run(nullptr);
+    return;
+  }
+
+  auto mojo_descriptors = side_panel::mojom::Descriptors::New();
+  std::vector<side_panel::mojom::DescriptorAPtr> mojo_descriptor_a_list;
+  for (const auto& descriptor : *descriptor_a) {
+    const base::Value::Dict& descriptor_dict = descriptor.GetDict();
+    auto* category = descriptor_dict.FindString("category");
+    auto* label_values = descriptor_dict.FindList("labels");
+    if (!category || !label_values) {
+      continue;
+    }
+    auto mojo_descriptor_a = side_panel::mojom::DescriptorA::New();
+    mojo_descriptor_a->category = *category;
+    std::vector<std::string> labels;
+    for (const auto& label_value : *label_values) {
+      labels.push_back(label_value.GetString());
+    }
+    mojo_descriptor_a->labels = std::move(labels);
+    mojo_descriptor_a_list.push_back(std::move(mojo_descriptor_a));
+  }
+  if (mojo_descriptor_a_list.empty()) {
+    std::move(get_descriptors_callback_).Run(nullptr);
+    return;
+  }
+  mojo_descriptors->descriptor_a = std::move(mojo_descriptor_a_list);
+  std::move(get_descriptors_callback_).Run(std::move(mojo_descriptors));
+}
+
 void CustomizeChromePageHandler::WallpaperSearchCallback(
     SearchWallpaperCallback callback,
     optimization_guide::OptimizationGuideModelExecutionResult result) {
@@ -241,6 +308,67 @@
   std::move(callback).Run(true);
 }
 
+void CustomizeChromePageHandler::GetDescriptors(
+    GetDescriptorsCallback callback) {
+  callback =
+      mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback), nullptr);
+  if (get_descriptors_callback_) {
+    return;
+  }
+  get_descriptors_callback_ = std::move(callback);
+
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("customize_chrome_page_handler", R"(
+        semantics {
+          sender: "Customize Chrome"
+          description:
+            "This service downloads different configurations "
+            "for Customize Chrome."
+          trigger:
+            "Opening Customize Chrome on the Desktop NTP, "
+            "if Google is the default search provider "
+            "and the user is signed in."
+          data: "None."
+          destination: GOOGLE_OWNED_SERVICE
+          internal {
+            contacts {
+              email: "chrome-desktop-ntp@google.com"
+            }
+          }
+          user_data {
+            type: NONE
+          }
+          last_reviewed: "2023-10-10"
+        }
+        policy {
+          cookies_allowed: NO
+          setting:
+            "Users can control this feature by signing out or "
+            "selecting a non-Google default search engine in Chrome "
+            "settings under 'Search Engine'."
+          chrome_policy {
+            DefaultSearchProviderEnabled {
+              policy_options {mode: MANDATORY}
+              DefaultSearchProviderEnabled: false
+            }
+          }
+        })");
+
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = GURL(
+      "https://static.corp.google.com/chrome-wallpaper-search/"
+      "descriptors_en-US.json");
+  resource_request->request_initiator =
+      url::Origin::Create(GURL(chrome::kChromeUINewTabURL));
+  simple_url_loader_ = network::SimpleURLLoader::Create(
+      std::move(resource_request), traffic_annotation);
+  simple_url_loader_->DownloadToString(
+      profile_->GetURLLoaderFactory().get(),
+      base::BindOnce(&CustomizeChromePageHandler::OnDescriptorsRetrieved,
+                     weak_ptr_factory_.GetWeakPtr()),
+      1024 * 1024);
+}
+
 void CustomizeChromePageHandler::SearchWallpaper(
     const std::string& query,
     SearchWallpaperCallback callback) {
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h
index a3c9909..9b3462d 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h
@@ -22,6 +22,7 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/native_theme/native_theme_observer.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
@@ -94,12 +95,15 @@
   void SetModuleDisabled(const std::string& module_id, bool disabled) override;
   void UpdateModulesSettings() override;
   void UpdateScrollToSection() override;
+  void GetDescriptors(GetDescriptorsCallback callback) override;
   void SearchWallpaper(const std::string& query,
                        SearchWallpaperCallback callback) override;
 
  private:
   void LogEvent(NTPLoggingEventType event);
 
+  void OnDescriptorsRetrieved(std::unique_ptr<std::string> response_body);
+  void OnDescriptorsJsonParsed(data_decoder::DataDecoder::ValueOrError result);
   void WallpaperSearchCallback(
       SearchWallpaperCallback callback,
       optimization_guide::OptimizationGuideModelExecutionResult result);
@@ -130,6 +134,7 @@
   void FileSelectionCanceled(void* params) override;
 
   ChooseLocalCustomBackgroundCallback choose_local_custom_background_callback_;
+  GetDescriptorsCallback get_descriptors_callback_;
   raw_ptr<NtpCustomBackgroundService> ntp_custom_background_service_;
   raw_ptr<Profile> profile_;
   scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
@@ -142,6 +147,7 @@
   base::TimeTicks background_images_request_start_time_;
   raw_ptr<ThemeService> theme_service_;
   const std::vector<std::pair<const std::string, int>> module_id_names_;
+  std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
   // Caches a request to scroll to a section in case the front-end queries the
   // last requested section, e.g. during load.
   CustomizeChromeSection last_requested_section_ =
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc
index c38a207b..b2ccafbb 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ptr_exclusion.h"
+#include "base/test/bind.h"
 #include "base/test/gmock_move_support.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
@@ -54,6 +55,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension_builder.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
@@ -316,6 +318,7 @@
     browser_.reset();
     browser_window_.reset();
     TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
+    test_url_loader_factory_.ClearResponses();
   }
 
   TestingProfile& profile() { return *profile_; }
@@ -829,11 +832,134 @@
     CustomizeChromePageHandlerTest::SetUp();
   }
 
+  const std::string kDescriptorsLoadURL =
+      "https://static.corp.google.com/chrome-wallpaper-search/"
+      "descriptors_en-US.json";
+  void SetUpDescriptorsResponseWithData(const std::string& response) {
+    test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
+        [&](const network::ResourceRequest& request) {}));
+    test_url_loader_factory_.AddResponse(kDescriptorsLoadURL, response);
+  }
+  void SetUpDescriptorsResponseWithNetworkError() {
+    test_url_loader_factory_.AddResponse(kDescriptorsLoadURL, std::string(),
+                                         net::HTTP_NOT_FOUND);
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_;
+  data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
 };
 
 TEST_F(CustomizeChromePageHandlerWithWallpaperSearchTest,
+       GetDescriptors_Success) {
+  side_panel::mojom::DescriptorsPtr descriptors;
+  base::MockCallback<CustomizeChromePageHandler::GetDescriptorsCallback>
+      callback;
+  EXPECT_CALL(callback, Run(_))
+      .Times(1)
+      .WillOnce(testing::Invoke(
+          [&descriptors](
+              side_panel::mojom::DescriptorsPtr descriptors_ptr_arg) {
+            descriptors = std::move(descriptors_ptr_arg);
+          }));
+  SetUpDescriptorsResponseWithData(
+      R"()]}'
+        {"descriptor_a":[
+          {"category":"foo","labels":["bar","baz"]},
+          {"category":"qux","labels":["foobar"]}
+      ]})");
+
+  ASSERT_FALSE(descriptors);
+  handler().GetDescriptors(callback.Get());
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(descriptors);
+  const auto& descriptor_a = descriptors->descriptor_a;
+  EXPECT_EQ(2u, descriptor_a.size());
+  const auto& foo_descriptor = descriptor_a[0];
+  EXPECT_EQ(foo_descriptor->category, "foo");
+  EXPECT_EQ(2u, foo_descriptor->labels.size());
+  EXPECT_EQ("bar", foo_descriptor->labels[0]);
+  EXPECT_EQ("baz", foo_descriptor->labels[1]);
+  const auto& qux_descriptor = descriptor_a[1];
+  EXPECT_EQ(qux_descriptor->category, "qux");
+  EXPECT_EQ(1u, qux_descriptor->labels.size());
+  EXPECT_EQ("foobar", qux_descriptor->labels[0]);
+}
+
+TEST_F(CustomizeChromePageHandlerWithWallpaperSearchTest,
+       GetDescriptors_Fails_NoValidDescriptors) {
+  side_panel::mojom::DescriptorsPtr descriptors;
+  base::MockCallback<CustomizeChromePageHandler::GetDescriptorsCallback>
+      callback;
+  EXPECT_CALL(callback, Run(_))
+      .Times(1)
+      .WillOnce(testing::Invoke(
+          [&descriptors](
+              side_panel::mojom::DescriptorsPtr descriptors_ptr_arg) {
+            descriptors = std::move(descriptors_ptr_arg);
+          }));
+  SetUpDescriptorsResponseWithData(
+      R"()]}'
+        {"not_a_valid_descriptor":[
+          {"category":"foo","labels":["bar","baz"]},
+          {"category":"qux","labels":["foobar"]}
+      ]})");
+  ASSERT_FALSE(descriptors);
+
+  handler().GetDescriptors(callback.Get());
+  task_environment_.RunUntilIdle();
+
+  EXPECT_FALSE(descriptors);
+}
+
+TEST_F(CustomizeChromePageHandlerWithWallpaperSearchTest,
+       GetDescriptors_Fails_NoCategoriesWithLabels) {
+  side_panel::mojom::DescriptorsPtr descriptors;
+  base::MockCallback<CustomizeChromePageHandler::GetDescriptorsCallback>
+      callback;
+  EXPECT_CALL(callback, Run(_))
+      .Times(1)
+      .WillOnce(testing::Invoke(
+          [&descriptors](
+              side_panel::mojom::DescriptorsPtr descriptors_ptr_arg) {
+            descriptors = std::move(descriptors_ptr_arg);
+          }));
+  SetUpDescriptorsResponseWithData(
+      R"()]}'
+        {"descriptor_a":[
+          {"category":"foo"}
+      ]})");
+  ASSERT_FALSE(descriptors);
+
+  handler().GetDescriptors(callback.Get());
+  task_environment_.RunUntilIdle();
+
+  EXPECT_FALSE(descriptors);
+}
+
+TEST_F(CustomizeChromePageHandlerWithWallpaperSearchTest,
+       GetDescriptors_Fails_DataIsUnreachable) {
+  side_panel::mojom::DescriptorsPtr descriptors;
+  base::MockCallback<CustomizeChromePageHandler::GetDescriptorsCallback>
+      callback;
+  EXPECT_CALL(callback, Run(_))
+      .Times(1)
+      .WillOnce(testing::Invoke(
+          [&descriptors](
+              side_panel::mojom::DescriptorsPtr descriptors_ptr_arg) {
+            descriptors = std::move(descriptors_ptr_arg);
+          }));
+  SetUpDescriptorsResponseWithNetworkError();
+  ASSERT_FALSE(descriptors);
+
+  handler().GetDescriptors(callback.Get());
+  task_environment_.RunUntilIdle();
+
+  EXPECT_FALSE(descriptors);
+}
+
+TEST_F(CustomizeChromePageHandlerWithWallpaperSearchTest,
        SearchWallpaper_Success) {
   optimization_guide::proto::ModelExecutionFeature feature;
   chrome_intelligence_modelexecution_proto::WallpaperSearchRequest request;
diff --git a/chrome/browser/web_applications/OWNERS b/chrome/browser/web_applications/OWNERS
index d5f98290..82877ba 100644
--- a/chrome/browser/web_applications/OWNERS
+++ b/chrome/browser/web_applications/OWNERS
@@ -11,7 +11,6 @@
 
 # Secondary
 cmp@chromium.org
-dominickn@chromium.org
 ortuno@chromium.org
 
 # OS shortcuts
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto
index ffe9744..d6677a8 100644
--- a/chrome/browser/web_applications/proto/web_app.proto
+++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -478,4 +478,10 @@
   // Contains bookkeeping details about attempts to fix broken icons from sync
   // installed web apps.
   optional GeneratedIconFix generated_icon_fix = 65;
+
+  // Records the number of times the user has ignored/dismissed the offer to
+  // turn on user link capturing after launching the app via the intent picker,
+  // specifically from the `EnableLinkCapturingInfoBarDelegate`.
+  optional int32 supported_links_offer_ignore_count = 66;
+  optional int32 supported_links_offer_dismiss_count = 67;
 }
diff --git a/chrome/browser/web_applications/test/web_app_test_utils.cc b/chrome/browser/web_applications/test/web_app_test_utils.cc
index ad73796..5a3f7c4 100644
--- a/chrome/browser/web_applications/test/web_app_test_utils.cc
+++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -949,6 +949,8 @@
     app->SetGeneratedIconFix(generated_icon_fix);
   }
 
+  app->SetSupportedLinksOfferIgnoreCount(random.next_uint());
+  app->SetSupportedLinksOfferDismissCount(random.next_uint());
   return app;
 }
 
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index dd25849..a3984c6 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -692,6 +692,14 @@
       is_user_selected_app_for_capturing_links;
 }
 
+void WebApp::SetSupportedLinksOfferIgnoreCount(int ignore_count) {
+  supported_links_offer_ignore_count_ = ignore_count;
+}
+
+void WebApp::SetSupportedLinksOfferDismissCount(int dismiss_count) {
+  supported_links_offer_dismiss_count_ = dismiss_count;
+}
+
 void WebApp::AddPlaceholderInfoToManagementExternalConfigMap(
     WebAppManagement::Type type,
     bool is_placeholder) {
@@ -983,7 +991,9 @@
         app.isolation_data_,
         app.is_user_selected_app_for_capturing_links_,
         app.latest_install_time_,
-        app.generated_icon_fix_
+        app.generated_icon_fix_,
+        app.supported_links_offer_ignore_count_,
+        app.supported_links_offer_dismiss_count_
         // clang-format on
     );
   };
@@ -1202,6 +1212,11 @@
   root.Set("generated_icon_fix", generated_icon_fix_util::ToDebugValue(
                                      base::OptionalToPtr(generated_icon_fix_)));
 
+  root.Set("supported_links_offer_ignore_count",
+           supported_links_offer_ignore_count_);
+  root.Set("supported_links_offer_dismiss_count",
+           supported_links_offer_dismiss_count_);
+
   return base::Value(std::move(root));
 }
 
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index 1fdda5a..ac8abc7 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -417,6 +417,13 @@
 
   const absl::optional<GeneratedIconFix>& generated_icon_fix() const;
 
+  int supported_links_offer_ignore_count() const {
+    return supported_links_offer_ignore_count_;
+  }
+  int supported_links_offer_dismiss_count() const {
+    return supported_links_offer_dismiss_count_;
+  }
+
   // A Web App can be installed from multiple sources simultaneously. Installs
   // add a source to the app. Uninstalls remove a source from the app.
   void AddSource(WebAppManagement::Type source);
@@ -511,6 +518,8 @@
   void SetIsolationData(IsolationData isolation_data);
   void SetIsUserSelectedAppForSupportedLinks(
       bool is_user_selected_app_for_capturing_links);
+  void SetSupportedLinksOfferIgnoreCount(int ignore_count);
+  void SetSupportedLinksOfferDismissCount(int dismiss_count);
 
   void AddPlaceholderInfoToManagementExternalConfigMap(
       WebAppManagement::Type source_type,
@@ -659,6 +668,9 @@
 
   absl::optional<GeneratedIconFix> generated_icon_fix_;
 
+  int supported_links_offer_ignore_count_ = 0;
+  int supported_links_offer_dismiss_count_ = 0;
+
   // New fields must be added to:
   //  - |operator==|
   //  - AsDebugValue()
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index 45c32db..28dd06f 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -910,6 +910,11 @@
         web_app.generated_icon_fix().value();
   }
 
+  local_data->set_supported_links_offer_ignore_count(
+      web_app.supported_links_offer_ignore_count());
+  local_data->set_supported_links_offer_dismiss_count(
+      web_app.supported_links_offer_dismiss_count());
+
   return local_data;
 }
 
@@ -1671,6 +1676,16 @@
     web_app->SetGeneratedIconFix(local_data.generated_icon_fix());
   }
 
+  if (local_data.has_supported_links_offer_ignore_count()) {
+    web_app->SetSupportedLinksOfferIgnoreCount(
+        local_data.supported_links_offer_ignore_count());
+  }
+
+  if (local_data.has_supported_links_offer_dismiss_count()) {
+    web_app->SetSupportedLinksOfferDismissCount(
+        local_data.supported_links_offer_dismiss_count());
+  }
+
   return web_app;
 }
 
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index c3fd25f..f8c0db5 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -19,6 +19,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/observer_list.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/to_string.h"
@@ -1027,6 +1028,23 @@
   return absl::nullopt;
 }
 
+bool WebAppRegistrar::IsLinkCapturableByApp(const webapps::AppId& app,
+                                            const GURL& url) const {
+  CHECK(url.is_valid());
+  // TODO(dmurph): Switch to GetAppExtendedScopeScore if the
+  // kWebAppEnableScopeExtensions feature is enabled. b/294079334
+  size_t app_score = GetUrlInAppScopeScore(url.spec(), app);
+  if (app_score == 0) {
+    return false;
+  }
+  return base::ranges::none_of(GetAppIds(), [&](const webapps::AppId& app_id) {
+    // TODO(b/294079334): Switch to GetAppExtendedScopeScore if the
+    // kWebAppEnableScopeExtensions feature is enabled.
+    return IsLocallyInstalled(app_id) && !IsShortcutApp(app_id) &&
+           GetUrlInAppScopeScore(url.spec(), app_id) > app_score;
+  });
+}
+
 std::vector<webapps::AppId> WebAppRegistrar::GetOverlappingAppsMatchingScope(
     const webapps::AppId& app_id) const {
   std::vector<webapps::AppId> all_apps_with_supported_links;
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h
index 93253b8..e5f09d7 100644
--- a/chrome/browser/web_applications/web_app_registrar.h
+++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -418,11 +418,21 @@
   // capture links by the user. If an app is not locally installed or is a
   // shortcut, this returns false.
   bool CapturesLinksInScope(const webapps::AppId& app_id) const;
+
   // Searches for all apps that can control this url, and chooses the best one
   // that also captures links.
   absl::optional<webapps::AppId> FindAppThatCapturesLinksInScope(
       const GURL& url) const;
 
+  // Returns true or false depending on whether the given `app` can be set as a
+  // preferred app to capture the input URL. This returns false if:
+  // 1. The app does not control the url, i.e. app scope has no match with
+  //    `url`.
+  // 2. There is another app in the DB that better controls `url`, i.e. has a
+  //    higher scope score than `app`.
+  // Note: This does NOT mean that `app` has user link capturing enabled.
+  bool IsLinkCapturableByApp(const webapps::AppId& app, const GURL& url) const;
+
   // Returns a set of app ids that match the scope for user link capturing.
   std::vector<webapps::AppId> GetOverlappingAppsMatchingScope(
       const webapps::AppId& app_id) const;
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index c9b8463..310c1c2 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1696939164-a7230a0570f2cabd88552fd349898467084d0b74.profdata
+chrome-android32-main-1696960791-c4572a9ba628afff87d3b6b6c86581902db8bb75.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 888c106..92c6bdb 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1696939164-1b9fe479ee4ffe46448bb3efcb9725abb496d2ad.profdata
+chrome-android64-main-1696960791-a3891e7ce1d554df5a87e1851505500505865333.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index b3017f9..07f5e313 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1696939164-787dd0d9352fb46e80bc57febc096e11c1aa95ce.profdata
+chrome-linux-main-1696960791-718dce9755181af7b5ea08010e46d347813a33da.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 4c7ae15..70cab83 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1696960791-762905b22462705f64cdc41d577ad8103a935518.profdata
+chrome-mac-arm-main-1696975158-c8dcbb0eea3dc510a58d17c99d90ffbf15bf8ce9.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index cd975c99..8d74bb8 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1696939164-2114e694ea2434712890b2e028b4fb34c9e066b4.profdata
+chrome-mac-main-1696960791-5613ca688c1e1cb48339cef54abab1e4cee45095.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index a54286c..271deac 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1696939164-30356e07b7bd3c94d1f9c47d2ce97f574d5a03e5.profdata
+chrome-win-arm64-main-1696960791-10e6e5bc24faa6771b8d77e3f7155a93fffc3bd7.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 1b1edcc..96945025 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1696949938-64a768dd62084d8442cea1031a71fe1185020720.profdata
+chrome-win32-main-1696960791-53c62ef92c4f0d599ad3fbe91841eea59909a5a6.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index be401f0..984740b 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1696949938-74b67a6a8a406e806237204f5250bfa49978e8ff.profdata
+chrome-win64-main-1696960791-559705329bff7c798076b7924e71eec09535f8e8.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index b2848fe..ee119ed 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -290,6 +290,7 @@
         "$root_gen_dir/chrome/sensor_info_resources.pak",
         "$root_gen_dir/chrome/supervision_resources.pak",
         "$root_gen_dir/chrome/vc_tray_tester_resources.pak",
+        "$root_gen_dir/chrome/web_app_install_resources.pak",
         "$root_gen_dir/chromeos/ash/ash_resources.pak",
         "$root_gen_dir/chromeos/chromeos_help_app_bundle_resources.pak",
         "$root_gen_dir/chromeos/chromeos_help_app_kids_magazine_bundle_resources.pak",
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 4acc328..5303d071 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -111,8 +111,11 @@
 const char kSwitchAccessExtensionId[] = "pmehocpgjmkenlokgjfkaichfjdhpeol";
 const char kSwitchAccessExtensionPath[] = "chromeos/accessibility";
 const char kSwitchAccessManifestFilename[] = "switch_access_manifest.json";
+const char kSwitchAccessManifestV3Filename[] = "switch_access_manifest_v3.json";
 const char kSwitchAccessGuestManifestFilename[] =
     "switch_access_manifest_guest.json";
+const char kSwitchAccessGuestManifestV3Filename[] =
+    "switch_access_manifest_guest_v3.json";
 const char kGuestManifestFilename[] = "manifest_guest.json";
 const char kFirstRunDialogId[] = "jdgcneonijmofocbhmijhacgchbihela";
 const char kEspeakSpeechSynthesisExtensionPath[] =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 32be69a8..9c2116c 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -217,8 +217,12 @@
 extern const char kSwitchAccessExtensionPath[];
 // The manifest filename of the Switch Access extension.
 extern const char kSwitchAccessManifestFilename[];
+// The manifest v3 filename of the Switch Access extension.
+extern const char kSwitchAccessManifestV3Filename[];
 // The guest manifest filename of the Switch Access extension.
 extern const char kSwitchAccessGuestManifestFilename[];
+// The guest manifest v3 filename of the Switch Access extension.
+extern const char kSwitchAccessGuestManifestV3Filename[];
 // Name of the manifest file in an extension when a special manifest is used
 // for guest mode.
 extern const char kGuestManifestFilename[];
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 0b7015f9..94eb372f 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -349,6 +349,8 @@
 const char kChromeUIDeviceEmulatorHost[] = "device-emulator";
 const char kChromeUIDeviceEmulatorURL[] = "chrome://device-emulator";
 const char kChromeUIDiagnosticsAppURL[] = "chrome://diagnostics";
+const char kChromeUIEmojiPickerURL[] = "chrome://emoji-picker/";
+const char kChromeUIEmojiPickerHost[] = "emoji-picker";
 const char kChromeUIEnterpriseReportingHost[] = "enterprise-reporting";
 const char kChromeUIEnterpriseReportingURL[] = "chrome://enterprise-reporting";
 const char kChromeUIFirmwareUpdaterAppURL[] = "chrome://accessory-update";
@@ -417,8 +419,9 @@
 const char kChromeUIVcTrayTesterURL[] = "chrome://vc-tray-tester";
 const char kChromeUIVmHost[] = "vm";
 const char kChromeUIVmUrl[] = "chrome://vm";
-const char kChromeUIEmojiPickerURL[] = "chrome://emoji-picker/";
-const char kChromeUIEmojiPickerHost[] = "emoji-picker";
+const char kChromeUIWebAppInstallDialogHost[] = "web-app-install-dialog";
+const char kChromeUIWebAppInstallDialogURL[] =
+    "chrome://web-app-install-dialog/";
 
 const char kChromeUIUrgentPasswordExpiryNotificationHost[] =
     "urgent-password-expiry-notification";
@@ -443,6 +446,7 @@
     kChromeUICrostiniInstallerHost,
     kChromeUICryptohomeHost,
     kChromeUIDeviceEmulatorHost,
+    kChromeUIEmojiPickerHost,
     kChromeUIInternetConfigDialogHost,
     kChromeUIInternetDetailDialogHost,
     kChromeUILockScreenNetworkHost,
@@ -460,7 +464,7 @@
     kChromeUISmbCredentialsHost,
     kChromeUISmbShareHost,
     kChromeUIVcTrayTesterHost,
-    kChromeUIEmojiPickerHost,
+    kChromeUIWebAppInstallDialogHost,
 #if BUILDFLAG(PLATFORM_CFM)
     kCfmNetworkSettingsHost,
 #endif  // BUILDFLAG(PLATFORM_CFM)
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index aa09a8a..cf14a91 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -387,6 +387,8 @@
 extern const char kChromeUIVcTrayTesterHost[];
 extern const char kChromeUIVmHost[];
 extern const char kChromeUIVmUrl[];
+extern const char kChromeUIWebAppInstallDialogHost[];
+extern const char kChromeUIWebAppInstallDialogURL[];
 
 // Returns true if this web UI is part of the "system UI". Generally this is
 // UI that opens in a window (not a browser tab) and that on other operating
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 451d6fa..81a3c09 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -883,6 +883,7 @@
     ]
     deps += [
       "//chrome/browser/ui/color:mixers",
+      "//components/color",
       "//components/user_education/views",
     ]
   }
@@ -3222,7 +3223,9 @@
       sources += [
         "../browser/external_protocol/external_protocol_policy_browsertest.cc",
         "../browser/lifetime/application_lifetime_browsertest.cc",
+        "../browser/ui/views/enable_link_capturing_infobar_browsertest.cc",
       ]
+      deps += [ "//chrome/browser/apps/link_capturing" ]
     }
 
     if (is_win || is_chromeos || is_mac) {
@@ -3821,6 +3824,8 @@
         "../browser/ui/test/test_app_window_icon_observer.h",
       ]
 
+      deps += [ "//components/eye_dropper" ]
+
       if (use_nss_certs) {
         sources += [ "../browser/ui/views/crypto_module_password_dialog_view_browsertest.cc" ]
       }
@@ -7995,6 +8000,7 @@
       "//chrome/browser/ui/webui/side_panel/user_notes:mojo_bindings",
       "//chrome/browser/web_applications:web_applications_test_support",
       "//components/app_constants",
+      "//components/color",
       "//components/commerce/core:cart_db_content_proto",
       "//components/commerce/core:coupon_db_content_proto",
       "//components/commerce/core:shopping_service_test_support",
diff --git a/chrome/test/DEPS b/chrome/test/DEPS
index 51722074..bd2069e 100644
--- a/chrome/test/DEPS
+++ b/chrome/test/DEPS
@@ -14,6 +14,7 @@
   "+components/bookmarks/browser",
   "+components/bookmarks/common",
   "+components/captive_portal",
+  "+components/color",
   "+components/commerce/core",
   "+components/component_updater",
   "+components/compose",
diff --git a/chrome/test/data/tpcd/inject_tpcd_support_ot.js b/chrome/test/data/tpcd/inject_tpcd_support_ot.js
new file mode 100644
index 0000000..65bcb5185
--- /dev/null
+++ b/chrome/test/data/tpcd/inject_tpcd_support_ot.js
@@ -0,0 +1,12 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generate this token with the command:
+// tools/origin_trials/generate_token.py https://example.test Tpcd --version 3 --is-third-party --expire-timestamp=2000000000
+const THIRD_PARTY_TOKEN = 'A4R02lBma1/SU5GBtWzt4xAJhrzX6r8K1YTPkOSIY8Y0rv4KbrJNumvUfQxGsJJ+Xcu+yTwdB5DG9F31rQACvQMAAABleyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiVHBjZCIsICJleHBpcnkiOiAyMDAwMDAwMDAwLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZX0=';
+
+const tokenElement = document.createElement('meta');
+tokenElement.httpEquiv = 'origin-trial';
+tokenElement.content = THIRD_PARTY_TOKEN;
+document.head.appendChild(tokenElement);
\ No newline at end of file
diff --git a/chrome/test/data/tpcd/page_with_cross_site_tpcd_support_ot.html b/chrome/test/data/tpcd/page_with_cross_site_tpcd_support_ot.html
new file mode 100644
index 0000000..ac0b263b
--- /dev/null
+++ b/chrome/test/data/tpcd/page_with_cross_site_tpcd_support_ot.html
@@ -0,0 +1,5 @@
+<html>
+<head>
+  <script src="https://example.test/tpcd/inject_tpcd_support_ot.js"></script>
+</head>
+</html>
\ No newline at end of file
diff --git a/chrome/test/data/web_apps/empty_web_app.json b/chrome/test/data/web_apps/empty_web_app.json
index cdd76128..662436e 100644
--- a/chrome/test/data/web_apps/empty_web_app.json
+++ b/chrome/test/data/web_apps/empty_web_app.json
@@ -58,6 +58,8 @@
    "shortcuts_menu_item_infos": [  ],
    "sources": [  ],
    "start_url": "",
+   "supported_links_offer_dismiss_count": 0,
+   "supported_links_offer_ignore_count": 0,
    "sync_fallback_data": {
       "manifest_icons": [  ],
       "name": "",
diff --git a/chrome/test/data/web_apps/nesting/nested/page1.html b/chrome/test/data/web_apps/nesting/nested/page1.html
new file mode 100644
index 0000000..373ed7ca
--- /dev/null
+++ b/chrome/test/data/web_apps/nesting/nested/page1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <link rel="icon" href="basic-48.png">
+</head>
+<body>
+  <h1>Simple page with no manifest, to serve as an in-scope page.</h1>
+</body>
+</html>
diff --git a/chrome/test/data/web_apps/page1.html b/chrome/test/data/web_apps/page1.html
new file mode 100644
index 0000000..373ed7ca
--- /dev/null
+++ b/chrome/test/data/web_apps/page1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <link rel="icon" href="basic-48.png">
+</head>
+<body>
+  <h1>Simple page with no manifest, to serve as an in-scope page.</h1>
+</body>
+</html>
diff --git a/chrome/test/data/web_apps/sample_web_app.json b/chrome/test/data/web_apps/sample_web_app.json
index 122b7125..4dc7a8e 100644
--- a/chrome/test/data/web_apps/sample_web_app.json
+++ b/chrome/test/data/web_apps/sample_web_app.json
@@ -421,6 +421,8 @@
    } ],
    "sources": [ "System", "Kiosk", "Policy", "OEM", "SubApp", "WebAppStore", "OneDriveIntegration", "Sync", "CommandLine", "ApsDefault", "Default" ],
    "start_url": "https://example.com/scope1234/start1234",
+   "supported_links_offer_dismiss_count": 445271870,
+   "supported_links_offer_ignore_count": 716143606,
    "sync_fallback_data": {
       "manifest_icons": [ {
          "purpose": "kAny",
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/combobox_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/combobox_test.ts
index b6c2c73..ba3e316b 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/combobox_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/combobox_test.ts
@@ -43,7 +43,30 @@
     assertFalse(isVisible(combobox.$.dropdown));
   });
 
-  test('HighlightsItemsOnKeydown', async () => {
+  test('OpensAndClosesDropdownOnKeydown', async () => {
+    const option1 = addOption();
+    const option2 = addOption();
+    await flushTasks();
+    assertFalse(isVisible(combobox.$.dropdown));
+
+    function assertDropdownOpensAndHighlightsFirst(
+        key: string, expectedHighlight: HTMLElement) {
+      combobox.dispatchEvent(new KeyboardEvent('keydown', {key}));
+      assertTrue(isVisible(combobox.$.dropdown));
+      assertEquals(expectedHighlight, combobox.querySelector('[highlighted]'));
+      // Close the dropdown.
+      combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'Escape'}));
+    }
+
+    assertDropdownOpensAndHighlightsFirst('ArrowDown', option1);
+    assertDropdownOpensAndHighlightsFirst('ArrowUp', option2);
+    assertDropdownOpensAndHighlightsFirst('Home', option1);
+    assertDropdownOpensAndHighlightsFirst('End', option2);
+    assertDropdownOpensAndHighlightsFirst('Enter', option1);
+    assertDropdownOpensAndHighlightsFirst('Space', option1);
+  });
+
+  test('HighlightsItemsOnKeydownWhenOpen', async () => {
     const groupA = addGroup();
     const optionA1 = addOption(groupA);
     const optionA2 = addOption(groupA);
@@ -51,10 +74,6 @@
     const optionB1 = addOption(groupB);
     await flushTasks();
 
-    // In collapsed state, should not highlight anything.
-    combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(null, combobox.querySelector('[highlighted]'));
-
     // ArrowDown should loop through list.
     combobox.$.input.click();
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
@@ -80,8 +99,9 @@
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'End'}));
     assertEquals(optionB1, combobox.querySelector('[highlighted]'));
 
-    // Resets highlighted item when collapsing.
-    combobox.$.input.dispatchEvent(new FocusEvent('focusout'));
+    // Closes when hitting Escape and resets highlight.
+    combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'Escape'}));
+    assertFalse(isVisible(combobox.$.dropdown));
     assertEquals(null, combobox.querySelector('[highlighted]'));
   });
 });
diff --git a/chrome/test/views/chrome_views_test_base.cc b/chrome/test/views/chrome_views_test_base.cc
index ad85a0c..f84289a 100644
--- a/chrome/test/views/chrome_views_test_base.cc
+++ b/chrome/test/views/chrome_views_test_base.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/color/chrome_color_mixers.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/test/views/chrome_test_widget.h"
+#include "components/color/color_mixers.h"
 #include "content/public/test/browser_task_environment.h"
 #include "ui/color/color_provider_manager.h"
 
@@ -51,6 +52,8 @@
       ChromeLayoutProvider::CreateLayoutProvider());
 
   ui::ColorProviderManager::Get().AppendColorProviderInitializer(
+      base::BindRepeating(color::AddComponentsColorMixers));
+  ui::ColorProviderManager::Get().AppendColorProviderInitializer(
       base::BindRepeating(AddChromeColorMixers));
 }
 
diff --git a/chrome/updater/app/app_server_win.cc b/chrome/updater/app/app_server_win.cc
index f6b3770..6124d83 100644
--- a/chrome/updater/app/app_server_win.cc
+++ b/chrome/updater/app/app_server_win.cc
@@ -252,6 +252,10 @@
   NOTREACHED();  // The instance of this class is a leaky singleton.
 }
 
+void AppServerWin::PostRpcTask(base::OnceClosure task) {
+  GetAppServerWinInstance()->PostRpcTaskOnMainSequence(std::move(task));
+}
+
 void AppServerWin::Stop() {
   VLOG(2) << __func__ << ": COM server is shutting down.";
   UnregisterClassObjects();
@@ -264,6 +268,10 @@
                               }));
 }
 
+void AppServerWin::PostRpcTaskOnMainSequence(base::OnceClosure task) {
+  main_task_runner_->PostTask(FROM_HERE, std::move(task));
+}
+
 bool AppServerWin::RestoreComInterfaces(bool is_internal) {
   return AreComInterfacesPresent(updater_scope(), is_internal) ||
          InstallComInterfaces(updater_scope(), is_internal);
diff --git a/chrome/updater/app/app_server_win.h b/chrome/updater/app/app_server_win.h
index 93177b8a..23b5e41 100644
--- a/chrome/updater/app/app_server_win.h
+++ b/chrome/updater/app/app_server_win.h
@@ -22,18 +22,6 @@
 // Returns S_OK if user install, or if the COM caller is admin. Error otherwise.
 HRESULT IsCOMCallerAllowed();
 
-// The COM objects involved in this server are free threaded. Incoming COM calls
-// arrive on COM RPC threads. Outgoing COM calls are posted from a blocking
-// sequenced task runner in the thread pool. Calls to the services hosted
-// in this server occur in the main sequence, which is bound to the main
-// thread of the process.
-//
-// If such a COM object has state which is visible to multiple threads, then the
-// access to the shared state of the object must be synchronized. This is done
-// by using a lock, internal to the object. Since the code running on the
-// main sequence can't use synchronization primitives, another task runner is
-// typically used to sequence the callbacks.
-//
 // This class is responsible for the lifetime of the COM server, as well as
 // class factory registration.
 //
@@ -46,15 +34,14 @@
   using AppServer::config;
   using AppServer::prefs;
 
-  scoped_refptr<base::SequencedTaskRunner> main_task_runner() {
-    return main_task_runner_;
-  }
+  // Posts the `task` to the sequence bound to this instance.
+  static void PostRpcTask(base::OnceClosure task);
+
   scoped_refptr<UpdateService> update_service() {
-    CHECK(update_service_);
     return update_service_;
   }
+
   scoped_refptr<UpdateServiceInternal> update_service_internal() {
-    CHECK(update_service_internal_);
     return update_service_internal_;
   }
 
@@ -74,7 +61,7 @@
   // `UpdateServiceInternal` method. Increments the WRL Module count.
   void TaskStarted();
 
-  // Overrides for AppServer
+  // Overrides for AppServer.
   void ActiveDuty(scoped_refptr<UpdateService> update_service) override;
   void ActiveDutyInternal(
       scoped_refptr<UpdateServiceInternal> update_service_internal) override;
@@ -105,6 +92,8 @@
   // Handles COM setup and registration.
   void Start(base::OnceCallback<HRESULT()> register_callback);
 
+  void PostRpcTaskOnMainSequence(base::OnceClosure task);
+
   // Task runner bound to the main sequence.
   scoped_refptr<base::SequencedTaskRunner> main_task_runner_ =
       base::SequencedTaskRunner::GetCurrentDefault();
diff --git a/chrome/updater/app/server/win/com_classes.cc b/chrome/updater/app/server/win/com_classes.cc
index 9c052f4..9f87b4b 100644
--- a/chrome/updater/app/server/win/com_classes.cc
+++ b/chrome/updater/app/server/win/com_classes.cc
@@ -40,6 +40,11 @@
 // Maximum string length for COM strings.
 constexpr size_t kMaxStringLen = 0x4000;  // 16KB.
 
+using IUpdaterCallbackPtr = Microsoft::WRL::ComPtr<IUpdaterCallback>;
+using IUpdaterInternalCallbackPtr =
+    Microsoft::WRL::ComPtr<IUpdaterInternalCallback>;
+using IUpdaterObserverPtr = Microsoft::WRL::ComPtr<IUpdaterObserver>;
+
 // Implements `IUpdaterAppState`. Initialized with an `UpdateService::AppState`.
 class UpdaterAppStateImpl : public IDispatchImpl<IUpdaterAppState> {
  public:
@@ -223,23 +228,29 @@
   if (!callback) {
     return E_INVALIDARG;
   }
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+
+  base::OnceCallback<void(int)> updater_callback = base::BindPostTask(
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
       base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             base::OnceCallback<void(int)> result_callback) {
-            update_service->FetchPolicies(std::move(result_callback));
+          [](IUpdaterCallbackPtr callback, int result) {
+            HRESULT hr = callback->Run(result);
+            VLOG(2) << "IUpdaterImpl::FetchPolicies. "
+                    << "IUpdaterCallback::Run returned " << std::hex << hr;
           },
-          com_server->update_service(),
-          base::BindPostTask(
-              base::ThreadPool::CreateSequencedTaskRunner(
-                  {base::MayBlock(),
-                   base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}),
-              base::BindOnce(
-                  [](Microsoft::WRL::ComPtr<IUpdaterCallback> callback,
-                     int result) { callback->Run(result); },
-                  Microsoft::WRL::ComPtr<IUpdaterCallback>(callback)))));
+          IUpdaterCallbackPtr(callback)));
+
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](base::OnceCallback<void(int)> updater_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(updater_callback).Run(-1);
+          return;
+        }
+        update_service->FetchPolicies(std::move(updater_callback));
+      },
+      std::move(updater_callback)));
   return S_OK;
 }
 
@@ -290,41 +301,33 @@
     return request;
   }();
 
-  if (!request)
+  if (!request) {
     return E_INVALIDARG;
+  }
 
-  using IUpdaterCallbackPtr = Microsoft::WRL::ComPtr<IUpdaterCallback>;
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-
-  // This task runner is responsible for sequencing the COM calls and callbacks.
-  auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+  base::OnceCallback<void(int)> updater_callback = base::BindPostTask(
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
       base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             const RegistrationRequest& request, IUpdaterCallbackPtr callback) {
-            update_service->RegisterApp(
-                request,
-                base::BindOnce(
-                    [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                       IUpdaterCallbackPtr callback, int result) {
-                      task_runner->PostTaskAndReplyWithResult(
-                          FROM_HERE,
-                          base::BindOnce(&IUpdaterCallback::Run, callback,
-                                         result),
-                          base::BindOnce([](HRESULT hr) {
-                            VLOG(2) << "UpdaterImpl::RegisterApp "
-                                    << "callback returned " << std::hex << hr;
-                          }));
-                    },
-                    task_runner, callback));
+          [](IUpdaterCallbackPtr callback, int result) {
+            HRESULT hr = callback->Run(result);
+            VLOG(2) << "IUpdaterImpl::RegisterApp. "
+                    << "IUpdaterCallback::Run returned " << std::hex << hr;
           },
-          com_server->update_service(), task_runner, *request,
-          IUpdaterCallbackPtr(callback)));
+          Microsoft::WRL::ComPtr<IUpdaterCallback>(callback)));
 
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](const RegistrationRequest& request,
+         base::OnceCallback<void(int)> updater_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(updater_callback).Run(-1);
+          return;
+        }
+        update_service->RegisterApp(request, std::move(updater_callback));
+      },
+      *request, std::move(updater_callback)));
   return S_OK;
 }
 
@@ -335,22 +338,22 @@
   if (!callback) {
     return E_INVALIDARG;
   }
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             base::OnceClosure callback_closure) {
-            update_service->RunPeriodicTasks(std::move(callback_closure));
-          },
-          com_server->update_service(),
-          base::BindPostTask(
-              base::ThreadPool::CreateSequencedTaskRunner(
-                  {base::MayBlock(),
-                   base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}),
-              base::BindOnce(base::IgnoreResult(&IUpdaterCallback::Run),
-                             Microsoft::WRL::ComPtr<IUpdaterCallback>(callback),
-                             0))));
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](base::OnceClosure callback_closure) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(callback_closure).Run();
+          return;
+        }
+        update_service->RunPeriodicTasks(std::move(callback_closure));
+      },
+      base::BindPostTask(
+          base::ThreadPool::CreateSequencedTaskRunner(
+              {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
+          base::BindOnce(base::IgnoreResult(&IUpdaterCallback::Run),
+                         Microsoft::WRL::ComPtr<IUpdaterCallback>(callback),
+                         0))));
   return S_OK;
 }
 
@@ -412,47 +415,47 @@
   }
 
   auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  using IUpdaterObserverPtr = Microsoft::WRL::ComPtr<IUpdaterObserver>;
-  auto observer_local = IUpdaterObserverPtr(observer);
-
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+  UpdateService::StateChangeCallback state_change_callback =
+      base::BindRepeating(
+          &StateChangeCallbackFilter::OnStateChange,
+          base::Owned(new StateChangeCallbackFilter(task_runner, observer)));
+  UpdateService::Callback complete_callback = base::BindPostTask(
+      task_runner,
       base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             const std::string& app_id, UpdateService::Priority priority,
-             bool same_version_update_allowed, IUpdaterObserverPtr observer) {
-            update_service->CheckForUpdate(
-                app_id, priority,
-                same_version_update_allowed
-                    ? UpdateService::PolicySameVersionUpdate::kAllowed
-                    : UpdateService::PolicySameVersionUpdate::kNotAllowed,
-                base::BindRepeating(&StateChangeCallbackFilter::OnStateChange,
-                                    base::Owned(new StateChangeCallbackFilter(
-                                        task_runner, observer))),
-                base::BindOnce(
-                    [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                       IUpdaterObserverPtr observer,
-                       UpdateService::Result result) {
-                      task_runner->PostTaskAndReplyWithResult(
-                          FROM_HERE,
-                          base::BindOnce(
-                              &IUpdaterObserver::OnComplete, observer,
-                              MakeComObjectOrCrash<CompleteStatusImpl>(
-                                  static_cast<int>(result), L"")),
-                          base::BindOnce([](HRESULT hr) {
-                            VLOG(2) << "UpdaterImpl::Update "
-                                    << "callback returned " << std::hex << hr;
-                          }));
-                    },
-                    task_runner, observer));
+          [](IUpdaterObserverPtr observer, UpdateService::Result result) {
+            HRESULT hr =
+                observer->OnComplete(MakeComObjectOrCrash<CompleteStatusImpl>(
+                                         static_cast<int>(result), L"")
+                                         .Get());
+            VLOG(2) << "IUpdaterImpl::CheckForUpdate. "
+                    << "IUpdaterObserver::OnComplete returned " << std::hex
+                    << hr;
           },
-          com_server->update_service(), task_runner, base::WideToUTF8(app_id),
-          static_cast<UpdateService::Priority>(priority),
-          same_version_update_allowed, observer_local));
+          IUpdaterObserverPtr(observer)));
+
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](const std::string& app_id, UpdateService::Priority priority,
+         bool same_version_update_allowed,
+         UpdateService::StateChangeCallback state_change_callback,
+         UpdateService::Callback complete_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(complete_callback)
+              .Run(UpdateService::Result::kServiceStopped);
+          return;
+        }
+        update_service->CheckForUpdate(
+            app_id, priority,
+            same_version_update_allowed
+                ? UpdateService::PolicySameVersionUpdate::kAllowed
+                : UpdateService::PolicySameVersionUpdate::kNotAllowed,
+            std::move(state_change_callback), std::move(complete_callback));
+      },
+      base::WideToUTF8(app_id), static_cast<UpdateService::Priority>(priority),
+      same_version_update_allowed, std::move(state_change_callback),
+      std::move(complete_callback)));
   return S_OK;
 }
 
@@ -471,53 +474,49 @@
     return E_INVALIDARG;
   }
 
-  // This task runner is responsible for sequencing the callbacks posted
-  // by the `UpdateService` and calling the outbound COM functions to
-  // notify the client about state changes in the `UpdateService`.
   auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  using IUpdaterObserverPtr = Microsoft::WRL::ComPtr<IUpdaterObserver>;
-  auto observer_local = IUpdaterObserverPtr(observer);
-
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+  UpdateService::StateChangeCallback state_change_callback =
+      base::BindRepeating(
+          &StateChangeCallbackFilter::OnStateChange,
+          base::Owned(new StateChangeCallbackFilter(task_runner, observer)));
+  UpdateService::Callback complete_callback = base::BindPostTask(
+      task_runner,
       base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             const std::string& app_id, const std::string& install_data_index,
-             UpdateService::Priority priority, bool same_version_update_allowed,
-             IUpdaterObserverPtr observer) {
-            update_service->Update(
-                app_id, install_data_index, priority,
-                same_version_update_allowed
-                    ? UpdateService::PolicySameVersionUpdate::kAllowed
-                    : UpdateService::PolicySameVersionUpdate::kNotAllowed,
-                base::BindRepeating(&StateChangeCallbackFilter::OnStateChange,
-                                    base::Owned(new StateChangeCallbackFilter(
-                                        task_runner, observer))),
-                base::BindOnce(
-                    [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                       IUpdaterObserverPtr observer,
-                       UpdateService::Result result) {
-                      task_runner->PostTaskAndReplyWithResult(
-                          FROM_HERE,
-                          base::BindOnce(
-                              &IUpdaterObserver::OnComplete, observer,
-                              MakeComObjectOrCrash<CompleteStatusImpl>(
-                                  static_cast<int>(result), L"")),
-                          base::BindOnce([](HRESULT hr) {
-                            VLOG(2) << "UpdaterImpl::Update "
-                                    << "callback returned " << std::hex << hr;
-                          }));
-                    },
-                    task_runner, observer));
+          [](IUpdaterObserverPtr observer, UpdateService::Result result) {
+            HRESULT hr =
+                observer->OnComplete(MakeComObjectOrCrash<CompleteStatusImpl>(
+                                         static_cast<int>(result), L"")
+                                         .Get());
+            VLOG(2) << "IUpdaterImpl::Update. "
+                    << "IUpdaterObserver::OnComplete returned " << std::hex
+                    << hr;
           },
-          com_server->update_service(), task_runner, base::WideToUTF8(app_id),
-          base::WideToUTF8(install_data_index),
-          static_cast<UpdateService::Priority>(priority),
-          same_version_update_allowed, observer_local));
+          IUpdaterObserverPtr(observer)));
+
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](const std::string& app_id, const std::string& install_data_index,
+         UpdateService::Priority priority, bool same_version_update_allowed,
+         UpdateService::StateChangeCallback state_change_callback,
+         UpdateService::Callback complete_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(complete_callback)
+              .Run(UpdateService::Result::kServiceStopped);
+          return;
+        }
+        update_service->Update(
+            app_id, install_data_index, priority,
+            same_version_update_allowed
+                ? UpdateService::PolicySameVersionUpdate::kAllowed
+                : UpdateService::PolicySameVersionUpdate::kNotAllowed,
+            std::move(state_change_callback), std::move(complete_callback));
+      },
+      base::WideToUTF8(app_id), base::WideToUTF8(install_data_index),
+      static_cast<UpdateService::Priority>(priority),
+      same_version_update_allowed, std::move(state_change_callback),
+      std::move(complete_callback)));
   return S_OK;
 }
 
@@ -527,41 +526,34 @@
     return E_INVALIDARG;
   }
 
-  using IUpdaterObserverPtr = Microsoft::WRL::ComPtr<IUpdaterObserver>;
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-
-  auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+  UpdateService::Callback complete_callback = base::BindPostTask(
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
       base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             IUpdaterObserverPtr observer) {
-            update_service->UpdateAll(
-                base::DoNothing(),
-                base::BindOnce(
-                    [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                       IUpdaterObserverPtr observer,
-                       UpdateService::Result result) {
-                      // The COM RPC outgoing call blocks and it must be posted
-                      // through the thread pool.
-                      task_runner->PostTaskAndReplyWithResult(
-                          FROM_HERE,
-                          base::BindOnce(
-                              &IUpdaterObserver::OnComplete, observer,
-                              MakeComObjectOrCrash<CompleteStatusImpl>(
-                                  static_cast<int>(result), L"")),
-                          base::BindOnce([](HRESULT hr) {
-                            VLOG(2) << "UpdaterImpl::UpdateAll "
-                                    << "callback returned " << std::hex << hr;
-                          }));
-                    },
-                    task_runner, observer));
+          [](IUpdaterObserverPtr observer, UpdateService::Result result) {
+            HRESULT hr =
+                observer->OnComplete(MakeComObjectOrCrash<CompleteStatusImpl>(
+                                         static_cast<int>(result), L"")
+                                         .Get());
+            VLOG(2) << "IUpdaterImpl::UpdateAll. "
+                    << "IUpdaterObserver::OnComplete returned " << std::hex
+                    << hr;
           },
-          com_server->update_service(), task_runner,
           IUpdaterObserverPtr(observer)));
+
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](UpdateService::Callback complete_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(complete_callback)
+              .Run(UpdateService::Result::kServiceStopped);
+          return;
+        }
+        update_service->UpdateAll(base::DoNothing(),
+                                  std::move(complete_callback));
+      },
+      std::move(complete_callback)));
   return S_OK;
 }
 
@@ -616,54 +608,52 @@
     return request;
   }();
 
-  if (!request)
+  if (!request) {
     return E_INVALIDARG;
+  }
 
-  // This task runner is responsible for sequencing the callbacks posted
-  // by the `UpdateService` and calling the outbound COM functions to
-  // notify the client about state changes in the `UpdateService`.
   auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  using IUpdaterObserverPtr = Microsoft::WRL::ComPtr<IUpdaterObserver>;
-  auto observer_local = IUpdaterObserverPtr(observer);
-
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+  UpdateService::StateChangeCallback state_change_callback =
+      base::BindRepeating(
+          &StateChangeCallbackFilter::OnStateChange,
+          base::Owned(new StateChangeCallbackFilter(task_runner, observer)));
+  UpdateService::Callback complete_callback = base::BindPostTask(
+      task_runner,
       base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             const RegistrationRequest& request,
-             const std::string& client_install_data,
-             const std::string& install_data_index,
-             UpdateService::Priority priority, IUpdaterObserverPtr observer) {
-            update_service->Install(
-                request, client_install_data, install_data_index, priority,
-                base::BindRepeating(&StateChangeCallbackFilter::OnStateChange,
-                                    base::Owned(new StateChangeCallbackFilter(
-                                        task_runner, observer))),
-                base::BindOnce(
-                    [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                       IUpdaterObserverPtr observer,
-                       UpdateService::Result result) {
-                      task_runner->PostTaskAndReplyWithResult(
-                          FROM_HERE,
-                          base::BindOnce(
-                              &IUpdaterObserver::OnComplete, observer,
-                              MakeComObjectOrCrash<CompleteStatusImpl>(
-                                  static_cast<int>(result), L"")),
-                          base::BindOnce([](HRESULT hr) {
-                            VLOG(1) << "UpdaterImpl::Install "
-                                    << "callback returned " << std::hex << hr;
-                          }));
-                    },
-                    task_runner, observer));
+          [](IUpdaterObserverPtr observer, UpdateService::Result result) {
+            HRESULT hr =
+                observer->OnComplete(MakeComObjectOrCrash<CompleteStatusImpl>(
+                                         static_cast<int>(result), L"")
+                                         .Get());
+            VLOG(2) << "IUpdaterImpl::Install. "
+                    << "IUpdaterObserver::OnComplete returned " << std::hex
+                    << hr;
           },
-          com_server->update_service(), task_runner, *request,
-          base::WideToUTF8(client_install_data),
-          base::WideToUTF8(install_data_index),
-          static_cast<UpdateService::Priority>(priority), observer_local));
+          IUpdaterObserverPtr(observer)));
+
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](const RegistrationRequest& request,
+         const std::string& client_install_data,
+         const std::string& install_data_index,
+         UpdateService::Priority priority,
+         UpdateService::StateChangeCallback state_change_callback,
+         UpdateService::Callback complete_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(complete_callback)
+              .Run(UpdateService::Result::kServiceStopped);
+          return;
+        }
+        update_service->Install(
+            request, client_install_data, install_data_index, priority,
+            std::move(state_change_callback), std::move(complete_callback));
+      },
+      *request, base::WideToUTF8(client_install_data),
+      base::WideToUTF8(install_data_index),
+      static_cast<UpdateService::Priority>(priority),
+      std::move(state_change_callback), std::move(complete_callback)));
   return S_OK;
 }
 
@@ -673,12 +663,16 @@
       !base::WideToUTF8(app_id, wcslen(app_id), &app_id_str)) {
     return E_INVALIDARG;
   }
-
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&UpdateService::CancelInstalls,
-                                com_server->update_service(), app_id_str));
-
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](const std::string& app_id_str) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          return;
+        }
+        update_service->CancelInstalls(app_id_str);
+      },
+      app_id_str));
   return S_OK;
 }
 
@@ -729,49 +723,47 @@
     return E_INVALIDARG;
   }
 
-  using IUpdaterObserverPtr = Microsoft::WRL::ComPtr<IUpdaterObserver>;
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-
-  // This task runner is responsible for sequencing the COM calls and callbacks.
   auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+  UpdateService::StateChangeCallback state_change_callback =
+      base::BindRepeating(
+          &StateChangeCallbackFilter::OnStateChange,
+          base::Owned(new StateChangeCallbackFilter(task_runner, observer)));
+  UpdateService::Callback complete_callback = base::BindPostTask(
+      task_runner,
       base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             const std::string& app_id, const base::FilePath& installer_path,
-             const std::string& install_args, const std::string& install_data,
-             const std::string& install_settings,
-             IUpdaterObserverPtr observer) {
-            update_service->RunInstaller(
-                app_id, installer_path, install_args, install_data,
-                install_settings,
-                base::BindRepeating(&StateChangeCallbackFilter::OnStateChange,
-                                    base::Owned(new StateChangeCallbackFilter(
-                                        task_runner, observer))),
-                base::BindOnce(
-                    [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                       IUpdaterObserverPtr observer,
-                       const UpdateService::Result result) {
-                      task_runner->PostTaskAndReplyWithResult(
-                          FROM_HERE,
-                          base::BindOnce(
-                              &IUpdaterObserver::OnComplete, observer,
-                              MakeComObjectOrCrash<CompleteStatusImpl>(
-                                  static_cast<int>(result), L"")),
-                          base::BindOnce([](HRESULT hr) {
-                            VLOG(2) << "UpdaterImpl::RunInstaller "
-                                    << "callback returned " << std::hex << hr;
-                          }));
-                    },
-                    task_runner, observer));
+          [](IUpdaterObserverPtr observer, UpdateService::Result result) {
+            HRESULT hr =
+                observer->OnComplete(MakeComObjectOrCrash<CompleteStatusImpl>(
+                                         static_cast<int>(result), L"")
+                                         .Get());
+            VLOG(2) << "IUpdaterImpl::RunInstaller. "
+                    << "IUpdaterObserver::OnComplete returned " << std::hex
+                    << hr;
           },
-          com_server->update_service(), task_runner, app_id_str,
-          base::FilePath(installer_path), install_args_str, install_data_str,
-          install_settings_str, IUpdaterObserverPtr(observer)));
+          IUpdaterObserverPtr(observer)));
 
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](const std::string& app_id, const base::FilePath& installer_path,
+         const std::string& install_args, const std::string& install_data,
+         const std::string& install_settings,
+         UpdateService::StateChangeCallback state_change_callback,
+         UpdateService::Callback complete_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(complete_callback)
+              .Run(UpdateService::Result::kServiceStopped);
+          return;
+        }
+        update_service->RunInstaller(app_id, installer_path, install_args,
+                                     install_data, install_settings,
+                                     std::move(state_change_callback),
+                                     std::move(complete_callback));
+      },
+      app_id_str, base::FilePath(installer_path), install_args_str,
+      install_data_str, install_settings_str, std::move(state_change_callback),
+      std::move(complete_callback)));
   return S_OK;
 }
 
@@ -779,21 +771,13 @@
   if (!callback) {
     return E_INVALIDARG;
   }
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          [](scoped_refptr<UpdateService> update_service,
-             base::OnceCallback<void(
-                 const std::vector<UpdateService::AppState>&)>
-                 result_callback) {
-            update_service->GetAppStates(std::move(result_callback));
-          },
-          com_server->update_service(),
+
+  base::OnceCallback<void(const std::vector<UpdateService::AppState>&)>
+      get_app_states_callback =
           base::BindPostTask(
               base::ThreadPool::CreateSequencedTaskRunner(
                   {base::MayBlock(),
-                   base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}),
+                   base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
               base::BindOnce(
                   [](Microsoft::WRL::ComPtr<IUpdaterAppStatesCallback> callback,
                      const std::vector<UpdateService::AppState>& app_states) {
@@ -801,23 +785,32 @@
                     // and calls `IUpdaterAppStatesCallback::Run` with the
                     // resulting `VARIANT`.
                     base::win::VariantVector updater_app_states;
-
                     for (const auto& app_state : app_states) {
                       Microsoft::WRL::ComPtr<IDispatch> dispatch;
                       CHECK(SUCCEEDED(
                           MakeAndInitializeComObject<UpdaterAppStateImpl>(
                               dispatch, app_state)));
-
                       updater_app_states.Insert<VT_DISPATCH>(dispatch.Get());
                     }
-
                     base::win::ScopedVariant variant;
                     variant.Reset(
                         updater_app_states.ReleaseAsSafearrayVariant());
                     callback->Run(variant);
                   },
-                  Microsoft::WRL::ComPtr<IUpdaterAppStatesCallback>(
-                      callback)))));
+                  Microsoft::WRL::ComPtr<IUpdaterAppStatesCallback>(callback)));
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](base::OnceCallback<void(const std::vector<UpdateService::AppState>&)>
+             get_app_states_callback) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          std::move(get_app_states_callback)
+              .Run(std::vector<UpdateService::AppState>());
+          return;
+        }
+        update_service->GetAppStates(std::move(get_app_states_callback));
+      },
+      std::move(get_app_states_callback)));
   return S_OK;
 }
 
@@ -831,35 +824,29 @@
     return E_INVALIDARG;
   }
 
-  using IUpdaterInternalCallbackPtr =
-      Microsoft::WRL::ComPtr<IUpdaterInternalCallback>;
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-
-  auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+  base::OnceClosure updater_internal_callback = base::BindPostTask(
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
       base::BindOnce(
-          [](scoped_refptr<UpdateServiceInternal> update_service_internal,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             IUpdaterInternalCallbackPtr callback) {
-            update_service_internal->Run(base::BindOnce(
-                [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                   IUpdaterInternalCallbackPtr callback) {
-                  task_runner->PostTaskAndReplyWithResult(
-                      FROM_HERE,
-                      base::BindOnce(&IUpdaterInternalCallback::Run, callback,
-                                     0),
-                      base::BindOnce([](HRESULT hr) {
-                        VLOG(2) << "UpdaterInternalImpl::Run "
-                                << "callback returned " << std::hex << hr;
-                      }));
-                },
-                task_runner, callback));
+          [](IUpdaterInternalCallbackPtr callback) {
+            HRESULT hr = callback->Run(0);
+            VLOG(2) << "UpdaterInternalImpl::Run. "
+                    << "IUpdaterInternalCallback::Run returned " << std::hex
+                    << hr;
           },
-          com_server->update_service_internal(), task_runner,
           IUpdaterInternalCallbackPtr(callback)));
+
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](base::OnceClosure updater_internal_callback) {
+        scoped_refptr<UpdateServiceInternal> update_service_internal =
+            GetAppServerWinInstance()->update_service_internal();
+        if (!update_service_internal) {
+          std::move(updater_internal_callback).Run();
+          return;
+        }
+        update_service_internal->Run(std::move(updater_internal_callback));
+      },
+      std::move(updater_internal_callback)));
   return S_OK;
 }
 
@@ -868,35 +855,29 @@
     return E_INVALIDARG;
   }
 
-  using IUpdaterInternalCallbackPtr =
-      Microsoft::WRL::ComPtr<IUpdaterInternalCallback>;
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-
-  auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
-      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
+  base::OnceClosure updater_internal_callback = base::BindPostTask(
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
       base::BindOnce(
-          [](scoped_refptr<UpdateServiceInternal> update_service_internal,
-             scoped_refptr<base::SequencedTaskRunner> task_runner,
-             IUpdaterInternalCallbackPtr callback) {
-            update_service_internal->Hello(base::BindOnce(
-                [](scoped_refptr<base::SequencedTaskRunner> task_runner,
-                   IUpdaterInternalCallbackPtr callback) {
-                  task_runner->PostTaskAndReplyWithResult(
-                      FROM_HERE,
-                      base::BindOnce(&IUpdaterInternalCallback::Run, callback,
-                                     0),
-                      base::BindOnce([](HRESULT hr) {
-                        VLOG(2) << "UpdaterInternalImpl::Hello "
-                                << "callback returned " << std::hex << hr;
-                      }));
-                },
-                task_runner, callback));
+          [](IUpdaterInternalCallbackPtr callback) {
+            HRESULT hr = callback->Run(0);
+            VLOG(2) << "UpdaterInternalImpl::Hello. "
+                    << "IUpdaterInternalCallback::Run returned " << std::hex
+                    << hr;
           },
-          com_server->update_service_internal(), task_runner,
           IUpdaterInternalCallbackPtr(callback)));
+
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](base::OnceClosure updater_internal_callback) {
+        scoped_refptr<UpdateServiceInternal> update_service_internal =
+            GetAppServerWinInstance()->update_service_internal();
+        if (!update_service_internal) {
+          std::move(updater_internal_callback).Run();
+          return;
+        }
+        update_service_internal->Hello(std::move(updater_internal_callback));
+      },
+      std::move(updater_internal_callback)));
   return S_OK;
 }
 
diff --git a/chrome/updater/app/server/win/com_classes_legacy.cc b/chrome/updater/app/server/win/com_classes_legacy.cc
index 82595ad..c9ca706 100644
--- a/chrome/updater/app/server/win/com_classes_legacy.cc
+++ b/chrome/updater/app/server/win/com_classes_legacy.cc
@@ -361,66 +361,76 @@
   // For backward-compatibility purposes, the `CheckForUpdate` call assumes
   // foreground priority and disallows same version updates.
   HRESULT CheckForUpdate() {
-    using AppWebImplPtr = Microsoft::WRL::ComPtr<AppWebImpl>;
-    scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-    com_server->main_task_runner()->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            [](scoped_refptr<UpdateService> update_service, AppWebImplPtr obj) {
-              update_service->CheckForUpdate(
-                  obj->app_id_, UpdateService::Priority::kForeground,
-                  obj->policy_same_version_update_,
-                  base::BindRepeating(
-                      [](AppWebImplPtr obj,
-                         const UpdateService::UpdateState& state_update) {
-                        obj->task_runner_->PostTask(
-                            FROM_HERE,
-                            base::BindOnce(&AppWebImpl::UpdateStateCallback,
-                                           obj, state_update));
-                      },
-                      obj),
-                  base::BindOnce(
-                      [](AppWebImplPtr obj, UpdateService::Result result) {
-                        obj->task_runner_->PostTask(
-                            FROM_HERE,
-                            base::BindOnce(&AppWebImpl::UpdateResultCallback,
-                                           obj, result));
-                      },
-                      obj));
+    AppWebImplPtr obj(this);
+    UpdateService::StateChangeCallback state_change_callback =
+        base::BindRepeating(
+            [](AppWebImplPtr obj,
+               const UpdateService::UpdateState& state_update) {
+              obj->task_runner_->PostTask(
+                  FROM_HERE, base::BindOnce(&AppWebImpl::UpdateStateCallback,
+                                            obj, state_update));
             },
-            com_server->update_service(), AppWebImplPtr(this)));
+            obj);
+    UpdateService::Callback complete_callback = base::BindOnce(
+        [](AppWebImplPtr obj, UpdateService::Result result) {
+          obj->task_runner_->PostTask(
+              FROM_HERE,
+              base::BindOnce(&AppWebImpl::UpdateResultCallback, obj, result));
+        },
+        obj);
+    AppServerWin::PostRpcTask(base::BindOnce(
+        [](UpdateService::StateChangeCallback state_change_callback,
+           UpdateService::Callback complete_callback, AppWebImplPtr obj) {
+          scoped_refptr<UpdateService> update_service =
+              GetAppServerWinInstance()->update_service();
+          if (!update_service) {
+            std::move(complete_callback)
+                .Run(UpdateService::Result::kServiceStopped);
+            return;
+          }
+          update_service->CheckForUpdate(
+              obj->app_id_, UpdateService::Priority::kForeground,
+              obj->policy_same_version_update_,
+              std::move(state_change_callback), std::move(complete_callback));
+        },
+        std::move(state_change_callback), std::move(complete_callback), obj));
     return S_OK;
   }
 
   HRESULT Update() {
-    using AppWebImplPtr = Microsoft::WRL::ComPtr<AppWebImpl>;
-    scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-    com_server->main_task_runner()->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            [](scoped_refptr<UpdateService> update_service, AppWebImplPtr obj) {
-              update_service->Update(
-                  obj->app_id_, "", UpdateService::Priority::kForeground,
-                  obj->policy_same_version_update_,
-                  base::BindRepeating(
-                      [](AppWebImplPtr obj,
-                         const UpdateService::UpdateState& state_update) {
-                        obj->task_runner_->PostTask(
-                            FROM_HERE,
-                            base::BindOnce(&AppWebImpl::UpdateStateCallback,
-                                           obj, state_update));
-                      },
-                      obj),
-                  base::BindOnce(
-                      [](AppWebImplPtr obj, UpdateService::Result result) {
-                        obj->task_runner_->PostTask(
-                            FROM_HERE,
-                            base::BindOnce(&AppWebImpl::UpdateResultCallback,
-                                           obj, result));
-                      },
-                      obj));
+    AppWebImplPtr obj(this);
+    UpdateService::StateChangeCallback state_change_callback =
+        base::BindRepeating(
+            [](AppWebImplPtr obj,
+               const UpdateService::UpdateState& state_update) {
+              obj->task_runner_->PostTask(
+                  FROM_HERE, base::BindOnce(&AppWebImpl::UpdateStateCallback,
+                                            obj, state_update));
             },
-            com_server->update_service(), AppWebImplPtr(this)));
+            obj);
+    UpdateService::Callback complete_callback = base::BindOnce(
+        [](AppWebImplPtr obj, UpdateService::Result result) {
+          obj->task_runner_->PostTask(
+              FROM_HERE,
+              base::BindOnce(&AppWebImpl::UpdateResultCallback, obj, result));
+        },
+        obj);
+    AppServerWin::PostRpcTask(base::BindOnce(
+        [](UpdateService::StateChangeCallback state_change_callback,
+           UpdateService::Callback complete_callback, AppWebImplPtr obj) {
+          scoped_refptr<UpdateService> update_service =
+              GetAppServerWinInstance()->update_service();
+          if (!update_service) {
+            std::move(complete_callback)
+                .Run(UpdateService::Result::kServiceStopped);
+            return;
+          }
+          update_service->Update(
+              obj->app_id_, "", UpdateService::Priority::kForeground,
+              obj->policy_same_version_update_,
+              std::move(state_change_callback), std::move(complete_callback));
+        },
+        std::move(state_change_callback), std::move(complete_callback), obj));
     return S_OK;
   }
 
@@ -445,8 +455,7 @@
     };
 
     auto result = base::MakeRefCounted<CurrentVersionResult>();
-    GetAppServerWinInstance()->main_task_runner()->PostTask(
-        FROM_HERE,
+    AppServerWin::PostRpcTask(
         base::BindOnce(
             [](const std::string app_id,
                scoped_refptr<CurrentVersionResult> result) {
@@ -617,6 +626,8 @@
   }
 
  private:
+  using AppWebImplPtr = Microsoft::WRL::ComPtr<AppWebImpl>;
+
   ~AppWebImpl() override = default;
 
   void UpdateStateCallback(UpdateService::UpdateState state_update) {
@@ -1112,8 +1123,7 @@
 
   static auto Get(ValueGetter value_getter) {
     auto result = base::WrapRefCounted(new PolicyStatusResult<T>(value_getter));
-    GetAppServerWinInstance()->main_task_runner()->PostTask(
-        FROM_HERE,
+    AppServerWin::PostRpcTask(
         base::BindOnce(&PolicyStatusResult::GetValueOnSequence, result));
     result->completion_event.TimedWait(base::Seconds(60));
     return result->value;
@@ -1146,8 +1156,7 @@
 
   using PolicyStatusImplPtr = Microsoft::WRL::ComPtr<PolicyStatusImpl>;
   auto result = base::MakeRefCounted<LastCheckedTimeResult>();
-  GetAppServerWinInstance()->main_task_runner()->PostTask(
-      FROM_HERE,
+  AppServerWin::PostRpcTask(
       base::BindOnce(
           [](PolicyStatusImplPtr obj,
              scoped_refptr<LastCheckedTimeResult> result) {
@@ -1195,12 +1204,16 @@
   // self reference of the COM object, otherwise the server could shutdown if
   // the caller releases its interface pointer when this function returns.
   using PolicyStatusImplPtr = Microsoft::WRL::ComPtr<PolicyStatusImpl>;
-  scoped_refptr<AppServerWin> com_server = GetAppServerWinInstance();
-  com_server->main_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&UpdateService::FetchPolicies,
-                     com_server->update_service(),
-                     base::DoNothingWithBoundArgs(PolicyStatusImplPtr(this))));
+  AppServerWin::PostRpcTask(base::BindOnce(
+      [](PolicyStatusImplPtr obj) {
+        scoped_refptr<UpdateService> update_service =
+            GetAppServerWinInstance()->update_service();
+        if (!update_service) {
+          return;
+        }
+        update_service->FetchPolicies(base::DoNothing());
+      },
+      PolicyStatusImplPtr(this)));
   return S_OK;
 }
 
diff --git a/chrome/updater/update_service.h b/chrome/updater/update_service.h
index c7f792e0..b734928 100644
--- a/chrome/updater/update_service.h
+++ b/chrome/updater/update_service.h
@@ -86,6 +86,10 @@
     // Failed to run app installer.
     kInstallFailed = 10,
 
+    // The service has been stopped, because the system is shutting down, or
+    // any other reason.
+    kServiceStopped = 11,
+
     // Update EnumTraits<UpdateService::Result> when adding new values.
   };
 
@@ -337,7 +341,7 @@
 struct EnumTraits<UpdateService::Result> {
   using Result = UpdateService::Result;
   static constexpr Result first_elem = Result::kSuccess;
-  static constexpr Result last_elem = Result::kInstallFailed;
+  static constexpr Result last_elem = Result::kServiceStopped;
 };
 
 template <>
diff --git a/chromeos/ash/components/drivefs/BUILD.gn b/chromeos/ash/components/drivefs/BUILD.gn
index 2b48c694..7fe81aaa 100644
--- a/chromeos/ash/components/drivefs/BUILD.gn
+++ b/chromeos/ash/components/drivefs/BUILD.gn
@@ -17,8 +17,8 @@
     "drivefs_host.h",
     "drivefs_http_client.cc",
     "drivefs_http_client.h",
-    "drivefs_pin_manager.cc",
-    "drivefs_pin_manager.h",
+    "drivefs_pinning_manager.cc",
+    "drivefs_pinning_manager.h",
     "drivefs_search.cc",
     "drivefs_search.h",
     "drivefs_session.cc",
@@ -42,7 +42,7 @@
     "//chromeos/ash/components/dbus/userdataauth",
     "//chromeos/ash/components/disks",
     "//chromeos/ash/components/drivefs/mojom",
-    "//chromeos/ash/components/drivefs/mojom:pin_manager_types",
+    "//chromeos/ash/components/drivefs/mojom:pinning_manager_types",
     "//chromeos/ash/components/file_manager",
     "//chromeos/ash/components/network",
     "//chromeos/components/mojo_bootstrap",
@@ -85,7 +85,7 @@
     "drivefs_bootstrap_unittest.cc",
     "drivefs_host_unittest.cc",
     "drivefs_http_client_unittest.cc",
-    "drivefs_pin_manager_unittest.cc",
+    "drivefs_pinning_manager_unittest.cc",
     "drivefs_search_unittest.cc",
     "drivefs_session_unittest.cc",
     "sync_status_tracker_unittest.cc",
@@ -102,7 +102,7 @@
     "//chromeos/ash/components/dbus/userdataauth",
     "//chromeos/ash/components/disks:test_support",
     "//chromeos/ash/components/drivefs/mojom",
-    "//chromeos/ash/components/drivefs/mojom:pin_manager_types",
+    "//chromeos/ash/components/drivefs/mojom:pinning_manager_types",
     "//chromeos/components/mojo_bootstrap",
     "//chromeos/dbus/power",
     "//chromeos/dbus/power:power_manager_proto",
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc b/chromeos/ash/components/drivefs/drivefs_pinning_manager.cc
similarity index 87%
rename from chromeos/ash/components/drivefs/drivefs_pin_manager.cc
rename to chromeos/ash/components/drivefs/drivefs_pinning_manager.cc
index 2621731..83fb02a 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
+++ b/chromeos/ash/components/drivefs/drivefs_pinning_manager.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 "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 
 #include <iomanip>
 #include <locale>
@@ -38,7 +38,7 @@
 using mojom::QueryItemPtr;
 using mojom::ShortcutDetails;
 using std::ostream;
-using Path = PinManager::Path;
+using Path = PinningManager::Path;
 using LookupStatus = ShortcutDetails::LookupStatus;
 
 int Percentage(const int64_t a, const int64_t b) {
@@ -48,12 +48,12 @@
 }
 
 // Calls the spaced daemon.
-void GetFreeSpace(const Path& path, PinManager::SpaceResult callback) {
+void GetFreeSpace(const Path& path, PinningManager::SpaceResult callback) {
   SpacedClient* const spaced = SpacedClient::Get();
   DCHECK(spaced);
   spaced->GetFreeDiskSpace(path.value(),
                            base::BindOnce(
-                               [](PinManager::SpaceResult callback,
+                               [](PinningManager::SpaceResult callback,
                                   const absl::optional<int64_t> space) {
                                  std::move(callback).Run(space.value_or(-1));
                                },
@@ -157,7 +157,7 @@
 
 ostream& operator<<(ostream& out, Quoter<ShortcutDetails> q) {
   const ShortcutDetails& s = *q.value;
-  out << "{" << PinManager::Id(s.target_stable_id);
+  out << "{" << PinningManager::Id(s.target_stable_id);
 
   if (s.target_lookup_status != LookupStatus::kOk) {
     out << " " << Quote(s.target_lookup_status);
@@ -169,7 +169,7 @@
 ostream& operator<<(ostream& out, Quoter<FileMetadata> q) {
   const FileMetadata& md = *q.value;
 
-  out << "{" << Quote(md.type) << " " << PinManager::Id(md.stable_id);
+  out << "{" << Quote(md.type) << " " << PinningManager::Id(md.stable_id);
 
   if (md.size != 0) {
     out << " of " << HumanReadableSize(md.size);
@@ -204,7 +204,7 @@
 
 ostream& operator<<(ostream& out, Quoter<mojom::ProgressEvent> q) {
   const mojom::ProgressEvent& e = *q.value;
-  out << "{" << PinManager::Id(e.stable_id) << " "
+  out << "{" << PinningManager::Id(e.stable_id) << " "
       << Quote(e.file_path ? *e.file_path : Path(e.path))
       << ", progress: " << base::StringPrintf("%hhu", e.progress) << "%}";
   return out;
@@ -213,13 +213,13 @@
 ostream& operator<<(ostream& out, Quoter<mojom::FileChange> q) {
   const mojom::FileChange& change = *q.value;
   return out << "{" << Quote(change.type) << " "
-             << PinManager::Id(change.stable_id) << " " << Quote(change.path)
-             << "}";
+             << PinningManager::Id(change.stable_id) << " "
+             << Quote(change.path) << "}";
 }
 
 ostream& operator<<(ostream& out, Quoter<mojom::DriveError> q) {
   const mojom::DriveError& e = *q.value;
-  return out << "{" << Quote(e.type) << " " << PinManager::Id(e.stable_id)
+  return out << "{" << Quote(e.type) << " " << PinningManager::Id(e.stable_id)
              << " " << Quote(e.path) << "}";
 }
 
@@ -249,7 +249,7 @@
   return out;
 }
 
-ostream& operator<<(ostream& out, const PinManager::Id id) {
+ostream& operator<<(ostream& out, const PinningManager::Id id) {
   return out << "#" << static_cast<int64_t>(id);
 }
 
@@ -284,7 +284,7 @@
   return out << " (" << std::setprecision(4) << d << " " << *unit << ")";
 }
 
-ostream& PinManager::File::PrintTo(ostream& out) const {
+ostream& PinningManager::File::PrintTo(ostream& out) const {
   return out << "{path: " << Quote(path)
              << ", transferred: " << HumanReadableSize(transferred)
              << ", total: " << HumanReadableSize(total)
@@ -402,9 +402,9 @@
 
 constexpr TimeDelta kStalledFileInterval = base::Seconds(10);
 
-bool PinManager::CanPin(const FileMetadata& md, const Path& path) {
+bool PinningManager::CanPin(const FileMetadata& md, const Path& path) {
   using Type = FileMetadata::Type;
-  const auto id = PinManager::Id(md.stable_id);
+  const auto id = PinningManager::Id(md.stable_id);
 
   if (md.shortcut_details) {
     VLOG(2) << "Skipped " << id << " " << Quote(path) << ": Shortcut to "
@@ -442,7 +442,7 @@
   return true;
 }
 
-bool PinManager::Add(const FileMetadata& md, const Path& path) {
+bool PinningManager::Add(const FileMetadata& md, const Path& path) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   const Id id = Id(md.stable_id);
@@ -512,9 +512,9 @@
   return true;
 }
 
-bool PinManager::Remove(const Id id,
-                        const Path& path,
-                        const int64_t transferred) {
+bool PinningManager::Remove(const Id id,
+                            const Path& path,
+                            const int64_t transferred) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   const Files::iterator it = files_to_track_.find(id);
@@ -528,9 +528,9 @@
   return true;
 }
 
-void PinManager::Remove(const Files::iterator it,
-                        const Path& path,
-                        const int64_t transferred) {
+void PinningManager::Remove(const Files::iterator it,
+                            const Path& path,
+                            const int64_t transferred) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   DCHECK(it != files_to_track_.end());
@@ -559,9 +559,9 @@
   VLOG(3) << "Stopped tracking " << id << " " << Quote(path);
 }
 
-bool PinManager::Update(const Id id,
-                        const Path& path,
-                        const int8_t progress_percent) {
+bool PinningManager::Update(const Id id,
+                            const Path& path,
+                            const int8_t progress_percent) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   const Files::iterator it = files_to_track_.find(id);
@@ -575,10 +575,10 @@
   return Update(*it, path, transferred, it->second.total);
 }
 
-bool PinManager::Update(const Id id,
-                        const Path& path,
-                        const int64_t transferred,
-                        const int64_t total) {
+bool PinningManager::Update(const Id id,
+                            const Path& path,
+                            const int64_t transferred,
+                            const int64_t total) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   const Files::iterator it = files_to_track_.find(id);
@@ -591,10 +591,10 @@
   return Update(*it, path, transferred, total);
 }
 
-bool PinManager::Update(Files::value_type& entry,
-                        const Path& path,
-                        const int64_t transferred,
-                        const int64_t total) {
+bool PinningManager::Update(Files::value_type& entry,
+                            const Path& path,
+                            const int64_t transferred,
+                            const int64_t total) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   const Id id = entry.first;
@@ -639,10 +639,10 @@
   return modified;
 }
 
-PinManager::PinManager(Path profile_path,
-                       Path mount_path,
-                       mojom::DriveFs* const drivefs,
-                       int64_t queue_size)
+PinningManager::PinningManager(Path profile_path,
+                               Path mount_path,
+                               mojom::DriveFs* const drivefs,
+                               int64_t queue_size)
     : profile_path_(std::move(profile_path)),
       mount_path_(std::move(mount_path)),
       drivefs_(drivefs),
@@ -652,13 +652,13 @@
   chromeos::PowerManagerClient* const p = chromeos::PowerManagerClient::Get();
   power_manager_.Observe(p);
   p->GetBatterySaverModeState(base::BindOnce(
-      &PinManager::OnGotBatterySaverState, weak_ptr_factory_.GetWeakPtr()));
+      &PinningManager::OnGotBatterySaverState, weak_ptr_factory_.GetWeakPtr()));
   user_data_auth_client_.Observe(ash::UserDataAuthClient::Get());
 }
 
-PinManager::~PinManager() = default;
+PinningManager::~PinningManager() = default;
 
-void PinManager::Start() {
+void PinningManager::Start() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (InProgress(progress_.stage)) {
@@ -692,10 +692,10 @@
 
   space_getter_.Run(
       profile_path_.AppendASCII("GCache"),
-      base::BindOnce(&PinManager::OnFreeSpaceRetrieved1, GetWeakPtr()));
+      base::BindOnce(&PinningManager::OnFreeSpaceRetrieved1, GetWeakPtr()));
 }
 
-void PinManager::Stop() {
+void PinningManager::Stop() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (progress_.stage != Stage::kStopped && !progress_.IsError()) {
@@ -704,7 +704,7 @@
   }
 }
 
-bool PinManager::CalculateRequiredSpace() {
+bool PinningManager::CalculateRequiredSpace() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (IsPausedOrInProgress(progress_.stage) && progress_.should_pin) {
     LOG(ERROR) << "Cannot calculate required space: "
@@ -717,7 +717,7 @@
   return true;
 }
 
-void PinManager::OnFreeSpaceRetrieved1(const int64_t free_space) {
+void PinningManager::OnFreeSpaceRetrieved1(const int64_t free_space) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(progress_.stage, Stage::kGettingFreeSpace);
 
@@ -739,26 +739,26 @@
   ListItems(Id::kNone, Path("/root"));
 }
 
-void PinManager::CheckFreeSpace() {
+void PinningManager::CheckFreeSpace() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   VLOG(2) << "Getting free space";
   space_getter_.Run(
       profile_path_.AppendASCII("GCache"),
-      base::BindOnce(&PinManager::OnFreeSpaceRetrieved2, GetWeakPtr()));
+      base::BindOnce(&PinningManager::OnFreeSpaceRetrieved2, GetWeakPtr()));
 }
 
-void PinManager::LowDiskSpace(const user_data_auth::LowDiskSpace& event) {
+void PinningManager::LowDiskSpace(const user_data_auth::LowDiskSpace& event) {
   LOG(ERROR) << "LowDiskSpace: " << HumanReadableSize(event.disk_free_bytes());
   OnFreeSpaceRetrieved2(event.disk_free_bytes());
 }
 
-void PinManager::OnSpaceUpdate(const SpaceEvent& event) {
+void PinningManager::OnSpaceUpdate(const SpaceEvent& event) {
   VLOG(1) << "OnSpaceUpdate: " << HumanReadableSize(event.free_space_bytes());
   OnFreeSpaceRetrieved2(event.free_space_bytes());
 }
 
-void PinManager::OnFreeSpaceRetrieved2(const int64_t free_space) {
+void PinningManager::OnFreeSpaceRetrieved2(const int64_t free_space) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (free_space < 0) {
@@ -781,14 +781,14 @@
   }
 }
 
-void PinManager::OnGotBatterySaverState(
+void PinningManager::OnGotBatterySaverState(
     absl::optional<power_manager::BatterySaverModeState> state) {
   if (state) {
     BatterySaverModeStateChanged(*state);
   }
 }
 
-void PinManager::BatterySaverModeStateChanged(
+void PinningManager::BatterySaverModeStateChanged(
     const power_manager::BatterySaverModeState& state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   is_battery_ok_ = !state.enabled();
@@ -805,7 +805,7 @@
   }
 }
 
-bool PinManager::IsTrackedAndUnpinned(Id id) const {
+bool PinningManager::IsTrackedAndUnpinned(Id id) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const Files::const_iterator it = files_to_track_.find(id);
   if (it == files_to_track_.end()) {
@@ -814,7 +814,7 @@
   return !it->second.pinned;
 }
 
-void PinManager::ListItems(const Id dir_id, Path dir_path) {
+void PinningManager::ListItems(const Id dir_id, Path dir_path) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   VLOG(1) << "Visiting " << dir_id << " " << Quote(dir_path);
 
@@ -841,7 +841,7 @@
   GetNextPage(dir_id, std::move(dir_path), std::move(query));
 }
 
-void PinManager::GetNextPage(const Id dir_id, Path dir_path, Query query) {
+void PinningManager::GetNextPage(const Id dir_id, Path dir_path, Query query) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(progress_.stage, Stage::kListingFiles);
   DCHECK(query);
@@ -851,11 +851,11 @@
           << Quote(dir_path);
   DCHECK(q);
   q->GetNextPage(base::BindOnce(
-      [](const base::WeakPtr<PinManager> pin_manager, Id dir_id, Path dir_path,
-         Query query, const drive::FileError error,
+      [](const base::WeakPtr<PinningManager> pinning_manager, Id dir_id,
+         Path dir_path, Query query, const drive::FileError error,
          const absl::optional<std::vector<QueryItemPtr>> items) {
-        if (pin_manager) {
-          pin_manager->OnSearchResult(
+        if (pinning_manager) {
+          pinning_manager->OnSearchResult(
               dir_id, std::move(dir_path), std::move(query), error,
               items ? *items : base::span<const QueryItemPtr>{});
         } else {
@@ -865,11 +865,12 @@
       GetWeakPtr(), dir_id, std::move(dir_path), std::move(query)));
 }
 
-void PinManager::OnSearchResult(const Id dir_id,
-                                Path dir_path,
-                                Query query,
-                                const drive::FileError error,
-                                const base::span<const QueryItemPtr> items) {
+void PinningManager::OnSearchResult(
+    const Id dir_id,
+    Path dir_path,
+    Query query,
+    const drive::FileError error,
+    const base::span<const QueryItemPtr> items) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(progress_.stage, Stage::kListingFiles);
 
@@ -887,7 +888,7 @@
         LOG(ERROR) << "Will retry in " << Quote(delay);
         SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
             FROM_HERE,
-            base::BindOnce(&PinManager::GetNextPage, GetWeakPtr(), dir_id,
+            base::BindOnce(&PinningManager::GetNextPage, GetWeakPtr(), dir_id,
                            std::move(dir_path), std::move(query)),
             delay);
         return;
@@ -960,9 +961,9 @@
   GetNextPage(dir_id, std::move(dir_path), std::move(query));
 }
 
-void PinManager::HandleQueryItem(Id dir_id,
-                                 const Path& dir_path,
-                                 const QueryItem& item) {
+void PinningManager::HandleQueryItem(Id dir_id,
+                                     const Path& dir_path,
+                                     const QueryItem& item) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(item.metadata);
   using Type = FileMetadata::Type;
@@ -1062,7 +1063,7 @@
              << " " << path << ": " << Quote(md);
 }
 
-void PinManager::Complete(const Stage stage) {
+void PinningManager::Complete(const Stage stage) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!InProgress(stage));
 
@@ -1129,7 +1130,7 @@
   }
 }
 
-void PinManager::StartPinning() {
+void PinningManager::StartPinning() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(progress_.stage, Stage::kListingFiles);
 
@@ -1164,7 +1165,8 @@
   EnableDocsOffline();
 
   SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-      FROM_HERE, base::BindOnce(&PinManager::CheckStalledFiles, GetWeakPtr()),
+      FROM_HERE,
+      base::BindOnce(&PinningManager::CheckStalledFiles, GetWeakPtr()),
       kStalledFileInterval);
 
   CheckFreeSpace();
@@ -1172,7 +1174,7 @@
   PinSomeFiles();
 }
 
-bool PinManager::StartMonitoringSpace() {
+bool PinningManager::StartMonitoringSpace() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (spaced_client_.IsObserving()) {
     VLOG(1) << "SpacedClient::Observer is already registered";
@@ -1191,12 +1193,12 @@
   return true;
 }
 
-void PinManager::StopMonitoringSpace() {
+void PinningManager::StopMonitoringSpace() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   spaced_client_.Reset();
 }
 
-void PinManager::EnableDocsOffline() {
+void PinningManager::EnableDocsOffline() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(drivefs_);
   drivefs_->SetDocsOfflineEnabled(
@@ -1209,7 +1211,7 @@
       }));
 }
 
-void PinManager::PinSomeFiles() {
+void PinningManager::PinSomeFiles() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (progress_.stage != Stage::kSyncing) {
@@ -1232,7 +1234,7 @@
     VLOG(2) << "Pinning " << id << " " << Quote(path);
     drivefs_->SetPinnedByStableId(
         static_cast<int64_t>(id), true,
-        base::BindOnce(&PinManager::OnFilePinned, GetWeakPtr(), id, path));
+        base::BindOnce(&PinningManager::OnFilePinned, GetWeakPtr(), id, path));
 
     file.pinned = true;
     progress_.syncing_files++;
@@ -1272,9 +1274,9 @@
   }
 }
 
-void PinManager::OnFilePinned(const Id id,
-                              const Path& path,
-                              const drive::FileError error) {
+void PinningManager::OnFilePinned(const Id id,
+                                  const Path& path,
+                                  const drive::FileError error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Records error in a UMA histogram. The `1 - error` expression converts the
@@ -1323,7 +1325,7 @@
   DCHECK(!files_to_pin_.contains(id));
 }
 
-void PinManager::OnItemProgress(const mojom::ProgressEvent& event) {
+void PinningManager::OnItemProgress(const mojom::ProgressEvent& event) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!InProgress(progress_.stage)) {
@@ -1361,7 +1363,7 @@
   PinSomeFiles();
 }
 
-void PinManager::NotifyDelete(const Id id, const Path& path) {
+void PinningManager::NotifyDelete(const Id id, const Path& path) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!Remove(id, path, 0)) {
@@ -1375,11 +1377,12 @@
   PinSomeFiles();
 }
 
-void PinManager::OnUnmounted() {
+void PinningManager::OnUnmounted() {
   VLOG(1) << "Unmounted DriveFS";
 }
 
-void PinManager::OnFilesChanged(const std::vector<mojom::FileChange>& changes) {
+void PinningManager::OnFilesChanged(
+    const std::vector<mojom::FileChange>& changes) {
   using Type = mojom::FileChange::Type;
   for (const mojom::FileChange& event : changes) {
     switch (event.type) {
@@ -1400,12 +1403,12 @@
   }
 }
 
-void PinManager::OnFileCreated(const mojom::FileChange& event) {
+void PinningManager::OnFileCreated(const mojom::FileChange& event) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(event.type, mojom::FileChange::Type::kCreate);
 
   if (!InProgress(progress_.stage)) {
-    VLOG(2) << "Ignored " << Quote(event) << ": PinManager is currently "
+    VLOG(2) << "Ignored " << Quote(event) << ": PinningManager is currently "
             << Quote(progress_.stage);
     return;
   }
@@ -1435,11 +1438,11 @@
   VLOG(1) << "Got " << Quote(event);
   drivefs_->GetMetadataByStableId(
       static_cast<int64_t>(id),
-      base::BindOnce(&PinManager::OnMetadataForCreatedFile, GetWeakPtr(), id,
-                     path));
+      base::BindOnce(&PinningManager::OnMetadataForCreatedFile, GetWeakPtr(),
+                     id, path));
 }
 
-void PinManager::OnFileDeleted(const mojom::FileChange& event) {
+void PinningManager::OnFileDeleted(const mojom::FileChange& event) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(event.type, mojom::FileChange::Type::kDelete);
 
@@ -1447,7 +1450,7 @@
   NotifyDelete(Id(event.stable_id), event.path);
 }
 
-void PinManager::OnFileModified(const mojom::FileChange& event) {
+void PinningManager::OnFileModified(const mojom::FileChange& event) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(event.type, mojom::FileChange::Type::kModify);
 
@@ -1468,11 +1471,11 @@
   VLOG(2) << "Checking changed " << id << " " << Quote(path);
   drivefs_->GetMetadataByStableId(
       static_cast<int64_t>(id),
-      base::BindOnce(&PinManager::OnMetadataForModifiedFile, GetWeakPtr(), id,
-                     path));
+      base::BindOnce(&PinningManager::OnMetadataForModifiedFile, GetWeakPtr(),
+                     id, path));
 }
 
-void PinManager::OnError(const mojom::DriveError& error) {
+void PinningManager::OnError(const mojom::DriveError& error) {
   LOG(ERROR) << "Got DriveError " << Quote(error);
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (error.type == mojom::DriveError::Type::kPinningFailedDiskFull &&
@@ -1481,7 +1484,7 @@
   }
 }
 
-void PinManager::NotifyProgress() {
+void PinningManager::NotifyProgress() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (progress_.pinned_bytes > 0) {
@@ -1496,7 +1499,7 @@
   }
 }
 
-void PinManager::CheckStalledFiles() {
+void PinningManager::CheckStalledFiles() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   for (auto& [id, file] : files_to_track_) {
@@ -1514,19 +1517,20 @@
     VLOG(1) << "Checking stalled " << id << " " << Quote(path);
     drivefs_->GetMetadataByStableId(
         static_cast<int64_t>(id),
-        base::BindOnce(&PinManager::OnMetadataForModifiedFile, GetWeakPtr(), id,
-                       path));
+        base::BindOnce(&PinningManager::OnMetadataForModifiedFile, GetWeakPtr(),
+                       id, path));
   }
 
   SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-      FROM_HERE, base::BindOnce(&PinManager::CheckStalledFiles, GetWeakPtr()),
+      FROM_HERE,
+      base::BindOnce(&PinningManager::CheckStalledFiles, GetWeakPtr()),
       kStalledFileInterval);
 }
 
-void PinManager::OnMetadataForCreatedFile(const Id id,
-                                          const Path& path,
-                                          const drive::FileError error,
-                                          const FileMetadataPtr metadata) {
+void PinningManager::OnMetadataForCreatedFile(const Id id,
+                                              const Path& path,
+                                              const drive::FileError error,
+                                              const FileMetadataPtr metadata) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (error != drive::FILE_ERROR_OK) {
@@ -1546,10 +1550,10 @@
   }
 }
 
-void PinManager::OnMetadataForModifiedFile(const Id id,
-                                           const Path& path,
-                                           const drive::FileError error,
-                                           const FileMetadataPtr metadata) {
+void PinningManager::OnMetadataForModifiedFile(const Id id,
+                                               const Path& path,
+                                               const drive::FileError error,
+                                               const FileMetadataPtr metadata) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (error != drive::FILE_ERROR_OK) {
@@ -1602,7 +1606,7 @@
   }
 }
 
-void PinManager::SetOnline(const bool online) {
+void PinningManager::SetOnline(const bool online) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   VLOG(2) << "Online: " << online << ", battery: " << is_battery_ok_;
   is_online_ = online;
@@ -1618,7 +1622,7 @@
   }
 }
 
-PinManager::Observer::~Observer() {
+PinningManager::Observer::~Observer() {
   CHECK(!IsInObserverList());
 }
 
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.h b/chromeos/ash/components/drivefs/drivefs_pinning_manager.h
similarity index 84%
rename from chromeos/ash/components/drivefs/drivefs_pin_manager.h
rename to chromeos/ash/components/drivefs/drivefs_pinning_manager.h
index 93d7a38..2801520 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.h
+++ b/chromeos/ash/components/drivefs/drivefs_pinning_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_ASH_COMPONENTS_DRIVEFS_DRIVEFS_PIN_MANAGER_H_
-#define CHROMEOS_ASH_COMPONENTS_DRIVEFS_DRIVEFS_PIN_MANAGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_DRIVEFS_DRIVEFS_PINNING_MANAGER_H_
+#define CHROMEOS_ASH_COMPONENTS_DRIVEFS_DRIVEFS_PINNING_MANAGER_H_
 
 #include <algorithm>
 #include <ostream>
@@ -29,7 +29,7 @@
 #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
 #include "chromeos/ash/components/drivefs/drivefs_host.h"
 #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
-#include "chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom.h"
+#include "chromeos/ash/components/drivefs/mojom/pinning_manager_types.mojom.h"
 #include "chromeos/ash/components/file_manager/speedometer.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "components/drive/file_errors.h"
@@ -64,7 +64,7 @@
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
 std::ostream& operator<<(std::ostream& out, HumanReadableSize size);
 
-using pin_manager_types::mojom::Stage;
+using pinning_manager_types::mojom::Stage;
 
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
 std::string ToString(Stage stage);
@@ -150,11 +150,11 @@
   // Estimated time remaining to pin and cache all the files.
   base::TimeDelta remaining_time = base::TimeDelta::Max();
 
-  // Should the PinManager actually pin files, or should it stop after checking
-  // the space requirements?
+  // Should the PinningManager actually pin files, or should it stop after
+  // checking the space requirements?
   bool should_pin = true;
 
-  // Has the PinManager ever emptied its set of tracking items?
+  // Has the PinningManager ever emptied its set of tracking items?
   bool emptied_queue = false;
 
   Progress();
@@ -174,7 +174,7 @@
 //  - Maintain pinning of files that are newly created.
 //  - Rebuild the progress of bulk pinned items (if turned off mid way through a
 //    bulk pinning event).
-class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) PinManager
+class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) PinningManager
     : DriveFsHost::Observer,
       ash::UserDataAuthClient::Observer,
       ash::SpacedClient::Observer,
@@ -182,15 +182,15 @@
  public:
   using Path = base::FilePath;
 
-  PinManager(Path profile_path,
-             Path mount_path,
-             mojom::DriveFs* drivefs,
-             int64_t queue_size);
+  PinningManager(Path profile_path,
+                 Path mount_path,
+                 mojom::DriveFs* drivefs,
+                 int64_t queue_size);
 
-  PinManager(const PinManager&) = delete;
-  PinManager& operator=(const PinManager&) = delete;
+  PinningManager(const PinningManager&) = delete;
+  PinningManager& operator=(const PinningManager&) = delete;
 
-  ~PinManager() override;
+  ~PinningManager() override;
 
   void SetDriveFsHost(DriveFsHost* const host) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -255,7 +255,7 @@
   void OnError(const mojom::DriveError& error) override;
   void OnItemProgress(const mojom::ProgressEvent& event) override;
 
-  base::WeakPtr<PinManager> GetWeakPtr() {
+  base::WeakPtr<PinningManager> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
 
@@ -290,8 +290,8 @@
   // Starts checking for free space.
   void CheckFreeSpace();
 
-  // Whether the supplied `id` is currently being tracked by the PinManager and
-  // that it is unpinned.
+  // Whether the supplied `id` is currently being tracked by the PinningManager
+  // and that it is unpinned.
   bool IsTrackedAndUnpinned(Id id) const;
 
   // For tests don't pin files after enumerating.
@@ -528,45 +528,46 @@
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<PinManager> weak_ptr_factory_{this};
+  base::WeakPtrFactory<PinningManager> weak_ptr_factory_{this};
 
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, Add);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, Update);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, Remove);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnSyncingEvent);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnSyncingStatusUpdate);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnItemProgress);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, CanPin);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnFileCreated);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnFileModified);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnFileDeleted);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnFilePinned);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnFilesChanged);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnMetadataForCreatedFile);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnMetadataForModifiedFile);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, CheckFreeSpace);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, CannotGetFreeSpace2);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, NotEnoughSpace2);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, NotEnoughSpace3);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnSpaceUpdate);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, StartMonitoringSpace);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, SetOnlineAndBatteryOk);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnTransientError);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnError);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, StartWhenInProgress);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, StartPinning);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, PinSomeFiles);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, CheckStalledFiles);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, NotifyProgress);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnSearchResult);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, HandleQueryItem);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, DropQuery);
-  FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, CalculateRequiredSpace);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, Add);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, Update);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, Remove);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnSyncingEvent);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnSyncingStatusUpdate);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnItemProgress);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, CanPin);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnFileCreated);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnFileModified);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnFileDeleted);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnFilePinned);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnFilesChanged);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnMetadataForCreatedFile);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest,
+                           OnMetadataForModifiedFile);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, CheckFreeSpace);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, CannotGetFreeSpace2);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, NotEnoughSpace2);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, NotEnoughSpace3);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnSpaceUpdate);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, StartMonitoringSpace);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, SetOnlineAndBatteryOk);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnTransientError);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnError);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, StartWhenInProgress);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, StartPinning);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, PinSomeFiles);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, CheckStalledFiles);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, NotifyProgress);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, OnSearchResult);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, HandleQueryItem);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, DropQuery);
+  FRIEND_TEST_ALL_PREFIXES(DriveFsPinningManagerTest, CalculateRequiredSpace);
 };
 
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
-std::ostream& operator<<(std::ostream& out, PinManager::Id id);
+std::ostream& operator<<(std::ostream& out, PinningManager::Id id);
 
 }  // namespace drivefs::pinning
 
-#endif  // CHROMEOS_ASH_COMPONENTS_DRIVEFS_DRIVEFS_PIN_MANAGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_DRIVEFS_DRIVEFS_PINNING_MANAGER_H_
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc b/chromeos/ash/components/drivefs/drivefs_pinning_manager_unittest.cc
similarity index 90%
rename from chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
rename to chromeos/ash/components/drivefs/drivefs_pinning_manager_unittest.cc
index 12eec73..9590abf 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
+++ b/chromeos/ash/components/drivefs/drivefs_pinning_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
+#include "chromeos/ash/components/drivefs/drivefs_pinning_manager.h"
 
 #include <iomanip>
 #include <list>
@@ -74,7 +74,7 @@
 using testing::SizeIs;
 using testing::UnorderedElementsAre;
 
-using Id = PinManager::Id;
+using Id = PinningManager::Id;
 using Path = base::FilePath;
 using CompletionCallback = base::MockOnceCallback<void(Stage)>;
 
@@ -195,10 +195,10 @@
 
 class MockSpaceGetter {
  public:
-  MOCK_METHOD(void, GetFreeSpace, (const Path&, PinManager::SpaceResult));
+  MOCK_METHOD(void, GetFreeSpace, (const Path&, PinningManager::SpaceResult));
 };
 
-class MockObserver : public PinManager::Observer {
+class MockObserver : public PinningManager::Observer {
  public:
   MOCK_METHOD(void, OnProgress, (const Progress&), (override));
 };
@@ -207,13 +207,13 @@
 
 }  // namespace
 
-class DriveFsPinManagerTest : public testing::Test {
+class DriveFsPinningManagerTest : public testing::Test {
  protected:
-  ~DriveFsPinManagerTest() override {
+  ~DriveFsPinningManagerTest() override {
     logging::SetMinLogLevel(original_log_level_);
   }
 
-  DriveFsPinManagerTest() {
+  DriveFsPinningManagerTest() {
     logging::SetMinLogLevel(-3);
     CHECK(temp_dir_.CreateUniqueTempDir());
     profile_path_ = temp_dir_.GetPath().Append("Profile");
@@ -233,7 +233,7 @@
     chromeos::PowerManagerClient::Shutdown();
   }
 
-  PinManager::SpaceGetter GetSpaceGetter() {
+  PinningManager::SpaceGetter GetSpaceGetter() {
     return base::BindRepeating(&MockSpaceGetter::GetFreeSpace,
                                base::Unretained(&space_getter_));
   }
@@ -249,7 +249,7 @@
 };
 
 // Tests ToString(Stage).
-TEST_F(DriveFsPinManagerTest, Stage) {
+TEST_F(DriveFsPinningManagerTest, Stage) {
   std::unordered_set<std::string> labels;
   for (const Stage stage : {
            Stage::kStopped,
@@ -273,7 +273,7 @@
 }
 
 // Tests Progress::IsError().
-TEST_F(DriveFsPinManagerTest, IsError) {
+TEST_F(DriveFsPinningManagerTest, IsError) {
   for (const Stage stage : {
            Stage::kCannotGetFreeSpace,
            Stage::kCannotListFiles,
@@ -299,8 +299,8 @@
   }
 }
 
-// Tests PinManager::CanPin().
-TEST_F(DriveFsPinManagerTest, CanPin) {
+// Tests PinningManager::CanPin().
+TEST_F(DriveFsPinningManagerTest, CanPin) {
   using Type = FileMetadata::Type;
   using CanPinStatus = FileMetadata::CanPinStatus;
 
@@ -314,75 +314,75 @@
 
   // Non-empty file can be pinned.
   md.type = Type::kFile;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // Hosted doc can't be pinned.
   md.size = 0;
   md.type = Type::kHosted;
-  EXPECT_FALSE(PinManager::CanPin(md, path));
+  EXPECT_FALSE(PinningManager::CanPin(md, path));
 
   // Directory cannot be pinned.
   md.type = Type::kDirectory;
-  EXPECT_FALSE(PinManager::CanPin(md, path));
+  EXPECT_FALSE(PinningManager::CanPin(md, path));
 
   // Back to pinnable case.
   md.type = Type::kFile;
   md.size = 1;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // Zero-sized file can be pinned.
   md.size = 0;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
   md.size = 1456754;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // Unpinnable file cannot be pinned.
   md.can_pin = CanPinStatus::kDisabled;
-  EXPECT_FALSE(PinManager::CanPin(md, path));
+  EXPECT_FALSE(PinningManager::CanPin(md, path));
   md.can_pin = CanPinStatus::kOk;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // Already pinned and cached file does not need to be pinned.
   md.pinned = true;
   md.available_offline = true;
-  EXPECT_FALSE(PinManager::CanPin(md, path));
+  EXPECT_FALSE(PinningManager::CanPin(md, path));
 
   // Already pinned file that is not cached yet should be monitored as if it was
   // just pinned.
   md.pinned = true;
   md.available_offline = false;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // Unpinned file should be pinned even if it is already cached.
   md.pinned = false;
   md.available_offline = true;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
   md.available_offline = false;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // Trashed item shouldn't be pinned.
   md.trashed = true;
-  EXPECT_FALSE(PinManager::CanPin(md, path));
+  EXPECT_FALSE(PinningManager::CanPin(md, path));
   md.trashed = false;
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // Shortcut cannot be pinned.
   md.shortcut_details = mojom::ShortcutDetails::New();
   md.shortcut_details->target_stable_id = 987;
   md.shortcut_details->target_lookup_status =
       mojom::ShortcutDetails::LookupStatus::kOk;
-  EXPECT_FALSE(PinManager::CanPin(md, path));
+  EXPECT_FALSE(PinningManager::CanPin(md, path));
   md.shortcut_details.reset();
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 
   // File that is not under /root/... can be pinned.
   path = Path("/shared/poi");
-  EXPECT_TRUE(PinManager::CanPin(md, path));
+  EXPECT_TRUE(PinningManager::CanPin(md, path));
 }
 
-// Tests PinManager::Add().
-TEST_F(DriveFsPinManagerTest, Add) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::Add().
+TEST_F(DriveFsPinningManagerTest, Add) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   {
     const Progress progress = manager.GetProgress();
@@ -618,9 +618,9 @@
   }
 }
 
-// Tests PinManager::Update().
-TEST_F(DriveFsPinManagerTest, Update) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::Update().
+TEST_F(DriveFsPinningManagerTest, Update) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.pinned_bytes = 5000;
@@ -646,7 +646,7 @@
   // Put in place a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, PinManager::File{.path = path1, .total = size1});
+        id1, PinningManager::File{.path = path1, .total = size1});
     ASSERT_TRUE(ok);
     manager.progress_.syncing_files++;
   }
@@ -795,9 +795,9 @@
   }
 }
 
-// Tests PinManager::Remove().
-TEST_F(DriveFsPinManagerTest, Remove) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::Remove().
+TEST_F(DriveFsPinningManagerTest, Remove) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.pinned_bytes = 5000;
@@ -821,11 +821,11 @@
   // Put in place a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, PinManager::File{.path = path1,
-                              .transferred = 1200,
-                              .total = 3000,
-                              .pinned = true,
-                              .in_progress = true});
+        id1, PinningManager::File{.path = path1,
+                                  .transferred = 1200,
+                                  .total = 3000,
+                                  .pinned = true,
+                                  .in_progress = true});
     ASSERT_TRUE(ok);
     manager.progress_.syncing_files++;
   }
@@ -874,11 +874,11 @@
   // Put in place a file to track.
   {
     ASSERT_TRUE(manager.files_to_track_
-                    .try_emplace(id1, PinManager::File{.path = path1,
-                                                       .transferred = 1200,
-                                                       .total = 3000,
-                                                       .pinned = false,
-                                                       .in_progress = true})
+                    .try_emplace(id1, PinningManager::File{.path = path1,
+                                                           .transferred = 1200,
+                                                           .total = 3000,
+                                                           .pinned = false,
+                                                           .in_progress = true})
                     .second);
     ASSERT_TRUE(manager.files_to_pin_.insert(id1).second);
   }
@@ -903,11 +903,11 @@
   // Put in place a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, PinManager::File{.path = path1,
-                              .transferred = 5000,
-                              .total = 6000,
-                              .pinned = true,
-                              .in_progress = true});
+        id1, PinningManager::File{.path = path1,
+                                  .transferred = 5000,
+                                  .total = 6000,
+                                  .pinned = true,
+                                  .in_progress = true});
     ASSERT_TRUE(ok);
     manager.progress_.syncing_files++;
   }
@@ -928,9 +928,9 @@
   }
 }
 
-// Tests PinManager::OnFileCreated().
-TEST_F(DriveFsPinManagerTest, OnFileCreated) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnFileCreated().
+TEST_F(DriveFsPinningManagerTest, OnFileCreated) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   EXPECT_EQ(manager.progress_.stage, Stage::kStopped);
@@ -1012,9 +1012,9 @@
   manager.progress_.stage = Stage::kStopped;
 }
 
-// Tests PinManager::OnFileDeleted().
-TEST_F(DriveFsPinManagerTest, OnFileDeleted) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnFileDeleted().
+TEST_F(DriveFsPinningManagerTest, OnFileDeleted) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
@@ -1051,9 +1051,9 @@
   manager.Stop();
 }
 
-// Tests PinManager::OnFilesChanged().
-TEST_F(DriveFsPinManagerTest, OnFilesChanged) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnFilesChanged().
+TEST_F(DriveFsPinningManagerTest, OnFilesChanged) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
@@ -1093,9 +1093,9 @@
   manager.Stop();
 }
 
-// Tests PinManager::OnFilePinned().
-TEST_F(DriveFsPinManagerTest, OnFilePinned) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnFilePinned().
+TEST_F(DriveFsPinningManagerTest, OnFilePinned) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
@@ -1113,7 +1113,7 @@
   // Add a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id, PinManager::File{.path = path, .total = size, .pinned = true});
+        id, PinningManager::File{.path = path, .total = size, .pinned = true});
     ASSERT_TRUE(ok);
     manager.progress_.syncing_files++;
     manager.progress_.bytes_to_pin += size;
@@ -1146,7 +1146,7 @@
 
   // Add a file to track.
   const auto [it, ok] = manager.files_to_track_.try_emplace(
-      id, PinManager::File{.path = path, .total = size, .pinned = true});
+      id, PinningManager::File{.path = path, .total = size, .pinned = true});
   ASSERT_TRUE(ok);
   manager.progress_.syncing_files++;
   manager.progress_.bytes_to_pin += size;
@@ -1178,9 +1178,9 @@
   manager.Stop();
 }
 
-// Tests PinManager::OnMetadataForCreatedFile().
-TEST_F(DriveFsPinManagerTest, OnMetadataForCreatedFile) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnMetadataForCreatedFile().
+TEST_F(DriveFsPinningManagerTest, OnMetadataForCreatedFile) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   EXPECT_THAT(manager.files_to_pin_, IsEmpty());
@@ -1228,9 +1228,9 @@
   manager.progress_.stage = Stage::kStopped;
 }
 
-// Tests PinManager::OnFileModified().
-TEST_F(DriveFsPinManagerTest, OnFileModified) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnFileModified().
+TEST_F(DriveFsPinningManagerTest, OnFileModified) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   EXPECT_EQ(manager.progress_.stage, Stage::kStopped);
@@ -1299,9 +1299,9 @@
   }
 }
 
-// Tests PinManager::OnMetadataForModifiedFile().
-TEST_F(DriveFsPinManagerTest, OnMetadataForModifiedFile) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnMetadataForModifiedFile().
+TEST_F(DriveFsPinningManagerTest, OnMetadataForModifiedFile) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   EXPECT_THAT(manager.files_to_pin_, IsEmpty());
@@ -1437,9 +1437,9 @@
   manager.progress_.stage = Stage::kStopped;
 }
 
-// Tests PinManager::OnItemProgress().
-TEST_F(DriveFsPinManagerTest, OnItemProgress) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnItemProgress().
+TEST_F(DriveFsPinningManagerTest, OnItemProgress) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.bytes_to_pin = 30000;
@@ -1464,14 +1464,14 @@
   // Put in place a couple of files to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, PinManager::File{
+        id1, PinningManager::File{
                  .path = Path("/Path 1"), .total = 10000, .pinned = true});
     ASSERT_TRUE(ok);
     manager.progress_.syncing_files++;
   }
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id2, PinManager::File{
+        id2, PinningManager::File{
                  .path = Path("/Path 2"), .total = 20000, .pinned = true});
     ASSERT_TRUE(ok);
     manager.progress_.syncing_files++;
@@ -1691,7 +1691,7 @@
 
   manager.Stop();
 
-  // Events received when the PinManager is stopped are ignored.
+  // Events received when the PinningManager is stopped are ignored.
   {
     ProgressEvent event;
     event.stable_id = static_cast<int64_t>(id2);
@@ -1712,9 +1712,9 @@
   }
 }
 
-// Tests what happens when PinManager cannot get free space during initial
+// Tests what happens when PinningManager cannot get free space during initial
 // setup.
-TEST_F(DriveFsPinManagerTest, CannotGetFreeSpace1) {
+TEST_F(DriveFsPinningManagerTest, CannotGetFreeSpace1) {
   CompletionCallback completion_callback;
   RunLoop run_loop;
 
@@ -1725,7 +1725,7 @@
   EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(-1));
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(completion_callback.Get());
   manager.Start();
@@ -1739,9 +1739,9 @@
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
-// Tests what happens when PinManager cannot get free space during the periodic
-// check.
-TEST_F(DriveFsPinManagerTest, CannotGetFreeSpace2) {
+// Tests what happens when PinningManager cannot get free space during the
+// periodic check.
+TEST_F(DriveFsPinningManagerTest, CannotGetFreeSpace2) {
   CompletionCallback completion_callback;
   RunLoop run_loop;
 
@@ -1750,7 +1750,7 @@
   EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(-1));
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(completion_callback.Get());
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
@@ -1766,7 +1766,7 @@
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
-TEST_F(DriveFsPinManagerTest, CannotListFiles) {
+TEST_F(DriveFsPinningManagerTest, CannotListFiles) {
   CompletionCallback completion_callback;
   RunLoop run_loop;
 
@@ -1778,7 +1778,7 @@
   EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(completion_callback.Get());
   manager.Start();
@@ -1792,9 +1792,9 @@
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
-// Tests what happens when PinManager cannot get enough free space during
+// Tests what happens when PinningManager cannot get enough free space during
 // the initial setup.
-TEST_F(DriveFsPinManagerTest, NotEnoughSpace) {
+TEST_F(DriveFsPinningManagerTest, NotEnoughSpace) {
   CompletionCallback completion_callback;
   RunLoop run_loop;
 
@@ -1813,7 +1813,7 @@
   EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(int64_t(2560) << 20));  // 2.5 GB.
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(completion_callback.Get());
   manager.Start();
@@ -1827,9 +1827,9 @@
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
-// Tests what happens when PinManager cannot get enough free space during
+// Tests what happens when PinningManager cannot get enough free space during
 // the periodic check.
-TEST_F(DriveFsPinManagerTest, NotEnoughSpace2) {
+TEST_F(DriveFsPinningManagerTest, NotEnoughSpace2) {
   CompletionCallback completion_callback;
   RunLoop run_loop;
 
@@ -1838,7 +1838,7 @@
   EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(200 << 20));  // 200 MB
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(completion_callback.Get());
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
@@ -1854,17 +1854,17 @@
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
-// Tests what happens when PinManager cannot get enough free space that has been
-// emitted by the `LowDiskSpace` message sent via cryptohome UserDataAuth
+// Tests what happens when PinningManager cannot get enough free space that has
+// been emitted by the `LowDiskSpace` message sent via cryptohome UserDataAuth
 // service.
-TEST_F(DriveFsPinManagerTest, NotEnoughSpace3) {
+TEST_F(DriveFsPinningManagerTest, NotEnoughSpace3) {
   CompletionCallback completion_callback;
   RunLoop run_loop;
 
   EXPECT_CALL(completion_callback, Run(Stage::kNotEnoughSpace))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetCompletionCallback(completion_callback.Get());
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
@@ -1879,8 +1879,8 @@
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
-TEST_F(DriveFsPinManagerTest, OnSpaceUpdate) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+TEST_F(DriveFsPinningManagerTest, OnSpaceUpdate) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
 
@@ -1931,8 +1931,8 @@
   manager.progress_.stage = Stage::kStopped;
 }
 
-TEST_F(DriveFsPinManagerTest, StartMonitoringSpace) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+TEST_F(DriveFsPinningManagerTest, StartMonitoringSpace) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
   EXPECT_FALSE(manager.spaced_client_.IsObserving());
@@ -1962,8 +1962,8 @@
   manager.progress_.stage = Stage::kStopped;
 }
 
-TEST_F(DriveFsPinManagerTest, CalculateRequiredSpace) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+TEST_F(DriveFsPinningManagerTest, CalculateRequiredSpace) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
@@ -2051,7 +2051,7 @@
   manager.progress_.stage = Stage::kStopped;
 }
 
-TEST_F(DriveFsPinManagerTest, JustCheckRequiredSpace) {
+TEST_F(DriveFsPinningManagerTest, JustCheckRequiredSpace) {
   base::HistogramTester histogram_tester;
   CompletionCallback completion_callback;
   RunLoop run_loop;
@@ -2070,7 +2070,7 @@
   EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(int64_t(2560) << 20));  // 2.5 GB.
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(completion_callback.Get());
   EXPECT_TRUE(manager.CalculateRequiredSpace());
@@ -2087,7 +2087,7 @@
       progress.time_spent_listing_items, 1);
 }
 
-TEST_F(DriveFsPinManagerTest, WhenMoreResultsReturnedNextPageIsAttempted) {
+TEST_F(DriveFsPinningManagerTest, WhenMoreResultsReturnedNextPageIsAttempted) {
   CompletionCallback completion_callback;
   RunLoop run_loop;
 
@@ -2106,7 +2106,7 @@
   EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(int64_t(2560) << 20));  // 2.5 GB.
 
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(completion_callback.Get());
   EXPECT_TRUE(manager.CalculateRequiredSpace());
@@ -2120,9 +2120,9 @@
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
-// Tests PinManager::SetOnline() and BatterySaverModeStateChanged().
-TEST_F(DriveFsPinManagerTest, SetOnlineAndBatteryOk) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::SetOnline() and BatterySaverModeStateChanged().
+TEST_F(DriveFsPinningManagerTest, SetOnlineAndBatteryOk) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.SetSpaceGetter(GetSpaceGetter());
 
   auto set_online = [&](bool online) {
@@ -2230,9 +2230,9 @@
   EXPECT_EQ(manager.progress_.stage, Stage::kStopped);
 }
 
-// Tests PinManager::HandleQueryItem().
-TEST_F(DriveFsPinManagerTest, HandleQueryItem) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::HandleQueryItem().
+TEST_F(DriveFsPinningManagerTest, HandleQueryItem) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kListingFiles;
@@ -2355,7 +2355,7 @@
   EXPECT_EQ(manager.progress_.pinned_bytes, 0);
   EXPECT_THAT(manager.listed_items_, SizeIs(1));
   EXPECT_THAT(manager.listed_items_,
-              UnorderedElementsAre<PinManager::ListedItems::value_type>(
+              UnorderedElementsAre<PinningManager::ListedItems::value_type>(
                   {target_id, dir_id}));
   EXPECT_THAT(manager.files_to_pin_, UnorderedElementsAre(target_id));
   reset();
@@ -2378,7 +2378,7 @@
   EXPECT_EQ(manager.progress_.pinned_bytes, 0);
   EXPECT_THAT(manager.listed_items_, SizeIs(1));
   EXPECT_THAT(manager.listed_items_,
-              UnorderedElementsAre<PinManager::ListedItems::value_type>(
+              UnorderedElementsAre<PinningManager::ListedItems::value_type>(
                   {target_id, dir_id}));
   EXPECT_THAT(manager.files_to_pin_, SizeIs(0));
   reset();
@@ -2487,10 +2487,10 @@
   manager.Stop();
 }
 
-// Tests PinManager::OnNextPage() when a query is dropped before the response
-// is received.
-TEST_F(DriveFsPinManagerTest, DropQuery) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnNextPage() when a query is dropped before the
+// response is received.
+TEST_F(DriveFsPinningManagerTest, DropQuery) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kListingFiles;
@@ -2505,7 +2505,7 @@
             return FileError::FILE_ERROR_OK;
           }));
 
-  PinManager::Query query;
+  PinningManager::Query query;
   EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(1);
   drivefs_.StartSearchQuery(query.BindNewPipeAndPassReceiver(),
                             QueryParameters::New());
@@ -2514,24 +2514,24 @@
   task_environment_.RunUntilIdle();
 }
 
-// Tests PinManager::OnSearchResult() when a query finishes and there are still
-// other active queries.
-TEST_F(DriveFsPinManagerTest, OnSearchResult) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnSearchResult() when a query finishes and there are
+// still other active queries.
+TEST_F(DriveFsPinningManagerTest, OnSearchResult) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kListingFiles;
   manager.progress_.max_active_queries = 2;
   manager.progress_.active_queries = 2;
 
-  manager.OnSearchResult(Id(101), Path("/root/My Folder"), PinManager::Query(),
-                         FileError::FILE_ERROR_OK, {});
+  manager.OnSearchResult(Id(101), Path("/root/My Folder"),
+                         PinningManager::Query(), FileError::FILE_ERROR_OK, {});
 
   EXPECT_EQ(manager.progress_.stage, Stage::kListingFiles);
   EXPECT_EQ(manager.progress_.max_active_queries, 2);
   EXPECT_EQ(manager.progress_.active_queries, 1);
 
-  manager.OnSearchResult(Id(100), Path("/root"), PinManager::Query(),
+  manager.OnSearchResult(Id(100), Path("/root"), PinningManager::Query(),
                          FileError::FILE_ERROR_OK, {});
 
   EXPECT_EQ(manager.progress_.stage, Stage::kNotEnoughSpace);
@@ -2541,9 +2541,9 @@
   manager.Stop();
 }
 
-// Tests PinManager::OnSearchResult() with transient errors.
-TEST_F(DriveFsPinManagerTest, OnTransientError) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnSearchResult() with transient errors.
+TEST_F(DriveFsPinningManagerTest, OnTransientError) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kListingFiles;
@@ -2570,9 +2570,9 @@
   EXPECT_EQ(manager.progress_.stage, Stage::kCannotListFiles);
 }
 
-// Tests PinManager::OnError().
-TEST_F(DriveFsPinManagerTest, OnError) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::OnError().
+TEST_F(DriveFsPinningManagerTest, OnError) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
@@ -2612,10 +2612,10 @@
   EXPECT_EQ(manager.progress_.stage, Stage::kNotEnoughSpace);
 }
 
-// Tests that calling PinManager::Start() when the PinManager is already in
-// progress does not have any effect.
-TEST_F(DriveFsPinManagerTest, StartWhenInProgress) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests that calling PinningManager::Start() when the PinningManager is already
+// in progress does not have any effect.
+TEST_F(DriveFsPinningManagerTest, StartWhenInProgress) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kGettingFreeSpace;
@@ -2627,9 +2627,9 @@
   manager.Stop();
 }
 
-// Tests PinManager::StartPinning().
-TEST_F(DriveFsPinManagerTest, StartPinning) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::StartPinning().
+TEST_F(DriveFsPinningManagerTest, StartPinning) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kListingFiles;
@@ -2703,9 +2703,9 @@
   manager.Stop();
 }
 
-// Tests PinManager::PinSomeFiles().
-TEST_F(DriveFsPinManagerTest, PinSomeFiles) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::PinSomeFiles().
+TEST_F(DriveFsPinningManagerTest, PinSomeFiles) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kListingFiles;
@@ -2838,9 +2838,9 @@
   manager.Stop();
 }
 
-// Tests PinManager::CheckStalledFiles().
-TEST_F(DriveFsPinManagerTest, CheckStalledFiles) {
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+// Tests PinningManager::CheckStalledFiles().
+TEST_F(DriveFsPinningManagerTest, CheckStalledFiles) {
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.stage = Stage::kSyncing;
@@ -2938,11 +2938,11 @@
   manager.Stop();
 }
 
-// Tests PinManager::NotifyProgress.
-TEST_F(DriveFsPinManagerTest, NotifyProgress) {
+// Tests PinningManager::NotifyProgress.
+TEST_F(DriveFsPinningManagerTest, NotifyProgress) {
   MockObserver observer;
-  PinManager::Observer observer2;
-  PinManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
+  PinningManager::Observer observer2;
+  PinningManager manager(profile_path_, mount_path_, &drivefs_, kMaxQueueSize);
   manager.AddObserver(&observer);
   manager.AddObserver(&observer2);
 
@@ -2952,6 +2952,6 @@
   manager.RemoveObserver(&observer);
 }
 
-TEST_F(DriveFsPinManagerTest, IsUntrackedPath) {}
+TEST_F(DriveFsPinningManagerTest, IsUntrackedPath) {}
 
 }  // namespace drivefs::pinning
diff --git a/chromeos/ash/components/drivefs/mojom/BUILD.gn b/chromeos/ash/components/drivefs/mojom/BUILD.gn
index 0b6aa2e..8009c5d 100644
--- a/chromeos/ash/components/drivefs/mojom/BUILD.gn
+++ b/chromeos/ash/components/drivefs/mojom/BUILD.gn
@@ -41,11 +41,11 @@
   ]
 }
 
-mojom_component("pin_manager_types") {
-  sources = [ "pin_manager_types.mojom" ]
+mojom_component("pinning_manager_types") {
+  sources = [ "pinning_manager_types.mojom" ]
 
-  output_prefix = "pin_manager_types_mojom"
-  macro_prefix = "PIN_MANAGER_TYPES_MOJOM"
+  output_prefix = "pinning_manager_types_mojom"
+  macro_prefix = "PINNING_MANAGER_TYPES_MOJOM"
 
   webui_module_path = "/"
   use_typescript_sources = true
diff --git a/chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom b/chromeos/ash/components/drivefs/mojom/pinning_manager_types.mojom
similarity index 96%
rename from chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom
rename to chromeos/ash/components/drivefs/mojom/pinning_manager_types.mojom
index a368a6b..e316fed 100644
--- a/chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom
+++ b/chromeos/ash/components/drivefs/mojom/pinning_manager_types.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module drivefs.pin_manager_types.mojom;
+module drivefs.pinning_manager_types.mojom;
 
 // The PinManager first undergoes a setup phase, where it audits the current
 // disk space, pins all available files (disk space willing) then moves to
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn
index 9027ac6..53d40adf 100644
--- a/chromeos/crosapi/mojom/BUILD.gn
+++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -45,6 +45,7 @@
     "emoji_picker.mojom",
     "extension_info_private.mojom",
     "extension_keeplist.mojom",
+    "eye_dropper.mojom",
     "feedback.mojom",
     "field_trial.mojom",
     "file_manager.mojom",
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom
index 85cf61a..d16e3cb 100644
--- a/chromeos/crosapi/mojom/crosapi.mojom
+++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -41,6 +41,7 @@
 import "chromeos/crosapi/mojom/emoji_picker.mojom";
 import "chromeos/crosapi/mojom/extension_info_private.mojom";
 import "chromeos/crosapi/mojom/extension_keeplist.mojom";
+import "chromeos/crosapi/mojom/eye_dropper.mojom";
 import "chromeos/crosapi/mojom/feedback.mojom";
 import "chromeos/crosapi/mojom/field_trial.mojom";
 import "chromeos/crosapi/mojom/file_manager.mojom";
@@ -147,8 +148,8 @@
 // please note the milestone when you added it, to help us reason about
 // compatibility between the client applications and older ash-chrome binaries.
 //
-// Next version: 120
-// Next method id: 122
+// Next version: 121
+// Next method id: 123
 [Stable, Uuid="8b79c34f-2bf8-4499-979a-b17cac522c1e",
  RenamedFrom="crosapi.mojom.AshChromeService"]
 interface Crosapi {
@@ -601,6 +602,10 @@
   // Added in M87.
   BindHidManager@4(pending_receiver<device.mojom.HidManager> receiver);
 
+  // Binds the EyeDropper interface for showing EyeDropper UI.
+  // Added in M120.
+  [MinVersion=120] BindEyeDropper@122(pending_receiver<EyeDropper> receiver);
+
   // Binds the Feedback interface for showing feedback UI.
   // Added in M87.
   [MinVersion=3] BindFeedback@5(pending_receiver<Feedback> receiver);
diff --git a/chromeos/crosapi/mojom/eye_dropper.mojom b/chromeos/crosapi/mojom/eye_dropper.mojom
new file mode 100644
index 0000000..3b077d6f
--- /dev/null
+++ b/chromeos/crosapi/mojom/eye_dropper.mojom
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module crosapi.mojom;
+
+import "skia/public/mojom/skcolor.mojom";
+
+// This interface is implemented by lacros-chrome to receive the selected color
+// from an EyeDropper.
+[Stable, Uuid="f677cd23-91aa-4011-b926-ac0f581f5eff"]
+interface EyeDropperListener {
+  // Called when users selects a color.
+  ColorSelected@0(skia.mojom.SkColor color);
+  // Called if the user cancels selection.
+  ColorSelectionCanceled@1();
+};
+
+// This interface is implemented by ash-chrome. It allows lacros-chrome to
+// request ash-chrome to display an EyeDropper.
+[Stable, Uuid="3802ee0f-f1c0-4e86-8c4e-dc8d3bc98d4b"]
+interface EyeDropper {
+  // Request ash-chrome to show the EyeDropper.
+  ShowEyeDropper@0(pending_remote<EyeDropperListener> listener);
+};
diff --git a/chromeos/lacros/lacros_service.cc b/chromeos/lacros/lacros_service.cc
index 508b93d..a817bd8 100644
--- a/chromeos/lacros/lacros_service.cc
+++ b/chromeos/lacros/lacros_service.cc
@@ -51,6 +51,7 @@
 #include "chromeos/crosapi/mojom/embedded_accessibility_helper.mojom.h"
 #include "chromeos/crosapi/mojom/emoji_picker.mojom.h"
 #include "chromeos/crosapi/mojom/extension_info_private.mojom.h"
+#include "chromeos/crosapi/mojom/eye_dropper.mojom.h"
 #include "chromeos/crosapi/mojom/feedback.mojom.h"
 #include "chromeos/crosapi/mojom/field_trial.mojom.h"
 #include "chromeos/crosapi/mojom/file_manager.mojom.h"
@@ -351,6 +352,9 @@
       crosapi::mojom::ExtensionInfoPrivate,
       &crosapi::mojom::Crosapi::BindExtensionInfoPrivate,
       Crosapi::MethodMinVersions::kBindExtensionInfoPrivateMinVersion>();
+  ConstructRemote<crosapi::mojom::EyeDropper,
+                  &crosapi::mojom::Crosapi::BindEyeDropper,
+                  Crosapi::MethodMinVersions::kBindEyeDropperMinVersion>();
   ConstructRemote<crosapi::mojom::Feedback,
                   &crosapi::mojom::Crosapi::BindFeedback,
                   Crosapi::MethodMinVersions::kBindFeedbackMinVersion>();
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 2c0f487..a20e4d06 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -169,9 +169,6 @@
   # b/296913657
   "secagentd.ProcessEvents@amd64-generic",
 
-  # b/300008090
-  "filemanager.Deletion",
-
   # READ COMMENT AT TOP BEFORE ADDING NEW TESTS HERE.
 ]
 
diff --git a/clank b/clank
index 83800f3..5c5f938 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 83800f3f248339c58e3cf76ab5b656a4346ceea9
+Subproject commit 5c5f938d64e779438a837a026ff3234e7050b392
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 77849146..b8a8cca 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -649,6 +649,7 @@
     "//build:branding_buildflags",
     "//build:chromeos_buildflags",
     "//components/commerce/core:commerce_types",
+    "//components/commerce/core:feature_list",
     "//components/commerce/core:utils",
     "//components/device_reauth",
     "//components/feature_engagement",
diff --git a/components/autofill/core/browser/payments/offer_notification_handler.cc b/components/autofill/core/browser/payments/offer_notification_handler.cc
index 23d6726..c376cf5 100644
--- a/components/autofill/core/browser/payments/offer_notification_handler.cc
+++ b/components/autofill/core/browser/payments/offer_notification_handler.cc
@@ -10,6 +10,7 @@
 #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
 #include "components/autofill/core/browser/payments/offer_notification_options.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/commerce_utils.h"
 #include "components/search/ntp_features.h"
 #include "url/gurl.h"
diff --git a/components/color/BUILD.gn b/components/color/BUILD.gn
new file mode 100644
index 0000000..aa7e592
--- /dev/null
+++ b/components/color/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+source_set("color_headers") {
+  sources = [ "color_id.h" ]
+
+  public_deps = [ "//ui/color:color_headers" ]
+}
+
+static_library("color") {
+  sources = [
+    "color_mixers.cc",
+    "color_mixers.h",
+  ]
+
+  deps = [
+    ":color_headers",
+    "//ui/color",
+  ]
+
+  if (use_aura) {
+    deps += [ "//components/eye_dropper:color_mixer" ]
+  }
+}
diff --git a/components/color/DEPS b/components/color/DEPS
new file mode 100644
index 0000000..6cda140
--- /dev/null
+++ b/components/color/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+components/eye_dropper",
+  "+third_party/skia/include",
+  "+ui/color",
+]
diff --git a/components/color/OWNERS b/components/color/OWNERS
new file mode 100644
index 0000000..3688a29
--- /dev/null
+++ b/components/color/OWNERS
@@ -0,0 +1 @@
+file://ui/color/OWNERS
diff --git a/components/color/README.md b/components/color/README.md
new file mode 100644
index 0000000..f799905b
--- /dev/null
+++ b/components/color/README.md
@@ -0,0 +1,4 @@
+# Components Color Pipeline
+
+This directory defines colors used within //components.
+See [ui/color/README.md](/ui/color/README.md).
diff --git a/components/color/color_id.h b/components/color/color_id.h
new file mode 100644
index 0000000..c65c78b
--- /dev/null
+++ b/components/color/color_id.h
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COLOR_COLOR_ID_H_
+#define COMPONENTS_COLOR_COLOR_ID_H_
+
+#include "build/build_config.h"
+#include "ui/color/color_id.h"
+
+namespace color {
+
+// clang-format off
+// Cross-platform IDs should be added here.
+#define COMMON_COMPONENTS_COLOR_IDS \
+
+#if defined(USE_AURA)
+#define COMPONENTS_COLOR_IDS COMMON_COMPONENTS_COLOR_IDS \
+  /* Eyedropper colors. */ \
+  E_CPONLY(kColorEyedropperBoundary) \
+  E_CPONLY(kColorEyedropperCentralPixelInnerRing) \
+  E_CPONLY(kColorEyedropperCentralPixelOuterRing) \
+  E_CPONLY(kColorEyedropperGrid) \
+
+#else
+#define COMPONENTS_COLOR_IDS COMMON_COMPONENTS_COLOR_IDS
+#endif
+
+#include "ui/color/color_id_macros.inc"
+
+enum ComponentsColorIds : ui::ColorId {
+  kComponentsColorsStart = ui::kUiColorsEnd,
+
+  COMPONENTS_COLOR_IDS
+
+  kComponentsColorsEnd,
+};
+
+// Note that this second include is not redundant. The second inclusion of the
+// .inc file serves to undefine the macros the first inclusion defined.
+#include "ui/color/color_id_macros.inc"
+
+// clang-format on
+
+}  // namespace color
+
+#endif  // COMPONENTS_COLOR_COLOR_ID_H_
diff --git a/components/color/color_mixers.cc b/components/color/color_mixers.cc
new file mode 100644
index 0000000..c578a60
--- /dev/null
+++ b/components/color/color_mixers.cc
@@ -0,0 +1,19 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/color/color_mixers.h"
+
+#include "build/build_config.h"
+#include "components/eye_dropper/color_mixer.h"
+
+namespace color {
+
+void AddComponentsColorMixers(ui::ColorProvider* provider,
+                              const ui::ColorProviderKey& key) {
+#if defined(USE_AURA)
+  eye_dropper::AddColorMixer(provider, key);
+#endif
+}
+
+}  // namespace color
diff --git a/components/color/color_mixers.h b/components/color/color_mixers.h
new file mode 100644
index 0000000..4d0d7f4d
--- /dev/null
+++ b/components/color/color_mixers.h
@@ -0,0 +1,21 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COLOR_COLOR_MIXERS_H_
+#define COMPONENTS_COLOR_COLOR_MIXERS_H_
+
+namespace ui {
+class ColorProvider;
+struct ColorProviderKey;
+}  // namespace ui
+
+namespace color {
+
+// Adds color mixers to `provider` that provide //components colors.
+void AddComponentsColorMixers(ui::ColorProvider* provider,
+                              const ui::ColorProviderKey& key);
+
+}  // namespace color
+
+#endif  // COMPONENTS_COLOR_COLOR_MIXERS_H_
diff --git a/components/commerce/core/BUILD.gn b/components/commerce/core/BUILD.gn
index 2fe2478..9cb43bc 100644
--- a/components/commerce/core/BUILD.gn
+++ b/components/commerce/core/BUILD.gn
@@ -22,16 +22,13 @@
     "flag_descriptions.cc",
     "flag_descriptions.h",
   ]
-  public_deps = [ ":utils" ]
   deps = [
     ":commerce_heuristics_data",
     ":pref_names",
     "//base",
-    "//components/country_codes",
     "//components/flags_ui",
     "//components/prefs",
     "//components/search",
-    "//components/variations/service",
     "//third_party/re2:re2",
     "//url:url",
   ]
@@ -337,6 +334,19 @@
   ]
 }
 
+source_set("country_code_checker") {
+  sources = [
+    "country_code_checker.cc",
+    "country_code_checker.h",
+  ]
+  deps = [
+    # TODO(crbug.com/1489531): We don't need base here after this bug is resolved.
+    "//base",
+    "//components/country_codes",
+    "//components/variations/service",
+  ]
+}
+
 source_set("account_checker") {
   sources = [
     "account_checker.cc",
@@ -426,7 +436,6 @@
   ]
   deps = [
     ":commerce_constants",
-    "//base",
     "//net:net",
   ]
 }
diff --git a/components/commerce/core/commerce_feature_list.cc b/components/commerce/core/commerce_feature_list.cc
index a4520cb..142eb1d 100644
--- a/components/commerce/core/commerce_feature_list.cc
+++ b/components/commerce/core/commerce_feature_list.cc
@@ -18,8 +18,6 @@
 #endif  // !BUILDFLAG(IS_ANDROID)
 #include "components/commerce/core/commerce_heuristics_data_metrics_helper.h"
 #include "components/commerce/core/pref_names.h"
-#include "components/country_codes/country_codes.h"
-#include "components/variations/service/variations_service.h"
 #include "third_party/re2/src/re2/re2.h"
 
 namespace commerce {
@@ -196,6 +194,9 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Discount on navigation
+BASE_FEATURE(kShowDiscountOnNavigation,
+             "ShowDiscountOnNavigation",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kShowDiscountOnNavigationRegionLaunched,
              "ShowDiscountOnNavigationRegionLaunched",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -451,21 +452,6 @@
   return !pref || pref->GetBool();
 }
 
-std::string GetCurrentCountryCode(variations::VariationsService* variations) {
-  std::string country;
-
-  if (variations)
-    country = variations->GetStoredPermanentCountry();
-
-  // Since variations doesn't provide a permanent country by default on things
-  // like local builds, we try to fall back to the country_codes component which
-  // should always have one.
-  if (country.empty())
-    country = country_codes::GetCurrentCountryCode();
-
-  return country;
-}
-
 bool IsEnabledForCountryAndLocale(const base::Feature& feature,
                                   std::string country,
                                   std::string locale) {
diff --git a/components/commerce/core/commerce_feature_list.h b/components/commerce/core/commerce_feature_list.h
index d299b26..ffacb36 100644
--- a/components/commerce/core/commerce_feature_list.h
+++ b/components/commerce/core/commerce_feature_list.h
@@ -17,10 +17,6 @@
 
 class PrefService;
 
-namespace variations {
-class VariationsService;
-}  // namespace variations
-
 namespace commerce {
 
 namespace switches {
@@ -111,6 +107,7 @@
 BASE_DECLARE_FEATURE(kShoppingPDPMetricsRegionLaunched);
 
 // Feature flag for Discounts on navigation.
+BASE_DECLARE_FEATURE(kShowDiscountOnNavigation);
 BASE_DECLARE_FEATURE(kShowDiscountOnNavigationRegionLaunched);
 
 BASE_DECLARE_FEATURE(kRetailCoupons);
@@ -403,10 +400,6 @@
 // Check if the shopping list feature is allowed for enterprise.
 bool IsShoppingListAllowedForEnterprise(PrefService* prefs);
 
-// Get the user's current country code. If access through variations fails,
-// the country_codes component is used.
-std::string GetCurrentCountryCode(variations::VariationsService* variations);
-
 // Check if commerce features are allowed to run for the specified country
 // and locale.
 bool IsEnabledForCountryAndLocale(const base::Feature& feature,
diff --git a/components/commerce/core/commerce_utils.cc b/components/commerce/core/commerce_utils.cc
index ae5fb420..dbe853db 100644
--- a/components/commerce/core/commerce_utils.cc
+++ b/components/commerce/core/commerce_utils.cc
@@ -10,11 +10,6 @@
 #include "url/gurl.h"
 
 namespace commerce {
-// Discount on navigation
-BASE_FEATURE(kShowDiscountOnNavigation,
-             "ShowDiscountOnNavigation",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 bool UrlContainsDiscountUtmTag(const GURL& url) {
   std::string utm_source;
   std::string utm_medium;
diff --git a/components/commerce/core/commerce_utils.h b/components/commerce/core/commerce_utils.h
index 0da3a38..758f9db 100644
--- a/components/commerce/core/commerce_utils.h
+++ b/components/commerce/core/commerce_utils.h
@@ -10,12 +10,6 @@
 class GURL;
 
 namespace commerce {
-
-// Feature flag for Discounts on navigation. This is supposed to be included in
-// the commerce_feature_list file, but because of crbug.com/1155712 we have to
-// move this feature flag here instead.
-BASE_DECLARE_FEATURE(kShowDiscountOnNavigation);
-
 // Returns whether the `url` contains the discount utm tags.
 bool UrlContainsDiscountUtmTag(const GURL& url);
 
diff --git a/components/commerce/core/country_code_checker.cc b/components/commerce/core/country_code_checker.cc
new file mode 100644
index 0000000..922aeaf
--- /dev/null
+++ b/components/commerce/core/country_code_checker.cc
@@ -0,0 +1,29 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/commerce/core/country_code_checker.h"
+
+#include "components/country_codes/country_codes.h"
+#include "components/variations/service/variations_service.h"
+
+namespace commerce {
+
+std::string GetCurrentCountryCode(variations::VariationsService* variations) {
+  std::string country;
+
+  if (variations) {
+    country = variations->GetStoredPermanentCountry();
+  }
+
+  // Since variations doesn't provide a permanent country by default on things
+  // like local builds, we try to fall back to the country_codes component which
+  // should always have one.
+  if (country.empty()) {
+    country = country_codes::GetCurrentCountryCode();
+  }
+
+  return country;
+}
+
+}  // namespace commerce
diff --git a/components/commerce/core/country_code_checker.h b/components/commerce/core/country_code_checker.h
new file mode 100644
index 0000000..98d7640
--- /dev/null
+++ b/components/commerce/core/country_code_checker.h
@@ -0,0 +1,23 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COMMERCE_CORE_COUNTRY_CODE_CHECKER_H_
+#define COMPONENTS_COMMERCE_CORE_COUNTRY_CODE_CHECKER_H_
+
+#include <string>
+
+namespace variations {
+class VariationsService;
+}  // namespace variations
+
+namespace commerce {
+// TODO(crbug.com/1155712): We need this in a separate file because of this bug,
+// otherwise it can be included in the commerce_utils.
+// Get the user's current country code. If access through variations fails, the
+// country_codes component is used.
+std::string GetCurrentCountryCode(variations::VariationsService* variations);
+
+}  // namespace commerce
+
+#endif  // COMPONENTS_COMMERCE_CORE_COUNTRY_CODE_CHECKER_H_
diff --git a/components/commerce/core/shopping_service.cc b/components/commerce/core/shopping_service.cc
index 00f6a66..b07c2d2 100644
--- a/components/commerce/core/shopping_service.cc
+++ b/components/commerce/core/shopping_service.cc
@@ -22,7 +22,6 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/commerce/core/bookmark_update_manager.h"
 #include "components/commerce/core/commerce_feature_list.h"
-#include "components/commerce/core/commerce_utils.h"
 #include "components/commerce/core/discounts_storage.h"
 #include "components/commerce/core/metrics/metrics_utils.h"
 #include "components/commerce/core/metrics/scheduled_metrics_manager.h"
diff --git a/components/commerce/core/shopping_service_unittest.cc b/components/commerce/core/shopping_service_unittest.cc
index 4621871d..b57f4f3 100644
--- a/components/commerce/core/shopping_service_unittest.cc
+++ b/components/commerce/core/shopping_service_unittest.cc
@@ -11,7 +11,6 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/commerce/core/commerce_feature_list.h"
-#include "components/commerce/core/commerce_utils.h"
 #include "components/commerce/core/mock_account_checker.h"
 #include "components/commerce/core/mock_discounts_storage.h"
 #include "components/commerce/core/pref_names.h"
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc
index ef469b2..8021bd8 100644
--- a/components/content_settings/core/browser/content_settings_registry.cc
+++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -286,7 +286,7 @@
            CONTENT_SETTING_BLOCK, WebsiteSettingsInfo::UNSYNCABLE,
            /*allowlisted_schemes=*/{},
            /*valid_settings=*/{CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK},
-           WebsiteSettingsInfo::REQUESTING_AND_TOP_SCHEMEFUL_SITE_SCOPE,
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_SCHEMEFUL_SITE_SCOPE,
            WebsiteSettingsRegistry::DESKTOP |
                WebsiteSettingsRegistry::PLATFORM_ANDROID,
            ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE,
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc
index 6fb48cc..4f0ef87 100644
--- a/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -186,6 +186,12 @@
       patterns.second =
           content_settings::URLToSchemefulSitePattern(secondary_url);
       break;
+    case WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_SCHEMEFUL_SITE_SCOPE:
+      CHECK(!secondary_url.is_empty());
+      patterns.first = ContentSettingsPattern::FromURLNoWildcard(primary_url);
+      patterns.second =
+          content_settings::URLToSchemefulSitePattern(secondary_url);
+      break;
     case WebsiteSettingsInfo::REQUESTING_SCHEMEFUL_SITE_ONLY_SCOPE:
       patterns.first = content_settings::URLToSchemefulSitePattern(primary_url);
       patterns.second = ContentSettingsPattern::Wildcard();
diff --git a/components/content_settings/core/browser/website_settings_info.cc b/components/content_settings/core/browser/website_settings_info.cc
index 1031bb2..7366584 100644
--- a/components/content_settings/core/browser/website_settings_info.cc
+++ b/components/content_settings/core/browser/website_settings_info.cc
@@ -70,6 +70,7 @@
     case REQUESTING_AND_TOP_ORIGIN_SCOPE:
     case TOP_ORIGIN_WITH_RESOURCE_EXCEPTIONS_SCOPE:
     case REQUESTING_AND_TOP_SCHEMEFUL_SITE_SCOPE:
+    case REQUESTING_ORIGIN_AND_TOP_SCHEMEFUL_SITE_SCOPE:
       return true;
     case REQUESTING_ORIGIN_ONLY_SCOPE:
     case TOP_ORIGIN_ONLY_SCOPE:
diff --git a/components/content_settings/core/browser/website_settings_info.h b/components/content_settings/core/browser/website_settings_info.h
index cc62dac..c639abcc 100644
--- a/components/content_settings/core/browser/website_settings_info.h
+++ b/components/content_settings/core/browser/website_settings_info.h
@@ -56,6 +56,13 @@
     // to get right and often result in surprising UX.
     REQUESTING_AND_TOP_SCHEMEFUL_SITE_SCOPE,
 
+    // Settings scoped to the origin of the requesting frame and the
+    // schemeful site of the top-level frame.
+    // Use only after strongly considering if this is the right choice;
+    // presenting settings that are scoped on two schemeful sites is difficult
+    // to get right and often result in surprising UX.
+    REQUESTING_ORIGIN_AND_TOP_SCHEMEFUL_SITE_SCOPE,
+
     // Settings scoped to the top-level origin that can have exceptions for
     // specific resource origins.
     TOP_ORIGIN_WITH_RESOURCE_EXCEPTIONS_SCOPE,
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index d3f7887..6e4a400 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -272,8 +272,9 @@
                                       gpu_memory_buffer_->CloneHandle());
   } else {
     mailbox_ = sii->CreateSharedImage(
-        gpu_memory_buffer_, gpu_memory_buffer_manager, color_space,
-        kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage, "ExoTexture");
+        gpu_memory_buffer_, gpu_memory_buffer_manager,
+        gfx::BufferPlane::DEFAULT, color_space, kTopLeft_GrSurfaceOrigin,
+        kPremul_SkAlphaType, usage, "ExoTexture");
   }
   DCHECK(!mailbox_.IsZero());
   gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
diff --git a/components/eye_dropper/BUILD.gn b/components/eye_dropper/BUILD.gn
new file mode 100644
index 0000000..36f92df9
--- /dev/null
+++ b/components/eye_dropper/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+static_library("eye_dropper") {
+  sources = [
+    "eye_dropper_view.cc",
+    "eye_dropper_view.h",
+    "eye_dropper_view_aura.cc",
+    "features.cc",
+    "features.h",
+  ]
+
+  deps = [
+    "//base",
+    "//build:chromeos_buildflags",
+    "//components/color:color_headers",
+    "//content/public/browser",
+    "//third_party/abseil-cpp:absl",
+    "//third_party/webrtc_overrides:webrtc_component",
+    "//ui/base",
+    "//ui/color",
+    "//ui/gfx/geometry",
+    "//ui/views",
+  ]
+}
+
+source_set("color_mixer") {
+  sources = [
+    "color_mixer.cc",
+    "color_mixer.h",
+  ]
+
+  deps = [
+    "//components/color:color_headers",
+    "//ui/color",
+  ]
+}
diff --git a/components/eye_dropper/DEPS b/components/eye_dropper/DEPS
new file mode 100644
index 0000000..226aada8
--- /dev/null
+++ b/components/eye_dropper/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+components/color",
+  "+content/public/browser",
+  "+third_party/skia",
+  "+third_party/webrtc",
+  "+ui",
+]
diff --git a/components/eye_dropper/DIR_METADATA b/components/eye_dropper/DIR_METADATA
new file mode 100644
index 0000000..67ae5a4
--- /dev/null
+++ b/components/eye_dropper/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Forms>Color"
+}
diff --git a/components/eye_dropper/OWNERS b/components/eye_dropper/OWNERS
new file mode 100644
index 0000000..cc8e0ec
--- /dev/null
+++ b/components/eye_dropper/OWNERS
@@ -0,0 +1,3 @@
+sajos@microsoft.com
+joelhockey@chromium.org
+pkasting@chromium.org
diff --git a/components/eye_dropper/README.md b/components/eye_dropper/README.md
new file mode 100644
index 0000000..7a4ed498
--- /dev/null
+++ b/components/eye_dropper/README.md
@@ -0,0 +1,15 @@
+# Eye Dropper Component
+
+Views implementation of JS [EyeDropper](https://wicg.github.io/eyedropper-api/)
+for desktop OSes using Aura.  The EyeDropper widget allows users to select any
+pixel on the screen.
+
+Win, Linux X11, and ChromeoS Ash use this widget.
+
+Mac uses a system NSColorSampler.
+
+Linux Wayland is not supported since Wayland does not have support to detect the
+cursor position or to place the EyeDropper widget outside the browser window.
+
+ChromeOS LaCrOS works around the Wayland restriction by using crosapi for Ash to
+display this widget.
diff --git a/components/eye_dropper/color_mixer.cc b/components/eye_dropper/color_mixer.cc
new file mode 100644
index 0000000..30b1a40
--- /dev/null
+++ b/components/eye_dropper/color_mixer.cc
@@ -0,0 +1,24 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/eye_dropper/color_mixer.h"
+
+#include "components/color/color_id.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/color/color_mixer.h"
+#include "ui/color/color_provider.h"
+#include "ui/color/color_recipe.h"
+
+namespace eye_dropper {
+
+void AddColorMixer(ui::ColorProvider* provider,
+                   const ui::ColorProviderKey& key) {
+  ui::ColorMixer& mixer = provider->AddMixer();
+  mixer[color::kColorEyedropperBoundary] = {SK_ColorDKGRAY};
+  mixer[color::kColorEyedropperCentralPixelInnerRing] = {SK_ColorBLACK};
+  mixer[color::kColorEyedropperCentralPixelOuterRing] = {SK_ColorWHITE};
+  mixer[color::kColorEyedropperGrid] = {SK_ColorGRAY};
+}
+
+}  // namespace eye_dropper
diff --git a/components/eye_dropper/color_mixer.h b/components/eye_dropper/color_mixer.h
new file mode 100644
index 0000000..702c1ea
--- /dev/null
+++ b/components/eye_dropper/color_mixer.h
@@ -0,0 +1,21 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EYE_DROPPER_COLOR_MIXER_H_
+#define COMPONENTS_EYE_DROPPER_COLOR_MIXER_H_
+
+namespace ui {
+class ColorProvider;
+struct ColorProviderKey;
+}  // namespace ui
+
+namespace eye_dropper {
+
+// Adds a color mixer to `provider` that provides EyeDropper colors.
+void AddColorMixer(ui::ColorProvider* provider,
+                   const ui::ColorProviderKey& key);
+
+}  // namespace eye_dropper
+
+#endif  // COMPONENTS_EYE_DROPPER_COLOR_MIXER_H_
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc b/components/eye_dropper/eye_dropper_view.cc
similarity index 92%
rename from chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc
rename to components/eye_dropper/eye_dropper_view.cc
index 7d2a14e..9596f76 100644
--- a/chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc
+++ b/components/eye_dropper/eye_dropper_view.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 "chrome/browser/ui/views/eye_dropper/eye_dropper_view.h"
+#include "components/eye_dropper/eye_dropper_view.h"
 
 #include "base/memory/raw_ptr.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/browser/ui/color/chrome_color_id.h"
-#include "chrome/browser/ui/ui_features.h"
-#include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
+#include "components/color/color_id.h"
+#include "components/eye_dropper/features.h"
 #include "content/public/browser/desktop_capture.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
@@ -28,11 +27,12 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/public/cpp/shell_window_ids.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/display/screen.h"
 #endif
 
+namespace eye_dropper {
+
 class EyeDropperView::ViewPositionHandler {
  public:
   explicit ViewPositionHandler(EyeDropperView* owner);
@@ -127,8 +127,9 @@
 void EyeDropperView::ScreenCapturer::OnCaptureResult(
     webrtc::DesktopCapturer::Result result,
     std::unique_ptr<webrtc::DesktopFrame> frame) {
-  if (result != webrtc::DesktopCapturer::Result::SUCCESS)
+  if (result != webrtc::DesktopCapturer::Result::SUCCESS) {
     return;
+  }
 
   frame_.allocN32Pixels(frame->size().width(), frame->size().height(), true);
   memcpy(frame_.getAddr32(0, 0), frame->data(),
@@ -183,6 +184,7 @@
 }
 
 EyeDropperView::EyeDropperView(gfx::NativeView parent,
+                               gfx::NativeView event_handler,
                                content::EyeDropperListener* listener)
     : listener_(listener),
       view_position_handler_(std::make_unique<ViewPositionHandler>(this)),
@@ -209,13 +211,7 @@
   params.force_software_compositing = true;
   params.z_order = ui::ZOrderLevel::kFloatingWindow;
   params.name = "MagnifierHost";
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Parent on a top-level container to allow moving between displays.
-  params.parent =
-      parent->GetRootWindow()->GetChildById(ash::kShellWindowId_MenuContainer);
-#else
   params.parent = parent;
-#endif
   params.delegate = this;
   views::Widget* widget = new views::Widget();
   widget->Init(std::move(params));
@@ -223,7 +219,7 @@
   MoveViewToFront();
   HideCursor();
   pre_dispatch_handler_ =
-      std::make_unique<PreEventDispatchHandler>(this, parent);
+      std::make_unique<PreEventDispatchHandler>(this, event_handler);
   widget->Show();
   CaptureInputIfNeeded();
   // The ignore selection time should be long enough to allow the user to see
@@ -236,13 +232,15 @@
 }
 
 EyeDropperView::~EyeDropperView() {
-  if (GetWidget())
+  if (GetWidget()) {
     GetWidget()->CloseNow();
+  }
 }
 
 void EyeDropperView::OnPaint(gfx::Canvas* view_canvas) {
-  if (screen_capturer_->GetBitmap().drawsNothing())
+  if (screen_capturer_->GetBitmap().drawsNothing()) {
     return;
+  }
 
   const float diameter = GetDiameter();
   constexpr float kPixelSize = 10;
@@ -299,7 +297,7 @@
   cc::PaintFlags flags;
   flags.setStrokeWidth(1);
   flags.setStyle(cc::PaintFlags::kStroke_Style);
-  flags.setColor(color_provider->GetColor(kColorEyedropperGrid));
+  flags.setColor(color_provider->GetColor(color::kColorEyedropperGrid));
   for (int i = 0; i < pixel_count; ++i) {
     view_canvas->DrawLine(
         gfx::PointF(padding.width() + i * kPixelSize, padding.height()),
@@ -318,19 +316,19 @@
                    (size().height() - kPixelSize) / 2, kPixelSize, kPixelSize);
   flags.setAntiAlias(true);
   flags.setColor(
-      color_provider->GetColor(kColorEyedropperCentralPixelOuterRing));
+      color_provider->GetColor(color::kColorEyedropperCentralPixelOuterRing));
   flags.setStrokeWidth(2);
   pixel.Inset(-0.5f);
   view_canvas->DrawRect(pixel, flags);
   flags.setColor(
-      color_provider->GetColor(kColorEyedropperCentralPixelInnerRing));
+      color_provider->GetColor(color::kColorEyedropperCentralPixelInnerRing));
   flags.setStrokeWidth(1);
   pixel.Inset(0.5f);
   view_canvas->DrawRect(pixel, flags);
 
   // Paint outline.
   flags.setStrokeWidth(2);
-  flags.setColor(color_provider->GetColor(kColorEyedropperBoundary));
+  flags.setColor(color_provider->GetColor(color::kColorEyedropperBoundary));
   flags.setAntiAlias(true);
   if (GetWidget()->IsTranslucentWindowOpacitySupported()) {
     view_canvas->DrawCircle(
@@ -368,13 +366,15 @@
 }
 
 void EyeDropperView::UpdatePosition() {
-  if (screen_capturer_->GetBitmap().drawsNothing() || !GetWidget())
+  if (screen_capturer_->GetBitmap().drawsNothing() || !GetWidget()) {
     return;
+  }
 
   gfx::Point cursor_position =
       display::Screen::GetScreen()->GetCursorScreenPoint();
-  if (cursor_position == GetWidget()->GetWindowBoundsInScreen().CenterPoint())
+  if (cursor_position == GetWidget()->GetWindowBoundsInScreen().CenterPoint()) {
     return;
+  }
 
   GetWidget()->SetBounds(
       gfx::Rect(gfx::Point(cursor_position.x() - size().width() / 2,
@@ -389,8 +389,9 @@
   }
 
   // Prevent the user from selecting a color for a period of time.
-  if (base::TimeTicks::Now() <= ignore_selection_time_)
+  if (base::TimeTicks::Now() <= ignore_selection_time_) {
     return;
+  }
 
   // Use the last selected color and notify listener.
   listener_->ColorSelected(selected_color_.value());
@@ -404,3 +405,5 @@
 ADD_READONLY_PROPERTY_METADATA(gfx::Size, Size)
 ADD_READONLY_PROPERTY_METADATA(float, Diameter)
 END_METADATA
+
+}  // namespace eye_dropper
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_view.h b/components/eye_dropper/eye_dropper_view.h
similarity index 86%
rename from chrome/browser/ui/views/eye_dropper/eye_dropper_view.h
rename to components/eye_dropper/eye_dropper_view.h
index 9be2bb96..b367c36 100644
--- a/chrome/browser/ui/views/eye_dropper/eye_dropper_view.h
+++ b/components/eye_dropper/eye_dropper_view.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_H_
+#ifndef COMPONENTS_EYE_DROPPER_EYE_DROPPER_VIEW_H_
+#define COMPONENTS_EYE_DROPPER_EYE_DROPPER_VIEW_H_
 
 #include <memory>
 
@@ -23,6 +23,8 @@
 #include "ui/aura/window_observer.h"
 #endif
 
+namespace eye_dropper {
+
 // EyeDropperView is used on Aura platforms.
 class EyeDropperView : public content::EyeDropper,
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -31,7 +33,9 @@
                        public views::WidgetDelegateView {
  public:
   METADATA_HEADER(EyeDropperView);
-  EyeDropperView(gfx::NativeView parent, content::EyeDropperListener* listener);
+  EyeDropperView(gfx::NativeView parent,
+                 gfx::NativeView event_handler,
+                 content::EyeDropperListener* listener);
   EyeDropperView(const EyeDropperView&) = delete;
   EyeDropperView& operator=(const EyeDropperView&) = delete;
   ~EyeDropperView() override;
@@ -53,7 +57,8 @@
 
   class PreEventDispatchHandler : public ui::EventHandler {
    public:
-    PreEventDispatchHandler(EyeDropperView* view, gfx::NativeView parent);
+    PreEventDispatchHandler(EyeDropperView* view,
+                            gfx::NativeView event_handler);
     PreEventDispatchHandler(const PreEventDispatchHandler&) = delete;
     PreEventDispatchHandler& operator=(const PreEventDispatchHandler&) = delete;
     ~PreEventDispatchHandler() override;
@@ -106,4 +111,6 @@
 #endif
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_H_
+}  // namespace eye_dropper
+
+#endif  // COMPONENTS_EYE_DROPPER_EYE_DROPPER_VIEW_H_
diff --git a/chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura.cc b/components/eye_dropper/eye_dropper_view_aura.cc
similarity index 88%
rename from chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura.cc
rename to components/eye_dropper/eye_dropper_view_aura.cc
index 8ef1f04..40d64128 100644
--- a/chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura.cc
+++ b/components/eye_dropper/eye_dropper_view_aura.cc
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/eye_dropper/eye_dropper_view.h"
+#include "components/eye_dropper/eye_dropper_view.h"
 
 #include "base/memory/raw_ptr.h"
 #include "build/build_config.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/focus_change_observer.h"
 #include "ui/aura/client/focus_client.h"
@@ -15,6 +13,8 @@
 #include "ui/base/ui_base_features.h"
 #include "ui/views/native_window_tracker.h"
 
+namespace eye_dropper {
+
 class EyeDropperView::PreEventDispatchHandler::KeyboardHandler
     : public ui::EventHandler {
  public:
@@ -44,8 +44,9 @@
 }
 
 EyeDropperView::PreEventDispatchHandler::KeyboardHandler::~KeyboardHandler() {
-  if (!parent_tracker_->WasNativeWindowDestroyed())
+  if (!parent_tracker_->WasNativeWindowDestroyed()) {
     parent_->RemovePreTargetHandler(this);
+  }
 }
 
 void EyeDropperView::PreEventDispatchHandler::KeyboardHandler::OnKeyEvent(
@@ -155,13 +156,4 @@
   return 90;
 }
 
-std::unique_ptr<content::EyeDropper> ShowEyeDropper(
-    content::RenderFrameHost* frame,
-    content::EyeDropperListener* listener) {
-  if (!features::IsEyeDropperEnabled() || !frame->GetView()->HasFocus()) {
-    return nullptr;
-  }
-  return std::make_unique<EyeDropperView>(
-      content::WebContents::FromRenderFrameHost(frame)->GetNativeView(),
-      listener);
-}
+}  // namespace eye_dropper
diff --git a/components/eye_dropper/features.cc b/components/eye_dropper/features.cc
new file mode 100644
index 0000000..cf6c3c09
--- /dev/null
+++ b/components/eye_dropper/features.cc
@@ -0,0 +1,21 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/eye_dropper/features.h"
+
+#include "build/build_config.h"
+
+namespace eye_dropper::features {
+
+// Enables the use of WGC for the Eye Dropper screen capture.
+BASE_FEATURE(kAllowEyeDropperWGCScreenCapture,
+             "AllowEyeDropperWGCScreenCapture",
+#if BUILDFLAG(IS_WIN)
+             base::FEATURE_ENABLED_BY_DEFAULT
+#else
+             base::FEATURE_DISABLED_BY_DEFAULT
+#endif  // BUILDFLAG(IS_WIN)
+);
+
+}  // namespace eye_dropper::features
diff --git a/components/eye_dropper/features.h b/components/eye_dropper/features.h
new file mode 100644
index 0000000..0d59eb7fd
--- /dev/null
+++ b/components/eye_dropper/features.h
@@ -0,0 +1,19 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the browser-specific base::FeatureList features that are
+// limited to top chrome UI.
+
+#ifndef COMPONENTS_EYE_DROPPER_FEATURES_H_
+#define COMPONENTS_EYE_DROPPER_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace eye_dropper::features {
+
+BASE_DECLARE_FEATURE(kAllowEyeDropperWGCScreenCapture);
+
+}  // namespace eye_dropper::features
+
+#endif  // COMPONENTS_EYE_DROPPER_FEATURES_H_
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 10d7ba2..f5032751 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -190,6 +190,7 @@
     BIDDING_AND_AUCTION_CONSENTED_DEBUGGING_DELEGATE = 116,
     PARCEL_TRACKING_INFOBAR_DELEGATE = 117,
     TEST_THIRD_PARTY_COOKIE_PHASEOUT_DELEGATE = 118,
+    ENABLE_LINK_CAPTURING_INFOBAR_DELEGATE = 119,
   };
 
   // Describes navigation events, used to decide whether infobars should be
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml
index 8c1fc17..8815c23 100644
--- a/components/policy/resources/templates/policies.yaml
+++ b/components/policy/resources/templates/policies.yaml
@@ -1165,6 +1165,7 @@
   1164: ProfileReauthPrompt
   1165: RelatedWebsiteSetsEnabled
   1166: DeviceExtendedFkeysModifier
+  1167: UnaffiliatedDeviceArcAllowed
 atomic_groups:
   1: Homepage
   2: RemoteAccess
diff --git a/components/policy/resources/templates/policy_definitions/Arc/UnaffiliatedDeviceArcAllowed.yaml b/components/policy/resources/templates/policy_definitions/Arc/UnaffiliatedDeviceArcAllowed.yaml
new file mode 100644
index 0000000..346a248
--- /dev/null
+++ b/components/policy/resources/templates/policy_definitions/Arc/UnaffiliatedDeviceArcAllowed.yaml
@@ -0,0 +1,24 @@
+caption: Allow enterprise users to use ARC on unaffiliated devices.
+desc:  |-
+  Unless ARC is turned off by other means, then setting the policy to True or leaving it unset lets managed users use ARC on unaffiliated devices. Setting the policy to False means managed users may not use ARC on unaffiliated devices.
+
+  Note that other restrictions, like those imposed by ArcEnabled and UnaffiliatedArcAllowed policies, continue to be respected, and ARC gets disabled if any of them specifies so.
+example_value: true
+default: true
+features:
+  dynamic_refresh: true
+  per_profile: false
+items:
+- caption: Allow users to use Android apps on unaffiliated devices
+  value: true
+- caption: Do not allow users to use Android apps on unaffiliated devices
+  value: false
+owners:
+- arc-commercial@google.com
+schema:
+  type: boolean
+supported_on:
+- chrome_os:120-
+tags: []
+type: main
+
diff --git a/components/policy/test/data/policy_test_cases.json b/components/policy/test/data/policy_test_cases.json
index ffe416f3..92a115c8 100644
--- a/components/policy/test/data/policy_test_cases.json
+++ b/components/policy/test/data/policy_test_cases.json
@@ -11886,6 +11886,42 @@
       }
     ]
   },
+  "UnaffiliatedDeviceArcAllowed": {
+    "os": [
+      "chromeos_ash"
+    ],
+    "policy_pref_mapping_tests": [
+      {
+        "note": "Default value (no policy set).",
+        "policies": {},
+        "prefs": {
+          "arc.unaffiliated.device.allowed": {
+            "default_value": true
+          }
+        }
+      },
+      {
+        "policies": {
+          "UnaffiliatedDeviceArcAllowed": false
+        },
+        "prefs": {
+          "arc.unaffiliated.device.allowed": {
+            "value": false
+          }
+        }
+      },
+      {
+        "policies": {
+          "UnaffiliatedDeviceArcAllowed": true
+        },
+        "prefs": {
+          "arc.unaffiliated.device.allowed": {
+            "value": true
+          }
+        }
+      }
+    ]
+  },
   "WebAuthnFactors": {
     "os": [
       "chromeos_ash"
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc
index ed1ada3..c3d93dc 100644
--- a/components/search/ntp_features.cc
+++ b/components/search/ntp_features.cc
@@ -362,6 +362,10 @@
              "HistoryClustersModuleEnableContentClustering",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kNtpTabResumptionModule,
+             "NtpTabResumptionModule",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 const char kNtpModulesEligibleForHappinessTrackingSurveyParam[] =
     "NtpModulesEligibleForHappinessTrackingSurveyParam";
 const char kNtpModulesLoadTimeoutMillisecondsParam[] =
diff --git a/components/search/ntp_features.h b/components/search/ntp_features.h
index e2be12f..9e2c8c4 100644
--- a/components/search/ntp_features.h
+++ b/components/search/ntp_features.h
@@ -89,6 +89,7 @@
 BASE_DECLARE_FEATURE(kNtpHistoryClustersModuleIncludeSyncedVisits);
 BASE_DECLARE_FEATURE(kNtpHistoryClustersModuleEnableContentClustering);
 BASE_DECLARE_FEATURE(kNtpHistoryClustersModuleDiscounts);
+BASE_DECLARE_FEATURE(kNtpTabResumptionModule);
 
 // Parameter for controlling the luminosity difference for NTP elements on light
 // backgrounds.
diff --git a/components/services/storage/public/cpp/buckets/bucket_info.cc b/components/services/storage/public/cpp/buckets/bucket_info.cc
index 785e53b..c55279c 100644
--- a/components/services/storage/public/cpp/buckets/bucket_info.cc
+++ b/components/services/storage/public/cpp/buckets/bucket_info.cc
@@ -8,6 +8,10 @@
 
 namespace storage {
 
+BASE_FEATURE(kDefaultBucketUsesRelaxedDurability,
+             "DefaultBucketUsesRelaxedDurability",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BucketInfo::BucketInfo(BucketId bucket_id,
                        blink::StorageKey storage_key,
                        blink::mojom::StorageType type,
@@ -23,7 +27,19 @@
       expiration(std::move(expiration)),
       quota(quota),
       persistent(persistent),
-      durability(durability) {}
+      durability(durability) {
+  // The default bucket's parameters are hard-coded in
+  // `BucketInitParams::ForDefaultBucket`, and then persisted in the
+  // quota database. The easiest way to override that in a reversible manner (in
+  // case of the flag being flipped on and off) is here.
+  // TODO(crbug.com/965883): migrate the quota db, update `BucketInitParams`,
+  // and remove this.
+  if (base::FeatureList::IsEnabled(
+          storage::kDefaultBucketUsesRelaxedDurability) &&
+      is_default()) {
+    this->durability = blink::mojom::BucketDurability::kRelaxed;
+  }
+}
 
 BucketInfo::BucketInfo() = default;
 BucketInfo::~BucketInfo() = default;
diff --git a/components/services/storage/public/cpp/buckets/bucket_info.h b/components/services/storage/public/cpp/buckets/bucket_info.h
index cdd2520..397d6d4 100644
--- a/components/services/storage/public/cpp/buckets/bucket_info.h
+++ b/components/services/storage/public/cpp/buckets/bucket_info.h
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "base/component_export.h"
+#include "base/feature_list.h"
 #include "base/time/time.h"
 #include "components/services/storage/public/cpp/buckets/bucket_id.h"
 #include "components/services/storage/public/cpp/buckets/bucket_locator.h"
@@ -20,6 +21,11 @@
 
 namespace storage {
 
+// Changes the hard-coded durability for default buckets to relaxed. This only
+// affects IndexedDB.
+COMPONENT_EXPORT(STORAGE_SERVICE_BUCKETS_SUPPORT)
+BASE_DECLARE_FEATURE(kDefaultBucketUsesRelaxedDurability);
+
 // Snapshot of a bucket's information in the quota database.
 //
 // Properties that can be updated by the Storage Buckets API, like
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/CredManHelper.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/CredManHelper.java
index d370c9f..71b7698 100644
--- a/components/webauthn/android/java/src/org/chromium/components/webauthn/CredManHelper.java
+++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/CredManHelper.java
@@ -187,11 +187,12 @@
                             CredManCreateRequestEnum.FAILURE);
                     return;
                 }
-                MakeCredentialAuthenticatorResponse response =
-                        MakeCredentialAuthenticatorResponse.deserialize(
-                                ByteBuffer.wrap(responseSerialized));
-                if (response == null) {
-                    Log.e(TAG, "Failed to parse Mojo object");
+                MakeCredentialAuthenticatorResponse response;
+                try {
+                    response = MakeCredentialAuthenticatorResponse.deserialize(
+                            ByteBuffer.wrap(responseSerialized));
+                } catch (org.chromium.mojo.bindings.DeserializationException e) {
+                    logDeserializationException(e);
                     errorCallback.onResult(AuthenticatorStatus.UNKNOWN_ERROR);
                     mMetricsHelper.recordCredManCreateRequestHistogram(
                             CredManCreateRequestEnum.FAILURE);
@@ -490,11 +491,12 @@
                     return;
                 }
 
-                GetAssertionAuthenticatorResponse response =
-                        GetAssertionAuthenticatorResponse.deserialize(
-                                ByteBuffer.wrap(responseSerialized));
-                if (response == null) {
-                    Log.e(TAG, "Failed to parse Mojo object");
+                GetAssertionAuthenticatorResponse response;
+                try {
+                    response = GetAssertionAuthenticatorResponse.deserialize(
+                            ByteBuffer.wrap(responseSerialized));
+                } catch (org.chromium.mojo.bindings.DeserializationException e) {
+                    logDeserializationException(e);
                     mMetricsHelper.reportGetCredentialMetrics(
                             CredManGetRequestEnum.FAILURE, mConditionalUiState);
                     mConditionalUiState = options.isConditional
@@ -790,4 +792,10 @@
         assert false : "Channel must be canary, dev, beta, stable or chrome must be built locally.";
         return null;
     }
+
+    private static void logDeserializationException(Throwable e) {
+        // clang-format off
+        Log.e(TAG, "Failed to parse Mojo object. If this is happening in a test, and authenticator.mojom was updated, then you'll need to update the fake Mojo structures in Fido2ApiTestHelper. Robolectric doesn't support JNI calls so the JNI calls to translate from JSON -> serialized Mojo are mocked out and the responses are hard-coded. If the Mojo structure is updated then the responses also need to be updated. Flip `kUpdateRobolectricTests` in `value_conversions_unittest.cc`, run `component_unittests --gtest_filter=\"WebAuthnentication*\"` and it'll print out updated Java literals for `Fido2ApiTestHelper.java`.", e);
+       // clang-format on
+    }
 }
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2Api.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2Api.java
index 51596bc..86b9a64 100644
--- a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2Api.java
+++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2Api.java
@@ -360,8 +360,15 @@
             final int b = writeHeader(11, parcel);
             final int c = writeHeader(OBJECT_MAGIC, parcel);
             final int d = writeHeader(1, parcel);
-            // length of PRF inputs. None for makeCredential.
-            parcel.writeInt(0);
+            if (options.prfInput != null) {
+                // Two bytestrings for a single PRF input: the null credential ID and then the
+                // hashed salts, concatenated.
+                parcel.writeInt(2);
+                writePrfInput(options.prfInput, /* prfInputsHashed= */ false, parcel);
+            } else {
+                // No PRF inputs.
+                parcel.writeInt(0);
+            }
             writeLength(d, parcel);
             writeLength(c, parcel);
             writeLength(b, parcel);
@@ -494,16 +501,7 @@
             final int d = writeHeader(1, parcel);
             parcel.writeInt(2 * options.extensions.prfInputs.length);
             for (PrfValues input : options.extensions.prfInputs) {
-                parcel.writeByteArray(input.id);
-                if (options.extensions.prfInputsHashed) {
-                    if (input.second == null) {
-                        parcel.writeByteArray(input.first);
-                    } else {
-                        parcel.writeByteArray(concat(input.first, input.second));
-                    }
-                } else {
-                    parcel.writeByteArray(hashPrfInputs(input));
-                }
+                writePrfInput(input, options.extensions.prfInputsHashed, parcel);
             }
             writeLength(d, parcel);
             writeLength(c, parcel);
@@ -523,6 +521,19 @@
         writeLength(a, parcel);
     }
 
+    private static void writePrfInput(PrfValues input, boolean prfInputsHashed, Parcel parcel) {
+        parcel.writeByteArray(input.id);
+        if (prfInputsHashed) {
+            if (input.second == null) {
+                parcel.writeByteArray(input.first);
+            } else {
+                parcel.writeByteArray(concat(input.first, input.second));
+            }
+        } else {
+            parcel.writeByteArray(hashPrfInputs(input));
+        }
+    }
+
     /**
      * Hash a PRF input.
      *
@@ -887,6 +898,7 @@
                 if (extensions.prf != null) {
                     creationResponse.echoPrf = true;
                     creationResponse.prf = extensions.prf.first;
+                    creationResponse.prfResults = extensions.getPrfResults();
                 }
             }
             return creationResponse;
@@ -908,17 +920,7 @@
             }
             if (extensions != null && extensions.prf != null) {
                 assertionResponse.extensions.echoPrf = true;
-                assertionResponse.extensions.prfResults = new PrfValues();
-                if (extensions.prf.second.length == 32) {
-                    assertionResponse.extensions.prfResults.first = extensions.prf.second;
-                } else {
-                    assertionResponse.extensions.prfResults.first = new byte[32];
-                    assertionResponse.extensions.prfResults.second = new byte[32];
-                    System.arraycopy(extensions.prf.second, 0,
-                            assertionResponse.extensions.prfResults.first, 0, 32);
-                    System.arraycopy(extensions.prf.second, 32,
-                            assertionResponse.extensions.prfResults.second, 0, 32);
-                }
+                assertionResponse.extensions.prfResults = extensions.getPrfResults();
             }
             if (attachment >= AuthenticatorAttachment.MIN_VALUE) {
                 assertionResponse.authenticatorAttachment = attachment;
@@ -1130,6 +1132,24 @@
         // prf contains an "enabled" flag and a bytestring that contains either
         // one or two 32-byte strings.
         public Pair<Boolean, byte[]> prf;
+
+        PrfValues getPrfResults() {
+            if (prf == null || prf.second == null) {
+                return null;
+            }
+
+            PrfValues prfResults = new PrfValues();
+            if (prf.second.length == 32) {
+                prfResults.first = prf.second;
+            } else {
+                prfResults.first = new byte[32];
+                prfResults.second = new byte[32];
+                System.arraycopy(prf.second, 0, prfResults.first, 0, 32);
+                System.arraycopy(prf.second, 32, prfResults.second, 0, 32);
+            }
+
+            return prfResults;
+        }
     }
 
     private static Extensions parseExtensionResponse(Parcel parcel)
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java
index e712b07..f6d76e2b 100644
--- a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java
+++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java
@@ -416,61 +416,65 @@
 
     // Serialized registration response converted from JSON received from the Credential Manager
     // API.
-    private static final byte[] TEST_SERIALIZED_CREDMAN_MAKE_CREDENTIAL_RESPONSE = new byte[] {64,
-            0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 104, 1, 0, 0, 0,
-            0, 0, 0, 48, 2, 0, 0, 0, 0, 0, 0, 56, 2, 0, 0, 0, 0, 0, 0, -7, -1, -1, -1, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0,
-            0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 43, 0, 0,
-            0, 78, 51, 103, 120, 53, 49, 101, 106, 103, 77, 79, 99, 107, 56, 54, 101, 49, 84, 76,
-            71, 118, 78, 67, 112, 51, 54, 90, 86, 49, 100, 101, 105, 102, 99, 117, 73, 95, 104, 87,
-            51, 101, 87, 107, 0, 0, 0, 0, 0, 40, 0, 0, 0, 32, 0, 0, 0, 55, 120, 49, -25, 87, -93,
-            -128, -61, -100, -109, -50, -98, -43, 50, -58, -68, -48, -87, -33, -90, 85, -43, -41,
-            -94, 125, -53, -120, -2, 21, -73, 121, 105, 8, 0, 0, 0, 0, 0, 0, 0, -84, 0, 0, 0, -92,
-            0, 0, 0, 17, -54, 103, 117, 94, -24, 15, -48, -108, 31, 8, 99, -50, -54, -38, 125, -48,
-            -25, 91, 114, 111, 41, 32, 108, -21, -25, 66, -10, -32, -107, -62, 102, 93, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 55, 120, 49, -25, 87, -93, -128,
-            -61, -100, -109, -50, -98, -43, 50, -58, -68, -48, -87, -33, -90, 85, -43, -41, -94,
-            125, -53, -120, -2, 21, -73, 121, 105, -91, 1, 2, 3, 38, 32, 1, 33, 88, 32, -44, 11,
-            -114, -24, 96, -51, 111, 103, 66, 47, -29, 52, 75, -3, -57, 84, -63, 121, -95, -102,
-            -54, -112, -12, 115, -82, -100, -11, 86, -118, -106, -3, 8, 34, 88, 32, -35, 48, -66,
-            126, 31, 89, 68, -128, 30, 121, 109, 105, 78, 6, 90, 36, -58, -12, -69, 67, -56, 102,
-            -27, -125, -20, 4, -49, 64, 8, -77, -22, -80, 0, 0, 0, 0, -54, 0, 0, 0, -62, 0, 0, 0,
-            -93, 99, 102, 109, 116, 100, 110, 111, 110, 101, 103, 97, 116, 116, 83, 116, 109, 116,
-            -96, 104, 97, 117, 116, 104, 68, 97, 116, 97, 88, -92, 17, -54, 103, 117, 94, -24, 15,
-            -48, -108, 31, 8, 99, -50, -54, -38, 125, -48, -25, 91, 114, 111, 41, 32, 108, -21, -25,
-            66, -10, -32, -107, -62, 102, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 32, 55, 120, 49, -25, 87, -93, -128, -61, -100, -109, -50, -98, -43, 50, -58,
-            -68, -48, -87, -33, -90, 85, -43, -41, -94, 125, -53, -120, -2, 21, -73, 121, 105, -91,
-            1, 2, 3, 38, 32, 1, 33, 88, 32, -44, 11, -114, -24, 96, -51, 111, 103, 66, 47, -29, 52,
-            75, -3, -57, 84, -63, 121, -95, -102, -54, -112, -12, 115, -82, -100, -11, 86, -118,
-            -106, -3, 8, 34, 88, 32, -35, 48, -66, 126, 31, 89, 68, -128, 30, 121, 109, 105, 78, 6,
-            90, 36, -58, -12, -69, 67, -56, 102, -27, -125, -20, 4, -49, 64, 8, -77, -22, -80, 0, 0,
-            0, 0, 0, 0, 16, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 99, 0, 0, 0, 91, 0, 0, 0,
-            48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72, -50, 61, 3, 1, 7,
-            3, 66, 0, 4, -44, 11, -114, -24, 96, -51, 111, 103, 66, 47, -29, 52, 75, -3, -57, 84,
-            -63, 121, -95, -102, -54, -112, -12, 115, -82, -100, -11, 86, -118, -106, -3, 8, -35,
-            48, -66, 126, 31, 89, 68, -128, 30, 121, 109, 105, 78, 6, 90, 36, -58, -12, -69, 67,
-            -56, 102, -27, -125, -20, 4, -49, 64, 8, -77, -22, -80, 0, 0, 0, 0, 0};
+    private static final byte[] TEST_SERIALIZED_CREDMAN_MAKE_CREDENTIAL_RESPONSE =
+            new byte[] {
+                72, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 127, 7, 0, 0, 80, 1,
+                0, 0, 0, 0, 0, 0, 24, 2, 0, 0, 0, 0, 0, 0, 32, 2, 0, 0, 0, 0, 0, 0, 88, 2, 0, 0, 0,
+                0, 0, 0, 121, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0,
+                0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 80,
+                0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 10, 0, 0, 0, 100, 71, 86, 122, 100, 67, 66, 112,
+                90, 65, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 7, 0, 0, 0, 116, 101, 115, 116, 32, 105, 100,
+                0, 29, 0, 0, 0, 21, 0, 0, 0, 116, 101, 115, 116, 32, 99, 108, 105, 101, 110, 116,
+                32, 100, 97, 116, 97, 32, 106, 115, 111, 110, 0, 0, 0, 44, 0, 0, 0, 36, 0, 0, 0, 38,
+                61, 114, 120, 62, 70, 55, 97, 113, 122, 33, 49, 10, 52, 68, 120, 38, 112, 38, 28,
+                65, 12, 114, 106, 31, 86, 96, 88, 85, 97, 27, 70, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 4, 39, 41, 1, 40, 110, 3, 80, 15, 47, 41, 58,
+                19, 51, 47, 127, 27, 40, 33, 99, 49, 9, 37, 68, 106, 84, 45, 115, 43, 28, 110, 22,
+                37, 1, 2, 3, 38, 32, 1, 33, 88, 32, 22, 69, 112, 93, 97, 55, 24, 88, 99, 78, 82, 22,
+                61, 23, 119, 47, 51, 94, 68, 116, 101, 45, 126, 101, 120, 104, 68, 110, 61, 57, 18,
+                117, 34, 88, 32, 113, 19, 12, 37, 54, 32, 60, 39, 101, 115, 54, 117, 31, 126, 42,
+                68, 15, 37, 32, 99, 6, 61, 26, 103, 84, 38, 33, 7, 81, 62, 12, 2, 0, 0, 0, 0, 74, 0,
+                0, 0, 66, 0, 0, 0, 35, 99, 102, 109, 116, 100, 110, 111, 110, 101, 103, 97, 116,
+                116, 83, 116, 109, 116, 32, 104, 97, 117, 116, 104, 68, 97, 116, 97, 88, 36, 38, 61,
+                114, 120, 62, 70, 55, 97, 113, 122, 33, 49, 10, 52, 68, 120, 38, 112, 38, 28, 65,
+                12, 114, 106, 31, 86, 96, 88, 85, 97, 27, 70, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 4, 39, 41, 1, 40, 110, 3, 80, 15, 47, 41, 58, 19,
+                51, 47, 127, 27, 40, 33, 99, 49, 9, 37, 68, 106, 84, 45, 115, 43, 28, 110, 22, 37,
+                1, 2, 3, 38, 32, 1, 33, 88, 32, 22, 69, 112, 93, 97, 55, 24, 88, 99, 78, 82, 22, 61,
+                23, 119, 47, 51, 94, 68, 116, 101, 45, 126, 101, 120, 104, 68, 110, 61, 57, 18, 117,
+                34, 88, 32, 113, 19, 12, 37, 54, 32, 60, 39, 101, 115, 54, 117, 31, 126, 42, 68, 15,
+                37, 32, 99, 6, 61, 26, 103, 84, 38, 33, 7, 81, 62, 12, 2, 0, 0, 0, 0, 0, 0, 12, 0,
+                0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 4, 0, 0, 0, 1,
+                2, 3, 4, 0, 0, 0, 0, 12, 0, 0, 0, 4, 0, 0, 0, 5, 6, 7, 8, 0, 0, 0, 0, 99, 0, 0, 0,
+                91, 0, 0, 0, 48, 89, 48, 19, 6, 7, 42, 6, 72, 78, 61, 2, 1, 6, 8, 42, 6, 72, 78, 61,
+                3, 1, 7, 3, 66, 0, 4, 22, 69, 112, 93, 97, 55, 24, 88, 99, 78, 82, 22, 61, 23, 119,
+                47, 51, 94, 68, 116, 101, 45, 126, 101, 120, 104, 68, 110, 61, 57, 18, 117, 113, 19,
+                12, 37, 54, 32, 60, 39, 101, 115, 54, 117, 31, 126, 42, 68, 15, 37, 32, 99, 6, 61,
+                26, 103, 84, 38, 33, 7, 81, 62, 12, 2, 0, 0, 0, 0, 0
+            };
 
     // Serialized assertion response converted from JSON received from the Credential Manager API.
-    private static final byte[] TEST_SERIALIZED_CREDMAN_GET_CREDENTIAL_RESPONSE = new byte[] {48, 0,
-            0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -64, 0, 0, 0, 0, 0,
-            0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 32, 1, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 32, 0,
-            0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0,
-            0, 0, 30, 0, 0, 0, 22, 0, 0, 0, 78, 81, 119, 83, 88, 81, 109, 80, 113, 99, 107, 112, 54,
-            86, 66, 114, 117, 74, 52, 84, 45, 65, 0, 0, 24, 0, 0, 0, 16, 0, 0, 0, 53, 12, 18, 93, 9,
-            -113, -87, -55, 41, -23, 80, 107, -72, -98, 19, -8, 17, 0, 0, 0, 9, 0, 0, 0, 60, 105,
-            110, 118, 97, 108, 105, 100, 62, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 37, 0, 0, 0, -56, 89,
-            -63, 83, -10, -10, 58, 88, -74, 13, 49, -64, 95, 85, -99, 61, -90, 100, -74, -120, 11,
-            20, 82, 85, -69, -47, 2, 101, 101, -105, -58, -109, 29, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0,
-            0, 71, 0, 0, 0, 48, 69, 2, 33, 0, -104, -2, -11, -58, 98, 106, -47, 80, 63, 82, 35, 47,
-            121, -87, -40, -119, 39, 121, -58, 107, -119, -108, 90, -22, -12, -36, -113, -56, -112,
-            -63, 21, 44, 2, 32, 47, 7, 8, 107, 110, 36, -60, -49, -32, 118, 54, -92, 84, 124, 77,
-            -80, 87, -9, 7, -50, -1, 24, -49, -7, -116, -42, -93, -23, -111, 91, 80, 87, 0, 26, 0,
-            0, 0, 18, 0, 0, 0, 49, 55, 51, 48, 54, 51, 55, 54, 56, 46, 57, 56, 53, 54, 49, 54, 57,
-            53, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0};
+    private static final byte[] TEST_SERIALIZED_CREDMAN_GET_CREDENTIAL_RESPONSE =
+            new byte[] {
+                48, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -64, 0, 0,
+                0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 32, 1, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0,
+                0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 88,
+                0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 22, 0, 0, 0, 78, 81, 119, 83, 88, 81, 109, 80,
+                113, 99, 107, 112, 54, 86, 66, 114, 117, 74, 52, 84, 45, 65, 0, 0, 24, 0, 0, 0, 16,
+                0, 0, 0, 53, 12, 18, 93, 9, -113, -87, -55, 41, -23, 80, 107, -72, -98, 19, -8, 17,
+                0, 0, 0, 9, 0, 0, 0, 60, 105, 110, 118, 97, 108, 105, 100, 62, 0, 0, 0, 0, 0, 0, 0,
+                45, 0, 0, 0, 37, 0, 0, 0, -56, 89, -63, 83, -10, -10, 58, 88, -74, 13, 49, -64, 95,
+                85, -99, 61, -90, 100, -74, -120, 11, 20, 82, 85, -69, -47, 2, 101, 101, -105, -58,
+                -109, 29, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 71, 0, 0, 0, 48, 69, 2, 33, 0, -104, -2,
+                -11, -58, 98, 106, -47, 80, 63, 82, 35, 47, 121, -87, -40, -119, 39, 121, -58, 107,
+                -119, -108, 90, -22, -12, -36, -113, -56, -112, -63, 21, 44, 2, 32, 47, 7, 8, 107,
+                110, 36, -60, -49, -32, 118, 54, -92, 84, 124, 77, -80, 87, -9, 7, -50, -1, 24, -49,
+                -7, -116, -42, -93, -23, -111, 91, 80, 87, 0, 26, 0, 0, 0, 18, 0, 0, 0, 49, 55, 51,
+                48, 54, 51, 55, 54, 56, 46, 57, 56, 53, 54, 49, 54, 57, 53, 0, 0, 0, 0, 0, 0, 56, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
 
     // TEST_USER_HANDLE is the user ID contained within `TEST_DISCOVERABLE_CREDENTIAL_ASSERTION`.
     public static final byte[] TEST_USER_HANDLE = "bob@example.com".getBytes(UTF_8);
diff --git a/components/webauthn/json/value_conversions.cc b/components/webauthn/json/value_conversions.cc
index d273b0c5..27bead6d 100644
--- a/components/webauthn/json/value_conversions.cc
+++ b/components/webauthn/json/value_conversions.cc
@@ -323,6 +323,15 @@
   return {nullptr, std::string("field missing or invalid: ") + field_name};
 }
 
+base::Value ToValue(const blink::mojom::PRFValuesPtr& prf_input) {
+  base::Value::Dict prf_value;
+  prf_value.Set("first", Base64UrlEncode(prf_input->first));
+  if (prf_input->second) {
+    prf_value.Set("second", Base64UrlEncode(*prf_input->second));
+  }
+  return base::Value(std::move(prf_value));
+}
+
 }  // namespace
 
 base::Value ToValue(
@@ -392,6 +401,9 @@
 
   if (options->prf_enable) {
     base::Value::Dict prf_value;
+    if (options->prf_input) {
+      prf_value.Set("eval", ToValue(options->prf_input));
+    }
     extensions.Set("prf", std::move(prf_value));
   }
 
@@ -411,15 +423,6 @@
   return base::Value(std::move(value));
 }
 
-base::Value ToValue(const blink::mojom::PRFValuesPtr& prf_input) {
-  base::Value::Dict prf_value;
-  prf_value.Set("first", Base64UrlEncode(prf_input->first));
-  if (prf_input->second) {
-    prf_value.Set("second", Base64UrlEncode(*prf_input->second));
-  }
-  return base::Value(std::move(prf_value));
-}
-
 base::Value ToValue(
     const blink::mojom::PublicKeyCredentialRequestOptionsPtr& options) {
   CHECK(!options->extensions.is_null());
@@ -509,6 +512,26 @@
   return base::Value(std::move(value));
 }
 
+absl::optional<blink::mojom::PRFValuesPtr> ParsePRFResults(
+    const base::Value::Dict* results, const JSONUser user) {
+  const absl::optional<std::string> first =
+      Base64UrlDecodeStringKey(*results, "first");
+  if (!first || first->size() != 32) {
+    return absl::nullopt;
+  }
+
+  auto [ok, second] =
+      Base64UrlDecodeOptionalStringKey(*results, "second", user);
+  if (!ok || (second && second->size() != 32)) {
+    return absl::nullopt;
+  }
+
+  return blink::mojom::PRFValues::New(
+      /*id=*/absl::nullopt, ToByteVector(*first),
+      second ? absl::optional<std::vector<uint8_t>>(ToByteVector(*second))
+             : absl::nullopt);
+}
+
 std::pair<blink::mojom::MakeCredentialAuthenticatorResponsePtr, std::string>
 MakeCredentialResponseFromValue(const base::Value& value, JSONUser user) {
   if (!value.is_dict()) {
@@ -717,10 +740,20 @@
   if (prf) {
     response->echo_prf = true;
     const absl::optional<bool> enabled = prf->FindBool("enabled");
-    if (!prf) {
+    if (!enabled) {
       return InvalidMakeCredentialField("prf");
     }
     response->prf = *enabled;
+
+    const base::Value::Dict* results = prf->FindDict("results");
+    if (results) {
+      absl::optional<blink::mojom::PRFValuesPtr> prf_results =
+          ParsePRFResults(results, user);
+      if (!prf_results) {
+        return InvalidMakeCredentialField("prf");
+      }
+      response->prf_results = std::move(*prf_results);
+    }
   }
 
   return {std::move(response), ""};
@@ -839,25 +872,14 @@
   if (prf) {
     const base::Value::Dict* results = prf->FindDict("results");
     if (results) {
-      absl::optional<std::string> first =
-          Base64UrlDecodeStringKey(*results, "first");
-      if (!first || first->size() != 32) {
-        return InvalidGetAssertionField("first");
-      }
-      absl::optional<std::string> second =
-          Base64UrlDecodeStringKey(*results, "second");
-      if (second && second->size() != 32) {
-        return InvalidGetAssertionField("second");
-      }
-
-      auto prf_values = blink::mojom::PRFValues::New();
-      prf_values->first.assign(first->begin(), first->end());
-      if (second) {
-        prf_values->second.emplace(second->begin(), second->end());
+      absl::optional<blink::mojom::PRFValuesPtr> prf_results =
+          ParsePRFResults(results, user);
+      if (!prf_results) {
+        return InvalidGetAssertionField("prf");
       }
 
       response->extensions->echo_prf = true;
-      response->extensions->prf_results = std::move(prf_values);
+      response->extensions->prf_results = std::move(*prf_results);
     }
   }
 
diff --git a/components/webauthn/json/value_conversions_unittest.cc b/components/webauthn/json/value_conversions_unittest.cc
index 3beabd6..bb74e9f0 100644
--- a/components/webauthn/json/value_conversions_unittest.cc
+++ b/components/webauthn/json/value_conversions_unittest.cc
@@ -25,7 +25,6 @@
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/blink/public/mojom/webauthn/authenticator.mojom-shared.h"
 #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
 
 namespace webauthn {
@@ -48,6 +47,23 @@
 using blink::mojom::RemoteDesktopClientOverride;
 using blink::mojom::RemoteDesktopClientOverridePtr;
 
+// kUpdateRobolectricTests can be set to cause these tests to print out values
+// that can be used in `Fido2ApiTestHelper.java`. This is needed whenever the
+// Mojo structures for responses in `authenticator.mojom` are updated.
+constexpr bool kUpdateRobolectricTests = false;
+
+void PrintJava(const char* name, base::span<const uint8_t> data) {
+  fprintf(stderr, "private static final byte[] %s = new byte[] {", name);
+  for (size_t i = 0; i < data.size(); i++) {
+    const uint8_t byte = data[i];
+    if (i) {
+      fprintf(stderr, ", ");
+    }
+    fprintf(stderr, "%d", byte < 128 ? byte : byte - 0x80);
+  }
+  fprintf(stderr, "};\n");
+}
+
 std::vector<uint8_t> ToByteVector(base::StringPiece in) {
   const uint8_t* in_ptr = reinterpret_cast<const uint8_t*>(in.data());
   return std::vector<uint8_t>(in_ptr, in_ptr + in.size());
@@ -85,6 +101,9 @@
 TEST(WebAuthenticationJSONConversionTest,
      PublicKeyCredentialCreationOptionsToValue) {
   // Exercise all supported fields.
+  auto prf_values = blink::mojom::PRFValues::New(
+      absl::nullopt, std::vector<uint8_t>({1, 2, 3, 4}),
+      std::vector<uint8_t>{5, 6, 7, 8});
   auto options = PublicKeyCredentialCreationOptions::New(
       device::PublicKeyCredentialRpEntity(kRpId, kRpName),
       device::PublicKeyCredentialUserEntity(kUserId, kUserName,
@@ -97,7 +116,9 @@
           device::UserVerificationRequirement::kRequired),
       device::AttestationConveyancePreference::kDirect,
       /*hmac_create_secret=*/true,
-      /*prf_enable=*/true, blink::mojom::ProtectionPolicy::UV_REQUIRED,
+      /*prf_enable=*/true,
+      /*prf_input=*/std::move(prf_values),
+      blink::mojom::ProtectionPolicy::UV_REQUIRED,
       /*enforce_protection_policy=*/true,
       /*appid_exclude=*/kAppId,
       /*cred_props=*/true, device::LargeBlobSupport::kRequired,
@@ -116,7 +137,7 @@
   ASSERT_TRUE(serializer.Serialize(value));
   EXPECT_EQ(
       json,
-      R"({"attestation":"direct","authenticatorSelection":{"authenticatorAttachment":"platform","residentKey":"required","userVerification":"required"},"challenge":"dGVzdCBjaGFsbGVuZ2U","excludeCredentials":[{"id":"FBUW","transports":["usb"],"type":"public-key"},{"id":"Hh8g","type":"public-key"}],"extensions":{"appIdExclude":"https://example.test/appid.json","credBlob":"dGVzdCBjcmVkIGJsb2I","credProps":true,"credentialProtectionPolicy":"userVerificationRequired","enforceCredentialProtectionPolicy":true,"hmacCreateSecret":true,"largeBlob":{"support":"required"},"minPinLength":true,"payment":{"isPayment":true},"prf":{},"remoteDesktopClientOverride":{"origin":"https://login.example.test","sameOriginWithAncestors":true}},"pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-257,"type":"public-key"}],"rp":{"id":"example.test","name":"Example LLC"},"user":{"displayName":"Example User","id":"dGVzdCB1c2VyIGlk","name":"user@example.test"}})");
+      R"({"attestation":"direct","authenticatorSelection":{"authenticatorAttachment":"platform","residentKey":"required","userVerification":"required"},"challenge":"dGVzdCBjaGFsbGVuZ2U","excludeCredentials":[{"id":"FBUW","transports":["usb"],"type":"public-key"},{"id":"Hh8g","type":"public-key"}],"extensions":{"appIdExclude":"https://example.test/appid.json","credBlob":"dGVzdCBjcmVkIGJsb2I","credProps":true,"credentialProtectionPolicy":"userVerificationRequired","enforceCredentialProtectionPolicy":true,"hmacCreateSecret":true,"largeBlob":{"support":"required"},"minPinLength":true,"payment":{"isPayment":true},"prf":{"eval":{"first":"AQIDBA","second":"BQYHCA"}},"remoteDesktopClientOverride":{"origin":"https://login.example.test","sameOriginWithAncestors":true}},"pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-257,"type":"public-key"}],"rp":{"id":"example.test","name":"Example LLC"},"user":{"displayName":"Example User","id":"dGVzdCB1c2VyIGlk","name":"user@example.test"}})");
 }
 
 TEST(WebAuthenticationJSONConversionTest,
@@ -220,7 +241,13 @@
     "credProps": { "rk": true },
     "hmacCreateSecret": true,
     "largeBlob": { "supported": true },
-    "prf": { "enabled": true }
+    "prf": {
+      "enabled": true,
+      "results": {
+        "first": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+        "second": "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE"
+      }
+    }
   },
   "id": "dGVzdCBpZA",
   "rawId": "dGVzdCBpZA",
@@ -245,6 +272,22 @@
       MakeCredentialResponseFromValue(*value, JSONUser::kAndroid);
   ASSERT_TRUE(response) << error;
 
+  if (kUpdateRobolectricTests) {
+    PrintJava("TEST_SERIALIZED_CREDMAN_MAKE_CREDENTIAL_RESPONSE",
+              blink::mojom::MakeCredentialAuthenticatorResponse::Serialize(
+                  &response));
+  }
+
+  auto prf_values = blink::mojom::PRFValues::New(
+      absl::nullopt,
+      std::vector<uint8_t>({
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      }),
+      std::vector<uint8_t>({
+          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+      }));
   auto expected = MakeCredentialAuthenticatorResponse::New(
       CommonCredentialInfo::New(kIdB64Url, kId, kClientDataJson,
                                 kAuthenticatorData),
@@ -252,7 +295,8 @@
       std::vector<device::FidoTransportProtocol>{
           device::FidoTransportProtocol::kUsbHumanInterfaceDevice},
       /*echo_hmac_create_secret=*/true, /*hmac_create_secret=*/true,
-      /*echo_prf=*/true, /*prf=*/true, /*echo_cred_blob=*/true,
+      /*echo_prf=*/true, /*prf=*/true, /*prf_results=*/std::move(prf_values),
+      /*echo_cred_blob=*/true,
       /*cred_blob=*/true, /*public_key_der=*/kPublicKey,
       /*public_key_algo=*/-7,
       /*echo_cred_props=*/true, /*has_cred_props_rk=*/true,
@@ -270,6 +314,8 @@
             expected->echo_hmac_create_secret);
   EXPECT_EQ(response->hmac_create_secret, expected->hmac_create_secret);
   EXPECT_EQ(response->echo_prf, expected->prf);
+  EXPECT_EQ(response->prf_results->first, expected->prf_results->first);
+  EXPECT_EQ(response->prf_results->second, expected->prf_results->second);
   EXPECT_EQ(response->echo_cred_blob, expected->echo_cred_blob);
   EXPECT_EQ(response->cred_blob, expected->cred_blob);
   EXPECT_EQ(response->public_key_der, expected->public_key_der);
@@ -508,6 +554,12 @@
       GetAssertionResponseFromValue(*value, JSONUser::kAndroid);
   ASSERT_TRUE(response) << error;
 
+  if (kUpdateRobolectricTests) {
+    PrintJava(
+        "TEST_SERIALIZED_CREDMAN_GET_CREDENTIAL_RESPONSE ",
+        blink::mojom::GetAssertionAuthenticatorResponse::Serialize(&response));
+  }
+
   auto expected = GetAssertionAuthenticatorResponse::New(
       CommonCredentialInfo::New(kIdB64Url, kId, kClientDataJson,
                                 kAuthenticatorData),
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
index 5366db5b..81f7053 100644
--- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
+++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
@@ -15,6 +15,7 @@
 #include "base/apple/owned_objc.h"
 #include "base/containers/contains.h"
 #include "base/debug/crash_logging.h"
+#import "base/mac/mac_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/remote_cocoa/app_shim/ns_view_ids.h"
@@ -1262,6 +1263,16 @@
 
     if (is_a_system_shortcut_event) {
       [[NSApp mainMenu] performKeyEquivalent:theEvent];
+
+      // Behavior changed in macOS Sonoma - now it's important we early-out
+      // rather than allow the code to reach
+      // _hostHelper->ForwardKeyboardEventWithCommands(). Go with the existing
+      // behavior for prior versions because we know it works for them.
+      if (base::mac::MacOSVersion() >= 14'00'00) {
+        _currentKeyDownCode.reset();
+        _host->EndKeyboardEvent();
+        return;
+      }
     } else {
       [self interpretKeyEvents:@[ theEvent ]];
     }
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index f6949faf..95bf7f1 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -1385,8 +1385,7 @@
     blink::mojom::IDBTransactionDurability durability) {
   switch (durability) {
     case blink::mojom::IDBTransactionDurability::Default:
-      NOTREACHED();
-      ABSL_FALLTHROUGH_INTENDED;
+      NOTREACHED_NORETURN();
     case blink::mojom::IDBTransactionDurability::Strict:
       return true;
     case blink::mojom::IDBTransactionDurability::Relaxed:
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 3b58e4f..54bfe35 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -554,19 +554,9 @@
   }
 
   // Set up an interceptor for prefetch.
-
-  // TODO(crbug.com/1431387): Do not depend on the initiator liveness, e.g. by
-  // plumbing `GlobalRenderFrameHostId` or switching to `LocalFrameToken`. See
-  // https://chromium-review.googlesource.com/c/chromium/src/+/4372403/comment/ff141ba3_0ffd99ff/
-  // for more details.
-  GlobalRenderFrameHostId initiator_render_frame_host_id;
-  if (RenderFrameHost* initiator_render_frame_host =
-          initiator_document_.AsRenderFrameHostIfValid()) {
-    initiator_render_frame_host_id = initiator_render_frame_host->GetGlobalId();
-  }
   std::unique_ptr<PrefetchURLLoaderInterceptor> prefetch_interceptor =
       content::PrefetchURLLoaderInterceptor::MaybeCreateInterceptor(
-          frame_tree_node_id_, initiator_render_frame_host_id);
+          frame_tree_node_id_, request_info_->initiator_document_token);
   if (prefetch_interceptor) {
     interceptors_.push_back(std::move(prefetch_interceptor));
   }
@@ -772,7 +762,12 @@
           request_info_->sandbox_flags,
           static_cast<ui::PageTransition>(resource_request_->transition_type),
           resource_request_->has_user_gesture, initiating_origin,
-          initiator_document_.AsRenderFrameHostIfValid(), &loader_factory);
+          request_info_->initiator_document_token
+              ? RenderFrameHostImpl::FromDocumentToken(
+                    request_info_->initiator_process_id,
+                    *request_info_->initiator_document_token)
+              : nullptr,
+          &loader_factory);
 
       if (loader_factory) {
         factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
@@ -1346,7 +1341,6 @@
       url_(request_info_->common_params->url),
       frame_tree_node_id_(request_info_->frame_tree_node_id),
       global_request_id_(GlobalRequestID::MakeBrowserInitiated()),
-      initiator_document_(request_info_->initiator_document),
       web_contents_getter_(
           base::BindRepeating(&WebContents::FromFrameTreeNodeId,
                               frame_tree_node_id_)),
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index 27357f2d..0542056 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -31,6 +31,7 @@
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/navigation/navigation_policy.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
 
 namespace net {
 struct RedirectInfo;
@@ -250,7 +251,6 @@
 
   const int frame_tree_node_id_;
   const GlobalRequestID global_request_id_;
-  const WeakDocumentPtr initiator_document_;
   net::RedirectInfo redirect_info_;
   int redirect_limit_ = net::URLRequest::kMaxRedirects;
   int accept_ch_restart_limit_ = net::URLRequest::kMaxRedirects;
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index cfe9b4b..2930363 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -278,7 +278,8 @@
             nullptr /* client_security_state */,
             absl::nullopt /* devtools_accepted_stream_types */,
             false /* is_pdf */,
-            content::WeakDocumentPtr() /* initiator_document */,
+            ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
+            absl::nullopt /* initiator_document_token */,
             GlobalRenderFrameHostId() /* previous_render_frame_host_id */,
             false /* allow_cookies_from_browser */, 0 /* navigation_id */,
             false /* shared_storage_writable */));
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index 1712acd..b237ea65 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -132,7 +132,8 @@
             nullptr /* client_security_state */,
             absl::nullopt /* devtools_accepted_stream_types */,
             false /* is_pdf */,
-            content::WeakDocumentPtr() /* initiator_document */,
+            ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
+            absl::nullopt /* initiator_document_token */,
             GlobalRenderFrameHostId() /* previous_render_frame_host_id */,
             false /* allow_cookies_from_browser */, 0 /* navigation_id */,
             false /* shared_storage_writable */));
diff --git a/content/browser/preloading/prefetch/no_vary_search_helper.h b/content/browser/preloading/prefetch/no_vary_search_helper.h
index 1ed09ec..11f731f 100644
--- a/content/browser/preloading/prefetch/no_vary_search_helper.h
+++ b/content/browser/preloading/prefetch/no_vary_search_helper.h
@@ -44,21 +44,31 @@
 // `callback` is called.
 enum class IterateCandidateResult { kContinue, kFinish };
 
-// Call `callback` on every `PrefetchContainer`s that can match with `url` via
-// No-Vary-Search:
-// - Has a URL with the same non-ref/query part as `url`,
-// - Has `NoVarySearchData`, AND
-// - `AreEquivalent()` is true or `check_are_equivalent` is false.
-// Note that if `PrefetchContainer` doesn't have a valid `NoVarySearchData`, it
-// is ignored even if its URL is exactly the same as `url`.
+// Call `callback` on every `PrefetchContainer`s that can match with `url`, in
+// the order of
+// 1. Exact match.
+// 2. No-Vary-Search matches if enabled.
+//   - Has a URL with the same non-ref/query part as `url`,
+//   - Has `NoVarySearchData`, AND
+//   - `AreEquivalent()` is true or `check_are_equivalent` is false.
 inline void IterateCandidates(
     const GURL& url,
     const std::map<GURL, base::WeakPtr<PrefetchContainer>>& prefetches,
     base::RepeatingCallback<
         IterateCandidateResult(base::WeakPtr<PrefetchContainer>)> callback,
     bool check_are_equivalent = true) {
-  DCHECK(
-      base::FeatureList::IsEnabled(network::features::kPrefetchNoVarySearch));
+  auto it_exact_match = prefetches.find(url);
+  if (it_exact_match != prefetches.end() && it_exact_match->second) {
+    if (callback.Run(it_exact_match->second) ==
+        IterateCandidateResult::kFinish) {
+      return;
+    }
+  }
+
+  // Fall back to No-Vary-Search equivalence if enabled.
+  if (!base::FeatureList::IsEnabled(network::features::kPrefetchNoVarySearch)) {
+    return;
+  }
 
   GURL::Replacements replacements;
   replacements.ClearRef();
@@ -77,6 +87,11 @@
        it != prefetches.end() && it->first.possibly_invalid_spec().starts_with(
                                      url_with_no_query.possibly_invalid_spec());
        ++it) {
+    // `it_exact_match` is already visited above and thus skipped.
+    if (it == it_exact_match) {
+      continue;
+    }
+
     if (!it->second) {
       continue;
     }
@@ -102,8 +117,10 @@
   }
 }
 
-// Get a PrefetchContainer from `prefetches` that can serve `url` according to
-// No-Vary-Search information.
+// Get a PrefetchContainer from `prefetches` that can serve `url`, either:
+// - Via exact match, or
+// - Via No-Vary-Search information if exact match is not found, the feature is
+// enabled and `SetNoVarySearchData()` is called for such `PrefetchContainer`s.
 inline base::WeakPtr<PrefetchContainer> MatchUrl(
     const GURL& url,
     const std::map<GURL, base::WeakPtr<PrefetchContainer>>& prefetches) {
diff --git a/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc b/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc
index f95cb485..91588435 100644
--- a/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc
+++ b/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc
@@ -18,26 +18,17 @@
 
 class NoVarySearchHelperTester final {
  public:
-  void AddUrl(const GURL& url, network::mojom::URLResponseHeadPtr head) {
-    std::unique_ptr<PrefetchContainer> prefetch_container =
-        std::make_unique<PrefetchContainer>(
-            GlobalRenderFrameHostId(1234, 5678), url,
-            PrefetchType(/*use_prefetch_proxy=*/true,
-                         blink::mojom::SpeculationEagerness::kEager),
-            blink::mojom::Referrer(),
-            /*no_vary_search_expected=*/absl::nullopt,
-            blink::mojom::SpeculationInjectionWorld::kNone,
-            /*prefetch_document_manager=*/nullptr);
+  PrefetchContainer* AddUrl(const GURL& url,
+                            network::mojom::URLResponseHeadPtr head) {
+    auto prefetch_container =
+        CreatePrefetchContainer(url, std::move(head));
+    prefetches_[url] = prefetch_container;
 
-    MakeServableStreamingURLLoaderForTest(prefetch_container.get(),
-                                          std::move(head), "test body");
-    prefetches_[url] = prefetch_container->GetWeakPtr();
-    no_vary_search::SetNoVarySearchData(prefetch_container->GetWeakPtr());
-    owned_prefetches_.push_back(std::move(prefetch_container));
+    return prefetch_container.get();
   }
 
-  base::WeakPtr<PrefetchContainer> MatchUrl(const GURL& url) {
-    return no_vary_search::MatchUrl(url, prefetches_);
+  PrefetchContainer* MatchUrl(const GURL& url) {
+    return no_vary_search::MatchUrl(url, prefetches_).get();
   }
 
   std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>>
@@ -47,6 +38,28 @@
   }
 
  private:
+  base::WeakPtr<PrefetchContainer> CreatePrefetchContainer(
+      const GURL& url,
+      network::mojom::URLResponseHeadPtr head) {
+    std::unique_ptr<PrefetchContainer> prefetch_container =
+        std::make_unique<PrefetchContainer>(
+            GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), url,
+            PrefetchType(/*use_prefetch_proxy=*/true,
+                         blink::mojom::SpeculationEagerness::kEager),
+            blink::mojom::Referrer(),
+            /*no_vary_search_expected=*/absl::nullopt,
+            blink::mojom::SpeculationInjectionWorld::kNone,
+            /*prefetch_document_manager=*/nullptr);
+
+    MakeServableStreamingURLLoaderForTest(prefetch_container.get(),
+                                          std::move(head), "test body");
+    auto weak_prefetch_container = prefetch_container->GetWeakPtr();
+    no_vary_search::SetNoVarySearchData(prefetch_container->GetWeakPtr());
+    owned_prefetches_.push_back(std::move(prefetch_container));
+
+    return weak_prefetch_container;
+  }
+
   std::vector<std::unique_ptr<PrefetchContainer>> owned_prefetches_;
   std::map<GURL, base::WeakPtr<PrefetchContainer>> prefetches_;
 };
@@ -85,7 +98,7 @@
   std::unique_ptr<NoVarySearchHelperTester> helper =
       std::make_unique<NoVarySearchHelperTester>();
   const GURL test_url("https://a.com/index.html?a=2&b=3");
-  helper->AddUrl(test_url, std::move(head));
+  auto* prefetch_container = helper->AddUrl(test_url, std::move(head));
 
   const auto urls_with_no_vary_search =
       helper->GetAllForUrlWithoutRefAndQueryForTesting(test_url);
@@ -105,8 +118,10 @@
   EXPECT_TRUE(urls_with_no_vary_search.at(0)
                   .second->GetNoVarySearchData()
                   ->vary_on_key_order());
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://a.com/index.html?b=4&a=2&c=5")));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://a.com/index.html?a=2")));
+  EXPECT_EQ(helper->MatchUrl(GURL("https://a.com/index.html?b=4&a=2&c=5")),
+            prefetch_container);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://a.com/index.html?a=2")),
+            prefetch_container);
   EXPECT_FALSE(helper->MatchUrl(GURL("https://a.com/index.html")));
   EXPECT_FALSE(helper->MatchUrl(GURL("https://a.com/index.html?b=4")));
 }
@@ -124,7 +139,7 @@
 
   std::unique_ptr<NoVarySearchHelperTester> helper =
       std::make_unique<NoVarySearchHelperTester>();
-  helper->AddUrl(test_url, std::move(head));
+  auto* prefetch_container = helper->AddUrl(test_url, std::move(head));
   const auto urls_with_no_vary_search =
       helper->GetAllForUrlWithoutRefAndQueryForTesting(test_url);
   ASSERT_EQ(urls_with_no_vary_search.size(), 1u);
@@ -143,9 +158,11 @@
   EXPECT_TRUE(urls_with_no_vary_search.at(0)
                   .second->GetNoVarySearchData()
                   ->vary_on_key_order());
-  EXPECT_TRUE(helper->MatchUrl(test_url));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://a.com/home.html?b=3")));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://a.com/home.html?b=3&a=4")));
+  EXPECT_EQ(helper->MatchUrl(test_url), prefetch_container);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://a.com/home.html?b=3")),
+            prefetch_container);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://a.com/home.html?b=3&a=4")),
+            prefetch_container);
   EXPECT_FALSE(helper->MatchUrl(GURL("https://a.com/home.html")));
   EXPECT_FALSE(helper->MatchUrl(GURL("https://a.com/home.html?b=4")));
 }
@@ -165,7 +182,7 @@
 
   std::unique_ptr<NoVarySearchHelperTester> helper =
       std::make_unique<NoVarySearchHelperTester>();
-  helper->AddUrl(test_url, std::move(head));
+  auto* prefetch_container = helper->AddUrl(test_url, std::move(head));
   const auto urls_with_no_vary_search =
       helper->GetAllForUrlWithoutRefAndQueryForTesting(test_url);
   ASSERT_EQ(urls_with_no_vary_search.size(), 1u);
@@ -193,8 +210,9 @@
       helper->MatchUrl(GURL("https://a.com/away.html?a=2&b=3&c=6&d=5")));
   EXPECT_FALSE(
       helper->MatchUrl(GURL("https://a.com/away.html?a=2&b=3&c=6&a=5")));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://a.com/away.html?b=3&c=6&a=2")));
-  EXPECT_TRUE(helper->MatchUrl(test_url));
+  EXPECT_EQ(helper->MatchUrl(GURL("https://a.com/away.html?b=3&c=6&a=2")),
+            prefetch_container);
+  EXPECT_EQ(helper->MatchUrl(test_url), prefetch_container);
 }
 
 TEST_F(NoVarySearchHelperTest, AddUrlWithoutNoVarySearchTest) {
@@ -209,12 +227,13 @@
   std::unique_ptr<NoVarySearchHelperTester> helper =
       std::make_unique<NoVarySearchHelperTester>();
   GURL test_url("https://a.com/index.html?a=2&b=3");
-  helper->AddUrl(test_url, std::move(head));
+  auto* prefetch_container = helper->AddUrl(test_url, std::move(head));
 
   auto urls_with_no_vary_search =
       helper->GetAllForUrlWithoutRefAndQueryForTesting(test_url);
-  ASSERT_TRUE(urls_with_no_vary_search.empty());
-  EXPECT_FALSE(helper->MatchUrl(test_url));
+  ASSERT_EQ(urls_with_no_vary_search.size(), 1u);
+  EXPECT_EQ(urls_with_no_vary_search.at(0).first, test_url);
+  EXPECT_EQ(helper->MatchUrl(test_url), prefetch_container);
 }
 
 TEST_F(NoVarySearchHelperTest, DoNotPrefixMatch) {
@@ -248,14 +267,15 @@
 
   // Call `AddUrl` in an order different from the URL sorted order to test that
   // `prefixes_` are sorted.
-  helper->AddUrl(no_match_url_num, head->Clone());
-  helper->AddUrl(matching_url_ref, head->Clone());
-  helper->AddUrl(no_match_url_foo, head->Clone());
-  helper->AddUrl(matching_url_a_1, head->Clone());
-  helper->AddUrl(matching_url_a_0, network::mojom::URLResponseHead::New());
-  helper->AddUrl(matching_url_a_2, head->Clone());
-  helper->AddUrl(no_match_url_top, head->Clone());
-  helper->AddUrl(matching_url_raw, head->Clone());
+  auto* pc_no_match_url_num = helper->AddUrl(no_match_url_num, head->Clone());
+  auto* pc_matching_url_ref = helper->AddUrl(matching_url_ref, head->Clone());
+  auto* pc_no_match_url_foo = helper->AddUrl(no_match_url_foo, head->Clone());
+  auto* pc_matching_url_a_1 = helper->AddUrl(matching_url_a_1, head->Clone());
+  auto* pc_matching_url_a_0 =
+      helper->AddUrl(matching_url_a_0, network::mojom::URLResponseHead::New());
+  auto* pc_matching_url_a_2 = helper->AddUrl(matching_url_a_2, head->Clone());
+  auto* pc_no_match_url_top = helper->AddUrl(no_match_url_top, head->Clone());
+  auto* pc_matching_url_raw = helper->AddUrl(matching_url_raw, head->Clone());
 
   // Even if the matching entries and non-matching entries (non-matching URLs
   // and `matching_url_a_0` without No-Vary-Search headers) are interleaved in
@@ -269,12 +289,26 @@
   EXPECT_EQ(urls_with_no_vary_search.at(2).first, matching_url_a_1);
   EXPECT_EQ(urls_with_no_vary_search.at(3).first, matching_url_a_2);
 
-  EXPECT_TRUE(
-      helper->MatchUrl(GURL("https://example.com/index.html?b=4&a=2&c=5")));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://example.com/index.html?a=1")));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://example.com/index.html?a=2")));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://example.com/index.html111?a=3")));
-  EXPECT_TRUE(helper->MatchUrl(GURL("https://example.com/index.htmlfoo?a=4")));
+  EXPECT_EQ(
+      helper->MatchUrl(GURL("https://example.com/index.html?b=4&a=2&c=5")),
+      pc_matching_url_a_2);
+  EXPECT_EQ(helper->MatchUrl(matching_url_a_0), pc_matching_url_a_0);
+  EXPECT_FALSE(helper->MatchUrl(GURL("https://example.com/index.html?a=0")));
+  EXPECT_EQ(helper->MatchUrl(GURL("https://example.com/index.html?a=1")),
+            pc_matching_url_a_1);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://example.com/index.html?a=2")),
+            pc_matching_url_a_2);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://example.com/index.html111?a=3")),
+            pc_no_match_url_num);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://example.com/index.htmlfoo?a=4")),
+            pc_no_match_url_foo);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://example.com/top.html?a=5")),
+            pc_no_match_url_top);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://example.com/index.html?b=3")),
+            pc_matching_url_raw);
+  EXPECT_EQ(helper->MatchUrl(matching_url_ref), pc_matching_url_ref);
+  EXPECT_EQ(helper->MatchUrl(GURL("https://example.com/index.html?b=3#ref")),
+            pc_matching_url_raw);
 
   // `matching_url_a_0` shouldn't match due to lack of the No-Vary-Search
   // header.
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc
index 122e6c66..8f38ecc 100644
--- a/content/browser/preloading/prefetch/prefetch_container.cc
+++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -361,6 +361,7 @@
 
 PrefetchContainer::PrefetchContainer(
     const GlobalRenderFrameHostId& referring_render_frame_host_id,
+    const blink::DocumentToken& referring_document_token,
     const GURL& url,
     const PrefetchType& prefetch_type,
     const blink::mojom::Referrer& referrer,
@@ -368,6 +369,7 @@
     blink::mojom::SpeculationInjectionWorld world,
     base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager)
     : referring_render_frame_host_id_(referring_render_frame_host_id),
+      referring_document_token_(referring_document_token),
       prefetch_url_(url),
       prefetch_type_(prefetch_type),
       referrer_(referrer),
diff --git a/content/browser/preloading/prefetch/prefetch_container.h b/content/browser/preloading/prefetch/prefetch_container.h
index 2b4cf14..7e242f59 100644
--- a/content/browser/preloading/prefetch/prefetch_container.h
+++ b/content/browser/preloading/prefetch/prefetch_container.h
@@ -20,6 +20,7 @@
 #include "net/http/http_no_vary_search_data.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
 #include "url/gurl.h"
 
 namespace network {
@@ -89,6 +90,7 @@
  public:
   PrefetchContainer(
       const GlobalRenderFrameHostId& referring_render_frame_host_id,
+      const blink::DocumentToken& referring_document_token,
       const GURL& url,
       const PrefetchType& prefetch_type,
       const blink::mojom::Referrer& referrer,
@@ -101,9 +103,9 @@
   PrefetchContainer& operator=(const PrefetchContainer&) = delete;
 
   // Defines the key to uniquely identify a prefetch.
-  using Key = std::pair<GlobalRenderFrameHostId, GURL>;
+  using Key = std::pair<blink::DocumentToken, GURL>;
   Key GetPrefetchContainerKey() const {
-    return std::make_pair(referring_render_frame_host_id_, prefetch_url_);
+    return std::make_pair(referring_document_token_, prefetch_url_);
   }
 
   // The ID of the RenderFrameHost that triggered the prefetch.
@@ -463,8 +465,9 @@
   // has redirect(s).
   const SinglePrefetch& GetPreviousSinglePrefetchToPrefetch() const;
 
-  // The ID of the RenderFrameHost that triggered the prefetch.
-  GlobalRenderFrameHostId referring_render_frame_host_id_;
+  // The ID of the RenderFrameHost/Document that triggered the prefetch.
+  const GlobalRenderFrameHostId referring_render_frame_host_id_;
+  const blink::DocumentToken referring_document_token_;
 
   // The URL that was requested to be prefetch.
   const GURL prefetch_url_;
diff --git a/content/browser/preloading/prefetch/prefetch_container_unittest.cc b/content/browser/preloading/prefetch/prefetch_container_unittest.cc
index 45a94cd..b62d61a 100644
--- a/content/browser/preloading/prefetch/prefetch_container_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_container_unittest.cc
@@ -110,8 +110,10 @@
 }  // namespace
 
 TEST_F(PrefetchContainerTest, CreatePrefetchContainer) {
+  blink::DocumentToken document_token;
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+      GlobalRenderFrameHostId(1234, 5678), document_token,
+      GURL("https://test.com"),
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -129,14 +131,14 @@
       prefetch_container.IsIsolatedNetworkContextRequiredForCurrentPrefetch());
 
   EXPECT_EQ(prefetch_container.GetPrefetchContainerKey(),
-            std::make_pair(GlobalRenderFrameHostId(1234, 5678),
-                           GURL("https://test.com")));
+            std::make_pair(document_token, GURL("https://test.com")));
   EXPECT_FALSE(prefetch_container.GetHead());
 }
 
 TEST_F(PrefetchContainerTest, PrefetchStatus) {
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+      GURL("https://test.com"),
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -155,7 +157,8 @@
 
 TEST_F(PrefetchContainerTest, IsDecoy) {
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+      GURL("https://test.com"),
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -171,7 +174,8 @@
 
 TEST_F(PrefetchContainerTest, Servable) {
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+      GURL("https://test.com"),
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -197,7 +201,7 @@
   const GURL kTestUrl3 = GURL("https://test3.com");
 
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), kTestUrl1,
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), kTestUrl1,
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -273,7 +277,7 @@
   const GURL kTestUrl = GURL("https://test.com");
   base::HistogramTester histogram_tester;
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), kTestUrl,
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), kTestUrl,
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -335,7 +339,7 @@
   const GURL kRedirectUrl2 = GURL("https://redirect2.com");
   base::HistogramTester histogram_tester;
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), kTestUrl,
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), kTestUrl,
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -465,7 +469,8 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+          GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+          GURL("https://test.com"),
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -586,7 +591,8 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+          GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+          GURL("https://test.com"),
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -659,7 +665,7 @@
           &web_contents()->GetPrimaryPage().GetMainDocument());
 
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), kTestUrl1,
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), kTestUrl1,
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -697,7 +703,7 @@
           &web_contents()->GetPrimaryPage().GetMainDocument());
 
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), kTestUrl1,
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), kTestUrl1,
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -746,7 +752,8 @@
   base::HistogramTester histogram_tester;
   for (const auto& test_case : test_cases) {
     PrefetchContainer prefetch_container(
-        GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+        GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+        GURL("https://test.com"),
         PrefetchType(/*use_prefetch_proxy=*/true, test_case.eagerness),
         blink::mojom::Referrer(),
         /*no_vary_search_expected=*/absl::nullopt,
@@ -802,7 +809,8 @@
   base::HistogramTester histogram_tester;
 
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+      GURL("https://test.com"),
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -825,7 +833,8 @@
   blink::mojom::Referrer referrer;
   referrer.url = GURL("https://test.com/referrer");
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com/prefetch"),
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+      GURL("https://test.com/prefetch"),
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       referrer, /*no_vary_search_expected=*/absl::nullopt,
@@ -872,7 +881,7 @@
   base::HistogramTester histogram_tester;
 
   auto prefetch_container = std::make_unique<PrefetchContainer>(
-      GlobalRenderFrameHostId(1234, 5678), kTestUrl1,
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), kTestUrl1,
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -967,7 +976,7 @@
   base::HistogramTester histogram_tester;
 
   PrefetchContainer prefetch_container(
-      GlobalRenderFrameHostId(1234, 5678), kTestUrl1,
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(), kTestUrl1,
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
@@ -1070,7 +1079,8 @@
 
 TEST_P(PrefetchContainerLifetimeTest, Lifetime) {
   auto prefetch_container = std::make_unique<PrefetchContainer>(
-      GlobalRenderFrameHostId(1234, 5678), GURL("https://test.com"),
+      GlobalRenderFrameHostId(1234, 5678), blink::DocumentToken(),
+      GURL("https://test.com"),
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
diff --git a/content/browser/preloading/prefetch/prefetch_document_manager.cc b/content/browser/preloading/prefetch/prefetch_document_manager.cc
index f75f273a..a7a0a1a 100644
--- a/content/browser/preloading/prefetch/prefetch_document_manager.cc
+++ b/content/browser/preloading/prefetch/prefetch_document_manager.cc
@@ -17,6 +17,7 @@
 #include "content/browser/preloading/prefetch/prefetch_service.h"
 #include "content/browser/preloading/prefetch/prefetch_serving_page_metrics_container.h"
 #include "content/browser/preloading/prefetch/prefetch_url_loader_helper.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/prefetch_metrics.h"
@@ -87,6 +88,8 @@
 PrefetchDocumentManager::PrefetchDocumentManager(RenderFrameHost* rfh)
     : DocumentUserData(rfh),
       WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
+      document_token_(
+          static_cast<RenderFrameHostImpl*>(rfh)->GetDocumentToken()),
       prefetch_destruction_callback_(base::DoNothing()) {}
 
 PrefetchDocumentManager::~PrefetchDocumentManager() {
@@ -151,20 +154,8 @@
   // navigations where the prefetch is used in a different tab.
   serving_page_metrics_container->SetSameTabAsPrefetchingTab(true);
 
-  base::WeakPtr<PrefetchContainer> prefetch_container = nullptr;
-
-  // Get the prefetch for the URL being navigated to. If there is no prefetch
-  // for that URL, then check if there is an equivalent prefetch using
-  // No-Vary-Search equivalence. If there is not then stop.
-  auto prefetch_iter = all_prefetches_.find(navigation_handle->GetURL());
-  if (prefetch_iter != all_prefetches_.end()) {
-    prefetch_container = prefetch_iter->second;
-  }
-
-  if (!prefetch_container &&
-      base::FeatureList::IsEnabled(network::features::kPrefetchNoVarySearch)) {
-    prefetch_container = MatchUrl(navigation_handle->GetURL());
-  }
+  base::WeakPtr<PrefetchContainer> prefetch_container =
+      MatchUrl(navigation_handle->GetURL());
 
   if (!prefetch_container) {
     DVLOG(1) << "PrefetchDocumentManager::DidStartNavigation() for "
@@ -296,8 +287,8 @@
   }
   // Create a new |PrefetchContainer| and take ownership of it
   auto container = std::make_unique<PrefetchContainer>(
-      render_frame_host().GetGlobalId(), url, prefetch_type, referrer,
-      std::move(no_vary_search_expected), world,
+      render_frame_host().GetGlobalId(), document_token_, url, prefetch_type,
+      referrer, std::move(no_vary_search_expected), world,
       weak_method_factory_.GetWeakPtr());
   container->SetDevToolsObserver(std::move(devtools_observer));
   DVLOG(1) << *container << ": created";
diff --git a/content/browser/preloading/prefetch/prefetch_document_manager.h b/content/browser/preloading/prefetch/prefetch_document_manager.h
index 6735b37..a3c1cfe0 100644
--- a/content/browser/preloading/prefetch/prefetch_document_manager.h
+++ b/content/browser/preloading/prefetch/prefetch_document_manager.h
@@ -145,6 +145,8 @@
   // Helper function to get the |PrefetchService| associated with |this|.
   PrefetchService* GetPrefetchService() const;
 
+  blink::DocumentToken document_token_;
+
   // This map holds references to all |PrefetchContainer| associated with
   // |this|, regardless of ownership.
   std::map<GURL, base::WeakPtr<PrefetchContainer>> all_prefetches_;
diff --git a/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc b/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc
index dd2f1b9a..06d96cc 100644
--- a/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc
@@ -329,7 +329,8 @@
     const auto urls_with_no_vary_search =
         prefetch_document_manager->GetAllForUrlWithoutRefAndQueryForTesting(
             test_url);
-    ASSERT_TRUE(urls_with_no_vary_search.empty());
+    ASSERT_EQ(urls_with_no_vary_search.size(), 1u);
+    ASSERT_EQ(urls_with_no_vary_search.at(0).first, test_url);
   }
 
   NavigateMainframeRendererTo(GetCrossOriginUrl("/candidate2.html?a=2&b=3"));
diff --git a/content/browser/preloading/prefetch/prefetch_service.cc b/content/browser/preloading/prefetch/prefetch_service.cc
index ce261ec2..10a4c3ad 100644
--- a/content/browser/preloading/prefetch/prefetch_service.cc
+++ b/content/browser/preloading/prefetch/prefetch_service.cc
@@ -1534,10 +1534,9 @@
 
   // Search for an inexact match using the No-Vary-Search hint.
   // It must either be servable now or potentially servable soon.
-  const auto frame_host_id = key.first;
   const GURL& nav_url = key.second;
   for (const auto& active_prefetch : active_prefetches_) {
-    if (active_prefetch.first != frame_host_id) {
+    if (active_prefetch.first != key.first) {
       continue;
     }
     PrefetchContainer* prefetch = all_prefetches_[active_prefetch].get();
diff --git a/content/browser/preloading/prefetch/prefetch_service_unittest.cc b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
index cc3b668..0ac6972 100644
--- a/content/browser/preloading/prefetch/prefetch_service_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
@@ -27,6 +27,7 @@
 #include "content/browser/preloading/preloading_attempt_impl.h"
 #include "content/browser/preloading/preloading_config.h"
 #include "content/browser/preloading/preloading_data_impl.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/common/features.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/frame_accept_header.h"
@@ -662,12 +663,16 @@
         *mock_navigation_handle_);
   }
 
+  blink::DocumentToken MainDocumentToken() {
+    return static_cast<RenderFrameHostImpl*>(main_rfh())->GetDocumentToken();
+  }
+
   void GetPrefetchToServe(
       base::test::TestFuture<PrefetchContainer::Reader>& future,
       const GURL& url,
-      GlobalRenderFrameHostId previous_render_frame_host_id) {
-    if (!previous_render_frame_host_id) {
-      previous_render_frame_host_id = main_rfh()->GetGlobalId();
+      absl::optional<blink::DocumentToken> initiator_document_token) {
+    if (!initiator_document_token) {
+      initiator_document_token = MainDocumentToken();
     }
     PrefetchMatchResolver* prefetch_match_resolver =
         GetPrefetchMatchResolverForMostRecentNavigation();
@@ -692,21 +697,21 @@
         base::Unretained(&future),
         base::Unretained(&request_handler_keep_alive_)));
     prefetch_service_->GetPrefetchToServe(
-        PrefetchContainer::Key(previous_render_frame_host_id, url),
+        PrefetchContainer::Key(*initiator_document_token, url),
         *prefetch_match_resolver);
   }
 
-  // A valid `previous_render_frame_host_id` is given as an argument when
+  // A valid `initiator_document_token` is given as an argument when
   // to test that prefetched results are not used for unexpected initiator
-  // Documents. In other cases, use the ID of the expected initiator
-  // Document (RenderFrameHost where the `PrefetchDocumentManager` is
+  // Documents. Otherwise (`absl::nullopt`), use the ID of the expected
+  // initiator Document (the Document where the `PrefetchDocumentManager` is
   // associated).
   PrefetchContainer::Reader GetPrefetchToServe(
       const GURL& url,
-      GlobalRenderFrameHostId previous_render_frame_host_id =
-          GlobalRenderFrameHostId()) {
+      absl::optional<blink::DocumentToken> initiator_document_token =
+          absl::nullopt) {
     base::test::TestFuture<PrefetchContainer::Reader> future;
-    GetPrefetchToServe(future, url, previous_render_frame_host_id);
+    GetPrefetchToServe(future, url, std::move(initiator_document_token));
     return future.Take();
   }
 
@@ -972,12 +977,9 @@
             base::Milliseconds(kHeaderLatency));
 
   // No servable PrefetchContainer is returned for different RenderFrameHost.
-  GlobalRenderFrameHostId different_render_frame_host_id =
-      main_rfh()->GetGlobalId();
-  different_render_frame_host_id.child_id += 1;
+  blink::DocumentToken different_document_token;
   PrefetchContainer::Reader serveable_reader_for_different_initiator =
-      GetPrefetchToServe(GURL("https://example.com"),
-                         different_render_frame_host_id);
+      GetPrefetchToServe(GURL("https://example.com"), different_document_token);
   ASSERT_FALSE(serveable_reader_for_different_initiator);
 
   PrefetchContainer::Reader serveable_reader =
@@ -4952,8 +4954,7 @@
   // Request the prefetch from the PrefetchService. The given callback shouldn't
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
-  GetPrefetchToServe(future, GURL("https://example.com"),
-                     main_rfh()->GetGlobalId());
+  GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   net::RedirectInfo redirect_info;
@@ -5250,8 +5251,7 @@
   // Request the prefetch from the PrefetchService. The given callback shouldn't
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
-  GetPrefetchToServe(future, GURL("https://example.com"),
-                     main_rfh()->GetGlobalId());
+  GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   task_environment()->FastForwardBy(base::Milliseconds(500));
@@ -5369,7 +5369,7 @@
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
   GetPrefetchToServe(future, GURL("https://example.com/index.html"),
-                     main_rfh()->GetGlobalId());
+                     MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
   task_environment()->FastForwardBy(base::Milliseconds(600));
 
@@ -5489,7 +5489,7 @@
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
   GetPrefetchToServe(future, GURL("https://example.com/index.html"),
-                     main_rfh()->GetGlobalId());
+                     MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   task_environment()->FastForwardBy(base::Milliseconds(700));
@@ -5601,7 +5601,7 @@
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
   GetPrefetchToServe(future, GURL("https://example.com/index.html"),
-                     main_rfh()->GetGlobalId());
+                     MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   task_environment()->FastForwardBy(base::Milliseconds(kHeaderLatency));
@@ -5701,8 +5701,7 @@
   // Request the prefetch from the PrefetchService. The given callback shouldn't
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
-  GetPrefetchToServe(future, GURL("https://example.com"),
-                     main_rfh()->GetGlobalId());
+  GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   task_environment()->FastForwardBy(base::Milliseconds(800));
@@ -5799,8 +5798,7 @@
   // Request the prefetch from the PrefetchService. The given callback shouldn't
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
-  GetPrefetchToServe(future, GURL("https://example.com"),
-                     main_rfh()->GetGlobalId());
+  GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   // If the prefetch times out while PrefetchService is blocking until head,
@@ -5904,8 +5902,7 @@
             get_prefetch_run_loop.Quit();
           }));
   prefetch_service_->GetPrefetchToServe(
-      PrefetchContainer::Key(main_rfh()->GetGlobalId(),
-                             GURL("https://example.com")),
+      PrefetchContainer::Key(MainDocumentToken(), GURL("https://example.com")),
       *prefetch_match_resolver);
   EXPECT_FALSE(serveable_reader);
 
@@ -5929,8 +5926,7 @@
             get_prefetch_run_loop.Quit();
           }));
   prefetch_service_->GetPrefetchToServe(
-      PrefetchContainer::Key(main_rfh()->GetGlobalId(),
-                             GURL("https://example.com")),
+      PrefetchContainer::Key(MainDocumentToken(), GURL("https://example.com")),
       *prefetch_match_resolver);
 
   get_prefetch_run_loop.Run();
@@ -6016,8 +6012,7 @@
   // Request the prefetch from the PrefetchService. The given callback shouldn't
   // be called until after the head is received.
   base::test::TestFuture<PrefetchContainer::Reader> future;
-  GetPrefetchToServe(future, GURL("https://example.com"),
-                     main_rfh()->GetGlobalId());
+  GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   task_environment()->FastForwardBy(base::Milliseconds(300));
@@ -6134,8 +6129,7 @@
   // Request the prefetch from the PrefetchService. The given callback should be
   // triggered once the timeout is exceeded.
   base::test::TestFuture<PrefetchContainer::Reader> future;
-  GetPrefetchToServe(future, GURL("https://example.com"),
-                     main_rfh()->GetGlobalId());
+  GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   task_environment()->FastForwardBy(base::Milliseconds(1000));
@@ -6226,8 +6220,7 @@
   // Request the prefetch from the PrefetchService. The given callback should be
   // triggered once the timeout is exceeded.
   base::test::TestFuture<PrefetchContainer::Reader> future;
-  GetPrefetchToServe(future, GURL("https://example.com"),
-                     main_rfh()->GetGlobalId());
+  GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken());
   EXPECT_FALSE(future.IsReady());
 
   task_environment()->FastForwardBy(base::Milliseconds(1000));
@@ -6322,7 +6315,7 @@
     prefetch_match_resolver->SetOnPrefetchToServeReadyCallback(base::BindOnce(
         [](PrefetchContainer::Reader prefetch_to_serve) { NOTREACHED(); }));
     prefetch_service_->GetPrefetchToServe(
-        PrefetchContainer::Key(main_rfh()->GetGlobalId(),
+        PrefetchContainer::Key(MainDocumentToken(),
                                GURL("https://example.com")),
         *prefetch_match_resolver);
   }
@@ -6332,7 +6325,7 @@
     // callback should be triggered once the timeout is exceeded.
     base::test::TestFuture<PrefetchContainer::Reader> future;
     GetPrefetchToServe(future, GURL("https://example.com"),
-                       main_rfh()->GetGlobalId());
+                       MainDocumentToken());
     EXPECT_FALSE(future.IsReady());
     task_environment()->FastForwardBy(base::Milliseconds(1000));
     PrefetchContainer::Reader serveable_reader = future.Take();
@@ -7188,7 +7181,7 @@
             get_prefetch_run_loop.Quit();
           }));
   prefetch_service_->GetPrefetchToServe(
-      PrefetchContainer::Key(main_rfh()->GetGlobalId(), GURL(kTestUrl)),
+      PrefetchContainer::Key(MainDocumentToken(), GURL(kTestUrl)),
       *prefetch_match_resolver);
   EXPECT_FALSE(is_nav_unblocked);
 
@@ -7422,7 +7415,7 @@
             get_prefetch_run_loop.Quit();
           }));
   prefetch_service_->GetPrefetchToServe(
-      PrefetchContainer::Key(main_rfh()->GetGlobalId(), GURL(kTestUrl)),
+      PrefetchContainer::Key(MainDocumentToken(), GURL(kTestUrl)),
       *prefetch_match_resolver);
   EXPECT_FALSE(is_fallback_navigation);
   task_environment()->RunUntilIdle();
@@ -7553,7 +7546,7 @@
             get_prefetch_run_loop.Quit();
           }));
   prefetch_service_->GetPrefetchToServe(
-      PrefetchContainer::Key(main_rfh()->GetGlobalId(), GURL(kTestUrl)),
+      PrefetchContainer::Key(MainDocumentToken(), GURL(kTestUrl)),
       *prefetch_match_resolver);
   EXPECT_FALSE(is_nav_unblocked);
   task_environment()->RunUntilIdle();
diff --git a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc
index 00b4498..ec9a9b6 100644
--- a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc
+++ b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc
@@ -44,23 +44,21 @@
 std::unique_ptr<PrefetchURLLoaderInterceptor>
 PrefetchURLLoaderInterceptor::MaybeCreateInterceptor(
     int frame_tree_node_id,
-    const GlobalRenderFrameHostId& referring_render_frame_host_id) {
-  if (!referring_render_frame_host_id) {
+    absl::optional<blink::DocumentToken> initiator_document_token) {
+  if (!initiator_document_token) {
     // This is expected to occur only in unit tests.
     return nullptr;
   }
 
   return std::make_unique<PrefetchURLLoaderInterceptor>(
-      frame_tree_node_id, referring_render_frame_host_id);
+      frame_tree_node_id, *initiator_document_token);
 }
 
 PrefetchURLLoaderInterceptor::PrefetchURLLoaderInterceptor(
     int frame_tree_node_id,
-    const GlobalRenderFrameHostId& referring_render_frame_host_id)
+    const blink::DocumentToken& initiator_document_token)
     : frame_tree_node_id_(frame_tree_node_id),
-      referring_render_frame_host_id_(referring_render_frame_host_id) {
-  CHECK(referring_render_frame_host_id_);
-}
+      initiator_document_token_(initiator_document_token) {}
 
 PrefetchURLLoaderInterceptor::~PrefetchURLLoaderInterceptor() = default;
 
@@ -127,7 +125,7 @@
       std::move(get_prefetch_callback)));
 
   prefetch_service->GetPrefetchToServe(
-      PrefetchContainer::Key(referring_render_frame_host_id_,
+      PrefetchContainer::Key(initiator_document_token_,
                              tentative_resource_request.url),
       prefetch_match_resolver);
 }
diff --git a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.h b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.h
index 753c6bd..29bf53af 100644
--- a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.h
+++ b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.h
@@ -27,11 +27,11 @@
  public:
   static std::unique_ptr<PrefetchURLLoaderInterceptor> MaybeCreateInterceptor(
       int frame_tree_node_id,
-      const GlobalRenderFrameHostId& referring_render_frame_host_id);
+      absl::optional<blink::DocumentToken> initiator_document_token);
 
   PrefetchURLLoaderInterceptor(
       int frame_tree_node_id,
-      const GlobalRenderFrameHostId& referring_render_frame_host_id);
+      const blink::DocumentToken& initiator_document_token);
   ~PrefetchURLLoaderInterceptor() override;
 
   PrefetchURLLoaderInterceptor(const PrefetchURLLoaderInterceptor&) = delete;
@@ -74,10 +74,9 @@
 
   // Corresponds to the ID of "navigable's active document" used for "finding a
   // matching prefetch record" in the spec. This is used as a part of
-  // `PrefetchContainer::Key` to make prefetches per-RenderFrameHost.
+  // `PrefetchContainer::Key` to make prefetches per-Document.
   // https://wicg.github.io/nav-speculation/prefetch.html
-  // TODO(https://crbug.com/1431804): This is not strictly per-Document.
-  const GlobalRenderFrameHostId referring_render_frame_host_id_;
+  const blink::DocumentToken initiator_document_token_;
 
   // Called once |this| has decided whether to intercept or not intercept the
   // navigation.
diff --git a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
index 6eff0e3..2800b0c 100644
--- a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
@@ -200,9 +200,9 @@
  public:
   TestPrefetchURLLoaderInterceptor(
       int frame_tree_node_id,
-      const GlobalRenderFrameHostId& previous_render_frame_host_id)
+      const blink::DocumentToken& initiator_document_token)
       : PrefetchURLLoaderInterceptor(frame_tree_node_id,
-                                     previous_render_frame_host_id) {}
+                                     initiator_document_token) {}
   ~TestPrefetchURLLoaderInterceptor() override = default;
 
   void AddPrefetch(base::WeakPtr<PrefetchContainer> prefetch_container) {
@@ -259,7 +259,7 @@
 
     interceptor_ = std::make_unique<TestPrefetchURLLoaderInterceptor>(
         web_contents()->GetPrimaryMainFrame()->GetFrameTreeNodeId(),
-        main_rfh()->GetGlobalId());
+        MainDocumentToken());
 
     test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
     attempt_entry_builder_ =
@@ -410,6 +410,10 @@
     // `PreloadingDecider`.
   }
 
+  blink::DocumentToken MainDocumentToken() {
+    return static_cast<RenderFrameHostImpl*>(main_rfh())->GetDocumentToken();
+  }
+
  private:
   std::unique_ptr<TestPrefetchURLLoaderInterceptor> interceptor_;
 
@@ -453,7 +457,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -530,7 +534,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -616,7 +620,7 @@
   referrer.url = GURL("https://example.com/referrer");
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/false,
                        blink::mojom::SpeculationEagerness::kEager),
           referrer,
@@ -712,7 +716,7 @@
   // Without a prefetched response, the navigation shouldn't be intercepted.
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -764,7 +768,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -821,7 +825,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -895,7 +899,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -950,7 +954,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -1017,7 +1021,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -1153,7 +1157,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
@@ -1268,7 +1272,7 @@
 
   std::unique_ptr<PrefetchContainer> prefetch_container =
       std::make_unique<PrefetchContainer>(
-          main_rfh()->GetGlobalId(), kTestUrl,
+          main_rfh()->GetGlobalId(), MainDocumentToken(), kTestUrl,
           PrefetchType(/*use_prefetch_proxy=*/true,
                        blink::mojom::SpeculationEagerness::kEager),
           referrer,
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 694c9f79..8853c37 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1692,7 +1692,7 @@
     RenderFrameHostImpl* initiator_rfh = RenderFrameHostImpl::FromFrameToken(
         GetInitiatorProcessId(), GetInitiatorFrameToken().value());
     if (initiator_rfh)
-      initiator_document_ = initiator_rfh->GetWeakDocumentPtr();
+      initiator_document_token_ = initiator_rfh->GetDocumentToken();
   }
 
   // Spec: https://github.com/whatwg/html/issues/8846
@@ -5018,9 +5018,10 @@
           frame_tree_node_->current_frame_host()->devtools_frame_token(),
           std::move(cors_exempt_headers),
           BuildClientSecurityStateForNavigationFetch(),
-          devtools_accepted_stream_types, is_pdf_, initiator_document_,
-          GetPreviousRenderFrameHostId(), allow_cookies_from_browser_,
-          navigation_id_, shared_storage_writable_),
+          devtools_accepted_stream_types, is_pdf_, GetInitiatorProcessId(),
+          initiator_document_token_, GetPreviousRenderFrameHostId(),
+          allow_cookies_from_browser_, navigation_id_,
+          shared_storage_writable_),
       std::move(navigation_ui_data), service_worker_handle_.get(),
       std::move(prefetched_signed_exchange_cache_), this, loader_type,
       CreateCookieAccessObserver(), CreateTrustTokenAccessObserver(),
@@ -7618,8 +7619,7 @@
       "Bug1454273", "embedder_origin",
       embedder ? embedder->GetLastCommittedOrigin().GetDebugString() : "");
 
-  RenderFrameHost* initiator_rfh =
-      initiator_document_.AsRenderFrameHostIfValid();
+  RenderFrameHost* initiator_rfh = GetInitiatorDocumentRenderFrameHost();
   SCOPED_CRASH_KEY_STRING256(
       "Bug1454273", "initiator_origin",
       initiator_rfh ? initiator_rfh->GetLastCommittedOrigin().GetDebugString()
@@ -8938,8 +8938,10 @@
 }
 
 RenderFrameHostImpl* NavigationRequest::GetInitiatorDocumentRenderFrameHost() {
-  return static_cast<RenderFrameHostImpl*>(
-      initiator_document_.AsRenderFrameHostIfValid());
+  return initiator_document_token_
+             ? RenderFrameHostImpl::FromDocumentToken(
+                   initiator_process_id_, *initiator_document_token_)
+             : nullptr;
 }
 
 void NavigationRequest::RecordAddressSpaceFeature() {
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 4ceaea1..d42023e 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -2528,9 +2528,9 @@
   // NavigationRequest.
   std::vector<ConsoleMessage> console_messages_;
 
-  // The initiator RenderFrameHost, if the same document is present as when this
+  // The initiator Document's token, if it is present when this
   // NavigationRequest was created.
-  WeakDocumentPtr initiator_document_;
+  absl::optional<blink::DocumentToken> initiator_document_token_;
 
   // Indicates that this navigation is for PDF content in a renderer.
   bool is_pdf_ = false;
diff --git a/content/browser/renderer_host/navigation_request_info.cc b/content/browser/renderer_host/navigation_request_info.cc
index 4d7d6775..9b13f24 100644
--- a/content/browser/renderer_host/navigation_request_info.cc
+++ b/content/browser/renderer_host/navigation_request_info.cc
@@ -30,7 +30,8 @@
     const absl::optional<std::vector<net::SourceStream::SourceType>>&
         devtools_accepted_stream_types,
     bool is_pdf,
-    WeakDocumentPtr initiator_document,
+    int initiator_process_id,
+    absl::optional<blink::DocumentToken> initiator_document_token,
     const GlobalRenderFrameHostId& previous_render_frame_host_id,
     bool allow_cookies_from_browser,
     int64_t navigation_id,
@@ -53,7 +54,8 @@
       client_security_state(std::move(client_security_state)),
       devtools_accepted_stream_types(devtools_accepted_stream_types),
       is_pdf(is_pdf),
-      initiator_document(std::move(initiator_document)),
+      initiator_process_id(initiator_process_id),
+      initiator_document_token(std::move(initiator_document_token)),
       previous_render_frame_host_id(previous_render_frame_host_id),
       allow_cookies_from_browser(allow_cookies_from_browser),
       navigation_id(navigation_id),
diff --git a/content/browser/renderer_host/navigation_request_info.h b/content/browser/renderer_host/navigation_request_info.h
index b39052e..fe42c18 100644
--- a/content/browser/renderer_host/navigation_request_info.h
+++ b/content/browser/renderer_host/navigation_request_info.h
@@ -16,6 +16,7 @@
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/client_security_state.mojom-forward.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/mojom/navigation/navigation_params.mojom-forward.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -47,7 +48,8 @@
       const absl::optional<std::vector<net::SourceStream::SourceType>>&
           devtools_accepted_stream_types,
       bool is_pdf,
-      WeakDocumentPtr initiator_document,
+      int initiator_process_id,
+      absl::optional<blink::DocumentToken> initiator_document_token,
       const GlobalRenderFrameHostId& previous_render_frame_host_id,
       bool allow_cookies_from_browser,
       int64_t navigation_id,
@@ -132,8 +134,9 @@
   // Indicates that this navigation is for PDF content in a renderer.
   const bool is_pdf;
 
-  // The initiator document, if still available.
-  const WeakDocumentPtr initiator_document;
+  // The initiator document's token and its process ID.
+  const int initiator_process_id;
+  const absl::optional<blink::DocumentToken> initiator_document_token;
 
   // The previous document's RenderFrameHostId, used for speculation rules
   // prefetch.
diff --git a/content/browser/system_dns_resolution/system_dns_resolver_browsertest.cc b/content/browser/system_dns_resolution/system_dns_resolver_browsertest.cc
index c9ee7a4..0716cac 100644
--- a/content/browser/system_dns_resolution/system_dns_resolver_browsertest.cc
+++ b/content/browser/system_dns_resolution/system_dns_resolver_browsertest.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/network_service_util.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/shell/browser/shell.h"
@@ -55,10 +56,7 @@
 
 class SystemDnsResolverBrowserTest : public content::ContentBrowserTest {
  public:
-  SystemDnsResolverBrowserTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        network::features::kOutOfProcessSystemDnsResolution);
-  }
+  SystemDnsResolverBrowserTest() = default;
 
   void SetUpOnMainThread() override {
     ContentBrowserTest::SetUpOnMainThread();
@@ -115,11 +113,13 @@
 
   const auto& addr_list1 = future.Get<absl::optional<net::AddressList>>();
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
-  // If system DNS resolution runs in the browser process, check here that the
-  // resolver received the correct number of resolves.
-  EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kHostname1), 1u);
-#endif
+  if (GetContentClientForTesting()
+          ->browser()
+          ->ShouldRunOutOfProcessSystemDnsResolution()) {
+    // If system DNS resolution runs in the browser process, check here that the
+    // resolver received the correct number of resolves.
+    EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kHostname1), 1u);
+  }
 
   ASSERT_TRUE(addr_list1);
   net::IPAddress address1;
@@ -138,12 +138,14 @@
   const auto& addr_list1 = future1.Get<absl::optional<net::AddressList>>();
   const auto& addr_list2 = future2.Get<absl::optional<net::AddressList>>();
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
-  // If system DNS resolution runs in the browser process, check here that the
-  // resolver received the correct number of resolves.
-  EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kHostname1), 1u);
-  EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kHostname2), 1u);
-#endif
+  if (GetContentClientForTesting()
+          ->browser()
+          ->ShouldRunOutOfProcessSystemDnsResolution()) {
+    // If system DNS resolution runs in the browser process, check here that the
+    // resolver received the correct number of resolves.
+    EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kHostname1), 1u);
+    EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kHostname2), 1u);
+  }
 
   ASSERT_TRUE(addr_list1);
   net::IPAddress address1;
@@ -166,11 +168,13 @@
   auto [result, resolve_error_info, resolved_addresses, endpoints] =
       future.Take();
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
-  // If system DNS resolution runs in the browser process, check here that
-  // the resolver received the correct number of resolves.
-  EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kFailHostname), 1u);
-#endif
+  if (GetContentClientForTesting()
+          ->browser()
+          ->ShouldRunOutOfProcessSystemDnsResolution()) {
+    // If system DNS resolution runs in the browser process, check here that
+    // the resolver received the correct number of resolves.
+    EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(kFailHostname), 1u);
+  }
 
   EXPECT_EQ(resolve_error_info.error, net::ERR_NAME_NOT_RESOLVED);
   EXPECT_EQ(result, net::ERR_NAME_NOT_RESOLVED);
@@ -198,11 +202,14 @@
 
   auto [addr_list, os_error_result, net_error_result] = future.Take();
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
-  // If system DNS resolution runs in the browser process, check here that the
-  // resolver received the correct number of resolves.
-  EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(net::GetHostName()), 1u);
-#endif
+  if (GetContentClientForTesting()
+          ->browser()
+          ->ShouldRunOutOfProcessSystemDnsResolution()) {
+    // If system DNS resolution runs in the browser process, check here that the
+    // resolver received the correct number of resolves.
+    EXPECT_EQ(host_resolver()->NumResolvesForHostPattern(net::GetHostName()),
+              1u);
+  }
 
   ASSERT_EQ(addr_list.size(), 1u);
   net::IPAddress address;
@@ -213,10 +220,6 @@
 class SystemDnsResolverPerfTest : public content::ContentBrowserTest {
  public:
   SystemDnsResolverPerfTest() {
-    // If disabling kOutOfProcessSystemDnsResolution, also disable
-    // sandbox::policy::features::kNetworkServiceSandbox.
-    scoped_feature_list_.InitWithFeatures(
-        {network::features::kOutOfProcessSystemDnsResolution}, {});
     SetAllowNetworkAccessToHostResolutions();
   }
 
diff --git a/content/browser/webauth/authenticator_common_impl.cc b/content/browser/webauth/authenticator_common_impl.cc
index 21672ce..f3c57255 100644
--- a/content/browser/webauth/authenticator_common_impl.cc
+++ b/content/browser/webauth/authenticator_common_impl.cc
@@ -402,7 +402,24 @@
   return digest;
 }
 
-absl::optional<std::vector<device::PRFInput>> ParsePRFInputs(
+absl::optional<device::PRFInput> ParsePRFInputForMakeCredential(
+    const blink::mojom::PRFValuesPtr& prf_input_from_renderer) {
+  // The input cannot be credential-specific because we haven't created the
+  // credential yet.
+  if (prf_input_from_renderer->id) {
+    return absl::nullopt;
+  }
+
+  device::PRFInput prf_input;
+  prf_input.salt1 = HashPRFValue(prf_input_from_renderer->first);
+  if (prf_input_from_renderer->second) {
+    prf_input.salt2 = HashPRFValue(*prf_input_from_renderer->second);
+  }
+
+  return prf_input;
+}
+
+absl::optional<std::vector<device::PRFInput>> ParsePRFInputsForGetAssertion(
     base::span<const blink::mojom::PRFValuesPtr> inputs) {
   std::vector<device::PRFInput> ret;
   bool is_first = true;
@@ -442,6 +459,20 @@
   return ret;
 }
 
+blink::mojom::PRFValuesPtr PRFResultsToValues(
+    base::span<const uint8_t> results) {
+  auto prf_values = blink::mojom::PRFValues::New();
+  DCHECK(results.size() == 32 || results.size() == 64);
+  prf_values->first =
+      device::fido_parsing_utils::Materialize(results.subspan(0, 32));
+  if (results.size() == 64) {
+    prf_values->second =
+        device::fido_parsing_utils::Materialize(results.subspan(32, 32));
+  }
+
+  return prf_values;
+}
+
 }  // namespace
 
 // RequestState contains all state that is specific to a single WebAuthn call.
@@ -896,6 +927,20 @@
   if (options->prf_enable) {
     req_state_->requested_extensions.insert(RequestExtension::kPRF);
     req_state_->ctap_make_credential_request->hmac_secret = true;
+
+    if (options->prf_input &&
+        base::FeatureList::IsEnabled(device::kWebAuthnPRFEvalDuringCreate)) {
+      absl::optional<device::PRFInput> prf_input =
+          ParsePRFInputForMakeCredential(options->prf_input);
+      if (!prf_input) {
+        mojo::ReportBadMessage("invalid PRF inputs");
+        CompleteMakeCredentialRequest(
+            blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
+        return;
+      }
+      req_state_->ctap_make_credential_request->prf_input =
+          std::move(*prf_input);
+    }
   }
   if (options->hmac_create_secret) {
     req_state_->requested_extensions.insert(RequestExtension::kHMACSecret);
@@ -1224,7 +1269,7 @@
     req_state_->requested_extensions.insert(RequestExtension::kPRF);
 
     absl::optional<std::vector<device::PRFInput>> prf_inputs =
-        ParsePRFInputs(options->extensions->prf_inputs);
+        ParsePRFInputsForGetAssertion(options->extensions->prf_inputs);
 
     // This should never happen for inputs from the renderer, which should sort
     // the values itself. Additionally, `prf_inputs_hashed` is for hybrid
@@ -1966,6 +2011,10 @@
       case RequestExtension::kPRF:
         response->echo_prf = true;
         response->prf = did_create_hmac_secret;
+        if (response_data.prf_results) {
+          response->prf_results =
+              PRFResultsToValues(*response_data.prf_results);
+        }
         break;
       case RequestExtension::kHMACSecret:
         response->echo_hmac_create_secret = true;
@@ -2092,18 +2141,9 @@
         break;
       case RequestExtension::kPRF: {
         response_extensions->echo_prf = true;
-        absl::optional<base::span<const uint8_t>> hmac_secret =
-            response_data.hmac_secret;
-        if (hmac_secret) {
-          auto prf_values = blink::mojom::PRFValues::New();
-          DCHECK(hmac_secret->size() == 32 || hmac_secret->size() == 64);
-          prf_values->first = device::fido_parsing_utils::Materialize(
-              hmac_secret->subspan(0, 32));
-          if (hmac_secret->size() == 64) {
-            prf_values->second = device::fido_parsing_utils::Materialize(
-                hmac_secret->subspan(32, 32));
-          }
-          response_extensions->prf_results = std::move(prf_values);
+        if (response_data.hmac_secret) {
+          response_extensions->prf_results =
+              PRFResultsToValues(*response_data.hmac_secret);
         } else {
           response_extensions->prf_not_evaluated =
               response_data.hmac_secret_not_evaluated;
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 97a22da..93aacad 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -8603,6 +8603,49 @@
   }
 }
 
+TEST_F(ResidentKeyAuthenticatorImplTest, PRFEvaluationDuringMakeCredential) {
+  // The WebAuthn "prf" extension supports evaluating the PRF when making a
+  // credential. The hmac-secret extension does not support this, but hybrid
+  // devices (and our virtual authenticator) can support it using the
+  // CTAP2-level "prf" extension.
+  NavigateAndCommit(GURL(kTestOrigin1));
+
+  device::VirtualCtap2Device::Config config;
+  config.prf_support = true;
+  config.internal_account_chooser = true;
+  config.always_uv = true;
+  config.pin_support = true;
+  config.resident_key_support = true;
+  virtual_device_factory_->SetCtap2Config(config);
+
+  PublicKeyCredentialCreationOptionsPtr options =
+      GetTestPublicKeyCredentialCreationOptions();
+  options->prf_enable = true;
+  options->authenticator_selection->resident_key =
+      device::ResidentKeyRequirement::kRequired;
+  options->user.id = {1, 2, 3, 4};
+  options->user.name = "name";
+  options->user.display_name = "displayName";
+  options->prf_input = blink::mojom::PRFValues::New();
+  const std::vector<uint8_t> salt1(32, 1);
+  const std::vector<uint8_t> salt2(32, 2);
+  options->prf_input->first = salt1;
+  options->prf_input->second = salt2;
+
+  MakeCredentialResult result = AuthenticatorMakeCredential(std::move(options));
+  EXPECT_EQ(result.status, AuthenticatorStatus::SUCCESS);
+
+  EXPECT_TRUE(result.response->echo_prf);
+  EXPECT_TRUE(result.response->prf);
+  ASSERT_TRUE(result.response->prf_results);
+  EXPECT_EQ(result.response->prf_results->first.size(), 32u);
+  EXPECT_EQ(result.response->prf_results->second->size(), 32u);
+}
+
+TEST_F(ResidentKeyAuthenticatorImplTest, MakeCredentialPRFExtension) {
+  NavigateAndCommit(GURL(kTestOrigin1));
+}
+
 TEST_F(ResidentKeyAuthenticatorImplTest,
        PRFExtensionOnUnconfiguredAuthenticator) {
   // If a credential is on a UV-capable, but not UV-configured authenticator and
diff --git a/content/browser/webauth/virtual_authenticator.cc b/content/browser/webauth/virtual_authenticator.cc
index aab822d..d250b14 100644
--- a/content/browser/webauth/virtual_authenticator.cc
+++ b/content/browser/webauth/virtual_authenticator.cc
@@ -128,7 +128,11 @@
       config.large_blob_support = has_large_blob_;
       config.cred_protect_support = config.cred_blob_support = has_cred_blob_;
       config.min_pin_length_extension_support = has_min_pin_length_;
-      config.hmac_secret_support = has_prf_;
+      if (has_prf_) {
+        config.prf_support = true;
+        // This is required when `prf_support` is set.
+        config.internal_account_chooser = true;
+      }
 
       if (
           // Writing a large blob requires obtaining a PinUvAuthToken with
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/AssistViewStructureTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/AssistViewStructureTest.java
index 37cb869..2f9cec2 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/AssistViewStructureTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/AssistViewStructureTest.java
@@ -30,11 +30,9 @@
 import java.util.ArrayList;
 import java.util.concurrent.TimeoutException;
 
-/**
- * Tests for the implementation of onProvideVirtualStructure in
- * WebContentsAccessibility.
- */
+/** Tests for the implementation of onProvideVirtualStructure in WebContentsAccessibility. */
 @RunWith(BaseJUnit4ClassRunner.class)
+// TODO(mschillaci): Migrate all these tests to the WebContentsAccessibilityTreeTest suite.
 public class AssistViewStructureTest {
     @Rule
     public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
@@ -91,11 +89,12 @@
     @MediumTest
     public void testSimpleParagraph() throws Throwable {
         TestViewStructure testViewStructure = getViewStructureFromHtml("<p>Hello World</p>");
-        Assert.assertEquals(testViewStructure.toString(),
-                "\n"
-                        + "  android.webkit.WebView\n"
-                        + "    android.view.View\n"
-                        + "      android.widget.TextView text='Hello World'\n");
+        Assert.assertEquals(
+                "WebView textSize:16.00 style:0 bundle:[display=\"\", htmlTag=\"#document\"]\n"
+                    + "++View textSize:16.00 style:0 bundle:[display=\"block\", htmlTag=\"p\"]\n"
+                    + "++++TextView text:\"Hello World\" textSize:16.00 style:0"
+                    + " bundle:[display=\"\", htmlTag=\"\"]",
+                testViewStructure.toString());
     }
 
     /**
@@ -109,19 +108,29 @@
                 + "  <li>Picard</li>"
                 + "  <li>Janeway</li>"
                 + "</ol>");
-        Assert.assertEquals(testViewStructure.toString(),
-                "\n"
-                        + "  android.webkit.WebView\n"
-                        + "    android.widget.ListView\n"
-                        + "      android.view.View\n"
-                        + "        android.view.View text='1. '\n"
-                        + "        android.widget.TextView text='Kirk'\n"
-                        + "      android.view.View\n"
-                        + "        android.view.View text='2. '\n"
-                        + "        android.widget.TextView text='Picard'\n"
-                        + "      android.view.View\n"
-                        + "        android.view.View text='3. '\n"
-                        + "        android.widget.TextView text='Janeway'\n");
+        Assert.assertEquals(
+                "WebView textSize:16.00 style:0 bundle:[display=\"\", htmlTag=\"#document\"]\n"
+                    + "++ListView textSize:16.00 style:0 bundle:[display=\"block\","
+                    + " htmlTag=\"ol\"]\n"
+                    + "++++View textSize:16.00 style:0 bundle:[display=\"list-item\","
+                    + " htmlTag=\"li\"]\n"
+                    + "++++++View text:\"1. \" textSize:16.00 style:0"
+                    + " bundle:[display=\"inline-block\", htmlTag=\"::marker\"]\n"
+                    + "++++++TextView text:\"Kirk\" textSize:16.00 style:0 bundle:[display=\"\","
+                    + " htmlTag=\"\"]\n"
+                    + "++++View textSize:16.00 style:0 bundle:[display=\"list-item\","
+                    + " htmlTag=\"li\"]\n"
+                    + "++++++View text:\"2. \" textSize:16.00 style:0"
+                    + " bundle:[display=\"inline-block\", htmlTag=\"::marker\"]\n"
+                    + "++++++TextView text:\"Picard\" textSize:16.00 style:0 bundle:[display=\"\","
+                    + " htmlTag=\"\"]\n"
+                    + "++++View textSize:16.00 style:0 bundle:[display=\"list-item\","
+                    + " htmlTag=\"li\"]\n"
+                    + "++++++View text:\"3. \" textSize:16.00 style:0"
+                    + " bundle:[display=\"inline-block\", htmlTag=\"::marker\"]\n"
+                    + "++++++TextView text:\"Janeway\" textSize:16.00 style:0 bundle:[display=\"\","
+                    + " htmlTag=\"\"]",
+                testViewStructure.toString());
     }
 
     /**
@@ -161,18 +170,28 @@
                 + "<a href='#' aria-label='AriaLabel'>Link</a>"
                 + "<button>Button</button>"
                 + "<button aria-label='AriaLabel'>Button</button>");
-        Assert.assertEquals(testViewStructure.toString(),
-                "\n"
-                        + "  android.webkit.WebView\n"
-                        + "    android.view.View\n"
-                        + "      android.view.View\n"
-                        + "        android.widget.TextView text='Link'\n"
-                        + "      android.view.View text='AriaLabel'\n"
-                        + "        android.widget.TextView text='Link'\n"
-                        + "      android.widget.Button\n"
-                        + "        android.widget.TextView text='Button'\n"
-                        + "      android.widget.Button text='AriaLabel'\n"
-                        + "        android.widget.TextView text='Button'\n");
+        Assert.assertEquals(
+                "WebView textSize:16.00 style:0 bundle:[display=\"\", htmlTag=\"#document\"]\n"
+                    + "++View textSize:16.00 style:0 bundle:[display=\"block\", htmlTag=\"body\"]\n"
+                    + "++++View textSize:16.00 style:4 fgColor:-16776978"
+                    + " bundle:[display=\"inline\", href=\"#\", htmlTag=\"a\"]\n"
+                    + "++++++TextView text:\"Link\" textSize:16.00 style:4 fgColor:-16776978"
+                    + " bundle:[display=\"\", htmlTag=\"\"]\n"
+                    + "++++View text:\"AriaLabel\" textSize:16.00 style:4 fgColor:-16776978"
+                    + " bundle:[aria-label=\"AriaLabel\", display=\"inline\", href=\"#\","
+                    + " htmlTag=\"a\"]\n"
+                    + "++++++TextView text:\"Link\" textSize:16.00 style:4 fgColor:-16776978"
+                    + " bundle:[display=\"\", htmlTag=\"\"]\n"
+                    + "++++Button textSize:13.33 style:0 bgColor:-1052689"
+                    + " bundle:[display=\"inline-block\", htmlTag=\"button\"]\n"
+                    + "++++++TextView text:\"Button\" textSize:13.33 style:0 bgColor:-1052689"
+                    + " bundle:[display=\"\", htmlTag=\"\"]\n"
+                    + "++++Button text:\"AriaLabel\" textSize:13.33 style:0 bgColor:-1052689"
+                    + " bundle:[aria-label=\"AriaLabel\", display=\"inline-block\","
+                    + " htmlTag=\"button\"]\n"
+                    + "++++++TextView text:\"Button\" textSize:13.33 style:0 bgColor:-1052689"
+                    + " bundle:[display=\"\", htmlTag=\"\"]",
+                testViewStructure.toString());
     }
 
     /**
@@ -184,17 +203,20 @@
         TestViewStructure testViewStructure = getViewStructureFromHtml("<h1>Heading</h1>"
                 + "  <p>Paragraph</p>"
                 + "  <div><input></div>");
-        testViewStructure.dumpHtmlTags();
-        Assert.assertEquals(testViewStructure.toString(),
-                "\n"
-                        + "  android.webkit.WebView htmlTag='#document'\n"
-                        + "    android.view.View htmlTag='h1'\n"
-                        + "      android.widget.TextView text='Heading'\n"
-                        + "    android.view.View htmlTag='p'\n"
-                        + "      android.widget.TextView text='Paragraph'\n"
-                        + "    android.view.View htmlTag='div'\n"
-                        + "      android.widget.EditText htmlTag='input'\n"
-                        + "        android.view.View htmlTag='div'\n");
+        Assert.assertEquals(
+                "WebView textSize:16.00 style:0 bundle:[display=\"\", htmlTag=\"#document\"]\n"
+                    + "++View textSize:32.00 style:1 bundle:[display=\"block\", htmlTag=\"h1\"]\n"
+                    + "++++TextView text:\"Heading\" textSize:32.00 style:1 bundle:[display=\"\","
+                    + " htmlTag=\"\"]\n"
+                    + "++View textSize:16.00 style:0 bundle:[display=\"block\", htmlTag=\"p\"]\n"
+                    + "++++TextView text:\"Paragraph\" textSize:16.00 style:0 bundle:[display=\"\","
+                    + " htmlTag=\"\"]\n"
+                    + "++View textSize:16.00 style:0 bundle:[display=\"block\", htmlTag=\"div\"]\n"
+                    + "++++EditText textSize:13.33 style:0 bundle:[display=\"inline-block\","
+                    + " htmlTag=\"input\"]\n"
+                    + "++++++View textSize:13.33 style:0 bundle:[display=\"flow-root\","
+                    + " htmlTag=\"div\"]",
+                testViewStructure.toString());
     }
 
     /**
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java
index 0faaba5..3028f21 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java
@@ -4,15 +4,25 @@
 
 package org.chromium.content.browser.accessibility;
 
+import static org.chromium.content.browser.accessibility.AccessibilityNodeInfoBuilder.EXTRAS_KEY_UNCLIPPED_HEIGHT;
+import static org.chromium.content.browser.accessibility.AccessibilityNodeInfoBuilder.EXTRAS_KEY_UNCLIPPED_LEFT;
+import static org.chromium.content.browser.accessibility.AccessibilityNodeInfoBuilder.EXTRAS_KEY_UNCLIPPED_TOP;
+import static org.chromium.content.browser.accessibility.AccessibilityNodeInfoBuilder.EXTRAS_KEY_UNCLIPPED_WIDTH;
+
+import static java.lang.String.CASE_INSENSITIVE_ORDER;
+
 import android.graphics.Matrix;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.text.TextUtils;
+import android.util.Pair;
 import android.view.ViewStructure;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Implementation of ViewStructure that allows us to print it out as a
@@ -22,10 +32,10 @@
     private CharSequence mText;
     private String mClassName;
     private Bundle mBundle;
+    private HtmlInfo mHtmlInfo;
     private int mChildCount;
     private ArrayList<TestViewStructure> mChildren = new ArrayList<TestViewStructure>();
     private boolean mDone = true;
-    private boolean mDumpHtmlTags;
     private float mTextSize;
     private int mFgColor;
     private int mBgColor;
@@ -48,8 +58,8 @@
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
-        recursiveDumpToString(builder, 0, mDumpHtmlTags);
-        return builder.toString();
+        recursiveDumpToString(builder, 0);
+        return builder.toString().trim();
     }
 
     public String getClassName() {
@@ -72,34 +82,95 @@
         return mStyle;
     }
 
-    private void recursiveDumpToString(StringBuilder builder, int indent, boolean dumpHtmlTags) {
-        for (int i = 0; i < indent; i++) {
-            builder.append("  ");
-        }
+    private static String bundleToString(Bundle extras) {
+        // Sort keys to ensure consistent output of tests.
+        List<String> sortedKeySet = new ArrayList<String>(extras.keySet());
+        Collections.sort(sortedKeySet, CASE_INSENSITIVE_ORDER);
 
-        if (!TextUtils.isEmpty(mClassName)) {
-            builder.append(mClassName);
-        }
-
-        if (!TextUtils.isEmpty(mText)) {
-            builder.append(" text='");
-            builder.append(mText);
-            builder.append("'");
-        }
-
-        if (mBundle != null) {
-            String htmlTag = mBundle.getCharSequence("htmlTag").toString();
-            if (dumpHtmlTags && !TextUtils.isEmpty(htmlTag)) {
-                builder.append(" htmlTag='");
-                builder.append(htmlTag);
-                builder.append("'");
+        List<String> bundleStrings = new ArrayList<>();
+        StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        for (String key : sortedKeySet) {
+            // Bundle extras related to bounding boxes should be ignored so the tests can safely
+            // run on varying devices and not be screen-dependent.
+            if (key.equals(EXTRAS_KEY_UNCLIPPED_LEFT)
+                    || key.equals(EXTRAS_KEY_UNCLIPPED_TOP)
+                    || key.equals(EXTRAS_KEY_UNCLIPPED_WIDTH)
+                    || key.equals(EXTRAS_KEY_UNCLIPPED_HEIGHT)
+                    || key.equals("url")) {
+                continue;
             }
+
+            // Simplify the key String before printing to make test outputs easier to read.
+            bundleStrings.add(
+                    key.replace("AccessibilityNodeInfo.", "")
+                            + "=\""
+                            + extras.get(key).toString()
+                            + "\"");
+        }
+        builder.append(TextUtils.join(", ", bundleStrings)).append("]");
+
+        return builder.toString();
+    }
+
+    private void recursiveDumpToString(StringBuilder builder, int indent) {
+        // We do not want to print the root node, start at the WebView.
+        if (mClassName == null) {
+            assert indent == 0;
+            assert mChildCount == 1;
+            mChildren.get(0).recursiveDumpToString(builder, indent);
+            return;
+        }
+
+        for (int i = 0; i < indent; i++) {
+            builder.append("++");
+        }
+
+        // Print classname first, but only print content after the last period to remove redundancy.
+        assert mClassName != null : "Classname should never be null";
+        assert !mClassName.contains("\\.") : "Classname should contain periods";
+        String[] classNameParts = mClassName.split("\\.");
+        builder.append(classNameParts[classNameParts.length - 1]);
+
+        // Print text unless it is empty (null is allowed).
+        if (mText == null) {
+            builder.append(" text:\"null\"");
+        } else if (!mText.toString().isEmpty()) {
+            builder.append(" text:\"").append(mText.toString().replace("\n", "\\n")).append("\"");
+        }
+
+        // Print text selection values if present.
+        if (mSelectionStart != 0 || getTextSelectionEnd() != 0) {
+            builder.append(" textSelectionStart:").append(mSelectionStart);
+            builder.append(" textSelectionEnd:").append(mSelectionEnd);
+        }
+
+        // Print font styling values.
+        builder.append(" textSize:").append(String.format("%.2f", mTextSize));
+        builder.append(" style:").append(mStyle);
+        if (mFgColor != 0xFF000000) {
+            builder.append(" fgColor:").append(mFgColor);
+        }
+        if (mBgColor != 0 && mBgColor != -1) {
+            builder.append(" bgColor:").append(mBgColor);
+        }
+
+        // Print Bundle extras and htmlInfo attributes.
+        if (mBundle != null) {
+            builder.append(" bundle:").append(bundleToString(mBundle));
+        }
+        if (mHtmlInfo != null) {
+            builder.append(" htmlInfo:[");
+            for (Pair<String, String> pair : mHtmlInfo.getAttributes()) {
+                builder.append(" {").append(pair.first).append(",").append(pair.second).append("}");
+            }
+            builder.append(" ]");
         }
 
         builder.append("\n");
 
         for (TestViewStructure child : mChildren) {
-            child.recursiveDumpToString(builder, indent + 1, dumpHtmlTags);
+            child.recursiveDumpToString(builder, indent + 1);
         }
     }
 
@@ -174,10 +245,6 @@
         return mChildren.size();
     }
 
-    public void dumpHtmlTags() {
-        mDumpHtmlTags = true;
-    }
-
     @Override
     public ViewStructure newChild(int index) {
         TestViewStructure viewStructure = new TestViewStructure();
@@ -274,7 +341,9 @@
     public void setHint(CharSequence hint) {}
 
     @Override
-    public void setHtmlInfo(HtmlInfo arg0) {}
+    public void setHtmlInfo(HtmlInfo htmlInfo) {
+        mHtmlInfo = htmlInfo;
+    }
 
     @Override
     public void setInputType(int arg0) {}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
index acce2a600..67d37797 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
@@ -10,6 +10,7 @@
 
 import android.annotation.SuppressLint;
 import android.os.Build.VERSION_CODES;
+import android.os.Environment;
 
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 import androidx.test.filters.SmallTest;
@@ -19,12 +20,15 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
+import java.io.File;
+
 /**
  * Tests for WebContentsAccessibilityImpl integration with accessibility services.
  */
@@ -38,6 +42,7 @@
     private static final String BASE_CSS_FILE_PATH = "content/test/data/accessibility/css/";
     private static final String BASE_HTML_FILE_PATH = "content/test/data/accessibility/html/";
     private static final String DEFAULT_FILE_SUFFIX = "-expected-android-external.txt";
+    private static final String ASSIST_DATA_FILE_SUFFIX = "-expected-android-assist-data.txt";
 
     @Rule
     public AccessibilityContentShellActivityTestRule mActivityTestRule =
@@ -48,6 +53,8 @@
      *      1. Open the given HTML file
      *      2. Generate the full AccessibilityNodeInfo tree
      *      3. Read expectations file and compare with results
+     *      4. Generate an AssistData structure for the page
+     *      5. Read AssistData expectations file and compare with results
      *
      * @param inputFile HTML test input file
      * @param expectationFile TXT expectations file
@@ -62,8 +69,33 @@
                 expectationFilePath, inputFile, expectationFilePath, expectationFile);
 
         // Generate full AccessibilityNodeInfo tree and verify results.
-        assertResults(expectationFilePath + expectationFile, generateAccessibilityNodeInfoTree(),
+        assertResults(
+                expectationFilePath + expectationFile,
+                generateAccessibilityNodeInfoTree(),
                 errorStringPrefix);
+
+        // TODO(mschillaci): remove this and add to verifyInputFile when upgrade is complete.
+        String assistDataFileName =
+                inputFile.substring(0, inputFile.length() - 5) + ASSIST_DATA_FILE_SUFFIX;
+        String directory =
+                Environment.getExternalStorageDirectory().getPath()
+                        + "/chromium_tests_root/"
+                        + expectationFilePath;
+        File expectedFile = new File(directory, "/" + assistDataFileName);
+        if (expectedFile.exists()) {
+            errorStringPrefix =
+                    String.format(
+                            "\n\nTesting: %s%s\nExpected output: %s%s",
+                            expectationFilePath,
+                            inputFile,
+                            expectationFilePath,
+                            assistDataFileName);
+            // Generate full AssistData tree and verify results.
+            assertResults(
+                    expectationFilePath + "/" + assistDataFileName,
+                    generateViewStructureTree(),
+                    errorStringPrefix);
+        }
     }
 
     // Helper methods to pass-through to the performTest method so each individual test does
@@ -144,6 +176,14 @@
         return builder.toString();
     }
 
+    private String generateViewStructureTree() {
+        TestViewStructure testViewStructure = new TestViewStructure();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> mActivityTestRule.mWcax.onProvideVirtualStructure(testViewStructure, false));
+        CriteriaHelper.pollUiThread(testViewStructure::isDone, "Failed to get AssistData.");
+        return testViewStructure.toString();
+    }
+
     /**
      * Recursively add AccessibilityNodeInfo descendants to the given builder.
      *
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 0ead476..14f3120 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -1249,8 +1249,18 @@
 }
 
 bool ContentBrowserClient::ShouldRunOutOfProcessSystemDnsResolution() {
-  return base::FeatureList::IsEnabled(
-      network::features::kOutOfProcessSystemDnsResolution);
+// This is only useful on Linux desktop and Android where system DNS
+// resolution cannot always run in a sandboxed network process. The Mac and
+// Windows sandboxing systems allow us to specify system DNS resolution as an
+// allowed action, and ChromeOS uses a simple, known system DNS configuration
+// that can be adequately sandboxed.
+// Currently Android's network service will not run out of process or sandboxed,
+// so OutOfProcessSystemDnsResolution is not currently enabled on Android.
+#if BUILDFLAG(IS_LINUX)
+  return true;
+#else
+  return false;
+#endif
 }
 
 std::string ContentBrowserClient::GetProduct() {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 0461d23..385ca4a 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -2196,7 +2196,8 @@
   virtual bool ShouldSandboxNetworkService();
 
   // Returns true if system DNS resolution should be run outside of the network
-  // service.
+  // service. This is useful if the network service is sandboxed but system DNS
+  // resolution cannot run sandboxed.
   virtual bool ShouldRunOutOfProcessSystemDnsResolution();
 
   // Browser-side API to log blink UseCounters for events that don't occur in
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index a8ffdb8c..2952422 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -152,15 +152,6 @@
   settings->SetAccessibilityIncludeSvgGElement(true);
 #endif
 
-#if BUILDFLAG(IS_FUCHSIA)
-  // TODO(crbug.com/1477047): WebSemanticsTest expects the events to be posted
-  // on a different thread.
-  // https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/ui/a11y/lib/semantics/tests/web_semantics_tests.cc#232
-  // The test facility needs to be updated, but we need sometime to make the
-  // change.
-  serialize_post_lifecycle_ = false;
-#endif
-
   // Optionally disable AXMenuList, which makes the internal pop-up menu
   // UI for a select element directly accessible. Disable by default on
   // Chrome OS, but some tests may override.
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist
index 2b2d956..d50eb34 100644
--- a/content/test/content_test_bundle_data.filelist
+++ b/content/test/content_test_bundle_data.filelist
@@ -10,6 +10,7 @@
 data/accept-header.html
 data/accessibility/accdescription/description-ignores-slot-expected-blink.txt
 data/accessibility/accdescription/description-ignores-slot.html
+data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt
 data/accessibility/accname/desc-combobox-focusable-expected-android-external.txt
 data/accessibility/accname/desc-combobox-focusable-expected-android.txt
 data/accessibility/accname/desc-combobox-focusable-expected-auralinux.txt
@@ -17,6 +18,7 @@
 data/accessibility/accname/desc-combobox-focusable-expected-mac.txt
 data/accessibility/accname/desc-combobox-focusable-expected-win.txt
 data/accessibility/accname/desc-combobox-focusable.html
+data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt
 data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-external.txt
 data/accessibility/accname/desc-from-content-of-describedby-element-expected-android.txt
 data/accessibility/accname/desc-from-content-of-describedby-element-expected-auralinux.txt
@@ -106,6 +108,7 @@
 data/accessibility/accname/name-checkbox-title.html
 data/accessibility/accname/name-combobox-focusable-alternative-expected-blink.txt
 data/accessibility/accname/name-combobox-focusable-alternative.html
+data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt
 data/accessibility/accname/name-combobox-focusable-expected-android-external.txt
 data/accessibility/accname/name-combobox-focusable-expected-android.txt
 data/accessibility/accname/name-combobox-focusable-expected-auralinux.txt
@@ -113,6 +116,7 @@
 data/accessibility/accname/name-combobox-focusable-expected-mac.txt
 data/accessibility/accname/name-combobox-focusable-expected-win.txt
 data/accessibility/accname/name-combobox-focusable.html
+data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt
 data/accessibility/accname/name-div-content-only-expected-android-external.txt
 data/accessibility/accname/name-div-content-only-expected-android.txt
 data/accessibility/accname/name-div-content-only-expected-auralinux.txt
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt
new file mode 100644
index 0000000..e60290dd
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt
@@ -0,0 +1,3 @@
+WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
+++Spinner text:"English" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="test", role="combobox", tabindex="0", title="Choose your language."]
+++++TextView text:"English" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt
new file mode 100644
index 0000000..e4fbca82
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt
@@ -0,0 +1,18 @@
+WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
+++EditText text:"Important stuff My name is Garaventa the weird. (QED) Where are my marbles?" textSize:13.33 style:0 bundle:[aria-describedby="descId", aria-label="Important stuff", display="inline-block", htmlTag="input", id="test", type="text"]
+++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
+++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="descId"]
+++++TextView text:"My" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+++++TextView text:" name is" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
+++++View text:"Garaventa" textSize:16.00 style:0 bundle:[aria-label="Garaventa", display="inline", htmlTag="span"]
+++++++TextView text:"Zambino" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+++++TextView text:"the weird." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+++++TextView text:" (QED)" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+++++View textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
+++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
+++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
+++++++++++TextView text:"Where" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
+++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
+++++++++++TextView text:"are my marbles?" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt b/content/test/data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt
new file mode 100644
index 0000000..e60290dd
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt
@@ -0,0 +1,3 @@
+WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
+++Spinner text:"English" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="test", role="combobox", tabindex="0", title="Choose your language."]
+++++TextView text:"English" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
diff --git a/content/test/data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt b/content/test/data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt
new file mode 100644
index 0000000..02b85fc6a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt
@@ -0,0 +1,3 @@
+WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
+++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="test"]
+++++TextView text:"Div with text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index e075c1c..2cd62363 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -46,6 +46,8 @@
     "opaque_attestation_statement.h",
     "p256_public_key.cc",
     "p256_public_key.h",
+    "prf_input.cc",
+    "prf_input.h",
     "public_key.cc",
     "public_key.h",
     "public_key_credential_descriptor.cc",
diff --git a/device/fido/authenticator_make_credential_response.cc b/device/fido/authenticator_make_credential_response.cc
index 48ab1c5..fb66eb35 100644
--- a/device/fido/authenticator_make_credential_response.cc
+++ b/device/fido/authenticator_make_credential_response.cc
@@ -134,6 +134,21 @@
   if (response.prf_enabled) {
     cbor::Value::MapValue prf;
     prf.emplace(kExtensionPRFEnabled, true);
+    if (response.prf_results) {
+      const std::vector<uint8_t>& results = *response.prf_results;
+      cbor::Value::MapValue prf_results;
+      if (results.size() == 32) {
+        prf_results.emplace(kExtensionPRFFirst, results);
+      } else {
+        CHECK_EQ(results.size(), 64u);
+        prf_results.emplace(kExtensionPRFFirst,
+                            std::vector<uint8_t>(&results[0], &results[32]));
+        prf_results.emplace(
+            kExtensionPRFSecond,
+            std::vector<uint8_t>(results.begin() + 32, results.end()));
+      }
+      prf.emplace(kExtensionPRFResults, std::move(prf_results));
+    }
     unsigned_extension_outputs.emplace(kExtensionPRF, std::move(prf));
   }
   if (response.large_blob_type == LargeBlobSupportType::kExtension) {
diff --git a/device/fido/authenticator_make_credential_response.h b/device/fido/authenticator_make_credential_response.h
index e4f64e8..89e6ccc 100644
--- a/device/fido/authenticator_make_credential_response.h
+++ b/device/fido/authenticator_make_credential_response.h
@@ -99,6 +99,9 @@
   // is in the authenticator data. However, note that the WebAuthn-level prf
   // extension may be using the `hmac-secret` extension at the CTAP layer.
   bool prf_enabled = false;
+
+  // hmac-secret contains the output of the prf extension.
+  absl::optional<std::vector<uint8_t>> prf_results;
 };
 
 // Through cbor::Writer, produces a CTAP style CBOR-encoded byte array
diff --git a/device/fido/ctap_get_assertion_request.cc b/device/fido/ctap_get_assertion_request.cc
index 712afa9e0..c4f2a1d 100644
--- a/device/fido/ctap_get_assertion_request.cc
+++ b/device/fido/ctap_get_assertion_request.cc
@@ -36,49 +36,6 @@
             param.first.GetInteger() <= 7u);
   });
 }
-
-cbor::Value::MapValue PRFInputToCBOR(const PRFInput& input) {
-  cbor::Value::MapValue ret;
-  ret.emplace(kExtensionPRFFirst,
-              std::vector<uint8_t>(input.salt1.begin(), input.salt1.end()));
-  if (input.salt2) {
-    ret.emplace(kExtensionPRFSecond,
-                std::vector<uint8_t>(input.salt2->begin(), input.salt2->end()));
-  }
-  return ret;
-}
-
-bool CBORToPRFValue(const cbor::Value& v, std::array<uint8_t, 32>* out) {
-  if (!v.is_bytestring()) {
-    return false;
-  }
-  return fido_parsing_utils::ExtractArray(v.GetBytestring(), 0, out);
-}
-
-absl::optional<PRFInput> CBORToPRFInput(const cbor::Value& v) {
-  if (!v.is_map()) {
-    return absl::nullopt;
-  }
-  const cbor::Value::MapValue& map = v.GetMap();
-  const auto first_it = map.find(cbor::Value(kExtensionPRFFirst));
-  if (first_it == map.end()) {
-    return absl::nullopt;
-  }
-
-  PRFInput ret;
-  if (!CBORToPRFValue(first_it->second, &ret.salt1)) {
-    return absl::nullopt;
-  }
-
-  const auto second_it = map.find(cbor::Value(kExtensionPRFSecond));
-  if (second_it != map.end()) {
-    ret.salt2.emplace();
-    if (!CBORToPRFValue(second_it->second, &ret.salt2.value())) {
-      return absl::nullopt;
-    }
-  }
-  return ret;
-}
 }  // namespace
 
 CtapGetAssertionOptions::CtapGetAssertionOptions() = default;
@@ -88,12 +45,6 @@
     default;
 CtapGetAssertionOptions::~CtapGetAssertionOptions() = default;
 
-PRFInput::PRFInput() = default;
-PRFInput::PRFInput(const PRFInput&) = default;
-PRFInput::PRFInput(PRFInput&&) = default;
-PRFInput& PRFInput::operator=(const PRFInput&) = default;
-PRFInput::~PRFInput() = default;
-
 bool operator<(const PRFInput& a, const PRFInput& b) {
   if (!a.credential_id.has_value()) {
     return b.credential_id.has_value();
@@ -258,7 +209,7 @@
         const cbor::Value::MapValue& prf = extension.second.GetMap();
         const auto eval_it = prf.find(cbor::Value(kExtensionPRFEval));
         if (eval_it != prf.end()) {
-          absl::optional<PRFInput> input = CBORToPRFInput(eval_it->second);
+          absl::optional<PRFInput> input = PRFInput::FromCBOR(eval_it->second);
           if (!input) {
             return absl::nullopt;
           }
@@ -272,7 +223,7 @@
           }
           const cbor::Value::MapValue& by_cred = by_cred_it->second.GetMap();
           for (const auto& cred : by_cred) {
-            absl::optional<PRFInput> input = CBORToPRFInput(cred.second);
+            absl::optional<PRFInput> input = PRFInput::FromCBOR(cred.second);
             if (!input || !cred.first.is_bytestring()) {
               return absl::nullopt;
             }
@@ -468,9 +419,9 @@
     cbor::Value::MapValue by_cred;
     for (const auto& input : request.prf_inputs) {
       if (!input.credential_id.has_value()) {
-        prf.emplace(kExtensionPRFEval, PRFInputToCBOR(input));
+        prf.emplace(kExtensionPRFEval, input.ToCBOR());
       } else {
-        by_cred.emplace(*input.credential_id, PRFInputToCBOR(input));
+        by_cred.emplace(*input.credential_id, input.ToCBOR());
       }
     }
     if (!by_cred.empty()) {
diff --git a/device/fido/ctap_get_assertion_request.h b/device/fido/ctap_get_assertion_request.h
index 7994c3f..756c9bd 100644
--- a/device/fido/ctap_get_assertion_request.h
+++ b/device/fido/ctap_get_assertion_request.h
@@ -20,6 +20,7 @@
 #include "device/fido/json_request.h"
 #include "device/fido/large_blob.h"
 #include "device/fido/pin.h"
+#include "device/fido/prf_input.h"
 #include "device/fido/public_key_credential_descriptor.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -29,20 +30,6 @@
 
 namespace device {
 
-// PRFInput contains salts for the hmac-secret or prf extension, potentially
-// specific to a given credential ID.
-struct COMPONENT_EXPORT(DEVICE_FIDO) PRFInput {
-  PRFInput();
-  PRFInput(const PRFInput&);
-  PRFInput(PRFInput&&);
-  PRFInput& operator=(const PRFInput&);
-  ~PRFInput();
-
-  absl::optional<std::vector<uint8_t>> credential_id;
-  std::array<uint8_t, 32> salt1;
-  absl::optional<std::array<uint8_t, 32>> salt2;
-};
-
 // CtapGetAssertionOptions contains values that are pertinent to a
 // |GetAssertionTask|, but are not specific to an individual
 // authenticatorGetAssertion command, i.e. would not be directly serialised into
diff --git a/device/fido/ctap_make_credential_request.cc b/device/fido/ctap_make_credential_request.cc
index 99ad4ec3..1df651955f 100644
--- a/device/fido/ctap_make_credential_request.cc
+++ b/device/fido/ctap_make_credential_request.cc
@@ -172,6 +172,14 @@
         if (!extension.second.is_map()) {
           return absl::nullopt;
         }
+        const cbor::Value::MapValue& prf = extension.second.GetMap();
+        const auto eval_it = prf.find(cbor::Value(kExtensionPRFEval));
+        if (eval_it != prf.end()) {
+          request.prf_input = PRFInput::FromCBOR(eval_it->second);
+          if (!request.prf_input) {
+            return absl::nullopt;
+          }
+        }
         request.prf = true;
       } else if (extension_name == kExtensionLargeBlobKey) {
         if (!extension.second.is_bool() || !extension.second.GetBool()) {
@@ -319,7 +327,13 @@
   }
 
   if (request.prf) {
-    extensions.emplace(kExtensionPRF, cbor::Value::MapValue());
+    cbor::Value::MapValue prf_ext;
+    if (request.prf_input) {
+      cbor::Value::MapValue eval;
+      prf_ext.emplace(kExtensionPRFEval, request.prf_input->ToCBOR());
+    }
+
+    extensions.emplace(kExtensionPRF, std::move(prf_ext));
   }
 
   if (request.large_blob_support != LargeBlobSupport::kNotRequested) {
diff --git a/device/fido/ctap_make_credential_request.h b/device/fido/ctap_make_credential_request.h
index b56f657..4d0c281d 100644
--- a/device/fido/ctap_make_credential_request.h
+++ b/device/fido/ctap_make_credential_request.h
@@ -17,6 +17,7 @@
 #include "device/fido/fido_constants.h"
 #include "device/fido/json_request.h"
 #include "device/fido/pin.h"
+#include "device/fido/prf_input.h"
 #include "device/fido/public_key_credential_descriptor.h"
 #include "device/fido/public_key_credential_params.h"
 #include "device/fido/public_key_credential_rp_entity.h"
@@ -82,6 +83,11 @@
   // the authenticator associate a PRF with the credential.
   bool prf = false;
 
+  // prf_input contains the hashed salts for doing a PRF evaluation at
+  // credential creation time. This is only possible when the authenticator
+  // supports the "prf" extension, i.e. over hybrid CTAP.
+  absl::optional<PRFInput> prf_input;
+
   // large_blob_support indicates whether support for largeBlobs should be
   // requested using the `largeBlob` extension. This should be mutually
   // exclusive with `large_blob_key`.
diff --git a/device/fido/device_response_converter.cc b/device/fido/device_response_converter.cc
index 2033d12..5bf1fecc 100644
--- a/device/fido/device_response_converter.cc
+++ b/device/fido/device_response_converter.cc
@@ -52,6 +52,35 @@
   return absl::nullopt;
 }
 
+absl::optional<std::vector<uint8_t>> GetPRFOutputs(
+    const cbor::Value& results_value) {
+  if (!results_value.is_map()) {
+    return absl::nullopt;
+  }
+  const cbor::Value::MapValue& results = results_value.GetMap();
+  auto first = results.find(cbor::Value(kExtensionPRFFirst));
+  if (first == results.end() || !first->second.is_bytestring()) {
+    return absl::nullopt;
+  }
+  std::vector<uint8_t> output = first->second.GetBytestring();
+  if (output.size() != kExtensionPRFOutputSize) {
+    return absl::nullopt;
+  }
+
+  auto second = results.find(cbor::Value(kExtensionPRFSecond));
+  if (second != results.end()) {
+    if (!second->second.is_bytestring()) {
+      return absl::nullopt;
+    }
+    const std::vector<uint8_t>& second_bytes = second->second.GetBytestring();
+    if (second_bytes.size() != kExtensionPRFOutputSize) {
+      return absl::nullopt;
+    }
+    output.insert(output.end(), second_bytes.begin(), second_bytes.end());
+  }
+  return output;
+}
+
 }  // namespace
 
 using CBOR = cbor::Value;
@@ -143,6 +172,13 @@
           }
           response.prf_enabled = enabled_it->second.GetBool();
         }
+        auto results_it = prf.find(cbor::Value(kExtensionPRFResults));
+        if (results_it != prf.end()) {
+          response.prf_results = GetPRFOutputs(results_it->second);
+          if (!response.prf_results) {
+            return absl::nullopt;
+          }
+        }
       } else if (extension_name == kExtensionLargeBlob) {
         if (response.large_blob_type || !map_it.second.is_map()) {
           // Authenticators cannot support both methods.
@@ -262,33 +298,10 @@
         const cbor::Value::MapValue& prf = map_it.second.GetMap();
         auto results_it = prf.find(cbor::Value(kExtensionPRFResults));
         if (results_it != prf.end()) {
-          if (!results_it->second.is_map()) {
+          response.hmac_secret = GetPRFOutputs(results_it->second);
+          if (!response.hmac_secret) {
             return absl::nullopt;
           }
-          const cbor::Value::MapValue& results = results_it->second.GetMap();
-          auto first = results.find(cbor::Value(kExtensionPRFFirst));
-          if (first == results.end() || !first->second.is_bytestring()) {
-            return absl::nullopt;
-          }
-          std::vector<uint8_t> output = first->second.GetBytestring();
-          if (output.size() != kExtensionPRFOutputSize) {
-            return absl::nullopt;
-          }
-
-          auto second = results.find(cbor::Value(kExtensionPRFSecond));
-          if (second != results.end()) {
-            if (!second->second.is_bytestring()) {
-              return absl::nullopt;
-            }
-            const std::vector<uint8_t>& second_bytes =
-                second->second.GetBytestring();
-            if (second_bytes.size() != kExtensionPRFOutputSize) {
-              return absl::nullopt;
-            }
-            output.insert(output.end(), second_bytes.begin(),
-                          second_bytes.end());
-          }
-          response.hmac_secret = std::move(output);
         }
       } else if (extension_name == kExtensionLargeBlob) {
         if (response.large_blob_key || !map_it.second.is_map()) {
diff --git a/device/fido/features.cc b/device/fido/features.cc
index 7a20e1a..3dd3f09 100644
--- a/device/fido/features.cc
+++ b/device/fido/features.cc
@@ -227,4 +227,9 @@
              "WebAuthenticationAndroidIncognitoConfirmation",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Enabled in M120. Remove in or after M123.
+BASE_FEATURE(kWebAuthnPRFEvalDuringCreate,
+             "WebAuthenticationPRFEvalDuringCreate",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 }  // namespace device
diff --git a/device/fido/features.h b/device/fido/features.h
index 3385ed3..8e19c127 100644
--- a/device/fido/features.h
+++ b/device/fido/features.h
@@ -183,6 +183,10 @@
 COMPONENT_EXPORT(DEVICE_FIDO)
 BASE_DECLARE_FEATURE(kWebAuthnAndroidIncognitoConfirmation);
 
+// Support evaluating PRFs during create() calls.
+COMPONENT_EXPORT(DEVICE_FIDO)
+BASE_DECLARE_FEATURE(kWebAuthnPRFEvalDuringCreate);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_FEATURES_H_
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc
index 0264943c..a098762 100644
--- a/device/fido/make_credential_request_handler.cc
+++ b/device/fido/make_credential_request_handler.cc
@@ -1075,6 +1075,11 @@
       request->user_verification =
           AtLeastUVPreferred(request->user_verification);
     }
+    // Evaluating the PRF at creation time is only supported with the "prf"
+    // extension.
+    if (request->prf_input && !auth_options.supports_prf) {
+      request->prf_input.reset();
+    }
   }
 
   if (request->min_pin_length_requested &&
diff --git a/device/fido/prf_input.cc b/device/fido/prf_input.cc
new file mode 100644
index 0000000..637949d
--- /dev/null
+++ b/device/fido/prf_input.cc
@@ -0,0 +1,67 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/fido/prf_input.h"
+
+#include <array>
+
+#include "components/cbor/values.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
+
+namespace device {
+
+namespace {
+bool CBORToPRFValue(const cbor::Value& v, std::array<uint8_t, 32>* out) {
+  if (!v.is_bytestring()) {
+    return false;
+  }
+  return fido_parsing_utils::ExtractArray(v.GetBytestring(), 0, out);
+}
+}  // namespace
+
+PRFInput::PRFInput() = default;
+PRFInput::PRFInput(const PRFInput&) = default;
+PRFInput::PRFInput(PRFInput&&) = default;
+PRFInput& PRFInput::operator=(const PRFInput&) = default;
+PRFInput::~PRFInput() = default;
+
+// static
+absl::optional<PRFInput> PRFInput::FromCBOR(const cbor::Value& v) {
+  if (!v.is_map()) {
+    return absl::nullopt;
+  }
+  const cbor::Value::MapValue& map = v.GetMap();
+  const auto first_it = map.find(cbor::Value(kExtensionPRFFirst));
+  if (first_it == map.end()) {
+    return absl::nullopt;
+  }
+
+  PRFInput ret;
+  if (!CBORToPRFValue(first_it->second, &ret.salt1)) {
+    return absl::nullopt;
+  }
+
+  const auto second_it = map.find(cbor::Value(kExtensionPRFSecond));
+  if (second_it != map.end()) {
+    ret.salt2.emplace();
+    if (!CBORToPRFValue(second_it->second, &ret.salt2.value())) {
+      return absl::nullopt;
+    }
+  }
+  return ret;
+}
+
+cbor::Value::MapValue PRFInput::ToCBOR() const {
+  cbor::Value::MapValue ret;
+  ret.emplace(kExtensionPRFFirst,
+              std::vector<uint8_t>(this->salt1.begin(), this->salt1.end()));
+  if (this->salt2) {
+    ret.emplace(kExtensionPRFSecond,
+                std::vector<uint8_t>(this->salt2->begin(), this->salt2->end()));
+  }
+  return ret;
+}
+
+}  // namespace device
diff --git a/device/fido/prf_input.h b/device/fido/prf_input.h
new file mode 100644
index 0000000..2a8c62c
--- /dev/null
+++ b/device/fido/prf_input.h
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_FIDO_PRF_INPUT_H_
+#define DEVICE_FIDO_PRF_INPUT_H_
+
+#include <stdint.h>
+
+#include <array>
+#include <vector>
+
+#include "base/component_export.h"
+#include "components/cbor/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace device {
+
+// PRFInput contains salts for the hmac-secret or prf extension, potentially
+// specific to a given credential ID.
+struct COMPONENT_EXPORT(DEVICE_FIDO) PRFInput {
+  PRFInput();
+  PRFInput(const PRFInput&);
+  PRFInput(PRFInput&&);
+  PRFInput& operator=(const PRFInput&);
+  ~PRFInput();
+
+  static absl::optional<PRFInput> FromCBOR(const cbor::Value& v);
+
+  cbor::Value::MapValue ToCBOR() const;
+
+  absl::optional<std::vector<uint8_t>> credential_id;
+  std::array<uint8_t, 32> salt1;
+  absl::optional<std::array<uint8_t, 32>> salt2;
+};
+
+}  // namespace device
+
+#endif  // DEVICE_FIDO_PRF_INPUT_H_
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index 21d7759..ad42f21 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -160,7 +160,8 @@
     bool enterprise_attestation_requested,
     absl::optional<LargeBlobSupportType> large_blob_type,
     const absl::optional<std::vector<uint8_t>>& dpk_signature,
-    bool prf_enabled) {
+    bool prf_enabled,
+    absl::optional<std::vector<uint8_t>> prf_results) {
   std::unique_ptr<OpaqueAttestationStatement> attestation_statement;
   if (!signature.empty()) {
     cbor::Value::MapValue attestation_map;
@@ -190,6 +191,7 @@
   make_credential_response.device_public_key_signature =
       std::move(dpk_signature);
   make_credential_response.prf_enabled = prf_enabled;
+  make_credential_response.prf_results = std::move(prf_results);
   return AsCTAPStyleCBORBytes(make_credential_response);
 }
 
@@ -1467,13 +1469,8 @@
     }
   }
 
-  *response = ConstructMakeCredentialResponse(
-      std::move(attestation_cert), sig, std::move(authenticator_data),
-      enterprise_attestation_requested, supports_large_blob, dpk_sig,
-      prf_enabled);
   RegistrationData registration(std::move(private_key), rp_id_hash,
                                 /*counter=*/1);
-
   if (request.resident_key_required) {
     // If there's already a registration for this RP and user ID, delete it.
     for (const auto& reg : mutable_state()->registrations) {
@@ -1503,12 +1500,20 @@
   registration.device_key = std::move(device_key);
   registration.cred_blob = std::move(request.cred_blob);
 
+  absl::optional<std::vector<uint8_t>> prf_results;
   if (request.hmac_secret || prf_enabled) {
     registration.hmac_key.emplace();
     RAND_bytes(registration.hmac_key->first.data(),
                registration.hmac_key->first.size());
     RAND_bytes(registration.hmac_key->second.data(),
                registration.hmac_key->second.size());
+    if (request.prf_input) {
+      const std::array<uint8_t, 32>& hmac_key =
+          user_verified ? registration.hmac_key->second
+                        : registration.hmac_key->first;
+      prf_results = EvaluateHMAC(hmac_key, request.prf_input->salt1,
+                                 request.prf_input->salt2);
+    }
   }
 
   if (request.large_blob_key) {
@@ -1518,6 +1523,11 @@
   }
 
   StoreNewKey(key_handle, std::move(registration));
+
+  *response = ConstructMakeCredentialResponse(
+      std::move(attestation_cert), sig, std::move(authenticator_data),
+      enterprise_attestation_requested, supports_large_blob, dpk_sig,
+      prf_enabled, std::move(prf_results));
   return CtapDeviceResponseCode::kSuccess;
 }
 
diff --git a/docs/security/tls-sha1-server-signatures.md b/docs/security/tls-sha1-server-signatures.md
index 404f34d..8f671df4 100644
--- a/docs/security/tls-sha1-server-signatures.md
+++ b/docs/security/tls-sha1-server-signatures.md
@@ -20,7 +20,7 @@
 
 ## Is my website affected?
 
-You can test your website by toggling the "Allow SHA-1 server signatures in TLS" flag. Go to `chrome://flags/#use-sha1-server-handshakes`. If setting it to "Enabled" causes the site to work, but setting it to "Disabled" causes it to break, the website is affected.
+You can test your website by toggling the "Allow SHA-1 server signatures in TLS" flag. Go to `chrome://flags/#use-sha1-server-handshakes`. If setting it to "Enabled" causes the site to work, but setting it to "Disabled" causes it to break, the website is affected. This flag is temporary and will be removed in the future. It may be used for now to help diagnose issues, but, long-term, the server should be fixed.
 
 Depending on the exact cause, this issue can appear differently, such as an `ERR_SSL_PROTOCOL_ERROR` or `ERR_CONNECTION_RESET`, though this is not the only possible cause of those errors.
 
diff --git a/docs/transcripts/wuwt-e02-dchecks.md b/docs/transcripts/wuwt-e02-dchecks.md
index 537e03d..1effa6a 100644
--- a/docs/transcripts/wuwt-e02-dchecks.md
+++ b/docs/transcripts/wuwt-e02-dchecks.md
@@ -16,10 +16,12 @@
 improving crash reports.
 
 Notes:
+
 - https://docs.google.com/document/d/146LoJ1E3N3E6fb4zDh92HPQc6yhRpNI7DSKlJjaYlLw/edit
 
 Links:
-- [What's Up With Pointers](https://www.youtube.com/watch?v=MpwbWSEDfjM)
+
+- [What's Up With Pointers]
 
 ---
 
@@ -39,14 +41,14 @@
 00:39 PETER: So a CHECK and a DCHECK are both sort of things that make sure
 that what you think is true is true. Right? So this should never be called with
 an empty vector. You might add a CHECK for it, or you might add a DCHECK for
-it. And it's sort of similar to a search, which you may have hit during earlier
+it. And it's sort of similar to asserts, which you may have hit during earlier
 programming outside of Chrome. And what it means is when this line gets hit, we
 check and see if it's true. And if it's not true, we crash. DCHECKs differ from
 CHECKs in that they are traditionally only in debug builds, or local
 development builds, or on our try-bots. So they have zero overhead when Chrome
 hits stable, because the CHECK just won't be there.
 
-01:24 SHARON: OK. So like if the D stands for Debug. That make sense.
+01:24 SHARON: OK. So I guess the D stands for Debug. That make sense.
 
 01:28 PETER: Yeah. I want debug to turn into developer, because now we have
 them by default if you're no longer - if you're doing a release build, and
@@ -126,7 +128,7 @@
 a CHECK?
 
 06:24 PETER: Right. So say that you have something in video code that for every
-video frame, for every pixel validates the alpha value as opaque, or something.
+video frame, for every pixel validates the alpha value is opaque, or something.
 That would probably make video conferencing a little bit worse performance.
 Another thing would just be if you have to traverse a graph on every frame, and
 it will sort of jump all over memory to see if some reachability problem in
@@ -141,10 +143,10 @@
 
 07:09 SHARON: OK. So since most places we should use CHECKs, are there any
 places where a DCHECK would be better then? Or any time you would have normally
-previously used a DCHECK, you should just make that a check?
+previously used a DCHECK, you should just make that a CHECK?
 
 07:23 PETER: So we have a new construct that's called `EXPENSIVE_DCHECK`s, or
-if `EXPENSIVE_DCHECK`s are on, I think we should add a corresponding macro for
+if `EXPENSIVE_DCHECKS_ARE_ON`, I think we should add a corresponding macro for
 `EXPENSIVE_DCHECK`. And then you should be able to just say, either it's
 expensive and has to be a DCHECK, so use `EXPENSIVE_DCHECK`; otherwise, use
 CHECK. And my hunch would be like 95% of what we have as DCHECKs would probably
@@ -214,7 +216,7 @@
 12:13 PETER: I mean, if you care about it, especially if it causes privacy or
 security or user-harm sort of things, just CHECK. Just CHECK, right? If it
 makes your code animate a thing slightly weirder, like it will just jump to the
-end position instead of going through your fence load, whatever. Maybe you can
+end position instead of going through your fancy little... whatever. Maybe you can
 make that a DCHECK. Maybe it doesn't matter. Like it's wrong, but it's not that
 bad. But most of the cases, you DCHECK something, where it's like the program
 is going to be in some indeterminate state, and we actually care about if it's
@@ -273,26 +275,26 @@
 16:20 PETER: Yeah. Well, they are uploaded to the same crash-reporting thing.
 They show up under a special branch. And you likely will get bugs filed to you
 if they hit very frequently, just like you would with crashes. There's a sort
-of slight difference, in that they say dump without crashing. And that's just
+of slight difference, in that they say DumpWithoutCrashing. And that's just
 sort of a rollout strategy for us. Because if we made DCHECK builds incredibly
 crashy, because they hit more than CHECKs, then we can never roll this thing
 out. Or it gets a lot scarier for us to put this on 5% of a new platform that
 we haven't tested. But as it is right now, the first DCHECK that gets hit for
 every process gets a crash dump uploaded.
 
-17:07 SHARON: OK. So I've been definitely told to use dump without crashing at
+17:07 SHARON: OK. So I've been definitely told to use DumpWithoutCrashing at
 certain points in CLs, where it's like, OK, we think that this shouldn't
 happen. But if it does, we don't necessarily want to crash the browser because
 of it. With the changes you've mentioned to DCHECKs happening, should those
-just be CHECKs instead now or should those still be dump without crashing?
+just be CHECKs instead now or should those still be DumpWithoutCrashing?
 
-17:29 PETER: So if you want dump without crashing, and you made those a DCHECK,
+17:29 PETER: So if you want DumpWithoutCrashing, and you made those a DCHECK,
 then you would only have coverage in the Canary channels that we are testing.
 Right? So if you want to get dump reports from the platforms that we're not
 currently testing, including all the way up to Stable, you probably still want
-to keep that a dump without crashing. You want to make sure that you're not
+to keep that a DumpWithoutCrashing. You want to make sure that you're not
 using the sort of - you want to make sure that you triage these, because you
-don't want to keep these generating crash dumps n forever. You should still
+don't want to keep these generating crash dumps forever. You should still
 treat them as if they were crashes. And I think the same thing should hold true
 for DCHECKs. You should only add them for an invariant that you care about
 being violated, right? So as it is violated, you should either figure out why
@@ -308,10 +310,10 @@
 19:01 PETER: So some of the stuff that we have is we have something called
 crash keys, which are essentially, you can write a piece of string data,
 essentially - there's probably some other data types - and if you write those
-before you're running dump without crashing, or before you hit a CHECK, or
+before you're running DumpWithoutCrashing, or before you hit a CHECK, or
 before you hit a DCHECK, then those will be uploaded along the crash dump. And
 if you talk to someone who knows where to find them, you can basically go in
-under a crash report, and then under field product data, or something like
+under a crash report, and then under Fields, Product data, or something like
 that, you should be able to find your key-value pair. And if you have
 information in there, you'll be able to look at it. The other thing that I like
 to do, which is probably the more obvious thing, is if you have somewhat of a
@@ -344,11 +346,11 @@
 program is going to crash, and you don't need to think about whether you throw
 a null pointer in or not. If you keep passing a RawRef around, then that's
 essentially you passing around a non-null pointer. And therefore, you don't
-have to check that it's not null pointer in every step of the way. You only
+have to check that it's not `nullptr` in every step of the way. You only
 need to do it when you're - I mean, the type will do it for you, but it only
 needs to happen when you're converting from a pointer to a ref, essentially, or
 a RawRef. And what's so good about that is now you have the - previously, you
-might just CHECK that this isn't called with null pointer or whatever. But then
+might just CHECK that this isn't called with `nullptr` or whatever. But then
 you would do that for four or five arguments. And you'd be like, null pointer
 CHECKs are this part of the function body. And then it just gets super-noisy.
 But if you're using the RawRef types, then the semantics of the type will
@@ -374,9 +376,9 @@
 
 24:28 SHARON: What do you mean by core types?
 
-24:30 PETER: Say that you make a `scoped_refptr` something, that ref pointer is
+24:30 PETER: Say that you make a `scoped_refptr` or something, that ref pointer is
 used everywhere. So if you CHECKed in the destructor, then you're validating
-all of the clients of your scope ref pointer. So for one CHECK, you get the
+all of the clients of your `scoped_refptr`. So for one CHECK, you get the
 price of a lot of CHECKing. Whereas if in your client code you're validating
 some parameters of an API call that only gets called once, then that's one
 CHECK you add for one case. But if you're re-use, then your CHECK gets a lot
@@ -397,7 +399,7 @@
 libraries that we use, like Abseil and WebRTC, which is a first-party
 third-party library, that they both use Chrome's crashing report system, which
 means that you get more predictable crash stacks because it's using the
-immediate crash macro. But also, you get the fatal logging field that I talked
+IMMEDIATE\_CRASH macro. But also, you get the fatal logging field that I talked
 about. That gets logged as part of crash dumps. So you hopefully have more
 glanceable, actionable crash reports whenever a CHECK is violated inside of
 Abseil, or in WebRTC, as it were. And then upcoming is we want to make sure
@@ -451,3 +453,5 @@
 29:26 PETER: Oh. Take four.
 
 29:29 SHARON: [LAUGHS] Take four. And action.
+
+[What's Up With Pointers]: https://www.youtube.com/watch?v=MpwbWSEDfjM
diff --git a/gpu/command_buffer/client/shared_image_interface.cc b/gpu/command_buffer/client/shared_image_interface.cc
index ac9223ef..53a341a 100644
--- a/gpu/command_buffer/client/shared_image_interface.cc
+++ b/gpu/command_buffer/client/shared_image_interface.cc
@@ -107,19 +107,6 @@
 void SharedImageInterface::NotifyMailboxAdded(const Mailbox& /*mailbox*/,
                                               uint32_t /*usage*/) {}
 
-Mailbox SharedImageInterface::CreateSharedImage(
-    gfx::GpuMemoryBuffer* gpu_memory_buffer,
-    GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    const gfx::ColorSpace& color_space,
-    GrSurfaceOrigin surface_origin,
-    SkAlphaType alpha_type,
-    uint32_t usage,
-    base::StringPiece debug_label) {
-  return CreateSharedImage(gpu_memory_buffer, gpu_memory_buffer_manager,
-                           gfx::BufferPlane::DEFAULT, color_space,
-                           surface_origin, alpha_type, usage, debug_label);
-}
-
 void SharedImageInterface::CopyToGpuMemoryBuffer(const SyncToken& sync_token,
                                                  const Mailbox& mailbox) {
   NOTREACHED();
diff --git a/gpu/command_buffer/client/shared_image_interface.h b/gpu/command_buffer/client/shared_image_interface.h
index 656cc7c..62bf64eb 100644
--- a/gpu/command_buffer/client/shared_image_interface.h
+++ b/gpu/command_buffer/client/shared_image_interface.h
@@ -213,19 +213,6 @@
       uint32_t usage,
       base::StringPiece debug_label) = 0;
 
-  // NOTE: The below method is DEPRECATED for `gpu_memory_buffer` only with
-  // single planar eg. RGB BufferFormats. Please use the equivalent method above
-  // taking in single planar SharedImageFormat with GpuMemoryBufferHandle.
-  //
-  // Same as the above, but specifies gfx::BufferPlane::DEFAULT for |plane|.
-  Mailbox CreateSharedImage(gfx::GpuMemoryBuffer* gpu_memory_buffer,
-                            GpuMemoryBufferManager* gpu_memory_buffer_manager,
-                            const gfx::ColorSpace& color_space,
-                            GrSurfaceOrigin surface_origin,
-                            SkAlphaType alpha_type,
-                            uint32_t usage,
-                            base::StringPiece debug_label);
-
   // Updates a shared image after its GpuMemoryBuffer (if any) was modified on
   // the CPU or through external devices, after |sync_token| has been released.
   virtual void UpdateSharedImage(const SyncToken& sync_token,
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index c7260bda..44bc0f9 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -3696,9 +3696,9 @@
     {
       "id": 414,
       "cr_bugs": [
-        1318380
+        1445741
       ],
-      "description": "Only enable video processor auto HDR on NVIDIA GPUs with 545+ driver",
+      "description": "Only enable video processor auto HDR on NVIDIA GPUs with 550.50+ driver",
       "os": {
         "type": "win"
       },
@@ -3711,7 +3711,7 @@
           "driver_version": {
             "schema": "nvidia_driver",
             "op": ">",
-            "value": "545.00"
+            "value": "550.50"
           }
         }
       ],
diff --git "a/infra/config/generated/builders/ci/Android WebView N \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Android WebView N \050dbg\051/properties.json"
deleted file mode 100644
index e173bec..0000000
--- "a/infra/config/generated/builders/ci/Android WebView N \050dbg\051/properties.json"
+++ /dev/null
@@ -1,111 +0,0 @@
-{
-  "$build/chromium_tests_builder_config": {
-    "builder_config": {
-      "builder_db": {
-        "entries": [
-          {
-            "builder_id": {
-              "bucket": "ci",
-              "builder": "Android WebView N (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "TEST",
-              "legacy_android_config": {
-                "apply_configs": [
-                  "remove_all_system_webviews"
-                ],
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              },
-              "parent": {
-                "bucket": "ci",
-                "builder": "Android arm64 Builder (dbg)",
-                "project": "chromium"
-              }
-            }
-          },
-          {
-            "builder_id": {
-              "bucket": "ci",
-              "builder": "Android arm64 Builder (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "COMPILE_AND_TEST",
-              "legacy_android_config": {
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              }
-            }
-          }
-        ]
-      },
-      "builder_ids": [
-        {
-          "bucket": "ci",
-          "builder": "Android WebView N (dbg)",
-          "project": "chromium"
-        }
-      ],
-      "mirroring_builder_group_and_names": [
-        {
-          "builder": "android-webview-nougat-arm64-dbg",
-          "group": "tryserver.chromium.android"
-        },
-        {
-          "builder": "android_arm64_dbg_recipe",
-          "group": "tryserver.chromium.android"
-        },
-        {
-          "builder": "android_unswarmed_pixel_aosp",
-          "group": "tryserver.chromium.android"
-        }
-      ]
-    }
-  },
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "chromium.android",
-  "recipe": "chromium",
-  "sheriff_rotations": [
-    "android"
-  ]
-}
\ No newline at end of file
diff --git "a/infra/config/generated/builders/ci/Android arm64 Builder \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Android arm64 Builder \050dbg\051/properties.json"
index df38afa9..b1e0d8f 100644
--- "a/infra/config/generated/builders/ci/Android arm64 Builder \050dbg\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Android arm64 Builder \050dbg\051/properties.json"
@@ -6,44 +6,6 @@
           {
             "builder_id": {
               "bucket": "ci",
-              "builder": "Android WebView N (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "TEST",
-              "legacy_android_config": {
-                "apply_configs": [
-                  "remove_all_system_webviews"
-                ],
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              },
-              "parent": {
-                "bucket": "ci",
-                "builder": "Android arm64 Builder (dbg)",
-                "project": "chromium"
-              }
-            }
-          },
-          {
-            "builder_id": {
-              "bucket": "ci",
               "builder": "Android WebView O (dbg)",
               "project": "chromium"
             },
@@ -264,11 +226,6 @@
       "builder_ids_in_scope_for_testing": [
         {
           "bucket": "ci",
-          "builder": "Android WebView N (dbg)",
-          "project": "chromium"
-        },
-        {
-          "bucket": "ci",
           "builder": "Android WebView O (dbg)",
           "project": "chromium"
         },
@@ -303,10 +260,6 @@
           "group": "tryserver.chromium.android"
         },
         {
-          "builder": "android-webview-nougat-arm64-dbg",
-          "group": "tryserver.chromium.android"
-        },
-        {
           "builder": "android-webview-oreo-arm64-dbg",
           "group": "tryserver.chromium.android"
         },
@@ -319,10 +272,6 @@
           "group": "tryserver.chromium.android"
         },
         {
-          "builder": "android_unswarmed_pixel_aosp",
-          "group": "tryserver.chromium.android"
-        },
-        {
           "builder": "try-nougat-phone-tester",
           "group": "tryserver.chromium.android"
         }
diff --git a/infra/config/generated/builders/try/android-webview-nougat-arm64-dbg/properties.json b/infra/config/generated/builders/try/android-webview-nougat-arm64-dbg/properties.json
deleted file mode 100644
index 8943d54..0000000
--- a/infra/config/generated/builders/try/android-webview-nougat-arm64-dbg/properties.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
-  "$build/chromium_tests_builder_config": {
-    "builder_config": {
-      "builder_db": {
-        "entries": [
-          {
-            "builder_id": {
-              "bucket": "ci",
-              "builder": "Android WebView N (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "TEST",
-              "legacy_android_config": {
-                "apply_configs": [
-                  "remove_all_system_webviews"
-                ],
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              },
-              "parent": {
-                "bucket": "ci",
-                "builder": "Android arm64 Builder (dbg)",
-                "project": "chromium"
-              }
-            }
-          },
-          {
-            "builder_id": {
-              "bucket": "ci",
-              "builder": "Android arm64 Builder (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "COMPILE_AND_TEST",
-              "legacy_android_config": {
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              }
-            }
-          }
-        ]
-      },
-      "builder_ids": [
-        {
-          "bucket": "ci",
-          "builder": "Android arm64 Builder (dbg)",
-          "project": "chromium"
-        }
-      ],
-      "builder_ids_in_scope_for_testing": [
-        {
-          "bucket": "ci",
-          "builder": "Android WebView N (dbg)",
-          "project": "chromium"
-        }
-      ]
-    }
-  },
-  "$build/reclient": {
-    "instance": "rbe-chromium-untrusted",
-    "jobs": 150,
-    "metrics_project": "chromium-reclient-metrics",
-    "scandeps_server": true
-  },
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "tryserver.chromium.android",
-  "recipe": "chromium_trybot"
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json b/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json
index c249dd7..154136e 100644
--- a/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json
+++ b/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json
@@ -6,44 +6,6 @@
           {
             "builder_id": {
               "bucket": "ci",
-              "builder": "Android WebView N (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "TEST",
-              "legacy_android_config": {
-                "apply_configs": [
-                  "remove_all_system_webviews"
-                ],
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              },
-              "parent": {
-                "bucket": "ci",
-                "builder": "Android arm64 Builder (dbg)",
-                "project": "chromium"
-              }
-            }
-          },
-          {
-            "builder_id": {
-              "bucket": "ci",
               "builder": "Android WebView O (dbg)",
               "project": "chromium"
             },
@@ -264,11 +226,6 @@
       "builder_ids_in_scope_for_testing": [
         {
           "bucket": "ci",
-          "builder": "Android WebView N (dbg)",
-          "project": "chromium"
-        },
-        {
-          "bucket": "ci",
           "builder": "Android WebView O (dbg)",
           "project": "chromium"
         },
diff --git a/infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json b/infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json
deleted file mode 100644
index 36876cd1..0000000
--- a/infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
-  "$build/chromium_tests_builder_config": {
-    "builder_config": {
-      "builder_db": {
-        "entries": [
-          {
-            "builder_id": {
-              "bucket": "ci",
-              "builder": "Android WebView N (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "TEST",
-              "legacy_android_config": {
-                "apply_configs": [
-                  "remove_all_system_webviews"
-                ],
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              },
-              "parent": {
-                "bucket": "ci",
-                "builder": "Android arm64 Builder (dbg)",
-                "project": "chromium"
-              }
-            }
-          },
-          {
-            "builder_id": {
-              "bucket": "ci",
-              "builder": "Android arm64 Builder (dbg)",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-android-archive",
-              "builder_group": "chromium.android",
-              "execution_mode": "COMPILE_AND_TEST",
-              "legacy_android_config": {
-                "config": "main_builder_mb"
-              },
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "download_xr_test_apks"
-                ],
-                "build_config": "Debug",
-                "config": "android",
-                "target_bits": 64,
-                "target_platform": "android"
-              },
-              "legacy_gclient_config": {
-                "apply_configs": [
-                  "android"
-                ],
-                "config": "chromium"
-              }
-            }
-          }
-        ]
-      },
-      "builder_ids": [
-        {
-          "bucket": "ci",
-          "builder": "Android arm64 Builder (dbg)",
-          "project": "chromium"
-        }
-      ],
-      "builder_ids_in_scope_for_testing": [
-        {
-          "bucket": "ci",
-          "builder": "Android WebView N (dbg)",
-          "project": "chromium"
-        }
-      ]
-    }
-  },
-  "$build/reclient": {
-    "instance": "rbe-chromium-untrusted",
-    "jobs": 500,
-    "metrics_project": "chromium-reclient-metrics",
-    "scandeps_server": true
-  },
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "tryserver.chromium.android",
-  "recipe": "chromium_trybot"
-}
\ No newline at end of file
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index a8d324fd..3cfc7e6 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -627,7 +627,7 @@
   * Experiment percentage: 10.0
 
 * [lacros-amd64-generic-rel](https://ci.chromium.org/p/chromium/builders/try/lacros-amd64-generic-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""lacros-amd64-generic-rel""))
-  * Experiment percentage: 1.0
+  * Experiment percentage: 50.0
 
 * [linux-siso-rel](https://ci.chromium.org/p/chromium/builders/try/linux-siso-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux-siso-rel""))
   * Experiment percentage: 10.0
diff --git a/infra/config/generated/health-specs/health-specs.json b/infra/config/generated/health-specs/health-specs.json
index a3f0ff32..994eb5d0 100644
--- a/infra/config/generated/health-specs/health-specs.json
+++ b/infra/config/generated/health-specs/health-specs.json
@@ -39,9 +39,6 @@
       "Android Release (Nexus 5X)": {
         "_default": "_default"
       },
-      "Android WebView N (dbg)": {
-        "_default": "_default"
-      },
       "Android WebView O (dbg)": {
         "_default": "_default"
       },
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index 6b0f67f..af8c154 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -1012,10 +1012,6 @@
         includable_only: true
       }
       builders {
-        name: "chromium/try/android-webview-nougat-arm64-dbg"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/android-webview-oreo-arm64-dbg"
         includable_only: true
       }
@@ -1467,10 +1463,6 @@
         }
       }
       builders {
-        name: "chromium/try/android_unswarmed_pixel_aosp"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/branch-config-verifier"
         disable_reuse: true
         location_filters {
@@ -2892,7 +2884,7 @@
       }
       builders {
         name: "chromium/try/lacros-amd64-generic-rel"
-        experiment_percentage: 1
+        experiment_percentage: 50
         location_filters {
           gerrit_host_regexp: ".*"
           gerrit_project_regexp: ".*"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 7e9f9d6..15904ae4 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -1603,101 +1603,6 @@
       contact_team_email: "chrome-gpu-infra@google.com"
     }
     builders {
-      name: "Android WebView N (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "free_space:standard"
-      dimensions: "os:Ubuntu-22.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/ci/Android WebView N (dbg)/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "chromium.android",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium",'
-        '  "sheriff_rotations": ['
-        '    "android"'
-        '  ]'
-        '}'
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium_swarming.expose_merge_script_failures"
-        value: 100
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-webview-nougat-arm64-dbg\">android-webview-nougat-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_unswarmed_pixel_aosp\">android_unswarmed_pixel_aosp</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_arm64_dbg_recipe\">android_arm64_dbg_recipe</a></li></ul>"
-      shadow_builder_adjustments {
-        service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-        pool: "luci.chromium.try"
-        dimensions: "free_space:"
-        dimensions: "pool:luci.chromium.try"
-      }
-      contact_team_email: "woa-engprod@google.com"
-    }
-    builders {
       name: "Android WebView O (dbg)"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -2070,7 +1975,7 @@
           use_invocation_timestamp: true
         }
       }
-      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-oreo-arm64-dbg\">android-oreo-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-pie-arm64-dbg\">android-pie-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-webview-nougat-arm64-dbg\">android-webview-nougat-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-webview-oreo-arm64-dbg\">android-webview-oreo-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-webview-pie-arm64-dbg\">android-webview-pie-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_arm64_dbg_recipe\">android_arm64_dbg_recipe</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_unswarmed_pixel_aosp\">android_unswarmed_pixel_aosp</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/try-nougat-phone-tester\">try-nougat-phone-tester</a></li></ul>"
+      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-oreo-arm64-dbg\">android-oreo-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-pie-arm64-dbg\">android-pie-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-webview-oreo-arm64-dbg\">android-webview-oreo-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-webview-pie-arm64-dbg\">android-webview-pie-arm64-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_arm64_dbg_recipe\">android_arm64_dbg_recipe</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/try-nougat-phone-tester\">try-nougat-phone-tester</a></li></ul>"
       shadow_builder_adjustments {
         service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
         pool: "luci.chromium.try"
@@ -68274,97 +68179,6 @@
       description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Android x64 Builder (dbg)\">Android x64 Builder (dbg)</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/android-webview-13-x64-dbg-tests\">android-webview-13-x64-dbg-tests</a></li></ul>"
     }
     builders {
-      name: "android-webview-nougat-arm64-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/try/android-webview-nougat-arm64-dbg/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "tryserver.chromium.android",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium_trybot"'
-        '}'
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      grace_period {
-        seconds: 120
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      experiments {
-        key: "chromium_swarming.expose_merge_script_failures"
-        value: 100
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-      description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Android arm64 Builder (dbg)\">Android arm64 Builder (dbg)</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Android WebView N (dbg)\">Android WebView N (dbg)</a></li></ul>"
-    }
-    builders {
       name: "android-webview-oreo-arm64-dbg"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -69652,97 +69466,6 @@
       }
     }
     builders {
-      name: "android_unswarmed_pixel_aosp"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "tryserver.chromium.android",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium_trybot"'
-        '}'
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      grace_period {
-        seconds: 120
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      experiments {
-        key: "chromium_swarming.expose_merge_script_failures"
-        value: 100
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-      description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Android arm64 Builder (dbg)\">Android arm64 Builder (dbg)</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Android WebView N (dbg)\">Android WebView N (dbg)</a></li></ul>"
-    }
-    builders {
       name: "branch-config-verifier"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -80620,12 +80343,11 @@
     builders {
       name: "lacros-amd64-generic-rel"
       swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
+      dimensions: "builder:lacros-amd64-generic-rel"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
       exe {
         cipd_package: "infra/chromium/bootstrapper/${platform}"
         cipd_version: "latest"
@@ -97632,7 +97354,7 @@
           use_invocation_timestamp: true
         }
       }
-      description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/win-angle-chromium-x64-builder\">win-angle-chromium-x64-builder</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/win10-angle-chromium-x64-intel\">win10-angle-chromium-x64-intel</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/win10-angle-chromium-x64-nvidia\">win10-angle-chromium-x64-nvidia</a></li></ul>"
+      description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/win10-angle-chromium-x64-intel\">win10-angle-chromium-x64-intel</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/win10-angle-chromium-x64-nvidia\">win10-angle-chromium-x64-nvidia</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/win-angle-chromium-x64-builder\">win-angle-chromium-x64-builder</a></li></ul>"
     }
     builders {
       name: "win-angle-chromium-x86-try"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 1b7c04f..e5c7ecd 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -1618,11 +1618,6 @@
     short_name: "P"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Android WebView N (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "N"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Android WebView O (dbg)"
     category: "chromium.android|tester|webview"
     short_name: "O"
@@ -5084,11 +5079,6 @@
     short_name: "12L"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Android WebView N (dbg)"
-    category: "tester|webview"
-    short_name: "N"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Android WebView O (dbg)"
     category: "tester|webview"
     short_name: "O"
@@ -17575,9 +17565,6 @@
     name: "buildbucket/luci.chromium.try/android-webview-13-x64-dbg"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/android-webview-nougat-arm64-dbg"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/android-webview-oreo-arm64-dbg"
   }
   builders {
@@ -17620,9 +17607,6 @@
     name: "buildbucket/luci.chromium.try/android_optional_gpu_tests_rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/android_unswarmed_pixel_aosp"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/branch-config-verifier"
   }
   builders {
@@ -18960,9 +18944,6 @@
     name: "buildbucket/luci.chromium.try/android-webview-13-x64-dbg"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/android-webview-nougat-arm64-dbg"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/android-webview-oreo-arm64-dbg"
   }
   builders {
@@ -19005,9 +18986,6 @@
     name: "buildbucket/luci.chromium.try/android_optional_gpu_tests_rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/android_unswarmed_pixel_aosp"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/gpu-fyi-cq-android-arm64"
   }
   builders {
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index 913adf3..693ab2c 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -184,15 +184,6 @@
   }
 }
 job {
-  id: "Android WebView N (dbg)"
-  realm: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "ci"
-    builder: "Android WebView N (dbg)"
-  }
-}
-job {
   id: "Android WebView O (dbg)"
   realm: "ci"
   buildbucket {
diff --git a/infra/config/generated/luci/realms.cfg b/infra/config/generated/luci/realms.cfg
index bd60100..6033461 100644
--- a/infra/config/generated/luci/realms.cfg
+++ b/infra/config/generated/luci/realms.cfg
@@ -133,7 +133,6 @@
     conditions {
       restrict {
         attribute: "scheduler.job.name"
-        values: "Android WebView N (dbg)"
         values: "Android WebView O (dbg)"
         values: "Android WebView P (dbg)"
         values: "Linux ASan LSan Tests (1)"
diff --git a/infra/config/generated/sheriff-rotations/android.txt b/infra/config/generated/sheriff-rotations/android.txt
index 82a54f4..668c085 100644
--- a/infra/config/generated/sheriff-rotations/android.txt
+++ b/infra/config/generated/sheriff-rotations/android.txt
@@ -1,5 +1,4 @@
 ci/Android ASAN (dbg)
-ci/Android WebView N (dbg)
 ci/Android WebView O (dbg)
 ci/Android WebView P (dbg)
 ci/Android arm Builder (dbg)
diff --git a/infra/config/generated/testing/gn_isolate_map.pyl b/infra/config/generated/testing/gn_isolate_map.pyl
index b9e8365..8534d94 100644
--- a/infra/config/generated/testing/gn_isolate_map.pyl
+++ b/infra/config/generated/testing/gn_isolate_map.pyl
@@ -1015,10 +1015,6 @@
       "--logs-dir=${ISOLATED_OUTDIR}",
     ],
   },
-  "lacros_chrome_browsertests": {
-    "label": "//chrome/test:lacros_chrome_browsertests",
-    "type": "windowed_test_launcher",
-  },
   "lacros_chrome_browsertests_run_in_series": {
     "label": "//chrome/test:lacros_chrome_browsertests_run_in_series",
     "type": "windowed_test_launcher",
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl
index 64ffebe..78866cd 100644
--- a/infra/config/generated/testing/test_suites.pyl
+++ b/infra/config/generated/testing/test_suites.pyl
@@ -4233,12 +4233,6 @@
     },
 
     'linux_lacros_chrome_browsertests_non_version_skew': {
-      'lacros_chrome_browsertests': {
-        'test': 'lacros_chrome_browsertests',
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter',
-        ],
-      },
       'lacros_chrome_browsertests_run_in_series': {
         'test': 'lacros_chrome_browsertests_run_in_series',
         'args': [
@@ -4251,11 +4245,6 @@
     },
 
     'linux_lacros_chrome_browsertests_version_skew': {
-      'lacros_chrome_browsertests': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter',
-        ],
-      },
       'lacros_chrome_browsertests_run_in_series': {
         'args': [
           '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter',
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index e1dce08..21dd8f8f 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -432,7 +432,7 @@
     'identifier': 'BRYA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'brya',
-      'cros_img': 'brya-release/R120-15639.0.0',
+      'cros_img': 'brya-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -441,7 +441,7 @@
     'identifier': 'BRYA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'brya',
-      'cros_img': 'brya-release/R120-15639.0.0',
+      'cros_img': 'brya-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -474,7 +474,7 @@
     'identifier': 'DEDEDE_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'dedede',
-      'cros_img': 'dedede-release/R120-15639.0.0',
+      'cros_img': 'dedede-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -503,7 +503,7 @@
     'identifier': 'FIZZ_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'fizz',
-      'cros_img': 'fizz-release/R120-15639.0.0',
+      'cros_img': 'fizz-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -536,7 +536,7 @@
     'identifier': 'GUYBRUSH_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'guybrush',
-      'cros_img': 'guybrush-release/R120-15639.0.0',
+      'cros_img': 'guybrush-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -569,7 +569,7 @@
     'identifier': 'PUFF_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'puff',
-      'cros_img': 'puff-release/R120-15639.0.0',
+      'cros_img': 'puff-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -602,7 +602,7 @@
     'identifier': 'EVE_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-public/R120-15639.0.0',
+      'cros_img': 'eve-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -613,7 +613,7 @@
     'identifier': 'HANA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'hana',
-      'cros_img': 'hana-release/R120-15639.0.0',
+      'cros_img': 'hana-release/R120-15642.0.0',
     },
   },
   'CROS_HANA_RELEASE_DEV': {
@@ -641,7 +641,7 @@
     'identifier': 'JACUZZI_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R120-15639.0.0',
+      'cros_img': 'jacuzzi-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -663,7 +663,7 @@
     'identifier': 'JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R120-15639.0.0',
+      'cros_img': 'jacuzzi-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
     },
   },
@@ -678,7 +678,7 @@
     'identifier': 'JACUZZI_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R120-15639.0.0',
+      'cros_img': 'jacuzzi-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -686,7 +686,7 @@
     'identifier': 'JACUZZI_CQ_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R120-15639.0.0',
+      'cros_img': 'jacuzzi-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
@@ -696,7 +696,7 @@
     'identifier': 'TROGDOR_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'trogdor',
-      'cros_img': 'trogdor-public/R120-15639.0.0',
+      'cros_img': 'trogdor-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -704,7 +704,7 @@
     'identifier': 'OCTOPUS_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-public/R120-15639.0.0',
+      'cros_img': 'octopus-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -720,7 +720,7 @@
     'identifier': 'OCTOPUS_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-release/R120-15639.0.0',
+      'cros_img': 'octopus-release/R120-15642.0.0',
     },
   },
   'CROS_OCTOPUS_RELEASE_DEV': {
@@ -748,7 +748,7 @@
     'identifier': 'STRONGBAD_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'strongbad',
-      'cros_img': 'strongbad-release/R120-15639.0.0',
+      'cros_img': 'strongbad-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -777,7 +777,7 @@
     'identifier': 'TROGDOR_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'trogdor',
-      'cros_img': 'trogdor-release/R120-15639.0.0',
+      'cros_img': 'trogdor-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
     },
   },
@@ -786,7 +786,7 @@
     'skylab': {
       'cros_board': 'volteer',
       'cros_model': 'voxel',
-      'cros_img': 'volteer-public/R120-15639.0.0',
+      'cros_img': 'volteer-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -797,7 +797,7 @@
     'identifier': 'VOLTEER_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'volteer',
-      'cros_img': 'volteer-release/R119-15629.0.0',
+      'cros_img': 'volteer-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
     },
   },
diff --git a/infra/config/lib/builder_health_indicators.star b/infra/config/lib/builder_health_indicators.star
index 41b42722..6f13bde 100644
--- a/infra/config/lib/builder_health_indicators.star
+++ b/infra/config/lib/builder_health_indicators.star
@@ -559,7 +559,6 @@
         "android-webview-10-x86-rel-tests",
         "android-webview-12-x64-dbg",
         "android-webview-13-x64-dbg",
-        "android-webview-nougat-arm64-dbg",
         "android-webview-oreo-arm64-dbg",
         "android-webview-pie-arm64-dbg",
         "android-webview-pie-x86-wpt-fyi-rel",
@@ -571,7 +570,6 @@
         "android_compile_x86_dbg",
         "android_cronet",
         "android_optional_gpu_tests_rel",
-        "android_unswarmed_pixel_aosp",
         "branch-config-verifier",
         "builder-config-verifier",
         "chromeos-amd64-generic-asan-rel",
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star
index 0c68df0..d3c9f57 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -79,43 +79,6 @@
 )
 
 ci.thin_tester(
-    name = "Android WebView N (dbg)",
-    branch_selector = branches.selector.ANDROID_BRANCHES,
-    triggered_by = ["ci/Android arm64 Builder (dbg)"],
-    builder_spec = builder_config.builder_spec(
-        execution_mode = builder_config.execution_mode.TEST,
-        gclient_config = builder_config.gclient_config(
-            config = "chromium",
-            apply_configs = [
-                "android",
-            ],
-        ),
-        chromium_config = builder_config.chromium_config(
-            config = "android",
-            apply_configs = [
-                "download_xr_test_apks",
-            ],
-            build_config = builder_config.build_config.DEBUG,
-            target_bits = 64,
-            target_platform = builder_config.target_platform.ANDROID,
-        ),
-        android_config = builder_config.android_config(
-            config = "main_builder_mb",
-            apply_configs = [
-                "remove_all_system_webviews",
-            ],
-        ),
-        build_gs_bucket = "chromium-android-archive",
-    ),
-    console_view_entry = consoles.console_view_entry(
-        category = "tester|webview",
-        short_name = "N",
-    ),
-    cq_mirrors_console_view = "mirrors",
-    contact_team_email = "woa-engprod@google.com",
-)
-
-ci.thin_tester(
     name = "Android WebView O (dbg)",
     branch_selector = branches.selector.ANDROID_BRANCHES,
     triggered_by = ["ci/Android arm64 Builder (dbg)"],
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
index 90f6488..8428123 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -586,16 +586,6 @@
 )
 
 try_.builder(
-    name = "android-webview-nougat-arm64-dbg",
-    branch_selector = branches.selector.ANDROID_BRANCHES,
-    mirrors = [
-        "ci/Android arm64 Builder (dbg)",
-        "ci/Android WebView N (dbg)",
-    ],
-    reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
-)
-
-try_.builder(
     name = "android-webview-oreo-arm64-dbg",
     branch_selector = branches.selector.ANDROID_BRANCHES,
     mirrors = [
@@ -800,14 +790,6 @@
 )
 
 try_.builder(
-    name = "android_unswarmed_pixel_aosp",
-    mirrors = [
-        "ci/Android arm64 Builder (dbg)",
-        "ci/Android WebView N (dbg)",
-    ],
-)
-
-try_.builder(
     name = "try-nougat-phone-tester",
     branch_selector = branches.selector.ANDROID_BRANCHES,
     mirrors = [
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
index 283edbc..370725e6 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
@@ -140,9 +140,10 @@
     mirrors = [
         "ci/lacros-amd64-generic-rel",
     ],
+    builderless = not settings.is_main,
     contact_team_email = "chrome-desktop-engprod@google.com",
     tryjob = try_.job(
-        experiment_percentage = 1,
+        experiment_percentage = 50,
     ),
 )
 
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star
index 269df8b6..65a26fb 100644
--- a/infra/config/targets/basic_suites.star
+++ b/infra/config/targets/basic_suites.star
@@ -4978,12 +4978,6 @@
 targets.legacy_basic_suite(
     name = "linux_lacros_chrome_browsertests_non_version_skew",
     tests = {
-        "lacros_chrome_browsertests": targets.legacy_test_config(
-            test = "lacros_chrome_browsertests",
-            args = [
-                "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter",
-            ],
-        ),
         "lacros_chrome_browsertests_run_in_series": targets.legacy_test_config(
             test = "lacros_chrome_browsertests_run_in_series",
             args = [
@@ -4999,11 +4993,6 @@
 targets.legacy_basic_suite(
     name = "linux_lacros_chrome_browsertests_version_skew",
     tests = {
-        "lacros_chrome_browsertests": targets.legacy_test_config(
-            args = [
-                "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-            ],
-        ),
         "lacros_chrome_browsertests_run_in_series": targets.legacy_test_config(
             args = [
                 "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
diff --git a/infra/config/targets/cros-skylab-variants.json b/infra/config/targets/cros-skylab-variants.json
index a0b584c..637486c1 100644
--- a/infra/config/targets/cros-skylab-variants.json
+++ b/infra/config/targets/cros-skylab-variants.json
@@ -2,8 +2,8 @@
   "CROS_BRYA_RELEASE_ASH_LKGM": {
     "skylab": {
       "cros_board": "brya",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "brya-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "brya-release/R120-15642.0.0",
       "autotest_name": "tast.chrome-from-gcs",
       "dut_pool": "chrome"
     },
@@ -12,8 +12,8 @@
   "CROS_BRYA_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "brya",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "brya-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "brya-release/R120-15642.0.0",
       "autotest_name": "tast.lacros-from-gcs",
       "dut_pool": "chrome"
     },
@@ -53,8 +53,8 @@
   "CROS_DEDEDE_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "dedede",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "dedede-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "dedede-release/R120-15642.0.0",
       "autotest_name": "tast.lacros-from-gcs"
     },
     "enabled": true,
@@ -90,8 +90,8 @@
   "CROS_FIZZ_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "fizz",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "fizz-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "fizz-release/R120-15642.0.0",
       "autotest_name": "tast.lacros-from-gcs",
       "dut_pool": "chrome"
     },
@@ -131,8 +131,8 @@
   "CROS_GUYBRUSH_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "guybrush",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "guybrush-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "guybrush-release/R120-15642.0.0",
       "autotest_name": "tast.lacros-from-gcs",
       "dut_pool": "chrome"
     },
@@ -172,8 +172,8 @@
   "CROS_PUFF_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "puff",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "puff-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "puff-release/R120-15642.0.0",
       "autotest_name": "tast.lacros-from-gcs",
       "dut_pool": "chrome"
     },
@@ -213,8 +213,8 @@
   "CROS_EVE_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "eve",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "eve-public/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "eve-public/R120-15642.0.0",
       "bucket": "chromiumos-image-archive",
       "dut_pool": "chromium",
       "public_builder": "cros_test_platform_public",
@@ -226,8 +226,8 @@
   "CROS_HANA_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "hana",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "hana-release/R120-15639.0.0"
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "hana-release/R120-15642.0.0"
     },
     "enabled": true,
     "identifier": "HANA_RELEASE_LKGM"
@@ -262,8 +262,8 @@
   "CROS_JACUZZI_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "jacuzzi-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "jacuzzi-release/R120-15642.0.0",
       "autotest_name": "tast.lacros-from-gcs"
     },
     "enabled": true,
@@ -290,8 +290,8 @@
   "CROS_JACUZZI_RELEASE_CHROME_FROM_TLS_ASH_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "jacuzzi-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "jacuzzi-release/R120-15642.0.0",
       "autotest_name": "tast.chrome-from-gcs"
     },
     "identifier": "JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM"
@@ -308,8 +308,8 @@
   "CROS_JACUZZI_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "jacuzzi-public/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "jacuzzi-public/R120-15642.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -318,8 +318,8 @@
   "CROS_JACUZZI_CQ_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "jacuzzi-public/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "jacuzzi-public/R120-15642.0.0",
       "bucket": "chromiumos-image-archive",
       "public_builder": "cros_test_platform_public",
       "public_builder_bucket": "testplatform-public"
@@ -330,8 +330,8 @@
   "CROS_TROGDOR_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "trogdor",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "trogdor-public/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "trogdor-public/R120-15642.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -340,8 +340,8 @@
   "CROS_OCTOPUS_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "octopus",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "octopus-public/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "octopus-public/R120-15642.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -358,8 +358,8 @@
   "CROS_OCTOPUS_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "octopus",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "octopus-release/R120-15639.0.0"
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "octopus-release/R120-15642.0.0"
     },
     "enabled": true,
     "identifier": "OCTOPUS_RELEASE_LKGM"
@@ -394,8 +394,8 @@
   "CROS_STRONGBAD_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "strongbad",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "strongbad-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "strongbad-release/R120-15642.0.0",
       "autotest_name": "tast.lacros-from-gcs"
     },
     "enabled": true,
@@ -431,8 +431,8 @@
   "CROS_TROGDOR_RELEASE_ASH_LKGM": {
     "skylab": {
       "cros_board": "trogdor",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "trogdor-release/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "trogdor-release/R120-15642.0.0",
       "autotest_name": "tast.chrome-from-gcs"
     },
     "identifier": "TROGDOR_RELEASE_LKGM"
@@ -441,8 +441,8 @@
     "skylab": {
       "cros_board": "volteer",
       "cros_model": "voxel",
-      "cros_chrome_version": "120.0.6051.0",
-      "cros_img": "volteer-public/R120-15639.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "volteer-public/R120-15642.0.0",
       "bucket": "chromiumos-image-archive",
       "dut_pool": "chromium",
       "public_builder": "cros_test_platform_public",
@@ -454,8 +454,8 @@
   "CROS_VOLTEER_RELEASE_ASH_LKGM": {
     "skylab": {
       "cros_board": "volteer",
-      "cros_chrome_version": "119.0.6034.0",
-      "cros_img": "volteer-release/R119-15629.0.0",
+      "cros_chrome_version": "120.0.6057.0",
+      "cros_img": "volteer-release/R120-15642.0.0",
       "autotest_name": "tast.chrome-from-gcs"
     },
     "identifier": "VOLTEER_RELEASE_LKGM"
diff --git a/infra/config/targets/targets.star b/infra/config/targets/targets.star
index 99b2d3d5..ef44687 100644
--- a/infra/config/targets/targets.star
+++ b/infra/config/targets/targets.star
@@ -1257,11 +1257,6 @@
 )
 
 targets.windowed_test_launcher(
-    name = "lacros_chrome_browsertests",
-    label = "//chrome/test:lacros_chrome_browsertests",
-)
-
-targets.windowed_test_launcher(
     name = "lacros_chrome_browsertests_run_in_series",
     label = "//chrome/test:lacros_chrome_browsertests_run_in_series",
     args = [
diff --git a/internal b/internal
index 302dcc1..f11a7d3 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 302dcc1312975e57a6cb0728959e87aa4d93e1d0
+Subproject commit f11a7d33a9d0c660a8c3b3b2fca966b25c575b3e
diff --git a/ios/chrome/browser/commerce/model/BUILD.gn b/ios/chrome/browser/commerce/model/BUILD.gn
index 93006c0..18af6ab5 100644
--- a/ios/chrome/browser/commerce/model/BUILD.gn
+++ b/ios/chrome/browser/commerce/model/BUILD.gn
@@ -38,6 +38,7 @@
     ":session_proto_db",
     "//base",
     "//components/commerce/core:commerce_subscription_db_content_proto",
+    "//components/commerce/core:country_code_checker",
     "//components/commerce/core:feature_list",
     "//components/commerce/core:parcel_tracking_db_content_proto",
     "//components/commerce/core:shopping_service",
diff --git a/ios/chrome/browser/commerce/model/push_notification/BUILD.gn b/ios/chrome/browser/commerce/model/push_notification/BUILD.gn
index 142d271..8a0662f 100644
--- a/ios/chrome/browser/commerce/model/push_notification/BUILD.gn
+++ b/ios/chrome/browser/commerce/model/push_notification/BUILD.gn
@@ -13,6 +13,7 @@
   deps = [
     "//base",
     "//components/bookmarks/browser:browser",
+    "//components/commerce/core:country_code_checker",
     "//components/commerce/core:feature_list",
     "//components/commerce/core:proto",
     "//components/commerce/core:shopping_service",
diff --git a/ios/chrome/browser/commerce/model/push_notification/push_notification_feature.mm b/ios/chrome/browser/commerce/model/push_notification/push_notification_feature.mm
index 1d4c183..12e870b 100644
--- a/ios/chrome/browser/commerce/model/push_notification/push_notification_feature.mm
+++ b/ios/chrome/browser/commerce/model/push_notification/push_notification_feature.mm
@@ -8,6 +8,7 @@
 #import "base/strings/string_util.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/commerce/core/commerce_feature_list.h"
+#import "components/commerce/core/country_code_checker.h"
 #import "components/commerce/core/shopping_service.h"
 #import "ios/chrome/browser/commerce/model/shopping_service_factory.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
diff --git a/ios/chrome/browser/commerce/model/shopping_service_factory.mm b/ios/chrome/browser/commerce/model/shopping_service_factory.mm
index 4f02512..2d70995 100644
--- a/ios/chrome/browser/commerce/model/shopping_service_factory.mm
+++ b/ios/chrome/browser/commerce/model/shopping_service_factory.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/commerce/model/shopping_service_factory.h"
 
 #import "components/commerce/core/commerce_feature_list.h"
+#import "components/commerce/core/country_code_checker.h"
 #import "components/commerce/core/proto/commerce_subscription_db_content.pb.h"
 #import "components/commerce/core/proto/parcel_tracking_db_content.pb.h"
 #import "components/commerce/core/shopping_service.h"
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_list.swift b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_list.swift
index bab4aff6..1990945 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_list.swift
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_list.swift
@@ -234,7 +234,7 @@
     return destination.shown
       ? L10nUtils.stringWithFixup(
         messageId: IDS_IOS_OVERFLOW_MENU_HIDE_ITEM_ACCESSIBILITY_HINT)
-      : ""
+      : L10nUtils.stringWithFixup(messageId: IDS_IOS_OVERFLOW_MENU_SHOW_ITEM_ACCESSIBILITY_HINT)
   }
 
   /// Finds the lower and upper breakpoint above and below `width`.
diff --git a/ios_internal b/ios_internal
index 51e348d..d8dd6ed 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 51e348d2f6443ffa00ae6db783ba2257f434d95e
+Subproject commit d8dd6ed38966faf2a6db0ac48dfbe1e33c671755
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 1620c72..8a6d9c6 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -671,6 +671,11 @@
 #endif
 );
 
+// Allows document picture-in-picture pages to request capture.
+BASE_FEATURE(kDocumentPictureInPictureCapture,
+             "DocumentPictureInPictureCapture",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Falls back to other decoders after audio/video decode error happens. The
 // implementation may choose different strategies on when to fallback. See
 // DecoderStream for details. When disabled, playback will fail immediately
@@ -1094,6 +1099,11 @@
              "AutoplayDisableSettings",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Whether we should allow color space changes to flush AcceleratedVideoDecoder.
+BASE_FEATURE(kAVDColorSpaceChanges,
+             "AVDColorSpaceChanges",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 #if BUILDFLAG(IS_ANDROID)
 // Should we allow video playback to use an overlay if it's not needed for
 // security?  Normally, we'd always want to allow this, except as part of the
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index e53c209ed..4c45308 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -167,6 +167,7 @@
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kAutoPictureInPictureForVideoPlayback);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kAutoplayIgnoreWebAudio);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kAutoplayDisableSettings);
+MEDIA_EXPORT BASE_DECLARE_FEATURE(kAVDColorSpaceChanges);
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kCameraMicEffects);
@@ -215,6 +216,7 @@
 #endif
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kD3D11VideoDecoderUseSharedHandle);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kDedicatedMediaServiceThread);
+MEDIA_EXPORT BASE_DECLARE_FEATURE(kDocumentPictureInPictureCapture);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kEnableTabMuting);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kExposeSwDecodersToWebRTC);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kExternalClearKeyForTesting);
diff --git a/media/fuchsia/video/fuchsia_video_decoder.cc b/media/fuchsia/video/fuchsia_video_decoder.cc
index 55aae87..63b34cf 100644
--- a/media/fuchsia/video/fuchsia_video_decoder.cc
+++ b/media/fuchsia/video/fuchsia_video_decoder.cc
@@ -144,8 +144,9 @@
     } else {
       mailbox_ =
           raster_context_provider_->SharedImageInterface()->CreateSharedImage(
-              gmb.get(), nullptr, color_space, kTopLeft_GrSurfaceOrigin,
-              kPremul_SkAlphaType, usage, "FuchsiaVideoDecoder");
+              gmb.get(), nullptr, gfx::BufferPlane::DEFAULT, color_space,
+              kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
+              "FuchsiaVideoDecoder");
     }
 
     create_sync_token_ = raster_context_provider_->SharedImageInterface()
diff --git a/media/gpu/accelerated_video_decoder.h b/media/gpu/accelerated_video_decoder.h
index 4b1ae46..e49b13bc 100644
--- a/media/gpu/accelerated_video_decoder.h
+++ b/media/gpu/accelerated_video_decoder.h
@@ -24,13 +24,12 @@
 // frame and state management.
 class MEDIA_GPU_EXPORT AcceleratedVideoDecoder {
  public:
-  AcceleratedVideoDecoder() {}
+  AcceleratedVideoDecoder() = default;
+  virtual ~AcceleratedVideoDecoder() = default;
 
   AcceleratedVideoDecoder(const AcceleratedVideoDecoder&) = delete;
   AcceleratedVideoDecoder& operator=(const AcceleratedVideoDecoder&) = delete;
 
-  virtual ~AcceleratedVideoDecoder() {}
-
   // Set the buffer owned by |decoder_buffer| as the current source of encoded
   // stream data. AcceleratedVideoDecoder doesn't have an ownership of the
   // buffer. |decoder_buffer| must be kept alive until Decode() returns
@@ -54,18 +53,10 @@
     // in decoding; in future it could perhaps be possible to fall back
     // to software decoding instead.
     // kStreamError,  // Error in stream.
-    kConfigChange,      // This is returned when some configuration (e.g.
-                        // profile or picture size) is changed. A client may
-                        // need to apply the client side the configuration
-                        // properly (e.g. allocate buffers with the new
-                        // resolution).
-    kColorSpaceChange,  // This is returned if the video color space is changed.
-                        // Color space changes off of key frames are discarded
-                        // only for VP9 decoder. When both ConfigChange and
-                        // ColorSpaceChange occur together, ConfigChange is
-                        // preferred over ColorSpaceChange. When triggered, it
-                        // is used for creating new shared images for the
-                        // D3D11VideoDecoder.
+    kConfigChange,  // Stream configuration has changed. E.g., profile, coded
+                    // size, bit depth, or color space. A client may need to
+                    // reallocate resources to apply the new configuration
+                    // properly. E.g. allocate buffers with the new resolution.
     kRanOutOfStreamData,  // Need more stream data to proceed.
     kRanOutOfSurfaces,    // Waiting for the client to free up output surfaces.
     kNeedContextUpdate,   // Waiting for the client to update decoding context
diff --git a/media/gpu/av1_decoder.cc b/media/gpu/av1_decoder.cc
index 192b2a9..5145025 100644
--- a/media/gpu/av1_decoder.cc
+++ b/media/gpu/av1_decoder.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/ranges/algorithm.h"
 #include "media/base/limits.h"
+#include "media/base/media_switches.h"
 #include "media/gpu/av1_picture.h"
 #include "third_party/libgav1/src/src/decoder_state.h"
 #include "third_party/libgav1/src/src/gav1/status_code.h"
@@ -321,12 +322,24 @@
           new_color_space = container_color_space_;
         }
 
+        bool is_color_space_change = false;
+        if (base::FeatureList::IsEnabled(kAVDColorSpaceChanges)) {
+          is_color_space_change = new_color_space.IsSpecified() &&
+                                  new_color_space != picture_color_space_;
+        }
+
         ClearReferenceFrames();
         // Issues kConfigChange only if either the dimensions, profile or bit
         // depth is changed.
         if (frame_size_ != new_frame_size ||
             visible_rect_ != new_visible_rect || profile_ != new_profile ||
-            bit_depth_ != new_bit_depth) {
+            bit_depth_ != new_bit_depth || is_color_space_change) {
+          DVLOG(1) << "New profile: " << GetProfileName(new_profile)
+                   << ", new resolution: " << new_frame_size.ToString()
+                   << ", new visible rect: " << new_visible_rect.ToString()
+                   << ", new bit depth: "
+                   << base::strict_cast<int>(new_bit_depth)
+                   << ", new color space: " << new_color_space.ToString();
           frame_size_ = new_frame_size;
           visible_rect_ = new_visible_rect;
           profile_ = new_profile;
@@ -335,14 +348,6 @@
           clear_current_frame.ReplaceClosure(base::DoNothing());
           return kConfigChange;
         }
-
-        // Trigger color space change if the previous picture color space is
-        // different from new color space.
-        if (new_color_space.IsSpecified() &&
-            picture_color_space_ != new_color_space) {
-          picture_color_space_ = new_color_space;
-          return kColorSpaceChange;
-        }
       }
     }
 
diff --git a/media/gpu/h264_decoder.cc b/media/gpu/h264_decoder.cc
index e3ca4f6c..f408c3d 100644
--- a/media/gpu/h264_decoder.cc
+++ b/media/gpu/h264_decoder.cc
@@ -1118,9 +1118,7 @@
   return true;
 }
 
-bool H264Decoder::ProcessSPS(int sps_id,
-                             bool* need_new_buffers,
-                             bool* color_space_changed) {
+bool H264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) {
   DVLOG(4) << "Processing SPS id:" << sps_id;
 
   const H264SPS* sps = parser_.GetSPS(sps_id);
@@ -1217,15 +1215,24 @@
     new_color_space = container_color_space_;
   }
 
+  bool is_color_space_change = false;
+  if (base::FeatureList::IsEnabled(kAVDColorSpaceChanges)) {
+    is_color_space_change = new_color_space.IsSpecified() &&
+                            new_color_space != picture_color_space_;
+  }
+
   if (pic_size_ != new_pic_size || dpb_.max_num_pics() != max_dpb_size ||
-      profile_ != new_profile || bit_depth_ != new_bit_depth) {
-    if (!Flush())
+      profile_ != new_profile || bit_depth_ != new_bit_depth ||
+      is_color_space_change) {
+    if (!Flush()) {
       return false;
+    }
     DVLOG(1) << "Codec profile: " << GetProfileName(new_profile)
              << ", level: " << base::strict_cast<int>(level)
              << ", DPB size: " << max_dpb_size
              << ", Picture size: " << new_pic_size.ToString()
-             << ", bit depth: " << base::strict_cast<int>(new_bit_depth);
+             << ", bit depth: " << base::strict_cast<int>(new_bit_depth)
+             << ", color_space: " << new_color_space.ToString();
     *need_new_buffers = true;
     profile_ = new_profile;
     bit_depth_ = new_bit_depth;
@@ -1234,18 +1241,6 @@
     dpb_.set_max_num_pics(max_dpb_size);
   }
 
-  // If the new color space is specified and different from picture color space
-  // then trigger color space change.
-  if (new_color_space.IsSpecified() &&
-      new_color_space != picture_color_space_) {
-    if (!Flush()) {
-      return false;
-    }
-    DVLOG(1) << "New color space: " << new_color_space.ToString();
-    picture_color_space_ = new_color_space;
-    *color_space_changed = true;
-  }
-
   gfx::Rect new_visible_rect = sps->GetVisibleRect().value_or(gfx::Rect());
   if (visible_rect_ != new_visible_rect) {
     DVLOG(2) << "New visible rect: " << new_visible_rect.ToString();
@@ -1602,8 +1597,7 @@
           SET_ERROR_AND_RETURN();
 
         bool need_new_buffers = false;
-        bool color_space_changed = false;
-        if (!ProcessSPS(sps_id, &need_new_buffers, &color_space_changed)) {
+        if (!ProcessSPS(sps_id, &need_new_buffers)) {
           SET_ERROR_AND_RETURN();
         }
         accelerator_->ProcessSPS(
@@ -1615,7 +1609,7 @@
         if (state_ == State::kNeedStreamMetadata)
           state_ = State::kAfterReset;
 
-        if (need_new_buffers || color_space_changed) {
+        if (need_new_buffers) {
           curr_pic_ = nullptr;
           curr_nalu_ = nullptr;
           ref_pic_list_p0_.clear();
@@ -1626,9 +1620,6 @@
         if (need_new_buffers) {
           return kConfigChange;
         }
-        if (color_space_changed) {
-          return kColorSpaceChange;
-        }
         break;
       }
 
diff --git a/media/gpu/h264_decoder.h b/media/gpu/h264_decoder.h
index 039d265..9a37813 100644
--- a/media/gpu/h264_decoder.h
+++ b/media/gpu/h264_decoder.h
@@ -239,9 +239,7 @@
   };
 
   // Process H264 stream structures.
-  bool ProcessSPS(int sps_id,
-                  bool* need_new_buffers,
-                  bool* color_space_changed);
+  bool ProcessSPS(int sps_id, bool* need_new_buffers);
 
   // Processes a CENCv1 encrypted slice header and fills in |curr_slice_hdr_|
   // with the relevant parsed fields.
diff --git a/media/gpu/h265_decoder.cc b/media/gpu/h265_decoder.cc
index c88402e..a2aaab29 100644
--- a/media/gpu/h265_decoder.cc
+++ b/media/gpu/h265_decoder.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/notreached.h"
 #include "media/base/limits.h"
+#include "media/base/media_switches.h"
 #include "media/gpu/h265_decoder.h"
 
 namespace media {
@@ -359,9 +360,8 @@
           state_ = kTryPreprocessCurrentSlice;
           if (curr_slice_hdr_->irap_pic) {
             bool need_new_buffers = false;
-            bool color_space_changed = false;
             if (!ProcessPPS(curr_slice_hdr_->slice_pic_parameter_set_id,
-                            &need_new_buffers, &color_space_changed)) {
+                            &need_new_buffers)) {
               SET_ERROR_AND_RETURN();
             }
 
@@ -369,10 +369,6 @@
               curr_pic_ = nullptr;
               return kConfigChange;
             }
-            if (color_space_changed) {
-              curr_pic_ = nullptr;
-              return kColorSpaceChange;
-            }
           }
         }
 
@@ -457,8 +453,7 @@
         // active stream.
         if (curr_pps_id_ == -1) {
           bool need_new_buffers = false;
-          bool color_space_changed = false;
-          if (!ProcessPPS(pps_id, &need_new_buffers, &color_space_changed)) {
+          if (!ProcessPPS(pps_id, &need_new_buffers)) {
             SET_ERROR_AND_RETURN();
           }
 
@@ -466,10 +461,6 @@
             curr_nalu_.reset();
             return kConfigChange;
           }
-          if (color_space_changed) {
-            curr_nalu_.reset();
-            return kColorSpaceChange;
-          }
         }
 
         break;
@@ -571,9 +562,7 @@
   return dpb_.max_num_pics();
 }
 
-bool H265Decoder::ProcessPPS(int pps_id,
-                             bool* need_new_buffers,
-                             bool* color_space_changed) {
+bool H265Decoder::ProcessPPS(int pps_id, bool* need_new_buffers) {
   DVLOG(4) << "Processing PPS id:" << pps_id;
 
   const H265PPS* pps = parser_.GetPPS(pps_id);
@@ -587,10 +576,6 @@
   if (need_new_buffers)
     *need_new_buffers = false;
 
-  if (color_space_changed) {
-    *color_space_changed = false;
-  }
-
   gfx::Size new_pic_size = sps->GetCodedSize();
   gfx::Rect new_visible_rect = sps->GetVisibleRect();
   if (visible_rect_ != new_visible_rect) {
@@ -632,9 +617,15 @@
     new_color_space = container_color_space_;
   }
 
+  bool is_color_space_change = false;
+  if (base::FeatureList::IsEnabled(kAVDColorSpaceChanges)) {
+    is_color_space_change = new_color_space.IsSpecified() &&
+                            new_color_space != picture_color_space_;
+  }
+
   if (pic_size_ != new_pic_size || dpb_.max_num_pics() != sps->max_dpb_size ||
       profile_ != new_profile || bit_depth_ != new_bit_depth ||
-      chroma_sampling_ != new_chroma_sampling) {
+      chroma_sampling_ != new_chroma_sampling || is_color_space_change) {
     if (!Flush())
       return false;
     DVLOG(1) << "Codec profile: " << GetProfileName(new_profile)
@@ -654,16 +645,6 @@
       *need_new_buffers = true;
   }
 
-  if (new_color_space.IsSpecified() &&
-      new_color_space != picture_color_space_) {
-    if (!Flush()) {
-      return false;
-    }
-    DVLOG(1) << "Picture color space: " << new_color_space.ToString();
-    picture_color_space_ = new_color_space;
-    *color_space_changed = true;
-  }
-
   return true;
 }
 
diff --git a/media/gpu/h265_decoder.h b/media/gpu/h265_decoder.h
index cc904a77..d50ff58 100644
--- a/media/gpu/h265_decoder.h
+++ b/media/gpu/h265_decoder.h
@@ -226,9 +226,7 @@
   };
 
   // Process H265 stream structures.
-  bool ProcessPPS(int pps_id,
-                  bool* need_new_buffers,
-                  bool* color_space_changed);
+  bool ProcessPPS(int pps_id, bool* need_new_buffers);
 
   // Process current slice header to discover if we need to start a new picture,
   // finishing up the current one.
diff --git a/media/gpu/mac/video_toolbox_video_decoder.cc b/media/gpu/mac/video_toolbox_video_decoder.cc
index 4e38b4b..70e6420c 100644
--- a/media/gpu/mac/video_toolbox_video_decoder.cc
+++ b/media/gpu/mac/video_toolbox_video_decoder.cc
@@ -265,7 +265,6 @@
         return;
 
       case AcceleratedVideoDecoder::kConfigChange:
-      case AcceleratedVideoDecoder::kColorSpaceChange:
         continue;
 
       case AcceleratedVideoDecoder::kRanOutOfStreamData:
diff --git a/media/gpu/v4l2/stateless/device.cc b/media/gpu/v4l2/stateless/device.cc
index 4932933..c25290e8 100644
--- a/media/gpu/v4l2/stateless/device.cc
+++ b/media/gpu/v4l2/stateless/device.cc
@@ -24,6 +24,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "media/base/video_types.h"
 #include "media/gpu/macros.h"
+#include "media/gpu/v4l2/stateless/utils.h"
 #include "media/gpu/v4l2/v4l2_utils.h"
 
 // This has not been accepted upstream.
@@ -119,6 +120,7 @@
 bool Device::SetInputFormat(VideoCodec codec,
                             gfx::Size resolution,
                             size_t encoded_buffer_size) {
+  DVLOGF(4);
   const uint32_t pix_fmt = VideoCodecToV4L2PixFmt(codec);
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
@@ -161,7 +163,9 @@
     }
   }
 
-  VPLOGF(1) << "VIDIOC_ENUM_FRAMESIZES failed, using default values";
+  VPLOGF(1) << "VIDIOC_ENUM_FRAMESIZES failed for "
+            << media::FourccToString(frame_size.pixel_format)
+            << ", using default values";
   return std::make_pair(kDefaultMinCodedSize, kDefaultMaxCodedSize);
 }
 
@@ -178,9 +182,7 @@
   const auto profile_cid = kV4L2CodecPixFmtToProfileCID.at(pix_fmt);
 
   v4l2_queryctrl query_ctrl = {.id = base::strict_cast<__u32>(profile_cid)};
-  const int ret = IoctlDevice(VIDIOC_QUERYCTRL, &query_ctrl);
-  if (ret != kIoctlOk) {
-    VPLOGF(1) << "VIDIOC_QUERYCTRL failed.";
+  if (IoctlDevice(VIDIOC_QUERYCTRL, &query_ctrl) != kIoctlOk) {
     return {};
   }
 
@@ -247,10 +249,26 @@
 
 Device::~Device() {}
 
-int Device::IoctlDevice(int request, void* arg) {
-  DCHECK(device_fd_.is_valid());
+int Device::Ioctl(const base::ScopedFD& fd, uint64_t request, void* arg) {
+  DCHECK(fd.is_valid());
+  const int ret = HANDLE_EINTR(ioctl(fd.get(), request, arg));
+  if (ret != kIoctlOk) {
+    const logging::SystemErrorCode err = logging::GetLastSystemErrorCode();
+    if (err == EAGAIN && request == VIDIOC_DQBUF) {
+      DVLOGF(4) << IoctlToString(request)
+                << " failed: " << logging::SystemErrorCodeToString(err)
+                << ": This is _usually_ an expected failure from trying to "
+                   "VIDIOC_DQBUF a buffer that is not done being processed.";
+    } else {
+      DVLOGF(1) << IoctlToString(request)
+                << " failed: " << logging::SystemErrorCodeToString(err);
+    }
+  }
+  return ret;
+}
 
-  return HANDLE_EINTR(ioctl(device_fd_.get(), request, arg));
+int Device::IoctlDevice(uint64_t request, void* arg) {
+  return Ioctl(device_fd_, request, arg);
 }
 
 }  //  namespace media
diff --git a/media/gpu/v4l2/stateless/device.h b/media/gpu/v4l2/stateless/device.h
index deca4fa..33c6662 100644
--- a/media/gpu/v4l2/stateless/device.h
+++ b/media/gpu/v4l2/stateless/device.h
@@ -66,7 +66,8 @@
 
  protected:
   virtual ~Device();
-  int IoctlDevice(int request, void* arg);
+  int Ioctl(const base::ScopedFD& fd, uint64_t request, void* arg);
+  int IoctlDevice(uint64_t request, void* arg);
   bool OpenDevice();
 };
 
diff --git a/media/gpu/v4l2/stateless/stateless_device.cc b/media/gpu/v4l2/stateless/stateless_device.cc
index 5d17482..bf9720f 100644
--- a/media/gpu/v4l2/stateless/stateless_device.cc
+++ b/media/gpu/v4l2/stateless/stateless_device.cc
@@ -34,7 +34,6 @@
   struct v4l2_capability caps;
   const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
   if (IoctlDevice(VIDIOC_QUERYCAP, &caps) != kIoctlOk) {
-    VPLOGF(1) << "VIDIOC_QUERYCAP failed.";
     return false;
   }
 
@@ -51,7 +50,6 @@
   reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
   reqbufs.memory = V4L2_MEMORY_MMAP;
   if (IoctlDevice(VIDIOC_REQBUFS, &reqbufs) != kIoctlOk) {
-    VPLOGF(1) << "VIDIOC_REQBUFS failed.";
     return false;
   }
 
@@ -71,7 +69,7 @@
   memset(&query_ctrl, 0, sizeof(query_ctrl));
   query_ctrl.id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR;
 
-  return IoctlDevice(VIDIOC_QUERYCTRL, &query_ctrl) == 0;
+  return (IoctlDevice(VIDIOC_QUERYCTRL, &query_ctrl) == kIoctlOk);
 }
 
 StatelessDevice::~StatelessDevice() {}
diff --git a/media/gpu/v4l2/stateless/utils.cc b/media/gpu/v4l2/stateless/utils.cc
index ccccf216..cb9a1f18 100644
--- a/media/gpu/v4l2/stateless/utils.cc
+++ b/media/gpu/v4l2/stateless/utils.cc
@@ -4,6 +4,8 @@
 
 #include "media/gpu/v4l2/stateless/utils.h"
 
+#include <linux/videodev2.h>
+
 #include "media/gpu/macros.h"
 
 namespace media {
@@ -35,4 +37,48 @@
   return supported_profiles;
 }
 
+std::string IoctlToString(uint64_t request) {
+#define IOCTL_TO_STR(i) \
+  case i:               \
+    return #i;
+
+  switch (request) {
+    IOCTL_TO_STR(VIDIOC_DECODER_CMD)
+    IOCTL_TO_STR(VIDIOC_DQBUF)
+    IOCTL_TO_STR(VIDIOC_DQEVENT)
+    IOCTL_TO_STR(VIDIOC_ENCODER_CMD)
+    IOCTL_TO_STR(VIDIOC_ENUM_FMT)
+    IOCTL_TO_STR(VIDIOC_ENUM_FRAMESIZES)
+    IOCTL_TO_STR(VIDIOC_EXPBUF)
+    IOCTL_TO_STR(VIDIOC_G_CROP)
+    IOCTL_TO_STR(VIDIOC_G_EXT_CTRLS)
+    IOCTL_TO_STR(VIDIOC_G_FMT)
+    IOCTL_TO_STR(VIDIOC_G_PARM)
+    IOCTL_TO_STR(VIDIOC_G_SELECTION)
+    IOCTL_TO_STR(VIDIOC_QBUF)
+    IOCTL_TO_STR(VIDIOC_QUERYBUF)
+    IOCTL_TO_STR(VIDIOC_QUERYCAP)
+    IOCTL_TO_STR(VIDIOC_QUERYCTRL)
+    IOCTL_TO_STR(VIDIOC_QUERYMENU)
+    IOCTL_TO_STR(VIDIOC_QUERY_EXT_CTRL)
+    IOCTL_TO_STR(VIDIOC_REQBUFS)
+    IOCTL_TO_STR(VIDIOC_STREAMOFF)
+    IOCTL_TO_STR(VIDIOC_STREAMON)
+    IOCTL_TO_STR(VIDIOC_SUBSCRIBE_EVENT)
+    IOCTL_TO_STR(VIDIOC_S_CROP)
+    IOCTL_TO_STR(VIDIOC_S_CTRL)
+    IOCTL_TO_STR(VIDIOC_S_EXT_CTRLS)
+    IOCTL_TO_STR(VIDIOC_S_FMT)
+    IOCTL_TO_STR(VIDIOC_S_PARM)
+    IOCTL_TO_STR(VIDIOC_S_SELECTION)
+    IOCTL_TO_STR(VIDIOC_TRY_DECODER_CMD)
+    IOCTL_TO_STR(VIDIOC_TRY_ENCODER_CMD)
+    IOCTL_TO_STR(VIDIOC_TRY_FMT)
+    IOCTL_TO_STR(VIDIOC_UNSUBSCRIBE_EVENT)
+  }
+
+  return "unknown";
+
+#undef IOCTL_TO_STR
+}
 }  // namespace media
diff --git a/media/gpu/v4l2/stateless/utils.h b/media/gpu/v4l2/stateless/utils.h
index 248254b..606945d 100644
--- a/media/gpu/v4l2/stateless/utils.h
+++ b/media/gpu/v4l2/stateless/utils.h
@@ -11,5 +11,6 @@
 namespace media {
 VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles(
     Device* device);
+std::string IoctlToString(uint64_t request);
 }  // namespace media
 #endif  // MEDIA_GPU_V4L2_STATELESS_UTILS_H_
diff --git a/media/gpu/v4l2/stateless/v4l2_stateless_video_decoder.cc b/media/gpu/v4l2/stateless/v4l2_stateless_video_decoder.cc
index 9f35c6f..adf56cbe7 100644
--- a/media/gpu/v4l2/stateless/v4l2_stateless_video_decoder.cc
+++ b/media/gpu/v4l2/stateless/v4l2_stateless_video_decoder.cc
@@ -243,10 +243,6 @@
                      << " of resolution " << decoder_->GetPicSize().ToString();
           }
           break;
-        case AcceleratedVideoDecoder::kColorSpaceChange:
-          VLOGF(2) << "AcceleratedVideoDecoder::kColorSpaceChange";
-          NOTIMPLEMENTED();
-          break;
         case AcceleratedVideoDecoder::kRanOutOfStreamData:
           VLOGF(2) << "AcceleratedVideoDecoder::kRanOutOfStreamData";
           // Handled on first entry to function.
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
index dd2eda3..3876c62 100644
--- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
@@ -439,10 +439,6 @@
         PumpOutputSurfaces();
         return true;
 
-      case AcceleratedVideoDecoder::kColorSpaceChange:
-        NOTIMPLEMENTED_LOG_ONCE();
-        return false;
-
       case AcceleratedVideoDecoder::kRanOutOfStreamData:
         // Current decode request is finished processing.
         if (current_decode_request_) {
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc
index 0e0f902..112b825 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.cc
+++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -431,9 +431,6 @@
       SetState(State::kChangingResolution);
       client_->PrepareChangeResolution();
       break;
-    case AcceleratedVideoDecoder::kColorSpaceChange:
-      NOTIMPLEMENTED_LOG_ONCE();
-      break;
     case AcceleratedVideoDecoder::kRanOutOfSurfaces:
       // No more surfaces to decode into available, wait until client returns
       // video frames to the frame pool.
diff --git a/media/gpu/vp9_decoder.cc b/media/gpu/vp9_decoder.cc
index 8dfb1a85..9f71d15 100644
--- a/media/gpu/vp9_decoder.cc
+++ b/media/gpu/vp9_decoder.cc
@@ -291,6 +291,12 @@
 
     DCHECK(!new_pic_size.IsEmpty());
 
+    bool is_color_space_change = false;
+    if (base::FeatureList::IsEnabled(kAVDColorSpaceChanges)) {
+      is_color_space_change = new_color_space.IsSpecified() &&
+                              new_color_space != picture_color_space_;
+    }
+
     const bool is_pic_size_different = new_pic_size != pic_size_;
     const bool is_pic_size_larger = new_pic_size.width() > pic_size_.width() ||
                                     new_pic_size.height() > pic_size_.height();
@@ -298,13 +304,15 @@
         (ignore_resolution_changes_to_smaller_for_testing_
              ? is_pic_size_larger
              : is_pic_size_different) ||
-        new_profile != profile_ || curr_frame_hdr_->bit_depth != bit_depth_;
+        new_profile != profile_ || curr_frame_hdr_->bit_depth != bit_depth_ ||
+        is_color_space_change;
 
     if (is_new_configuration_different_enough) {
       DVLOG(1) << "New profile: " << GetProfileName(new_profile)
                << ", new resolution: " << new_pic_size.ToString()
                << ", new bit depth: "
-               << base::strict_cast<int>(curr_frame_hdr_->bit_depth);
+               << base::strict_cast<int>(curr_frame_hdr_->bit_depth)
+               << ", new color space: " << new_color_space.ToString();
 
       if (!curr_frame_hdr_->IsKeyframe() &&
           !(curr_frame_hdr_->IsIntra() && pic_size_.IsEmpty())) {
@@ -339,19 +347,6 @@
       return kConfigChange;
     }
 
-    if (new_color_space.IsSpecified() &&
-        new_color_space != picture_color_space_ &&
-        curr_frame_hdr_->IsKeyframe()) {
-      // TODO(posciak): This requires us to be on a keyframe (see above) and is
-      // required, because VDA clients expect all surfaces to be returned before
-      // they can cycle surface sets after receiving kConfigChange.
-      // This is only an implementation detail of VDAs and can be improved.
-      ref_frames_.Clear();
-
-      picture_color_space_ = new_color_space;
-      return kColorSpaceChange;
-    }
-
     scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture();
     if (!pic) {
       return kRanOutOfSurfaces;
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 7528ca2..3bd3187 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -643,24 +643,29 @@
       const auto new_coded_size = accelerated_video_decoder_->GetPicSize();
       const auto new_chroma_sampling =
           accelerated_video_decoder_->GetChromaSampling();
+      const auto new_color_space =
+          accelerated_video_decoder_->GetVideoColorSpace();
       if (new_profile == config_.profile() &&
           new_coded_size == config_.coded_size() &&
           new_bit_depth == bit_depth_ && !picture_buffers_.size() &&
-          new_chroma_sampling == chroma_sampling_) {
+          new_chroma_sampling == chroma_sampling_ &&
+          new_color_space == color_space_) {
         continue;
       }
 
       // Update the config.
       MEDIA_LOG(INFO, media_log_)
           << "D3D11VideoDecoder config change: profile: "
-          << static_cast<int>(new_profile) << " chroma_sampling_format: "
+          << GetProfileName(new_profile) << ", chroma_sampling_format: "
           << VideoChromaSamplingToString(new_chroma_sampling)
-          << " coded_size: (" << new_coded_size.width() << ", "
-          << new_coded_size.height() << ")";
+          << ", coded_size: " << new_coded_size.ToString()
+          << ", bit_depth: " << base::strict_cast<int>(new_bit_depth)
+          << ", color_space: " << new_color_space.ToString();
       profile_ = new_profile;
       config_.set_profile(profile_);
       config_.set_coded_size(new_coded_size);
       chroma_sampling_ = new_chroma_sampling;
+      color_space_ = new_color_space;
 
       // Replace the decoder, and clear any picture buffers we have.  It's okay
       // if we don't have any picture buffer yet; this might be before the
@@ -677,14 +682,6 @@
       CHECK(set_accelerator_decoder_wrapper_cb_);
       set_accelerator_decoder_wrapper_cb_.Run(std::move(wrapper));
       picture_buffers_.clear();
-    } else if (result == media::AcceleratedVideoDecoder::kColorSpaceChange) {
-      MEDIA_LOG(INFO, media_log_)
-          << "D3D11VideoDecoder color space change: color_space: "
-          << accelerated_video_decoder_->GetVideoColorSpace().ToString();
-
-      // Clear the picture buffers and recreate the pictures leading to new
-      // shared images with new color space.
-      picture_buffers_.clear();
     } else if (result == media::AcceleratedVideoDecoder::kTryAgain) {
       LOG(ERROR) << "Try again is not supported";
       NotifyError(D3D11Status::Codes::kTryAgainNotSupported);
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h
index 8d5d14d..f0ded91 100644
--- a/media/gpu/windows/d3d11_video_decoder.h
+++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -289,6 +289,10 @@
   // need to recreate the decoder.
   uint8_t bit_depth_ = 8u;
 
+  // The currently configured color space for the decoder. When this changes we
+  // need to recreate the decoder.
+  VideoColorSpace color_space_;
+
   // The currently configured chroma sampling format on the accelerator. When
   // this changes we need to recreate the decoder.
   VideoChromaSampling chroma_sampling_ = VideoChromaSampling::k420;
diff --git a/media/muxers/mp4_movie_box_writer.cc b/media/muxers/mp4_movie_box_writer.cc
index 403ecf8..5945f5a 100644
--- a/media/muxers/mp4_movie_box_writer.cc
+++ b/media/muxers/mp4_movie_box_writer.cc
@@ -88,10 +88,16 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   AddChildBox(std::make_unique<Mp4MovieHeaderBoxWriter>(context, box_.header));
 
-  if (auto video_track = context.GetVideoTrack()) {
+  bool video_is_first_track = false;
+  auto video_track = context.GetVideoTrack();
+  if (video_track) {
     DCHECK_LE(video_track.value().index, box_.tracks.size());
-    AddChildBox(std::make_unique<Mp4MovieTrackBoxWriter>(
-        context, box_.tracks[video_track.value().index]));
+
+    video_is_first_track = video_track.value().index == 0;
+    if (video_is_first_track) {
+      AddChildBox(std::make_unique<Mp4MovieTrackBoxWriter>(
+          context, box_.tracks[video_track.value().index]));
+    }
   }
 
   if (auto audio_track = context.GetAudioTrack()) {
@@ -100,6 +106,11 @@
         context, box_.tracks[audio_track.value().index]));
   }
 
+  if (!video_is_first_track && video_track) {
+    AddChildBox(std::make_unique<Mp4MovieTrackBoxWriter>(
+        context, box_.tracks[video_track.value().index]));
+  }
+
   AddChildBox(
       std::make_unique<Mp4MovieExtendsBoxWriter>(context, box_.extends));
 }
diff --git a/media/muxers/mp4_muxer.cc b/media/muxers/mp4_muxer.cc
index a31ff43..cb3fa7f 100644
--- a/media/muxers/mp4_muxer.cc
+++ b/media/muxers/mp4_muxer.cc
@@ -59,7 +59,8 @@
 
   DCHECK(!is_key_frame || codec_description.has_value());
 
-  base::TimeTicks adjusted_timestamp = AdjustTimestamp(timestamp, false);
+  base::TimeTicks adjusted_timestamp =
+      AdjustTimestamp(timestamp, /*audio=*/false);
 
   mp4_muxer_delegate_->AddVideoFrame(params, encoded_data, codec_description,
                                      adjusted_timestamp, is_key_frame);
@@ -83,7 +84,8 @@
   DCHECK(latest_audio_timestamp_ != base::TimeTicks::Min() ||
          codec_description.has_value());
 
-  base::TimeTicks adjusted_timestamp = AdjustTimestamp(timestamp, false);
+  base::TimeTicks adjusted_timestamp =
+      AdjustTimestamp(timestamp, /*audio=*/true);
 
   mp4_muxer_delegate_->AddAudioFrame(params, encoded_data, codec_description,
                                      adjusted_timestamp);
diff --git a/media/muxers/mp4_muxer_delegate.cc b/media/muxers/mp4_muxer_delegate.cc
index aeb705d..92d2cab 100644
--- a/media/muxers/mp4_muxer_delegate.cc
+++ b/media/muxers/mp4_muxer_delegate.cc
@@ -177,24 +177,24 @@
   auto fragment = std::make_unique<Mp4MuxerDelegate::Fragment>();
   fragment->moof.header.sequence_number = fragments.size() + 1;
 
-  for (uint32_t i = 0; i < total_tracks_count; ++i) {
-    // Added track could be non-zero index so we have to add all track
-    // entries before that index.
-    AddTrackEntry(*fragment, i, decode_time, is_audio);
-  }
-
-  if (!fragments.empty()) {
-    DCHECK_LE(fragments.back()->moof.track_fragments.size(), 2u);
-    for (auto& prior_track_frag : fragments.back()->moof.track_fragments) {
-      if (prior_track_frag.run.sample_timestamps.empty()) {
-        // If no sample is added for the track, we don't add the last one.
-        continue;
-      }
-
-      // Add an additional timestamp on the previous fragment so that it can
-      // get sample duration during box writer for last sample.
-      prior_track_frag.run.sample_timestamps.emplace_back(timestamp);
+  // Keep consistent of the track index across the fragments.
+  if (total_tracks_count == 1) {
+    AddTrackEntry(*fragment, 0, decode_time, is_audio);
+  } else if (total_tracks_count == 2) {
+    // Ensures the order of the added track.
+    bool audio_is_first_track =
+        (is_audio && (track_index == 0)) || (!is_audio && (track_index == 1));
+    if (audio_is_first_track) {
+      AddTrackEntry(*fragment, 0, decode_time, /*is_audio=*/true);
     }
+    AddTrackEntry(*fragment, audio_is_first_track ? 1 : 0, decode_time,
+                  /*is_audio=*/false);
+    if (!audio_is_first_track) {
+      AddTrackEntry(*fragment, 1, decode_time, /*is_audio=*/true);
+    }
+  } else {
+    // Supports only video and audio track now.
+    NOTREACHED();
   }
 
   fragments.emplace_back(std::move(fragment));
@@ -307,6 +307,19 @@
   track.media.header.duration = track_duration;
 }
 
+void AddTimestampToPriorFragment(Mp4MuxerDelegate::Fragment* prior_fragment,
+                                 size_t index,
+                                 base::TimeTicks timestamp) {
+  if (prior_fragment->moof.track_fragments.size() <= index) {
+    return;
+  }
+
+  auto& prior_track_frag = prior_fragment->moof.track_fragments[index];
+  if (!prior_track_frag.run.sample_timestamps.empty()) {
+    prior_track_frag.run.sample_timestamps.emplace_back(timestamp);
+  }
+}
+
 }  // namespace
 
 Mp4MuxerDelegate::Mp4MuxerDelegate(
@@ -426,6 +439,11 @@
   video_trun.sample_sizes.emplace_back(encoded_data.size());
 
   // Add sample timestamp.
+  if (video_trun.sample_timestamps.empty() && fragments_.size() > 1) {
+    // Needs to add timestamp to the previous fragment.
+    AddTimestampToPriorFragment(fragments_[fragments_.size() - 2].get(),
+                                *video_track_index_, last_video_time_);
+  }
   video_trun.sample_timestamps.emplace_back(last_video_time_);
 
   // Add sample data to the data box.
@@ -478,6 +496,7 @@
       std::move(codec_description);
   description.audio_sample_entry = std::move(audio_entry);
 #endif
+  description.entry_count = 1;
 
   BuildTrack(*moov_, *audio_track_index_, true,
              context_->GetAudioTrack().value().timescale, description);
@@ -521,6 +540,11 @@
   audio_trun.sample_sizes.emplace_back(encoded_data.size());
 
   // Add sample timestamp.
+  if (audio_trun.sample_timestamps.empty() && fragments_.size() > 1) {
+    // Needs to add timestamp to the previous fragment.
+    AddTimestampToPriorFragment(fragments_[fragments_.size() - 2].get(),
+                                *audio_track_index_, last_audio_time_);
+  }
   audio_trun.sample_timestamps.emplace_back(last_audio_time_);
 
   // Add sample data to the data box.
diff --git a/media/muxers/mp4_muxer_delegate_unittest.cc b/media/muxers/mp4_muxer_delegate_unittest.cc
index 59189e45..ac2025b1 100644
--- a/media/muxers/mp4_muxer_delegate_unittest.cc
+++ b/media/muxers/mp4_muxer_delegate_unittest.cc
@@ -68,7 +68,8 @@
   }
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-  void PopulateAVCDecoderConfiguration(std::vector<uint8_t>& code_description) {
+  void PopulateAVCDecoderConfiguration(
+      std::vector<uint8_t>& video_codec_description) {
     // copied from box_reader_unittest.cc.
     std::vector<uint8_t> test_data{
         0x1,        // configurationVersion = 1
@@ -94,13 +95,13 @@
     };
     mp4::AVCDecoderConfigurationRecord avc_config;
     ASSERT_TRUE(avc_config.Parse(test_data.data(), test_data.size()));
-    ASSERT_TRUE(avc_config.Serialize(code_description));
+    ASSERT_TRUE(avc_config.Serialize(video_codec_description));
   }
 
-  void PopulateAacAdts(std::vector<uint8_t>& code_description) {
+  void PopulateAacAdts(std::vector<uint8_t>& audio_video_codec_description) {
     // copied from aac_unittest.cc.
     std::vector<uint8_t> test_data = {0x12, 0x10};
-    code_description = test_data;
+    audio_video_codec_description = test_data;
   }
 #endif
 
@@ -174,8 +175,8 @@
       run_loop.QuitClosure(), &total_written_data, &moov_written_data,
       &first_moof_written_data, &second_moof_written_data, &callback_count));
 
-  std::vector<uint8_t> code_description;
-  PopulateAVCDecoderConfiguration(code_description);
+  std::vector<uint8_t> video_codec_description;
+  PopulateAVCDecoderConfiguration(video_codec_description);
 
   base::TimeTicks base_time_ticks = base::TimeTicks::Now();
 
@@ -187,7 +188,7 @@
   media::Muxer::VideoParameters params(gfx::Size(kWidth, kHeight), 30,
                                        media::VideoCodec::kH264,
                                        gfx::ColorSpace());
-  delegate.AddVideoFrame(params, video_stream_1, code_description,
+  delegate.AddVideoFrame(params, video_stream_1, video_codec_description,
                          base_time_ticks, true);
   for (int i = 0; i < 3; ++i) {
     delta += base::Milliseconds(kSampleDurations[i]);
@@ -196,7 +197,7 @@
   }
 
   delta += base::Milliseconds(kSampleDurations[3]);
-  delegate.AddVideoFrame(params, video_stream_1, code_description,
+  delegate.AddVideoFrame(params, video_stream_1, video_codec_description,
                          base_time_ticks + delta, true);
   for (int i = 0; i < 2; ++i) {
     delta += base::Milliseconds(kSampleDurations[i]);
@@ -490,13 +491,13 @@
       run_loop.QuitClosure(), &total_written_data, &moov_written_data,
       &first_moof_written_data, &callback_count));
 
-  std::vector<uint8_t> code_description;
-  PopulateAacAdts(code_description);
+  std::vector<uint8_t> audio_codec_description;
+  PopulateAacAdts(audio_codec_description);
 
   base::TimeTicks base_time_ticks = base::TimeTicks::Now();
   base::TimeDelta delta;
 
-  delegate.AddAudioFrame(params, audio_stream, code_description,
+  delegate.AddAudioFrame(params, audio_stream, audio_codec_description,
                          base_time_ticks);
   int incremental_delta = 30;
 
@@ -725,13 +726,13 @@
           &callback_count),
       base::Milliseconds(300));
 
-  std::vector<uint8_t> code_description;
-  PopulateAacAdts(code_description);
+  std::vector<uint8_t> audio_codec_description;
+  PopulateAacAdts(audio_codec_description);
 
   base::TimeTicks base_time_ticks = base::TimeTicks::Now();
   base::TimeDelta delta;
 
-  delegate.AddAudioFrame(params, audio_stream, code_description,
+  delegate.AddAudioFrame(params, audio_stream, audio_codec_description,
                          base_time_ticks);
   // Total count is 24, which will have 3 fragments and the last fragment
   // has 4 samples.
@@ -994,7 +995,7 @@
 
     // `trun` test of audio.
     EXPECT_EQ(1u, traf_boxes[0].runs[0].sample_count);
-    EXPECT_EQ(184u, traf_boxes[0].runs[0].data_offset);
+    EXPECT_EQ(180u, traf_boxes[0].runs[0].data_offset);
     ASSERT_EQ(1u, traf_boxes[0].runs[0].sample_durations.size());
 
     // video track.
@@ -1004,7 +1005,7 @@
     // `trun` test of video.
     ASSERT_EQ(1u, traf_boxes[1].runs.size());
     EXPECT_EQ(1u, traf_boxes[1].runs[0].sample_count);
-    EXPECT_EQ(555u, traf_boxes[1].runs[0].data_offset);
+    EXPECT_EQ(551u, traf_boxes[1].runs[0].data_offset);
 
     ASSERT_EQ(1u, traf_boxes[1].runs[0].sample_durations.size());
 
@@ -1077,13 +1078,13 @@
           &fourth_moof_written_data, &mfra_written_data, &callback_count),
       base::Milliseconds(300));
 
-  std::vector<uint8_t> code_description;
-  PopulateAacAdts(code_description);
+  std::vector<uint8_t> audio_codec_description;
+  PopulateAacAdts(audio_codec_description);
 
   base::TimeTicks base_time_ticks = base::TimeTicks::Now();
   base::TimeDelta delta;
 
-  delegate.AddAudioFrame(params, audio_stream, code_description,
+  delegate.AddAudioFrame(params, audio_stream, audio_codec_description,
                          base_time_ticks);
   // Total count is 24, which will have 3 fragments and the last fragment
   // has 4 samples.
@@ -1096,13 +1097,13 @@
   }
 
   // video stream, third fragment.
-  std::vector<uint8_t> video_code_description;
-  PopulateAVCDecoderConfiguration(video_code_description);
+  std::vector<uint8_t> video_codec_description;
+  PopulateAVCDecoderConfiguration(video_codec_description);
 
   media::Muxer::VideoParameters video_params(gfx::Size(kWidth, kHeight), 30,
                                              media::VideoCodec::kH264,
                                              gfx::ColorSpace());
-  delegate.AddVideoFrame(video_params, video_stream, video_code_description,
+  delegate.AddVideoFrame(video_params, video_stream, video_codec_description,
                          base_time_ticks, true);
   for (int i = 0; i < kMaxAudioSampleFragment; ++i) {
     delta += base::Milliseconds(30);
@@ -1111,7 +1112,7 @@
   }
 
   // video stream, fourth fragment.
-  delegate.AddVideoFrame(video_params, video_stream, video_code_description,
+  delegate.AddVideoFrame(video_params, video_stream, video_codec_description,
                          base_time_ticks + base::Milliseconds(50), true);
   delegate.AddAudioFrame(params, audio_stream, absl::nullopt,
                          base_time_ticks + delta + base::Milliseconds(30));
@@ -1248,24 +1249,24 @@
           &callback_count),
       base::Milliseconds(300));
 
-  std::vector<uint8_t> code_description;
-  PopulateAacAdts(code_description);
+  std::vector<uint8_t> audio_codec_description;
+  PopulateAacAdts(audio_codec_description);
 
   base::TimeTicks base_time_ticks = base::TimeTicks::Now();
   base::TimeDelta delta;
 
   // video stream.
-  std::vector<uint8_t> video_code_description;
-  PopulateAVCDecoderConfiguration(video_code_description);
+  std::vector<uint8_t> video_codec_description;
+  PopulateAVCDecoderConfiguration(video_codec_description);
 
   media::Muxer::VideoParameters video_params(gfx::Size(kWidth, kHeight), 30,
                                              media::VideoCodec::kH264,
                                              gfx::ColorSpace());
-  delegate.AddVideoFrame(video_params, video_stream, video_code_description,
+  delegate.AddVideoFrame(video_params, video_stream, video_codec_description,
                          base_time_ticks, true);
 
   // audio stream.
-  delegate.AddAudioFrame(params, audio_stream, code_description,
+  delegate.AddAudioFrame(params, audio_stream, audio_codec_description,
                          base_time_ticks);
   // Total count is 24, which will have 3 fragments and the last fragment
   // has 4 samples.
@@ -1348,6 +1349,143 @@
   }
 }
 
+TEST_F(Mp4MuxerDelegateTest, AudioVideoAndAudioVideoFragment) {
+  // Add audio and video the first fragment, but video and audio
+  // on the second segment.
+  media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+                                media::ChannelLayoutConfig::Stereo(),
+                                kAudioSampleRate, 1000);
+
+  base::MemoryMappedFile mapped_file_1;
+  LoadEncodedFile("aac-44100-packet-0", mapped_file_1);
+  base::StringPiece audio_stream(
+      reinterpret_cast<const char*>(mapped_file_1.data()),
+      mapped_file_1.length());
+
+  base::MemoryMappedFile mapped_file_2;
+  LoadEncodedFile("avc-bitstream-format-0.h264", mapped_file_2);
+  base::StringPiece video_stream(
+      reinterpret_cast<const char*>(mapped_file_1.data()),
+      mapped_file_1.length());
+
+  base::RunLoop run_loop;
+
+  std::vector<uint8_t> total_written_data;
+  std::vector<uint8_t> first_moof_written_data;
+  std::vector<uint8_t> second_moof_written_data;
+
+  int callback_count = 0;
+  Mp4MuxerDelegate delegate(
+      base::BindRepeating(
+          [](base::OnceClosure run_loop_quit,
+             std::vector<uint8_t>* total_written_data,
+             std::vector<uint8_t>* first_moof_written_data,
+             std::vector<uint8_t>* second_moof_written_data,
+             int* callback_count, base::StringPiece mp4_data_string) {
+            std::copy(mp4_data_string.begin(), mp4_data_string.end(),
+                      std::back_inserter(*total_written_data));
+
+            ++(*callback_count);
+            switch (*callback_count) {
+              case 1:
+              case 2:
+                // DO Nothing.
+                break;
+              case 3:
+                std::copy(mp4_data_string.begin(), mp4_data_string.end(),
+                          std::back_inserter(*first_moof_written_data));
+                break;
+              case 4:
+                std::copy(mp4_data_string.begin(), mp4_data_string.end(),
+                          std::back_inserter(*second_moof_written_data));
+                // Quit.
+                std::move(run_loop_quit).Run();
+                break;
+            }
+          },
+          run_loop.QuitClosure(), &total_written_data, &first_moof_written_data,
+          &second_moof_written_data, &callback_count),
+      base::Milliseconds(300));
+
+  std::vector<uint8_t> audio_codec_description;
+  PopulateAacAdts(audio_codec_description);
+
+  // video stream.
+  std::vector<uint8_t> video_codec_description;
+  PopulateAVCDecoderConfiguration(video_codec_description);
+
+  base::TimeTicks base_time_ticks = base::TimeTicks::Now();
+  constexpr base::TimeDelta kDelta = base::Milliseconds(30);
+  media::Muxer::VideoParameters video_params(gfx::Size(kWidth, kHeight), 30,
+                                             media::VideoCodec::kH264,
+                                             gfx::ColorSpace());
+
+  // The first fragment; audio (1 sample) -> video (2 samples) track.
+  delegate.AddAudioFrame(params, audio_stream, audio_codec_description,
+                         base_time_ticks);
+  delegate.AddVideoFrame(video_params, video_stream, video_codec_description,
+                         base_time_ticks, true);
+  delegate.AddVideoFrame(video_params, video_stream, absl::nullopt,
+                         base_time_ticks + kDelta, false);
+
+  // The second fragment; video (1 sample) -> audio (2 samples) track.
+  delegate.AddVideoFrame(video_params, video_stream, video_codec_description,
+                         base_time_ticks + kDelta * 2, true);
+  delegate.AddAudioFrame(params, audio_stream, absl::nullopt,
+                         base_time_ticks + kDelta);
+  delegate.AddAudioFrame(params, audio_stream, absl::nullopt,
+                         base_time_ticks + kDelta * 2);
+  // Write box data to the callback.
+  delegate.Flush();
+
+  run_loop.Run();
+
+  {
+    // The first `moof`validation.
+    std::unique_ptr<mp4::BoxReader> moof_reader;
+    mp4::ParseResult result = mp4::BoxReader::ReadTopLevelBox(
+        first_moof_written_data.data(), first_moof_written_data.size(), nullptr,
+        &moof_reader);
+    EXPECT_EQ(result, mp4::ParseResult::kOk);
+    // `moof` test.
+    EXPECT_EQ(mp4::FOURCC_MOOF, moof_reader->type());
+    EXPECT_TRUE(moof_reader->ScanChildren());
+
+    // `traf` test.
+    std::vector<mp4::TrackFragment> traf_boxes;
+    EXPECT_TRUE(moof_reader->ReadChildren(&traf_boxes));
+    ASSERT_EQ(traf_boxes.size(), 2u);
+
+    // The first framgment: `trun`.
+    // The first track is audio, the second is video.
+    EXPECT_EQ(1u, traf_boxes[0].runs[0].sample_count);
+    EXPECT_EQ(2u, traf_boxes[1].runs[0].sample_count);
+  }
+  {
+    // The second `moof` validation.
+    std::unique_ptr<mp4::BoxReader> moof_reader;
+    mp4::ParseResult result = mp4::BoxReader::ReadTopLevelBox(
+        second_moof_written_data.data(), second_moof_written_data.size(),
+        nullptr, &moof_reader);
+    EXPECT_EQ(result, mp4::ParseResult::kOk);
+    // `moof` test.
+    EXPECT_EQ(mp4::FOURCC_MOOF, moof_reader->type());
+    EXPECT_TRUE(moof_reader->ScanChildren());
+
+    // `traf` test.
+    std::vector<mp4::TrackFragment> traf_boxes;
+    EXPECT_TRUE(moof_reader->ReadChildren(&traf_boxes));
+    ASSERT_EQ(traf_boxes.size(), 2u);
+
+    // The first framgment: `trun`.
+
+    // The track order should be same:
+    // first track is audio, the second is video.
+    EXPECT_EQ(2u, traf_boxes[0].runs[0].sample_count);
+    EXPECT_EQ(1u, traf_boxes[1].runs[0].sample_count);
+  }
+}
+
 #endif
 
 }  // namespace media
diff --git a/services/accessibility/fake_service_client.cc b/services/accessibility/fake_service_client.cc
index b15f8fa7..5787499 100644
--- a/services/accessibility/fake_service_client.cc
+++ b/services/accessibility/fake_service_client.cc
@@ -114,6 +114,13 @@
     focus_rings_callback_.Run();
   }
 }
+
+void FakeServiceClient::SetHighlights(const std::vector<gfx::Rect>& rects,
+                                      SkColor color) {
+  if (highlights_callback_) {
+    highlights_callback_.Run(rects, color);
+  }
+}
 #endif  // BUILDFLAG(SUPPORTS_OS_ACCESSIBILITY_SERVICE)
 
 void FakeServiceClient::BindAccessibilityServiceClientForTest() {
@@ -147,6 +154,13 @@
     base::RepeatingCallback<void()> callback) {
   focus_rings_callback_ = std::move(callback);
 }
+
+void FakeServiceClient::SetHighlightsCallback(
+    base::RepeatingCallback<void(const std::vector<gfx::Rect>& rects,
+                                 SkColor color)> callback) {
+  highlights_callback_ = callback;
+}
+
 bool FakeServiceClient::UserInterfaceIsBound() const {
   return ux_receivers_.size();
 }
diff --git a/services/accessibility/fake_service_client.h b/services/accessibility/fake_service_client.h
index f24cd16..945ccad 100644
--- a/services/accessibility/fake_service_client.h
+++ b/services/accessibility/fake_service_client.h
@@ -65,6 +65,8 @@
   // ax::mojom::UserInterface:
   void SetFocusRings(std::vector<ax::mojom::FocusRingInfoPtr> focus_rings,
                      ax::mojom::AssistiveTechnologyType at_type) override;
+  void SetHighlights(const std::vector<gfx::Rect>& rects,
+                     SkColor color) override;
 #endif  // BUILDFLAG(SUPPORTS_OS_ACCESSIBILITY_SERVICE)
 
   // Methods for testing.
@@ -83,6 +85,9 @@
   void SetFocusRingsCallback(base::RepeatingCallback<void()> callback);
   const std::vector<ax::mojom::FocusRingInfoPtr>& GetFocusRingsForType(
       mojom::AssistiveTechnologyType type) const;
+  void SetHighlightsCallback(
+      base::RepeatingCallback<void(const std::vector<gfx::Rect>& rects,
+                                   SkColor color)> callback);
 #endif  // BUILDFLAG(SUPPORTS_OS_ACCESSIBILITY_SERVICE)
   base::WeakPtr<FakeServiceClient> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
@@ -105,6 +110,10 @@
   std::map<mojom::AssistiveTechnologyType,
            std::vector<ax::mojom::FocusRingInfoPtr>>
       focus_rings_for_type_;
+
+  base::RepeatingCallback<void(const std::vector<gfx::Rect>& rects,
+                               SkColor color)>
+      highlights_callback_;
 #endif  // BUILDFLAG(SUPPORTS_OS_ACCESSIBILITY_SERVICE)
   mojo::Receiver<mojom::AccessibilityServiceClient> a11y_client_receiver_{this};
 
diff --git a/services/accessibility/features/atp_js_api_test.cc b/services/accessibility/features/atp_js_api_test.cc
index 2ed5f31f..3a0007b 100644
--- a/services/accessibility/features/atp_js_api_test.cc
+++ b/services/accessibility/features/atp_js_api_test.cc
@@ -436,7 +436,7 @@
     ASSERT_EQ(focus_rings.size(), 1u);
     auto& focus_ring = focus_rings[0];
     EXPECT_EQ(focus_ring->type, mojom::FocusType::kGlow);
-    EXPECT_EQ(focus_ring->color, 13369395u);
+    EXPECT_EQ(focus_ring->color, SK_ColorRED);
     ASSERT_EQ(focus_ring->rects.size(), 1u);
     EXPECT_EQ(focus_ring->rects[0], gfx::Rect(50, 100, 200, 300));
 
@@ -450,7 +450,7 @@
     const focusRingInfo = {
       rects: [{left: 50, top: 100, width: 200, height: 300}],
       type: 'glow',
-      color: '#cc0033',
+      color: '#ff0000',
     };
     chrome.accessibilityPrivate.setFocusRings([focusRingInfo],
         chrome.accessibilityPrivate.AssistiveTechnologyType.CHROME_VOX);
@@ -484,7 +484,7 @@
     ASSERT_EQ(focus_rings.size(), 2u);
     auto& focus_ring1 = focus_rings[0];
     EXPECT_EQ(focus_ring1->type, mojom::FocusType::kSolid);
-    EXPECT_EQ(focus_ring1->color, 13369378u);
+    EXPECT_EQ(focus_ring1->color, SK_ColorWHITE);
     ASSERT_EQ(focus_ring1->rects.size(), 2u);
     EXPECT_EQ(focus_ring1->rects[0], gfx::Rect(150, 200, 300, 400));
     EXPECT_EQ(focus_ring1->rects[1], gfx::Rect(0, 50, 150, 250));
@@ -492,24 +492,24 @@
     EXPECT_EQ(focus_ring1->stacking_order.value(),
               mojom::FocusRingStackingOrder::kAboveAccessibilityBubbles);
     ASSERT_TRUE(focus_ring1->background_color.has_value());
-    EXPECT_EQ(focus_ring1->background_color.value(), 11259375u);
+    EXPECT_EQ(focus_ring1->background_color.value(), SK_ColorYELLOW);
     ASSERT_TRUE(focus_ring1->secondary_color.has_value());
-    EXPECT_EQ(focus_ring1->secondary_color.value(), 1193046u);
+    EXPECT_EQ(focus_ring1->secondary_color.value(), SK_ColorMAGENTA);
     ASSERT_TRUE(focus_ring1->id.has_value());
     EXPECT_EQ(focus_ring1->id.value(), "lovelace");
 
     auto& focus_ring2 = focus_rings[1];
     EXPECT_EQ(focus_ring2->type, mojom::FocusType::kDashed);
-    EXPECT_EQ(focus_ring2->color, 0u);
+    EXPECT_EQ(focus_ring2->color, SK_ColorBLACK);
     ASSERT_EQ(focus_ring2->rects.size(), 1u);
     EXPECT_EQ(focus_ring2->rects[0], gfx::Rect(4, 3, 2, 1));
     ASSERT_TRUE(focus_ring2->stacking_order.has_value());
     EXPECT_EQ(focus_ring2->stacking_order.value(),
               mojom::FocusRingStackingOrder::kBelowAccessibilityBubbles);
     ASSERT_TRUE(focus_ring2->background_color.has_value());
-    EXPECT_EQ(focus_ring2->background_color.value(), 16702650u);
+    EXPECT_EQ(focus_ring2->background_color.value(), SK_ColorRED);
     ASSERT_TRUE(focus_ring2->secondary_color.has_value());
-    EXPECT_EQ(focus_ring2->secondary_color.value(), 6636321u);
+    EXPECT_EQ(focus_ring2->secondary_color.value(), SK_ColorCYAN);
     ASSERT_TRUE(focus_ring2->id.has_value());
     EXPECT_EQ(focus_ring2->id.value(), "curie");
   }));
@@ -521,9 +521,10 @@
         {left: 0, top: 50, width: 150, height: 250}
       ],
       type: 'solid',
-      color: '#cc0022',
-      backgroundColor: '#abcdef',
-      secondaryColor: '#123456',
+      color: '#ffffff',
+      backgroundColor: '#ffff00',
+      // Ensure capitalization doesn't matter.
+      secondaryColor: '#FF00ff',
       stackingOrder:
           stackingOrder.ABOVE_ACCESSIBILITY_BUBBLES,
       id: 'lovelace',
@@ -532,8 +533,8 @@
       rects: [{left: 4, top: 3, width: 2, height: 1}],
       type: 'dashed',
       color: '#000000',
-      backgroundColor: 'fedcba',
-      secondaryColor: '#654321',
+      backgroundColor: 'ff0000',
+      secondaryColor: '#00FFFF',
       stackingOrder:
           stackingOrder.BELOW_ACCESSIBILITY_BUBBLES,
       id: 'curie',
@@ -545,4 +546,37 @@
   waiter.Run();
 }
 
+TEST_F(AccessibilityPrivateJSApiTest, SetHighlights) {
+  base::RunLoop waiter;
+  client_->SetHighlightsCallback(base::BindLambdaForTesting(
+      [&waiter](const std::vector<gfx::Rect>& rects, SkColor color) {
+        waiter.Quit();
+        ASSERT_EQ(rects.size(), 2u);
+        EXPECT_EQ(rects[0], gfx::Rect(1, 22, 1973, 100));
+        EXPECT_EQ(rects[1], gfx::Rect(2, 4, 6, 8));
+        EXPECT_EQ(color, SK_ColorGREEN);
+      }));
+  ExecuteJS(R"JS(
+    const rects = [
+        {left: 1, top: 22, width: 1973, height: 100},
+        {left: 2, top: 4, width: 6, height: 8}
+    ];
+    chrome.accessibilityPrivate.setHighlights(rects, '#00FF00');
+  )JS");
+  waiter.Run();
+}
+
+TEST_F(AccessibilityPrivateJSApiTest, SetHighlightsEmptyRects) {
+  base::RunLoop waiter;
+  client_->SetHighlightsCallback(base::BindLambdaForTesting(
+      [&waiter](const std::vector<gfx::Rect>& rects, SkColor color) {
+        waiter.Quit();
+        ASSERT_EQ(rects.size(), 0u);
+      }));
+  ExecuteJS(R"JS(
+    chrome.accessibilityPrivate.setHighlights([], '#FF0000');
+  )JS");
+  waiter.Run();
+}
+
 }  // namespace ax
diff --git a/services/accessibility/features/javascript/accessibility_private.js b/services/accessibility/features/javascript/accessibility_private.js
index 4021447..187cff1 100644
--- a/services/accessibility/features/javascript/accessibility_private.js
+++ b/services/accessibility/features/javascript/accessibility_private.js
@@ -80,15 +80,8 @@
     for (let focusRingInfo of focusRingInfos) {
       let mojomFocusRing = new ax.mojom.FocusRingInfo();
       if (focusRingInfo.rects && focusRingInfo.rects.length) {
-        mojomFocusRing.rects = [];
-        for (let rect of focusRingInfo.rects) {
-          let mojomRect = new gfx.mojom.Rect();
-          mojomRect.x = rect.left;
-          mojomRect.y = rect.top;
-          mojomRect.width = rect.width;
-          mojomRect.height = rect.height;
-          mojomFocusRing.rects.push(mojomRect);
-        }
+        mojomFocusRing.rects =
+            AtpAccessibilityPrivate.convertRectsToMojom_(focusRingInfo.rects);
       }
       if (focusRingInfo.type !== undefined) {
         switch (focusRingInfo.type) {
@@ -106,20 +99,17 @@
         }
       }
       if (focusRingInfo.color !== undefined) {
-        mojomFocusRing.color = new skia.mojom.SkColor();
-        mojomFocusRing.color.value =
-            AtpAccessibilityPrivate.parseHexColor_(focusRingInfo.color);
+        mojomFocusRing.color =
+            AtpAccessibilityPrivate.convertColorToMojom_(focusRingInfo.color);
       }
       if (focusRingInfo.secondaryColor !== undefined) {
-        mojomFocusRing.secondaryColor = new skia.mojom.SkColor();
-        mojomFocusRing.secondaryColor.value =
-            AtpAccessibilityPrivate.parseHexColor_(
+        mojomFocusRing.secondaryColor =
+            AtpAccessibilityPrivate.convertColorToMojom_(
                 focusRingInfo.secondaryColor);
       }
       if (focusRingInfo.backgroundColor !== undefined) {
-        mojomFocusRing.backgroundColor = new skia.mojom.SkColor();
-        mojomFocusRing.backgroundColor.value =
-            AtpAccessibilityPrivate.parseHexColor_(
+        mojomFocusRing.backgroundColor =
+            AtpAccessibilityPrivate.convertColorToMojom_(
                 focusRingInfo.backgroundColor);
       }
       if (focusRingInfo.stackingOrder !== undefined) {
@@ -146,11 +136,52 @@
     this.userInterfaceRemote_.setFocusRings(mojomFocusRings, mojomAtType);
   }
 
-  static parseHexColor_(colorString) {
+  /**
+   * Sets the given focus highlights.
+   * @param {!Array<!chrome.accessibilityPrivate.ScreenRect>} rects
+   * @param {string} color
+   */
+  setHighlights(rects, color) {
+    const mojomColor = AtpAccessibilityPrivate.convertColorToMojom_(color);
+    const mojomRects = AtpAccessibilityPrivate.convertRectsToMojom_(rects);
+    this.userInterfaceRemote_.setHighlights(mojomRects, mojomColor);
+  }
+
+  /**
+   * Convert array of accessibilityPrivate.ScreenRect to gfx.mojom.Rects.
+   * @param {!Array<!chrome.accessibilityPrivate.ScreenRect>} rects
+   * @return {!Array<!gfx.mojom.Rect>}
+   * @private
+   */
+  static convertRectsToMojom_(rects) {
+    let mojomRects = [];
+    for (const rect of rects) {
+      let mojomRect = new gfx.mojom.Rect();
+      mojomRect.x = rect.left;
+      mojomRect.y = rect.top;
+      mojomRect.width = rect.width;
+      mojomRect.height = rect.height;
+      mojomRects.push(mojomRect);
+    }
+    return mojomRects;
+  }
+
+  /**
+   * Converts a hex string to SkColor object.
+   * @param {string} colorString
+   * @return {skia.mojom.SkColor}
+   * @private
+   */
+  static convertColorToMojom_(colorString) {
+    let result = new skia.mojom.SkColor();
     if (colorString[0] === '#') {
       colorString = colorString.substr(1);
     }
-    return parseInt(colorString, 16);
+    if (colorString.length === 6) {
+      colorString = 'FF' + colorString;
+    }
+    result.value = parseInt(colorString, 16);
+    return result;
   }
 }
 
diff --git a/services/accessibility/public/mojom/user_interface.mojom b/services/accessibility/public/mojom/user_interface.mojom
index 06ca851..91c36ad7 100644
--- a/services/accessibility/public/mojom/user_interface.mojom
+++ b/services/accessibility/public/mojom/user_interface.mojom
@@ -59,4 +59,7 @@
     // FocusRingInfo.
     SetFocusRings(array<FocusRingInfo> focus_rings,
         AssistiveTechnologyType at_type);
+
+    // Sets the bounds and color of the accessibility highlight.
+    SetHighlights(array<gfx.mojom.Rect> rects, skia.mojom.SkColor color);
 };
\ No newline at end of file
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index 4f7fcc6..03944f13 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -366,24 +366,6 @@
              "PrivateNetworkAccessPermissionPrompt",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables out-of-process system DNS resolution so getaddrinfo() never runs in
-// the network service sandbox. System DNS resolution will instead be brokered
-// out over Mojo, likely to run in the browser process.
-//
-// This is only necessary on Linux desktop and Android where system DNS
-// resolution cannot always run in a sandboxed network process. The Mac and
-// Windows sandboxing systems allow us to specify system DNS resolution as an
-// allowed action, and ChromeOS uses a simple, known system DNS configuration
-// that can be adequately sandboxed.
-BASE_FEATURE(kOutOfProcessSystemDnsResolution,
-             "OutOfProcessSystemDnsResolution",
-#if BUILDFLAG(IS_LINUX)
-             base::FEATURE_ENABLED_BY_DEFAULT
-#else
-             base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-);
-
 BASE_FEATURE(kAccessControlAllowMethodsInCORSPreflightSpecConformant,
              "AccessControlAllowMethodsInCORSPreflightSpecConformant",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index d1e5876a..111723e0 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -123,9 +123,6 @@
 extern const base::FeatureParam<bool> kPrefetchDNSWithURLAllAnchorElements;
 
 COMPONENT_EXPORT(NETWORK_CPP)
-BASE_DECLARE_FEATURE(kOutOfProcessSystemDnsResolution);
-
-COMPONENT_EXPORT(NETWORK_CPP)
 BASE_DECLARE_FEATURE(kAccessControlAllowMethodsInCORSPreflightSpecConformant);
 
 // If enabled, then navigation requests should check the match responses in the
diff --git a/testing/buildbot/autoshard_exceptions.json b/testing/buildbot/autoshard_exceptions.json
index efccf35..0ec633d 100644
--- a/testing/buildbot/autoshard_exceptions.json
+++ b/testing/buildbot/autoshard_exceptions.json
@@ -17,17 +17,17 @@
             },
             "webview_instrumentation_test_apk": {
                 "debug": {
-                    "avg_num_builds_per_peak_hour": "72.0",
-                    "estimated_bot_hour_delta": "2.68",
-                    "prev_avg_pending_time_sec": "22.8",
+                    "avg_num_builds_per_peak_hour": "86.0",
+                    "estimated_bot_hour_delta": "3.27",
+                    "prev_avg_pending_time_sec": "56.8",
                     "prev_p50_pending_time_sec": "2.0",
-                    "prev_p90_pending_time_sec": "87.0",
-                    "prev_percentile_duration_minutes": "15.74",
-                    "prev_shard_count": "12",
-                    "simulated_max_shard_duration": "14.53",
+                    "prev_p90_pending_time_sec": "153.0",
+                    "prev_percentile_duration_minutes": "15.02",
+                    "prev_shard_count": "13",
+                    "simulated_max_shard_duration": "13.95",
                     "try_builder": "android-12-x64-rel"
                 },
-                "shards": "13"
+                "shards": "14"
             },
             "webview_trichrome_64_cts_tests full_mode": {
                 "debug": {
@@ -49,17 +49,17 @@
         "chromeos-amd64-generic-rel": {
             "chrome_all_tast_tests": {
                 "debug": {
-                    "avg_num_builds_per_peak_hour": "81.0",
-                    "estimated_bot_hour_delta": "6.47",
-                    "prev_avg_pending_time_sec": "42.6",
-                    "prev_p50_pending_time_sec": "10.0",
-                    "prev_p90_pending_time_sec": "120.0",
-                    "prev_percentile_duration_minutes": "16.19",
-                    "prev_shard_count": "15",
-                    "simulated_max_shard_duration": "14.29",
+                    "avg_num_builds_per_peak_hour": "80.0",
+                    "estimated_bot_hour_delta": "-7.82",
+                    "prev_avg_pending_time_sec": "200.2",
+                    "prev_p50_pending_time_sec": "45.0",
+                    "prev_p90_pending_time_sec": "678.0",
+                    "prev_percentile_duration_minutes": "13.34",
+                    "prev_shard_count": "17",
+                    "simulated_max_shard_duration": "15.12",
                     "try_builder": "chromeos-amd64-generic-rel"
                 },
-                "shards": "17"
+                "shards": "15"
             }
         },
         "linux-chromeos-rel": {
@@ -263,17 +263,17 @@
             },
             "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash stable": {
                 "debug": {
-                    "avg_num_builds_per_peak_hour": "75.0",
-                    "estimated_bot_hour_delta": "1.97",
-                    "prev_avg_pending_time_sec": "186.7",
-                    "prev_p50_pending_time_sec": "22.0",
-                    "prev_p90_pending_time_sec": "656.0",
-                    "prev_percentile_duration_minutes": "16.41",
-                    "prev_shard_count": "4",
-                    "simulated_max_shard_duration": "13.13",
+                    "avg_num_builds_per_peak_hour": "82.0",
+                    "estimated_bot_hour_delta": "-2.28",
+                    "prev_avg_pending_time_sec": "311.1",
+                    "prev_p50_pending_time_sec": "60.0",
+                    "prev_p90_pending_time_sec": "939.0",
+                    "prev_percentile_duration_minutes": "12.09",
+                    "prev_shard_count": "5",
+                    "simulated_max_shard_duration": "15.11",
                     "try_builder": "linux-lacros-rel"
                 },
-                "shards": "5"
+                "shards": "4"
             }
         }
     },
@@ -461,17 +461,17 @@
             },
             "interactive_ui_tests": {
                 "debug": {
-                    "avg_num_builds_per_peak_hour": "83.0",
-                    "estimated_bot_hour_delta": "5.72",
-                    "prev_avg_pending_time_sec": "583.9",
-                    "prev_p50_pending_time_sec": "181.0",
-                    "prev_p90_pending_time_sec": "1807.0",
-                    "prev_percentile_duration_minutes": "15.45",
-                    "prev_shard_count": "40",
-                    "simulated_max_shard_duration": "14.71",
+                    "avg_num_builds_per_peak_hour": "79.0",
+                    "estimated_bot_hour_delta": "-5.49",
+                    "prev_avg_pending_time_sec": "167.1",
+                    "prev_p50_pending_time_sec": "17.0",
+                    "prev_p90_pending_time_sec": "560.0",
+                    "prev_percentile_duration_minutes": "14.21",
+                    "prev_shard_count": "42",
+                    "simulated_max_shard_duration": "14.92",
                     "try_builder": "linux_chromium_tsan_rel_ng"
                 },
-                "shards": "42"
+                "shards": "40"
             },
             "sync_integration_tests": {
                 "debug": {
diff --git a/testing/buildbot/chrome.gpu.fyi.json b/testing/buildbot/chrome.gpu.fyi.json
index 4c8247ca..f69c2c4 100644
--- a/testing/buildbot/chrome.gpu.fyi.json
+++ b/testing/buildbot/chrome.gpu.fyi.json
@@ -18,7 +18,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "context_lost_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -46,7 +46,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "expected_color_pixel_passthrough_test JACUZZI_RELEASE_LKGM",
         "precommit_args": [
@@ -74,7 +74,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "gpu_process_launch_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -97,7 +97,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "hardware_accelerated_feature_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -124,7 +124,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --force_high_performance_gpu",
         "name": "info_collection_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -147,7 +147,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "mediapipe_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -176,7 +176,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "pixel_skia_gold_passthrough_test JACUZZI_RELEASE_LKGM",
         "precommit_args": [
@@ -205,7 +205,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "screenshot_sync_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -229,7 +229,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "trace_test JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -253,7 +253,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "webcodecs_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -279,7 +279,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu",
         "name": "webgl2_conformance_gles_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -304,7 +304,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu",
         "name": "webgl_conformance_gles_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index bb175a0..a7cbc5f 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1177,7 +1177,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R120-15639.0.0",
+        "cros_img": "brya-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "name": "chrome_all_tast_tests BRYA_RELEASE_LKGM",
         "shards": 10,
@@ -1191,7 +1191,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R120-15639.0.0",
+        "cros_img": "brya-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests BRYA_RELEASE_LKGM",
@@ -1206,7 +1206,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R120-15639.0.0",
+        "cros_img": "brya-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests BRYA_RELEASE_LKGM",
@@ -1406,7 +1406,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "name": "chrome_all_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 10,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1419,7 +1419,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 3,
@@ -1433,7 +1433,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 2,
@@ -1569,7 +1569,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "volteer",
-        "cros_img": "volteer-release/R119-15629.0.0",
+        "cros_img": "volteer-release/R120-15642.0.0",
         "name": "chrome_all_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 10,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1582,7 +1582,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "volteer",
-        "cros_img": "volteer-release/R119-15629.0.0",
+        "cros_img": "volteer-release/R120-15642.0.0",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 3,
@@ -1596,7 +1596,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "volteer",
-        "cros_img": "volteer-release/R119-15629.0.0",
+        "cros_img": "volteer-release/R120-15642.0.0",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 2,
@@ -1676,7 +1676,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R120-15639.0.0",
+        "cros_img": "brya-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "name": "lacros_all_tast_tests BRYA_RELEASE_LKGM",
         "resultdb": {
@@ -1743,7 +1743,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "dedede",
-        "cros_img": "dedede-release/R120-15639.0.0",
+        "cros_img": "dedede-release/R120-15642.0.0",
         "name": "lacros_all_tast_tests DEDEDE_RELEASE_LKGM",
         "resultdb": {
           "enable": true,
@@ -1810,7 +1810,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "fizz",
-        "cros_img": "fizz-release/R120-15639.0.0",
+        "cros_img": "fizz-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "name": "lacros_all_tast_tests FIZZ_RELEASE_LKGM",
         "resultdb": {
@@ -1879,7 +1879,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "guybrush",
-        "cros_img": "guybrush-release/R120-15639.0.0",
+        "cros_img": "guybrush-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "name": "lacros_all_tast_tests GUYBRUSH_RELEASE_LKGM",
         "resultdb": {
@@ -1948,7 +1948,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "puff",
-        "cros_img": "puff-release/R120-15639.0.0",
+        "cros_img": "puff-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "name": "lacros_all_tast_tests PUFF_RELEASE_LKGM",
         "resultdb": {
@@ -2047,7 +2047,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "name": "lacros_all_tast_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
           "enable": true,
@@ -2112,7 +2112,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "strongbad",
-        "cros_img": "strongbad-release/R120-15639.0.0",
+        "cros_img": "strongbad-release/R120-15642.0.0",
         "name": "lacros_all_tast_tests STRONGBAD_RELEASE_LKGM",
         "resultdb": {
           "enable": true,
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index dfbf7a4..e5d07b8 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -6,368 +6,6 @@
       "all"
     ]
   },
-  "Android WebView N (dbg)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_webview_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "android_webview_unittests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "android_webview_unittests",
-        "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "system_webview_shell_layout_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "system_webview_shell_layout_test_apk",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "system_webview_shell_layout_test_apk",
-        "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_cts_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webview_cts_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/android_webview/tools/cts_archive",
-              "location": "android_webview/tools/cts_archive",
-              "revision": "akIIr4yAFQwo3j5WYo2PQvy6z8XI51UiwiikPYzI4tUC"
-            }
-          ],
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "webview_cts_tests",
-        "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/"
-      },
-      {
-        "args": [
-          "--disable-field-trial-config",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_cts_tests_no_field_trial"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webview_cts_tests_no_field_trial",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/android_webview/tools/cts_archive",
-              "location": "android_webview/tools/cts_archive",
-              "revision": "akIIr4yAFQwo3j5WYo2PQvy6z8XI51UiwiikPYzI4tUC"
-            }
-          ],
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "webview_cts_tests",
-        "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/"
-      },
-      {
-        "args": [
-          "--use-apk-under-test-flags-file",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_instrumentation_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webview_instrumentation_test_apk",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 12
-        },
-        "test": "webview_instrumentation_test_apk",
-        "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/"
-      },
-      {
-        "args": [
-          "--disable-field-trial-config",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_instrumentation_test_apk_no_field_trial"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webview_instrumentation_test_apk_no_field_trial",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 12
-        },
-        "test": "webview_instrumentation_test_apk",
-        "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_ui_test_app_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webview_ui_test_app_test_apk",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "webview_ui_test_app_test_apk",
-        "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/"
-      },
-      {
-        "args": [
-          "--disable-field-trial-config",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_ui_test_app_test_apk_no_field_trial"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webview_ui_test_app_test_apk_no_field_trial",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "dimensions": {
-            "device_os": "N2G48C",
-            "device_os_type": "userdebug",
-            "device_type": "bullhead",
-            "os": "Android"
-          },
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "webview_ui_test_app_test_apk",
-        "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/"
-      }
-    ]
-  },
   "Android WebView O (dbg)": {
     "gtest_tests": [
       {
@@ -9937,7 +9575,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 13
+          "shards": 14
         },
         "test": "webview_instrumentation_test_apk",
         "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/"
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 2e4d846..0715f82 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -188,7 +188,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 17
+          "shards": 15
         },
         "test": "chrome_all_tast_tests",
         "test_id_prefix": "ninja://chromeos:chrome_all_tast_tests/"
@@ -1131,7 +1131,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R120-15639.0.0",
+        "cros_img": "volteer-public/R120-15642.0.0",
         "cros_model": "voxel",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests VOLTEER_PUBLIC_LKGM",
@@ -1475,7 +1475,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R120-15639.0.0",
+        "cros_img": "jacuzzi-public/R120-15642.0.0",
         "name": "chromeos_integration_tests JACUZZI_PUBLIC_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
@@ -1484,7 +1484,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R120-15639.0.0",
+        "cros_img": "jacuzzi-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -1513,7 +1513,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
-        "cros_img": "trogdor-public/R120-15639.0.0",
+        "cros_img": "trogdor-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests TROGDOR_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -5176,136 +5176,6 @@
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5993.60/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 118.0.5993.60",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash beta",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5993.60",
-              "revision": "version:118.0.5993.60"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash beta"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v120.0.6059.0/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 120.0.6059.0",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash canary",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v120.0.6059.0",
-              "revision": "version:120.0.6059.0"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash canary"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v119.0.6045.10/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 119.0.6045.10",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash dev",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v119.0.6045.10",
-              "revision": "version:119.0.6045.10"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash dev"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5938.157/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 117.0.5938.157",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash stable",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5938.157",
-              "revision": "version:117.0.5938.157"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash stable"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
         "name": "lacros_chrome_browsertests_run_in_series",
         "swarming": {
           "dimensions": {
@@ -5427,7 +5297,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 5
+          "shards": 4
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 2b5c485..5d95e70 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -25556,136 +25556,6 @@
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5993.60/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 118.0.5993.60",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash beta",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5993.60",
-              "revision": "version:118.0.5993.60"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash beta"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v120.0.6059.0/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 120.0.6059.0",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash canary",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v120.0.6059.0",
-              "revision": "version:120.0.6059.0"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash canary"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v119.0.6045.10/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 119.0.6045.10",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash dev",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v119.0.6045.10",
-              "revision": "version:119.0.6045.10"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash dev"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5938.157/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 117.0.5938.157",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash stable",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5938.157",
-              "revision": "version:117.0.5938.157"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash stable"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
         "name": "lacros_chrome_browsertests_run_in_series",
         "swarming": {
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 9f72b5e1..4ee18fa 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -41181,7 +41181,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "eve",
-        "cros_img": "eve-public/R120-15639.0.0",
+        "cros_img": "eve-public/R120-15642.0.0",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests EVE_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
@@ -41201,7 +41201,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "octopus",
-        "cros_img": "octopus-public/R120-15639.0.0",
+        "cros_img": "octopus-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests OCTOPUS_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41225,7 +41225,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R120-15639.0.0",
+        "cros_img": "jacuzzi-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41242,7 +41242,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
-        "cros_img": "trogdor-public/R120-15639.0.0",
+        "cros_img": "trogdor-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests TROGDOR_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41266,7 +41266,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R120-15639.0.0",
+        "cros_img": "jacuzzi-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests JACUZZI_CQ_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
         "public_builder_bucket": "testplatform-public",
@@ -41285,7 +41285,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R120-15639.0.0",
+        "cros_img": "jacuzzi-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41302,7 +41302,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
-        "cros_img": "trogdor-public/R120-15639.0.0",
+        "cros_img": "trogdor-public/R120-15642.0.0",
         "name": "lacros_all_tast_tests TROGDOR_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -43633,136 +43633,6 @@
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5993.60/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 118.0.5993.60",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash beta",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5993.60",
-              "revision": "version:118.0.5993.60"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash beta"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v120.0.6059.0/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 120.0.6059.0",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash canary",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v120.0.6059.0",
-              "revision": "version:120.0.6059.0"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash canary"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v119.0.6045.10/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 119.0.6045.10",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash dev",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v119.0.6045.10",
-              "revision": "version:119.0.6045.10"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash dev"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5938.157/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 117.0.5938.157",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash stable",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5938.157",
-              "revision": "version:117.0.5938.157"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash stable"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
         "name": "lacros_chrome_browsertests_run_in_series",
         "swarming": {
           "dimensions": {
@@ -45237,136 +45107,6 @@
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5993.60/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 118.0.5993.60",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash beta",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5993.60",
-              "revision": "version:118.0.5993.60"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash beta"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v120.0.6059.0/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 120.0.6059.0",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash canary",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v120.0.6059.0",
-              "revision": "version:120.0.6059.0"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash canary"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v119.0.6045.10/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 119.0.6045.10",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash dev",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v119.0.6045.10",
-              "revision": "version:119.0.6045.10"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash dev"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5938.157/test_ash_chrome"
-        ],
-        "description": "Run with ash-chrome version 117.0.5938.157",
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash stable",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5938.157",
-              "revision": "version:117.0.5938.157"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04",
-            "ssd": "0"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash stable"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
         "name": "lacros_chrome_browsertests_run_in_series",
         "swarming": {
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 03c78ae..2bac6b3 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -8415,7 +8415,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 42
+          "shards": 40
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
@@ -16488,151 +16488,6 @@
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5993.60/test_ash_chrome",
-          "--test-launcher-print-test-stdio=always",
-          "--combine-ash-logs-on-bots",
-          "--asan-symbolize-output"
-        ],
-        "description": "Run with ash-chrome version 118.0.5993.60",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash beta",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5993.60",
-              "revision": "version:118.0.5993.60"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash beta"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v120.0.6059.0/test_ash_chrome",
-          "--test-launcher-print-test-stdio=always",
-          "--combine-ash-logs-on-bots",
-          "--asan-symbolize-output"
-        ],
-        "description": "Run with ash-chrome version 120.0.6059.0",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash canary",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v120.0.6059.0",
-              "revision": "version:120.0.6059.0"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash canary"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v119.0.6045.10/test_ash_chrome",
-          "--test-launcher-print-test-stdio=always",
-          "--combine-ash-logs-on-bots",
-          "--asan-symbolize-output"
-        ],
-        "description": "Run with ash-chrome version 119.0.6045.10",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash dev",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v119.0.6045.10",
-              "revision": "version:119.0.6045.10"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash dev"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5938.157/test_ash_chrome",
-          "--test-launcher-print-test-stdio=always",
-          "--combine-ash-logs-on-bots",
-          "--asan-symbolize-output"
-        ],
-        "description": "Run with ash-chrome version 117.0.5938.157",
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash stable",
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5938.157",
-              "revision": "version:117.0.5938.157"
-            }
-          ],
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "lacros_chrome_browsertests",
-        "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash stable"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter",
-          "--test-launcher-print-test-stdio=always",
-          "--combine-ash-logs-on-bots",
-          "--asan-symbolize-output"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
         "name": "lacros_chrome_browsertests_run_in_series",
         "swarming": {
           "dimensions": {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index b9e8365..8534d94 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1015,10 +1015,6 @@
       "--logs-dir=${ISOLATED_OUTDIR}",
     ],
   },
-  "lacros_chrome_browsertests": {
-    "label": "//chrome/test:lacros_chrome_browsertests",
-    "type": "windowed_test_launcher",
-  },
   "lacros_chrome_browsertests_run_in_series": {
     "label": "//chrome/test:lacros_chrome_browsertests_run_in_series",
     "type": "windowed_test_launcher",
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index 154acd9..3d5b730 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1118,7 +1118,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R120-15639.0.0",
+        "cros_img": "brya-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "name": "chrome_all_tast_tests BRYA_RELEASE_LKGM",
         "shards": 10,
@@ -1132,7 +1132,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R120-15639.0.0",
+        "cros_img": "brya-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests BRYA_RELEASE_LKGM",
@@ -1147,7 +1147,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R120-15639.0.0",
+        "cros_img": "brya-release/R120-15642.0.0",
         "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests BRYA_RELEASE_LKGM",
@@ -1171,7 +1171,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "name": "chrome_all_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 10,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1184,7 +1184,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 3,
@@ -1198,7 +1198,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R120-15639.0.0",
+        "cros_img": "jacuzzi-release/R120-15642.0.0",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 2,
@@ -1245,7 +1245,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "trogdor",
-        "cros_img": "trogdor-release/R120-15639.0.0",
+        "cros_img": "trogdor-release/R120-15642.0.0",
         "name": "chrome_all_tast_tests TROGDOR_RELEASE_LKGM",
         "shards": 10,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1284,7 +1284,7 @@
       },
       {
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R120-15639.0.0",
+        "cros_img": "octopus-release/R120-15642.0.0",
         "name": "lacros_fyi_tast_tests OCTOPUS_RELEASE_LKGM",
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_fyi_tast_tests",
@@ -1322,7 +1322,7 @@
       },
       {
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R120-15639.0.0",
+        "cros_img": "octopus-release/R120-15642.0.0",
         "name": "ozone_unittests OCTOPUS_RELEASE_LKGM",
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -1367,7 +1367,7 @@
       },
       {
         "cros_board": "hana",
-        "cros_img": "hana-release/R120-15639.0.0",
+        "cros_img": "hana-release/R120-15642.0.0",
         "name": "lacros_all_tast_tests HANA_RELEASE_LKGM",
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
@@ -1398,7 +1398,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "strongbad",
-        "cros_img": "strongbad-release/R120-15639.0.0",
+        "cros_img": "strongbad-release/R120-15642.0.0",
         "name": "lacros_all_tast_tests STRONGBAD_RELEASE_LKGM",
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
@@ -1446,7 +1446,7 @@
       },
       {
         "cros_board": "hana",
-        "cros_img": "hana-release/R120-15639.0.0",
+        "cros_img": "hana-release/R120-15642.0.0",
         "name": "ozone_unittests HANA_RELEASE_LKGM",
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -1474,7 +1474,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "strongbad",
-        "cros_img": "strongbad-release/R120-15639.0.0",
+        "cros_img": "strongbad-release/R120-15642.0.0",
         "name": "ozone_unittests STRONGBAD_RELEASE_LKGM",
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -1519,7 +1519,7 @@
       },
       {
         "cros_board": "hana",
-        "cros_img": "hana-release/R120-15639.0.0",
+        "cros_img": "hana-release/R120-15642.0.0",
         "name": "viz_unittests HANA_RELEASE_LKGM",
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -1547,7 +1547,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "strongbad",
-        "cros_img": "strongbad-release/R120-15639.0.0",
+        "cros_img": "strongbad-release/R120-15642.0.0",
         "name": "viz_unittests STRONGBAD_RELEASE_LKGM",
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 64ffebe..78866cd 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4233,12 +4233,6 @@
     },
 
     'linux_lacros_chrome_browsertests_non_version_skew': {
-      'lacros_chrome_browsertests': {
-        'test': 'lacros_chrome_browsertests',
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter',
-        ],
-      },
       'lacros_chrome_browsertests_run_in_series': {
         'test': 'lacros_chrome_browsertests_run_in_series',
         'args': [
@@ -4251,11 +4245,6 @@
     },
 
     'linux_lacros_chrome_browsertests_version_skew': {
-      'lacros_chrome_browsertests': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter',
-        ],
-      },
       'lacros_chrome_browsertests_run_in_series': {
         'args': [
           '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter',
diff --git a/testing/buildbot/tryserver.chromium.chromiumos.json b/testing/buildbot/tryserver.chromium.chromiumos.json
index 61bffae..2762a63 100644
--- a/testing/buildbot/tryserver.chromium.chromiumos.json
+++ b/testing/buildbot/tryserver.chromium.chromiumos.json
@@ -9,7 +9,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R120-15639.0.0",
+        "cros_img": "volteer-public/R120-15642.0.0",
         "cros_model": "voxel",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests VOLTEER_PUBLIC_LKGM",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index e1dce08..21dd8f8f 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -432,7 +432,7 @@
     'identifier': 'BRYA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'brya',
-      'cros_img': 'brya-release/R120-15639.0.0',
+      'cros_img': 'brya-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -441,7 +441,7 @@
     'identifier': 'BRYA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'brya',
-      'cros_img': 'brya-release/R120-15639.0.0',
+      'cros_img': 'brya-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -474,7 +474,7 @@
     'identifier': 'DEDEDE_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'dedede',
-      'cros_img': 'dedede-release/R120-15639.0.0',
+      'cros_img': 'dedede-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -503,7 +503,7 @@
     'identifier': 'FIZZ_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'fizz',
-      'cros_img': 'fizz-release/R120-15639.0.0',
+      'cros_img': 'fizz-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -536,7 +536,7 @@
     'identifier': 'GUYBRUSH_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'guybrush',
-      'cros_img': 'guybrush-release/R120-15639.0.0',
+      'cros_img': 'guybrush-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -569,7 +569,7 @@
     'identifier': 'PUFF_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'puff',
-      'cros_img': 'puff-release/R120-15639.0.0',
+      'cros_img': 'puff-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
       'dut_pool': 'chrome',
     },
@@ -602,7 +602,7 @@
     'identifier': 'EVE_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-public/R120-15639.0.0',
+      'cros_img': 'eve-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -613,7 +613,7 @@
     'identifier': 'HANA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'hana',
-      'cros_img': 'hana-release/R120-15639.0.0',
+      'cros_img': 'hana-release/R120-15642.0.0',
     },
   },
   'CROS_HANA_RELEASE_DEV': {
@@ -641,7 +641,7 @@
     'identifier': 'JACUZZI_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R120-15639.0.0',
+      'cros_img': 'jacuzzi-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -663,7 +663,7 @@
     'identifier': 'JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R120-15639.0.0',
+      'cros_img': 'jacuzzi-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
     },
   },
@@ -678,7 +678,7 @@
     'identifier': 'JACUZZI_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R120-15639.0.0',
+      'cros_img': 'jacuzzi-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -686,7 +686,7 @@
     'identifier': 'JACUZZI_CQ_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R120-15639.0.0',
+      'cros_img': 'jacuzzi-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
@@ -696,7 +696,7 @@
     'identifier': 'TROGDOR_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'trogdor',
-      'cros_img': 'trogdor-public/R120-15639.0.0',
+      'cros_img': 'trogdor-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -704,7 +704,7 @@
     'identifier': 'OCTOPUS_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-public/R120-15639.0.0',
+      'cros_img': 'octopus-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -720,7 +720,7 @@
     'identifier': 'OCTOPUS_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-release/R120-15639.0.0',
+      'cros_img': 'octopus-release/R120-15642.0.0',
     },
   },
   'CROS_OCTOPUS_RELEASE_DEV': {
@@ -748,7 +748,7 @@
     'identifier': 'STRONGBAD_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'strongbad',
-      'cros_img': 'strongbad-release/R120-15639.0.0',
+      'cros_img': 'strongbad-release/R120-15642.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -777,7 +777,7 @@
     'identifier': 'TROGDOR_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'trogdor',
-      'cros_img': 'trogdor-release/R120-15639.0.0',
+      'cros_img': 'trogdor-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
     },
   },
@@ -786,7 +786,7 @@
     'skylab': {
       'cros_board': 'volteer',
       'cros_model': 'voxel',
-      'cros_img': 'volteer-public/R120-15639.0.0',
+      'cros_img': 'volteer-public/R120-15642.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -797,7 +797,7 @@
     'identifier': 'VOLTEER_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'volteer',
-      'cros_img': 'volteer-release/R119-15629.0.0',
+      'cros_img': 'volteer-release/R120-15642.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
     },
   },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 1b940b3..2c4eed7 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -573,20 +573,6 @@
           'all',
         ],
       },
-      'Android WebView N (dbg)': {
-        'test_suites': {
-          'gtest_tests': 'webview_bot_all_gtests',
-        },
-        'mixins': [
-          'has_native_resultdb_integration',
-          'nougat',
-          'bullhead',
-        ],
-        'swarming': {
-          'expiration': 10800,
-        },
-        'os_type': 'android',
-      },
       'Android WebView O (dbg)': {
         'mixins': [
           'has_native_resultdb_integration',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 06a07c4..2113319 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -8377,21 +8377,6 @@
             ]
         }
     ],
-    "IOSFeedPersistentDatastore": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "EnableDiskPersistentStore"
-                    ]
-                }
-            ]
-        }
-    ],
     "IOSFeedSignedOutViewDemotion": [
         {
             "platforms": [
@@ -15384,7 +15369,6 @@
                 "android_webview",
                 "chromeos",
                 "chromeos_lacros",
-                "fuchsia",
                 "linux",
                 "mac",
                 "windows"
diff --git a/third_party/angle b/third_party/angle
index d1cf2d4..05c21cf 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit d1cf2d432624fb178868db0f57bcba140ca95071
+Subproject commit 05c21cfc68099ee4edd20c880e99b185700a8c4c
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 102a878c..c3cfc0d 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1615,7 +1615,13 @@
 
 BASE_FEATURE(kSerializeAccessibilityPostLifecycle,
              "SerializeAccessibilityPostLifecycle",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+// TODO(crbug.com/1477047, fuchsia:132924): Enable for Fuchsia once tests pass.
+#if BUILDFLAG(IS_FUCHSIA)
+             base::FEATURE_DISABLED_BY_DEFAULT
+#else
+             base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+);
 
 // Experiment of the delay from navigation to starting an update of a service
 // worker's script.
diff --git a/third_party/blink/public/mojom/webauthn/authenticator.mojom b/third_party/blink/public/mojom/webauthn/authenticator.mojom
index 2d5357b..5de0cb1 100644
--- a/third_party/blink/public/mojom/webauthn/authenticator.mojom
+++ b/third_party/blink/public/mojom/webauthn/authenticator.mojom
@@ -122,6 +122,7 @@
   // so, |prf| contains the value of the `enabled` member.
   bool echo_prf;
   bool prf;
+  PRFValues? prf_results;
 
   // True if getClientExtensionResults() called on the returned
   // PublicKeyCredential instance should contain a `credBlob` extension output.
@@ -498,11 +499,13 @@
   // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#sctn-hmac-secret-extension
   bool hmac_create_secret;
 
-  // Whether the PRF extension was present. (Evaluation of the PRF at creation
-  // time is never supported currently, owing to a lack of hardware support.)
+  // Whether the PRF extension was present.
   // https://w3c.github.io/webauthn/#prf-extension
   bool prf_enable;
 
+  // Optional PRF input. Cannot have the `id` field set.
+  PRFValues? prf_input;
+
   // The value of the `credentialProtectionPolicy` extension, or UNSPECIFIED if
   // none was provided.
   ProtectionPolicy protection_policy;
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index 674453d..e26c098 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -4283,8 +4283,7 @@
     case CSSPropertyID::kWebkitMaskClip:
       return ConsumePrefixedBackgroundBox(range, AllowTextValue::kAllow);
     case CSSPropertyID::kMaskOrigin:
-      // TODO(crbug.com/1490702) update the allowed mask-origin value.
-      return ConsumePrefixedBackgroundBox(range, AllowTextValue::kForbid);
+      return ConsumeGeometryBox(range);
     case CSSPropertyID::kWebkitMaskOrigin:
       return ConsumePrefixedBackgroundBox(range, AllowTextValue::kForbid);
     default:
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 563ce99..5083ec2 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -9339,10 +9339,14 @@
 const CSSValue* WebkitMaskOrigin::ParseSingleValue(
     CSSParserTokenRange& range,
     const CSSParserContext&,
-    const CSSParserLocalContext&) const {
+    const CSSParserLocalContext& local_context) const {
+  if (local_context.UseAliasParsing()) {
+    return css_parsing_utils::ConsumeCommaSeparatedList(
+        css_parsing_utils::ConsumePrefixedBackgroundBox, range,
+        css_parsing_utils::AllowTextValue::kForbid);
+  }
   return css_parsing_utils::ConsumeCommaSeparatedList(
-      css_parsing_utils::ConsumePrefixedBackgroundBox, range,
-      css_parsing_utils::AllowTextValue::kForbid);
+      css_parsing_utils::ConsumeGeometryBox, range);
 }
 
 const CSSValue* WebkitMaskOrigin::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
index df84aa6..61379d8 100644
--- a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
@@ -618,8 +618,10 @@
 }
 
 Position CompositeEditCommand::PositionOutsideTabSpan(const Position& pos) {
-  if (!IsTabHTMLSpanElementTextNode(pos.AnchorNode()))
+  Node* anchor_node = pos.AnchorNode();
+  if (!IsTabHTMLSpanElementTextNode(anchor_node)) {
     return pos;
+  }
 
   switch (pos.AnchorType()) {
     case PositionAnchorType::kAfterChildren:
@@ -628,9 +630,9 @@
     case PositionAnchorType::kOffsetInAnchor:
       break;
     case PositionAnchorType::kBeforeAnchor:
-      return Position::InParentBeforeNode(*pos.AnchorNode());
+      return Position::InParentBeforeNode(*anchor_node);
     case PositionAnchorType::kAfterAnchor:
-      return Position::InParentAfterNode(*pos.AnchorNode());
+      return Position::InParentAfterNode(*anchor_node);
   }
 
   HTMLSpanElement* tab_span = TabSpanElement(pos.ComputeContainerNode());
@@ -643,8 +645,14 @@
   if (pos.OffsetInContainerNode() <= CaretMinOffset(pos.ComputeContainerNode()))
     return Position::InParentBeforeNode(*tab_span);
 
-  if (pos.OffsetInContainerNode() >= CaretMaxOffset(pos.ComputeContainerNode()))
-    return Position::InParentAfterNode(*tab_span);
+  if (pos.OffsetInContainerNode() >=
+      CaretMaxOffset(pos.ComputeContainerNode())) {
+    return anchor_node->HasNextSibling() &&
+                   RuntimeEnabledFeatures::
+                       PositionOutsideTabSpanCheckSiblingNodeEnabled()
+               ? Position::InParentAfterNode(*anchor_node)
+               : Position::InParentAfterNode(*tab_span);
+  }
 
   SplitTextNodeContainingElement(To<Text>(pos.ComputeContainerNode()),
                                  pos.OffsetInContainerNode());
diff --git a/third_party/blink/renderer/core/editing/serializers/serialization.cc b/third_party/blink/renderer/core/editing/serializers/serialization.cc
index f2d93e4..280379e 100644
--- a/third_party/blink/renderer/core/editing/serializers/serialization.cc
+++ b/third_party/blink/renderer/core/editing/serializers/serialization.cc
@@ -916,18 +916,22 @@
 }
 
 // Returns true if any svg <use> element is removed.
-static bool StripSVGUseDataURLs(Node& node) {
+static bool StripSVGUseNonLocalHrefs(Node& node) {
   if (auto* use = DynamicTo<SVGUseElement>(node)) {
     SVGURLReferenceResolver resolver(use->HrefString(), use->GetDocument());
-    if (resolver.AbsoluteUrl().ProtocolIsData())
+    if ((RuntimeEnabledFeatures::PastingBlocksSVGUseNonLocalHrefsEnabled() &&
+         !resolver.IsLocal()) ||
+        resolver.AbsoluteUrl().ProtocolIsData()) {
       node.remove();
+    }
     return true;
   }
   bool stripped = false;
   for (Node* child = node.firstChild(); child;) {
     Node* next = child->nextSibling();
-    if (StripSVGUseDataURLs(*child))
+    if (StripSVGUseNonLocalHrefs(*child)) {
       stripped = true;
+    }
     child = next;
   }
   return stripped;
@@ -974,8 +978,9 @@
     bool needs_sanitization = false;
     if (ContainsStyleElements(*fragment))
       needs_sanitization = true;
-    if (StripSVGUseDataURLs(*fragment))
+    if (StripSVGUseNonLocalHrefs(*fragment)) {
       needs_sanitization = true;
+    }
 
     if (!needs_sanitization) {
       markup = CreateMarkup(fragment);
diff --git a/third_party/blink/renderer/core/html/forms/resources/input_alert.svg b/third_party/blink/renderer/core/html/forms/resources/input_alert.svg
index a192e9b9..b81e8d76 100644
--- a/third_party/blink/renderer/core/html/forms/resources/input_alert.svg
+++ b/third_party/blink/renderer/core/html/forms/resources/input_alert.svg
@@ -3,20 +3,20 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="23" height="23" viewBox="0 0 47 47" id="icon">
-  <rect x="0" y="0" width="47" height="47" rx="4" ry="4" fill="#ff8c00"/>
+<rect x="0" y="0" width="47" height="47" rx="4" ry="4" fill="#ffa300"/>
 
-  <rect x="19" y="10" width="9" height="15" fill="#ffbc4f" />
-  <rect x="20" y="10" width="7" height="15" fill="#ffffff" />
-  <rect x="20" y="9" width="7" height="1" fill="#ffb53d" />
-  <rect x="20" y="25" width="7" height="1" fill="#ffd6af" />
-  <rect x="20" y="26" width="7" height="1" fill="#ff7e00" />
+<rect x="19" y="10" width="9" height="15" fill="#ffbc4f" />
+<rect x="20" y="10" width="7" height="15" fill="#ffffff" />
+<rect x="20" y="9" width="7" height="1" fill="#ffb53d" />
+<rect x="20" y="25" width="7" height="1" fill="#ffd6af" />
+<rect x="20" y="26" width="7" height="1" fill="#ff7e00" />
 
-  <defs>
-    <linearGradient id="g1" x1="0" y1="0" x2="0" y2="1">
-      <stop offset="0%" stop-color="#ffb53d" />
-      <stop offset="100%" stop-color="#ff7e00" />
-    </linearGradient>
-  </defs>
-  <circle cx="23.5" cy="33" r="4.5" fill="url(#g1)"/>
-  <circle cx="23.5" cy="33" r="3.5" fill="#ffffff"/>
+<defs>
+<linearGradient id="g1" x1="0" y1="0" x2="0" y2="1">
+<stop offset="0%" stop-color="#ffb53d" />
+<stop offset="100%" stop-color="#ff7e00" />
+</linearGradient>
+</defs>
+<circle cx="23.5" cy="33" r="4.5" fill="url(#g1)"/>
+<circle cx="23.5" cy="33" r="3.5" fill="#ffffff"/>
 </svg>
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 3ed757a..bf8f4b4 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3346,6 +3346,7 @@
   const WritingMode writing_mode = StyleRef().GetWritingMode();
   absl::optional<PhysicalRect> layout_overflow;
   LayoutUnit consumed_block_size;
+  LayoutUnit fragment_width_sum;
 
   // Iterate over all the fragments and unite their individual layout-overflow
   // to determine the final layout-overflow.
@@ -3362,6 +3363,11 @@
         break;
       case WritingMode::kVerticalRl:
       case WritingMode::kSidewaysRl:
+        // For flipped-blocks writing-modes, we build the total overflow rect
+        // from right-to-left (adding with negative offsets). At the end we
+        // need to make the origin relative to the LHS, so we add the total
+        // fragment width.
+        fragment_width_sum += fragment.Size().width;
         offset_adjust = {-fragment.Size().width - consumed_block_size,
                          LayoutUnit()};
         break;
@@ -3396,10 +3402,8 @@
   if (!layout_overflow)
     return;
 
-  // layout-overflow is stored respecting flipped-blocks.
   if (IsFlippedBlocksWritingMode(writing_mode)) {
-    layout_overflow->offset.left =
-        -layout_overflow->offset.left - layout_overflow->size.width;
+    layout_overflow->offset.left += fragment_width_sum;
   }
 
   if (layout_overflow->IsEmpty() ||
@@ -3409,7 +3413,7 @@
   DCHECK(!LayoutOverflowIsSet());
   if (!overflow_)
     overflow_ = MakeGarbageCollected<BoxOverflowModel>();
-  overflow_->layout_overflow.emplace(layout_overflow->ToLayoutRect());
+  overflow_->layout_overflow.emplace(*layout_overflow);
 }
 
 RecalcLayoutOverflowResult LayoutBox::RecalcLayoutOverflowNG() {
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 918bb1b..975aa97a 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -424,8 +424,7 @@
     NOT_DESTROYED();
     DCHECK(!IsLayoutMultiColumnSet());
     return LayoutOverflowIsSet()
-               ? FlipForWritingMode(
-                     overflow_->layout_overflow->LayoutOverflowRect())
+               ? overflow_->layout_overflow->LayoutOverflowRect()
                : NoOverflowRect();
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
index 3627944e..63835f59 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -219,7 +219,11 @@
 
 const NGLayoutResult*
 NGSimplifiedLayoutAlgorithm::CreateResultAfterManualChildLayout() {
-  return container_builder_.ToBoxFragment();
+  const NGLayoutResult* result = container_builder_.ToBoxFragment();
+  if (result->PhysicalFragment().IsOutOfFlowPositioned()) {
+    result->CopyMutableOutOfFlowData(previous_result_);
+  }
+  return result;
 }
 
 const NGLayoutResult* NGSimplifiedLayoutAlgorithm::Layout() {
diff --git a/third_party/blink/renderer/core/layout/overflow_model.h b/third_party/blink/renderer/core/layout/overflow_model.h
index 3067af0..e79c17c 100644
--- a/third_party/blink/renderer/core/layout/overflow_model.h
+++ b/third_party/blink/renderer/core/layout/overflow_model.h
@@ -32,9 +32,9 @@
 // BoxOverflowModel class tracks content that spills out of an object.
 // It is used by LayoutBox.
 //
-// All overflows are in the coordinate space of the object (i.e. physical
-// coordinates with flipped block-flow direction). See documentation of
-// LayoutBoxModelObject and LayoutBox::NoOverflowRect() for more details.
+// All overflows are in the physical coordinate space of the object. See
+// documentation of LayoutBoxModelObject and LayoutBox::NoOverflowRect() for
+// more details.
 //
 // The class models the overflows as rectangles that unite all the sources of
 // overflow. This is the natural choice for layout overflow (scrollbars are
@@ -93,15 +93,15 @@
 // invariant.
 class BoxLayoutOverflowModel {
  public:
-  BoxLayoutOverflowModel(const LayoutRect& layout_rect)
-      : layout_overflow_(layout_rect) {}
+  explicit BoxLayoutOverflowModel(const PhysicalRect& overflow_rect)
+      : layout_overflow_(overflow_rect) {}
   BoxLayoutOverflowModel(const BoxLayoutOverflowModel&) = delete;
   BoxLayoutOverflowModel& operator=(const BoxLayoutOverflowModel&) = delete;
 
-  const LayoutRect& LayoutOverflowRect() const { return layout_overflow_; }
+  const PhysicalRect& LayoutOverflowRect() const { return layout_overflow_; }
 
  private:
-  LayoutRect layout_overflow_;
+  PhysicalRect layout_overflow_;
 };
 
 class BoxVisualOverflowModel {
diff --git a/third_party/blink/renderer/core/layout/overflow_model_test.cc b/third_party/blink/renderer/core/layout/overflow_model_test.cc
index 2db5e330..3054f2b 100644
--- a/third_party/blink/renderer/core/layout/overflow_model_test.cc
+++ b/third_party/blink/renderer/core/layout/overflow_model_test.cc
@@ -32,13 +32,12 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
 
 namespace blink {
 namespace {
 
-LayoutRect InitialLayoutOverflow() {
-  return LayoutRect(10, 10, 80, 80);
+PhysicalRect InitialLayoutOverflow() {
+  return PhysicalRect(10, 10, 80, 80);
 }
 
 PhysicalRect InitialVisualOverflow() {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
index 81fc880..4f7fc024 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -39,8 +39,7 @@
 using HighlightDecoration = NGHighlightOverlay::HighlightDecoration;
 using HighlightPart = NGHighlightOverlay::HighlightPart;
 
-// ClampOffset modifies |offset| fixed in a range of |text_fragment| start/end
-// offsets.
+// Modifies |offset| fixed in a range of |fragment_range| start/end offsets.
 // |offset| points not each character but each span between character.
 // With that concept, we can clear catch what is inside start / end.
 // Suppose we have "foo_bar"('_' is a space).
@@ -49,12 +48,114 @@
 // 0 1 2 3 4 5 6 7
 // If "bar" is a TextFragment. That start(), end() {4, 7} correspond this
 // offset. If a marker has StartOffset / EndOffset as {2, 6},
-// ClampOffset returns{ 4,6 }, which represents "ba" on "foo_bar".
-unsigned ClampOffset(unsigned offset, const NGFragmentItem& text_fragment) {
-  return std::min(std::max(offset, text_fragment.StartOffset()),
-                  text_fragment.EndOffset());
+// this function returns{ 4,6 }, which represents "ba" on "foo_bar".
+unsigned ClampToFragmentRange(const NGTextOffsetRange& fragment_range,
+                              unsigned offset) {
+  return std::min(std::max(offset, fragment_range.start), fragment_range.end);
 }
 
+base::span<const NGOffsetMappingUnit> GetMappingUnits(
+    const NGFragmentItem& text_fragment) {
+  const NGOffsetMapping* const offset_mapping =
+      NGOffsetMapping::GetFor(text_fragment.GetLayoutObject());
+  DCHECK(offset_mapping);
+  return offset_mapping->GetMappingUnitsForTextContentOffsetRange(
+      text_fragment.StartOffset(), text_fragment.EndOffset());
+}
+
+// Helper for mapping from DOM offset (range) to text content offset.
+//
+// Exploits the fact that DocumentMarkers are sorted in DOM offset order, to
+// maintain a cached starting point within the unit mapping range and thus
+// amortize the cost of unit lookup.
+class MarkerRangeMappingContext {
+  STACK_ALLOCATED();
+
+ private:
+  // The internal class that implements the mapping.
+  class DOMToTextContentOffsetMapper {
+    STACK_ALLOCATED();
+
+   public:
+    explicit DOMToTextContentOffsetMapper(const NGFragmentItem& text_fragment)
+        : units_(GetMappingUnits(text_fragment)), units_begin_(units_.begin()) {
+      DCHECK(units_.size());
+    }
+
+    unsigned GetTextContentOffset(unsigned dom_offset) const {
+      auto unit = FindUnit(units_begin_, dom_offset);
+      // Update the cached search starting point.
+      units_begin_ = unit;
+      // Since the unit range only covers the fragment, map anything that falls
+      // outside of that range to the start/end.
+      if (dom_offset < unit->DOMStart()) {
+        return unit->TextContentStart();
+      }
+      if (dom_offset > unit->DOMEnd()) {
+        return unit->TextContentEnd();
+      }
+      return unit->ConvertDOMOffsetToTextContent(dom_offset);
+    }
+
+    unsigned GetTextContentOffsetNoCache(unsigned dom_offset) const {
+      auto unit = FindUnit(units_begin_, dom_offset);
+      // Since the unit range only covers the fragment, map anything that falls
+      // outside of that range to the start/end.
+      if (dom_offset < unit->DOMStart()) {
+        return unit->TextContentStart();
+      }
+      if (dom_offset > unit->DOMEnd()) {
+        return unit->TextContentEnd();
+      }
+      return unit->ConvertDOMOffsetToTextContent(dom_offset);
+    }
+
+   private:
+    // Find the mapping unit for `dom_offset`, starting from `begin`.
+    base::span<const NGOffsetMappingUnit>::iterator FindUnit(
+        base::span<const NGOffsetMappingUnit>::iterator begin,
+        unsigned dom_offset) const {
+      if (dom_offset <= begin->DOMEnd()) {
+        return begin;
+      }
+      return std::prev(std::upper_bound(
+          begin, units_.end(), dom_offset,
+          [](unsigned offset, const NGOffsetMappingUnit& unit) {
+            return offset < unit.DOMStart();
+          }));
+    }
+
+    base::span<const NGOffsetMappingUnit> units_;
+    mutable base::span<const NGOffsetMappingUnit>::iterator units_begin_;
+  };
+
+ public:
+  explicit MarkerRangeMappingContext(const NGFragmentItem& text_fragment)
+      : mapper_(DOMToTextContentOffsetMapper(text_fragment)),
+        fragment_range_(text_fragment.TextOffset()),
+        text_length_(To<Text>(*text_fragment.GetNode()).length()) {}
+
+  std::pair<unsigned, unsigned> MapToTextContent(
+      const DocumentMarker& marker) const {
+    // TODO(yoichio): Sanitize DocumentMarker around text length.
+    const unsigned start_dom_offset =
+        std::min(marker.StartOffset(), text_length_);
+    const unsigned end_dom_offset = std::min(marker.EndOffset(), text_length_);
+    const unsigned text_content_start =
+        mapper_.GetTextContentOffset(start_dom_offset);
+    const unsigned text_content_end =
+        mapper_.GetTextContentOffsetNoCache(end_dom_offset);
+    return std::make_pair(
+        ClampToFragmentRange(fragment_range_, text_content_start),
+        ClampToFragmentRange(fragment_range_, text_content_end));
+  }
+
+ private:
+  const DOMToTextContentOffsetMapper mapper_;
+  const NGTextOffsetRange fragment_range_;
+  const unsigned text_length_;
+};
+
 PhysicalRect MarkerRectForForeground(const NGFragmentItem& text_fragment,
                                      StringView text,
                                      unsigned start_offset,
@@ -513,18 +614,12 @@
     return;
 
   DCHECK(fragment_item_.GetNode());
-  const auto& text_node = To<Text>(*fragment_item_.GetNode());
   const StringView text = cursor_.CurrentText();
 
+  const MarkerRangeMappingContext mapping_context(fragment_item_);
   for (const DocumentMarker* marker : markers_) {
-    const unsigned marker_start_offset =
-        GetTextContentOffset(text_node, marker->StartOffset());
-    const unsigned marker_end_offset =
-        GetTextContentOffset(text_node, marker->EndOffset());
-    const unsigned paint_start_offset =
-        ClampOffset(marker_start_offset, fragment_item_);
-    const unsigned paint_end_offset =
-        ClampOffset(marker_end_offset, fragment_item_);
+    const auto [paint_start_offset, paint_end_offset] =
+        mapping_context.MapToTextContent(*marker);
     if (paint_start_offset == paint_end_offset)
       continue;
 
@@ -722,15 +817,10 @@
     const Text& text_node,
     const StringView& text,
     const DocumentMarkerVector& markers) {
+  const MarkerRangeMappingContext mapping_context(fragment_item_);
   for (const DocumentMarker* marker : markers) {
-    const unsigned marker_start_offset =
-        GetTextContentOffset(text_node, marker->StartOffset());
-    const unsigned marker_end_offset =
-        GetTextContentOffset(text_node, marker->EndOffset());
-    const unsigned paint_start_offset =
-        ClampOffset(marker_start_offset, fragment_item_);
-    const unsigned paint_end_offset =
-        ClampOffset(marker_end_offset, fragment_item_);
+    const auto [paint_start_offset, paint_end_offset] =
+        mapping_context.MapToTextContent(*marker);
     if (paint_start_offset == paint_end_offset)
       continue;
     PaintOneSpellingGrammarDecoration(marker->GetType(), text,
@@ -856,12 +946,11 @@
     absl::optional<AffineTransform> rotation) {
   DCHECK_EQ(paint_case_, kOverlay);
 
-  // |node| might not be a Text node (e.g. <br>), or it might be nullptr (e.g.
+  // |node_| might not be a Text node (e.g. <br>), or it might be nullptr (e.g.
   // ::first-letter). In both cases, we should still try to paint kOriginating
   // and kSelection if necessary, but we can’t paint marker-based highlights,
   // because GetTextContentOffset requires a Text node. Markers are defined and
   // stored in terms of Text nodes anyway, so this should never be a problem.
-  const auto* text_node = DynamicTo<Text>(node_);
   const Document& document = layout_object_->GetDocument();
 
   // For each overlay, paint its backgrounds and shadows over every highlighted
@@ -874,6 +963,7 @@
     const DocumentMarkerVector* markers =
         SelectMarkers(layer.id, custom_, grammar_, spelling_, target_);
 
+    const MarkerRangeMappingContext mapping_context(fragment_item_);
     for (const auto& marker : *markers) {
       if (layer.id.type == HighlightLayerType::kCustom) {
         // Filter custom highlight markers to one highlight at a time.
@@ -882,13 +972,9 @@
           continue;
       }
 
-      const unsigned content_start =
-          GetTextContentOffset(*text_node, marker->StartOffset());
-      const unsigned content_end =
-          GetTextContentOffset(*text_node, marker->EndOffset());
-      const unsigned clamped_start = ClampOffset(content_start, fragment_item_);
-      const unsigned clamped_end = ClampOffset(content_end, fragment_item_);
-      const unsigned length = clamped_end - clamped_start;
+      const auto [paint_start_offset, paint_end_offset] =
+          mapping_context.MapToTextContent(*marker);
+      const unsigned length = paint_end_offset - paint_start_offset;
       if (length == 0)
         continue;
 
@@ -899,16 +985,17 @@
 
       // TODO(crbug.com/1434114) paint rects pixel-snapped in physical space,
       // not writing-mode space (SelectionPaintState::PaintSelectionBackground)
-      PaintRect(paint_info_.context, PhysicalOffset(box_origin_),
-                fragment_item_.LocalRect(text, clamped_start, clamped_end),
-                background_color,
-                PaintAutoDarkMode(originating_style_,
-                                  DarkModeFilter::ElementRole::kSelection));
+      PaintRect(
+          paint_info_.context, PhysicalOffset(box_origin_),
+          fragment_item_.LocalRect(text, paint_start_offset, paint_end_offset),
+          background_color,
+          PaintAutoDarkMode(originating_style_,
+                            DarkModeFilter::ElementRole::kSelection));
 
       if (layer.text_style.shadow) {
         text_painter_.Paint(
-            fragment_paint_info_.Slice(clamped_start, clamped_end), length,
-            layer.text_style, node_id, foreground_auto_dark_mode_,
+            fragment_paint_info_.Slice(paint_start_offset, paint_end_offset),
+            length, layer.text_style, node_id, foreground_auto_dark_mode_,
             TextPainterBase::kShadowsOnly);
       }
     }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 5945ba4..d4d6c6f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -729,6 +729,8 @@
                                      const ui::AXMode& ax_mode)
     : document_(document),
       ax_mode_(ax_mode),
+      serialize_post_lifecycle_(base::FeatureList::IsEnabled(
+          blink::features::kSerializeAccessibilityPostLifecycle)),
       validation_message_axid_(0),
       active_aria_modal_dialog_(nullptr),
       accessibility_event_permission_(mojom::blink::PermissionStatus::ASK),
@@ -1832,7 +1834,8 @@
 
 void AXObjectCacheImpl::RemoveSubtreeWithFlatTraversal(const Node* node,
                                                        bool remove_root,
-                                                       bool notify_parent) {
+                                                       bool notify_parent,
+                                                       bool only_layout) {
   DCHECK(node);
   // Previously used DCHECK(AXObject::CanSafelyUseFlatTreeTraversalNow()) but
   // failed because document had pending slot assignment in
@@ -1849,7 +1852,8 @@
     for (Node* child_node = LayoutTreeBuilderTraversal::FirstChild(*node);
          child_node;
          child_node = LayoutTreeBuilderTraversal::NextSibling(*child_node)) {
-      RemoveSubtreeWithFlatTraversal(child_node, /* remove_root */ true);
+      RemoveSubtreeWithFlatTraversal(child_node, /* remove_root */ true,
+                                     /* notify_parent */ false, only_layout);
     }
   }
 
@@ -1870,7 +1874,8 @@
     } else if (ax_included_child->GetNode()) {
       DCHECK(ax_included_child->GetNode() != node);
       RemoveSubtreeWithFlatTraversal(ax_included_child->GetNode(),
-                                     /* remove_root */ true);
+                                     /* remove_root */ true,
+                                     /* notify_parent */ false, only_layout);
     } else {
       RemoveIncludedSubtree(ax_included_child, /* remove_root */ true);
     }
@@ -1882,7 +1887,9 @@
   AXObject* parent_to_notify =
       notify_parent ? object->CachedParentObject() : nullptr;
   if (remove_root) {
-    Remove(object, /* notify_parent */ false);
+    if (!only_layout || IsA<AXLayoutObject>(object)) {
+      Remove(object, /* notify_parent */ false);
+    }
   }
   if (parent_to_notify) {
     if (processing_deferred_events_) {
@@ -2268,11 +2275,17 @@
     return;
   }
 
+  // If we're removing layout from a subtree, we only need to remove
+  // AXLayoutObjects. This helps avoid duplicate menu hide events,  e.g.
+  // in DumpAccessibilityEventsTest.AccessibilityEventsMenubarShowHideMenus.
+  bool only_layout = IsA<AXLayoutObject>(obj) && !node->GetLayoutObject();
+
   // Note that technically we do not need to remove the root node for a
   // display-locking (content-visibility) change, since it is only the
   // descendants that gain or lose their objects, but its easier to be
   // consistent here.
-  RemoveSubtreeWithFlatTraversal(node);
+  RemoveSubtreeWithFlatTraversal(node, /* remove_root */ true,
+                                 /* notify_parent */ true, only_layout);
 }
 
 void AXObjectCacheImpl::NodeIsAttached(Node* node) {
@@ -2304,7 +2317,8 @@
     if (AXObject* obj = SafeGet(node); obj && !IsA<AXLayoutObject>(obj)) {
       // Had a previous AXObject, but wasn't an AXLayoutObject, even though
       // there is a layout object available.
-      RemoveSubtreeWithFlatTraversal(node);
+      RemoveSubtreeWithFlatTraversal(node, /* remove_root */ true,
+                                     /* notify_parent */ true);
       return;
     }
   }
@@ -4455,9 +4469,9 @@
     bool& need_to_send_location_changes) {
   // TODO(accessibility) Remove this once non-postlifecycle serialization code
   // is completely removed, as it is redundant with other calls.
-#if BUILDFLAG(IS_FUCHSIA)
-  CheckTreeIsUpdated();
-#endif
+  if (!serialize_post_lifecycle_) {
+    CheckTreeIsUpdated();
+  }
 
   // Make a copy of the events, because it's possible that
   // actions inside this loop will cause more events to be
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index db207746..6014bfa 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -145,12 +145,12 @@
   void Dispose() override;
 
   void Freeze() override {
-    // TODO(crbug.com/1477047, fuchsia:132924): Remove Fuchsia case once post
-    // lifecycle serialization is enabled for it.
-#if BUILDFLAG(IS_FUCHSIA)
-    pause_tree_updates_until_more_loaded_content_ = false;
-    UpdateAXForAllDocuments();
-#endif
+    if (!serialize_post_lifecycle_) {
+      // TODO(accessibility) Remove this once non-postlifecycle serialization
+      // code is completely removed, as it is redundant with other calls.
+      pause_tree_updates_until_more_loaded_content_ = false;
+      UpdateAXForAllDocuments();
+    }
     ax_tree_source_->Freeze();
     is_frozen_ = true;
   }
@@ -209,7 +209,8 @@
   // corresponded with an AXLayoutObject (useful for subtrees that lose layout).
   void RemoveSubtreeWithFlatTraversal(const Node*,
                                       bool remove_root = true,
-                                      bool notify_parent = true);
+                                      bool notify_parent = true,
+                                      bool only_layout_objects = false);
   void RemoveSubtreeWhenSafe(Node*, bool remove_root = true) override;
 
   // Remove the cached subtree of included AXObjects. If |remove_root| is false,
@@ -796,6 +797,8 @@
   Member<Document> popup_document_;
 
   ui::AXMode ax_mode_;
+  const bool serialize_post_lifecycle_;
+
   HeapHashMap<AXID, Member<AXObject>> objects_;
   HeapHashMap<Member<AccessibleNode>, AXID> accessible_node_mapping_;
   HeapHashMap<Member<const LayoutObject>, AXID> layout_object_mapping_;
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
index 2f1f0dd7..e05041c 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
@@ -664,6 +664,10 @@
     }
     if (extensions->hasPrf()) {
       mojo_options->prf_enable = true;
+      if (extensions->prf()->hasEval()) {
+        mojo_options->prf_input =
+            ConvertTo<PRFValuesPtr>(*extensions->prf()->eval());
+      }
     }
   }
 
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
index de79289..7a41479 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
@@ -635,6 +635,18 @@
 }
 #endif
 
+AuthenticationExtensionsPRFValues* GetPRFExtensionResults(
+    const mojom::blink::PRFValuesPtr& prf_results) {
+  auto* values = AuthenticationExtensionsPRFValues::Create();
+  values->setFirst(MakeGarbageCollected<V8UnionArrayBufferOrArrayBufferView>(
+      VectorToDOMArrayBuffer(std::move(prf_results->first))));
+  if (prf_results->second) {
+    values->setSecond(MakeGarbageCollected<V8UnionArrayBufferOrArrayBufferView>(
+        VectorToDOMArrayBuffer(std::move(prf_results->second.value()))));
+  }
+  return values;
+}
+
 void OnMakePublicKeyCredentialComplete(
     std::unique_ptr<ScopedPromiseResolver> scoped_resolver,
     std::unique_ptr<ScopedAbortState> scoped_abort_state,
@@ -723,6 +735,9 @@
   if (credential->echo_prf) {
     auto* prf_outputs = AuthenticationExtensionsPRFOutputs::Create();
     prf_outputs->setEnabled(credential->prf);
+    if (credential->prf_results) {
+      prf_outputs->setResults(GetPRFExtensionResults(credential->prf_results));
+    }
     extension_outputs->setPrf(prf_outputs);
   }
   resolver->Resolve(MakeGarbageCollected<PublicKeyCredential>(
@@ -892,18 +907,8 @@
     if (extensions->echo_prf) {
       auto* prf_outputs = AuthenticationExtensionsPRFOutputs::Create();
       if (extensions->prf_results) {
-        auto* values = AuthenticationExtensionsPRFValues::Create();
-        values->setFirst(
-            MakeGarbageCollected<V8UnionArrayBufferOrArrayBufferView>(
-                VectorToDOMArrayBuffer(
-                    std::move(extensions->prf_results->first))));
-        if (extensions->prf_results->second) {
-          values->setSecond(
-              MakeGarbageCollected<V8UnionArrayBufferOrArrayBufferView>(
-                  VectorToDOMArrayBuffer(
-                      std::move(extensions->prf_results->second.value()))));
-        }
-        prf_outputs->setResults(values);
+        prf_outputs->setResults(
+            GetPRFExtensionResults(extensions->prf_results));
       }
       extension_outputs->setPrf(prf_outputs);
     }
@@ -1055,6 +1060,23 @@
   return nullptr;
 }
 
+const char* validateCreatePublicKeyCredentialPRFExtension(
+    const AuthenticationExtensionsPRFInputs& prf) {
+  if (prf.hasEval()) {
+    const char* error = validatePRFInputs(*prf.eval());
+    if (error != nullptr) {
+      return error;
+    }
+  }
+
+  if (prf.hasEvalByCredential()) {
+    return "The 'evalByCredential' field cannot be set when creating a "
+           "credential.";
+  }
+
+  return nullptr;
+}
+
 const char* validateGetPublicKeyCredentialPRFExtension(
     const AuthenticationExtensionsPRFInputs& prf,
     const HeapVector<Member<PublicKeyCredentialDescriptor>>&
@@ -1814,12 +1836,11 @@
       return promise;
     }
     if (options->publicKey()->extensions()->hasPrf()) {
-      const auto& prf = *options->publicKey()->extensions()->prf();
-      if (prf.hasEvalByCredential()) {
+      const char* error = validateCreatePublicKeyCredentialPRFExtension(
+          *options->publicKey()->extensions()->prf());
+      if (error != nullptr) {
         resolver->Reject(MakeGarbageCollected<DOMException>(
-            DOMExceptionCode::kNotSupportedError,
-            "The 'evalByCredential' field cannot be set when creating a "
-            "credential."));
+            DOMExceptionCode::kNotSupportedError, error));
         return promise;
       }
     }
diff --git a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
index e68963a..b23ad8f1 100644
--- a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
+++ b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
@@ -85,10 +85,19 @@
       source_string.data(),
       base::checked_cast<unsigned>(source_string.length()));
 
+// TODO(crbug.com/1353987): Remove the special case for Android after the
+// RemotingMediaSource on Android has been updated to parse the new Remote
+// Playback URL format.
+#if BUILDFLAG(IS_ANDROID)
+  return KURL(
+      base::StrCat({kRemotePlaybackPresentationUrlScheme, "://"}).c_str() +
+      encoded_source);
+#else
   return KURL(StringView(kRemotePlaybackPresentationUrlScheme) + "://" +
               encoded_source +
               "?video_codec=" + media::GetCodecName(video_codec).c_str() +
               "&audio_codec=" + media::GetCodecName(audio_codec).c_str());
+#endif
 }
 
 bool IsBackgroundAvailabilityMonitoringDisabled() {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index b10bc89..6d8af07 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1582,12 +1582,14 @@
     {
       name: "EyeDropperAPI",
       status: {
-        // EyeDropper UI is available only on Windows, Mac, and Linux. This list
-        // should match the supported operating systems for the kEyeDropper
-        // base::Feature.
+        // EyeDropper UI is available on ChromeOS, Linux (x11), Mac, and Win.
+        // This list should match the supported operating systems for the
+        // kEyeDropper base::Feature.
+        "ChromeOS_Ash": "stable",
+        "ChromeOS_Lacros": "stable",
+        "Linux": "stable",
         "Mac": "stable",
         "Win": "stable",
-        "Linux": "stable",
       },
       base_feature: "none",
     },
@@ -2823,6 +2825,10 @@
       base_feature: "none",
     },
     {
+      name: "PastingBlocksSVGUseNonLocalHrefs",
+      status: "stable",
+    },
+    {
       name: "PaymentApp",
       depends_on: ["PaymentRequest"],
       public: true,
@@ -2959,6 +2965,10 @@
       copied_from_base_feature_if: "overridden",
     },
     {
+      name: "PositionOutsideTabSpanCheckSiblingNode",
+      status: "stable",
+    },
+    {
       name: "PreciseMemoryInfo",
       base_feature: "none",
       public: true,
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 155d28c..d84b878a 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -812,12 +812,8 @@
 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-image-6.html [ Skip ]
 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-positioning-3.html [ Skip ]
 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-positioning-4.html [ Skip ]
-external/wpt/css/css-backgrounds/background-image-007.html [ Skip ]
 external/wpt/css/css-backgrounds/background-repeat/background-repeat-round-roundup.xht [ Skip ]
 external/wpt/css/css-backgrounds/background-repeat/background-repeat-round.xht [ Skip ]
-external/wpt/css/css-backgrounds/background-size-025.html [ Skip ]
-external/wpt/css/css-backgrounds/background-size-027.html [ Skip ]
-external/wpt/css/css-backgrounds/background-size-029.html [ Skip ]
 external/wpt/css/css-backgrounds/background-size/background-size-contain.xht [ Skip ]
 external/wpt/css/css-backgrounds/background-size/vector/background-size-vector-003.html [ Skip ]
 external/wpt/css/css-backgrounds/background-size/vector/background-size-vector-004.html [ Skip ]
@@ -928,10 +924,6 @@
 external/wpt/css/css-backgrounds/background-size/vector/wide--cover--percent-width-nonpercent-height-viewbox.html [ Skip ]
 external/wpt/css/css-backgrounds/background-size/vector/wide--cover--percent-width-omitted-height-viewbox.html [ Skip ]
 external/wpt/css/css-backgrounds/background-size/vector/wide--cover--percent-width-percent-height-viewbox.html [ Skip ]
-external/wpt/css/css-backgrounds/css-border-radius-001.html [ Skip ]
-external/wpt/css/css-backgrounds/css-box-shadow-001.html [ Skip ]
-external/wpt/css/css-backgrounds/css3-background-origin-padding-box.html [ Skip ]
-external/wpt/css/css-backgrounds/css3-background-size-001.html [ Skip ]
 external/wpt/css/css-backgrounds/first-letter-space-not-selected.html [ Skip ]
 
 # Failures on the initial import of css-color. Test suite had many other bugs,
diff --git a/third_party/blink/web_tests/editing/inserting/insert-text-into-tab-span.html b/third_party/blink/web_tests/editing/inserting/insert-text-into-tab-span.html
new file mode 100644
index 0000000..b0e5f646
--- /dev/null
+++ b/third_party/blink/web_tests/editing/inserting/insert-text-into-tab-span.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
+<script>
+selection_test(
+  [
+    '<div contenteditable>',
+      '<span style="white-space: pre;">\t<span>|hello</span></span>',
+    '</div>',
+  ],
+  'insertText X',
+  [
+    '<div contenteditable>',
+      '<span style="white-space: pre;">\tX|<span>hello</span></span>',
+    '</div>',
+  ],
+  'Insert text into tab span');
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/editing/pasteboard/paste-svg-use.html b/third_party/blink/web_tests/editing/pasteboard/paste-svg-use.html
index 7f9d4e7..c722c8c2 100644
--- a/third_party/blink/web_tests/editing/pasteboard/paste-svg-use.html
+++ b/third_party/blink/web_tests/editing/pasteboard/paste-svg-use.html
@@ -35,4 +35,16 @@
   },
   '<div contenteditable><div><br></div><div>      <u title="</div><div>      </div><div>      ">asdasd|</div></div>',
   'Paste blocks data URI in SVG use element injection via <noscript>');
+
+// crbug.com/1490811
+selection_test(
+  '<div contenteditable>|</div>',
+  selection => {
+    selection.setClipboardData(
+      `<svg><use xlink:href="https://example.com/external.svg#xss" /></svg>` +
+      `<svg><use href="https://example.com/external.svg#xss" /></svg>`);
+    selection.document.execCommand('paste');
+  },
+  '<div contenteditable>|<svg></svg><svg></svg></div>',
+  'Paste blocks non-local hrefs in SVG use elements');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-insets-multicol-absolute-crash.html b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-insets-multicol-absolute-crash.html
new file mode 100644
index 0000000..81b0b88
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-insets-multicol-absolute-crash.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>Chromium bug: getComputedStyle() crashes with inset properties on abspos in multicol</title>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1473508">
+<style>
+html {
+  column-count:2;
+}
+body {
+  transform: scale(1);
+}
+div#test {
+  column-count:2;
+  position:absolute;
+}
+</style>
+
+<div id="test">
+  <svg xmlns="http://www.w3.org/2000/svg"></svg>
+  <div style="transform: scale(1)">
+    <ruby style="position: absolute">
+      <rt>foo</rt>
+    </ruby>
+  </div>
+</div>
+
+<script>
+getComputedStyle(test).right;
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-prf.https.html b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-prf.https.html
index 7243e088d..ac2d5b5f 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-prf.https.html
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-prf.https.html
@@ -37,6 +37,31 @@
     });
     return promise_rejects_dom(t, "NotSupportedError", promise);
   }, "navigator.credentials.create() with nonsensical evalByCredential");
+
+  promise_test(async t => {
+    // Evaluating the PRF at creation time is not supported by security keys
+    // because it cannot be expressed with the CTAP2 hmac-secret extension,
+    // but it is defined at the WebAuthn level.
+
+    const credential = await createCredential({
+      options: {
+        publicKey: {
+          extensions: {
+            prf: {eval: {first: new Uint8Array([1,2,3,4]).buffer}},
+          },
+        },
+      },
+    });
+    assert_true(credential.getClientExtensionResults().prf.enabled,
+                "prf.enabled");
+    assert_true('results' in credential.getClientExtensionResults().prf,
+                "has results");
+    assert_true('first' in credential.getClientExtensionResults().prf.results,
+                "has results.first");
+    assert_equals(
+        credential.getClientExtensionResults().prf.results.first.byteLength, 32,
+        "correct length output");
+  }, "navigator.credentials.create() with eval");
 }, {
   protocol: "ctap2_1",
   extensions: ["prf"],
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 866c3af9..46d18c04 100644
--- a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index caf265b..30627d6 100644
--- a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/custom-elements/form-validation-bubble-appearance-expected.png b/third_party/blink/web_tests/platform/linux/custom-elements/form-validation-bubble-appearance-expected.png
index 51931b21..f0e3c908 100644
--- a/third_party/blink/web_tests/platform/linux/custom-elements/form-validation-bubble-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/custom-elements/form-validation-bubble-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png
index ecc4396c..a6a998ef 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-escape-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-escape-expected.png
index a33c5286..22cf1ef 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-escape-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-escape-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png
index b580c35..86f93e12 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-newline-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-newline-expected.png
index ac0c74a..0d0e849 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-newline-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-newline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
index 9b5de06..53f73f9 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-wrap-expected.png
index 62d0e92f..5e2d5a1b 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-change-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-change-expected.png
index 98e71229..a00ae22 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-change-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-expected.png
index 0993e72a..1450194 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/validation-bubble-device-emulation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
index 23da7c32..d54b71b 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
index da0e776..2833350 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 866c3af9..46d18c04 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index caf265b..30627d6 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/custom-elements/form-validation-bubble-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/custom-elements/form-validation-bubble-appearance-expected.png
index 40623a00..f898489 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/custom-elements/form-validation-bubble-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/custom-elements/form-validation-bubble-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-edge-expected.png
index 6e93c87..bf0670d3 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-escape-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-escape-expected.png
index 1e78d1be..0b12aff 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-escape-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-escape-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-iframe-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-iframe-expected.png
index 2e0cd57..8dcbd47 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-iframe-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-iframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-newline-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-newline-expected.png
index 96be44d..5cf5139 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-newline-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-newline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
index 937a44159..3291a9b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-wrap-expected.png
index ac38a5f..c926b76 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-change-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-change-expected.png
index adc77e9..7018618 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-change-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-expected.png
index a1a0dff..bfa9e2b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/fast/forms/validation-bubble-device-emulation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
index ce0127b..df0d17a6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
index e24429b..41bfd789 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 6b1299d..b00f861c 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 6b1299d..75b5a4b 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/mac-mac11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 6b1299d..75b5a4b 100644
--- a/third_party/blink/web_tests/platform/mac-mac11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 6b1299d..75b5a4b 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/mac-mac12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 6b1299d..75b5a4b 100644
--- a/third_party/blink/web_tests/platform/mac-mac12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 6b1299d..75b5a4b 100644
--- a/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac13-arm64/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/custom-elements/form-validation-bubble-appearance-expected.png b/third_party/blink/web_tests/platform/mac/custom-elements/form-validation-bubble-appearance-expected.png
index 40623a00..eef7d07 100644
--- a/third_party/blink/web_tests/platform/mac/custom-elements/form-validation-bubble-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac/custom-elements/form-validation-bubble-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-edge-expected.png
index 6e93c87..47c42d2 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-escape-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-escape-expected.png
index 1e78d1be..ab7ddd5 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-escape-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-escape-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-iframe-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-iframe-expected.png
index 2e0cd57..c018290 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-iframe-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-iframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-newline-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-newline-expected.png
index 96be44d..b3297c91 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-newline-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-newline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
index 937a44159..35e859f 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-wrap-expected.png
index ac38a5f..c430a58 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-change-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-change-expected.png
index adc77e9..69c17ad 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-change-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-expected.png
index a1a0dff..b321bc6 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/validation-bubble-device-emulation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
index ce0127b..c7a343e3 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
index e24429b..446c627 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 6b1299d..75b5a4b 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/custom-elements/form-validation-bubble-appearance-expected.png b/third_party/blink/web_tests/platform/win/custom-elements/form-validation-bubble-appearance-expected.png
index 0847017..983d60c 100644
--- a/third_party/blink/web_tests/platform/win/custom-elements/form-validation-bubble-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win/custom-elements/form-validation-bubble-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png
index 0680711..4c70526 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-escape-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-escape-expected.png
index 7783036..9493caeb 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-escape-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-escape-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png
index 0872bd9..bd985ad 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-newline-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-newline-expected.png
index 8c86ae0e..ae88d1a 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-newline-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-newline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
index 8510549..59cce9d 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-wrap-expected.png
index 4b58a1e..c8e4612 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-change-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-change-expected.png
index d857de0..2ca5873 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-change-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-expected.png
index 5c67d3190..569e50050 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/validation-bubble-device-emulation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
index 31f9303f..c472fbc 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
index 193f234..1a1584e 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/validation-bubble-appearance-wrap-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 1ead4e4..d59d3c1 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index a7d3eb1..d4f8c27 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win10/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 1ead4e4..d59d3c1 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/platform/win10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index a7d3eb1..d4f8c27 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png b/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png
index 0847017..9bd37ab0 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/different-initiators-2.https-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/different-initiators-2.https-expected.txt
deleted file mode 100644
index 418df05..0000000
--- a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/different-initiators-2.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Prefetches from different initiator Documents with same RenderFrameHost assert_equals: Prefetch should not work for different initiators. expected "" but got "prefetch"
-Harness: the test ran to completion.
-
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index 65b0fed..a6071ce 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit 65b0fed5e12fd5e19eb8da9efa8229103f8c56df
+Subproject commit a6071ce9ef65c87750ea901b57a58185a2253718
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index cf056dd..5fde161 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit cf056dd795e94a797a3a748d07568c8d5f936d41
+Subproject commit 5fde161dd4df5e1bc613121743ca9a6f92e1acf8
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 1616c8d..4ef9c73 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 1616c8df453c98d7f9a48efc3bd4afe7b998a755
+Subproject commit 4ef9c73c536379ce499e8771304ef3f999fc86b6
diff --git a/third_party/eigen3/README.chromium b/third_party/eigen3/README.chromium
index d28457a7..74eb198 100644
--- a/third_party/eigen3/README.chromium
+++ b/third_party/eigen3/README.chromium
@@ -1,8 +1,8 @@
 Name: Eigen
 Short Name: eigen3
 URL: http://eigen.tuxfamily.org/
-Version: 18018ed013029ca3f28f52a62360999b5a659eac
-Date: 2023/08/31
+Version: e8515f78ac098329ab9f8cab21c87caede090a3f
+Date: 2023-10-10
 License: MPL 2
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/eigen3/src b/third_party/eigen3/src
index 18018ed..e8515f7 160000
--- a/third_party/eigen3/src
+++ b/third_party/eigen3/src
@@ -1 +1 @@
-Subproject commit 18018ed013029ca3f28f52a62360999b5a659eac
+Subproject commit e8515f78ac098329ab9f8cab21c87caede090a3f
diff --git a/third_party/ml b/third_party/ml
index bfd9549..9797a09 160000
--- a/third_party/ml
+++ b/third_party/ml
@@ -1 +1 @@
-Subproject commit bfd95492122f567f2d3163bb0fb2b56f450618de
+Subproject commit 9797a0977fd4de5ca4398943e6a6a61fc3ac5180
diff --git a/third_party/openscreen/src b/third_party/openscreen/src
index b926e156..cba24a9 160000
--- a/third_party/openscreen/src
+++ b/third_party/openscreen/src
@@ -1 +1 @@
-Subproject commit b926e156d3d888dd6df3ecaaf1407ae00b5aa54e
+Subproject commit cba24a91356b6d7d2930797541168ff6e0d17885
diff --git a/third_party/pdfium b/third_party/pdfium
index 85bb72c..cdc2dda 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit 85bb72cc15e6797e16f5e36cff917b31026c7f7d
+Subproject commit cdc2dda5a9576ca869b1a3d7c2104edb45187319
diff --git a/third_party/skia b/third_party/skia
index 475286f..b72fe6f 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 475286f0f6f1aa711478328e70eceb1d90b36b68
+Subproject commit b72fe6f76c61be2fd9cf6878f6e3defd44960af8
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium
index 8a85217..e0345a78 100644
--- a/third_party/tflite/README.chromium
+++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@
 Name: TensorFlow Lite
 Short Name: tflite
 URL: https://github.com/tensorflow/tensorflow
-Version: 85a1b2f83ce8075b9f1ca23ed6857784ede9965c
-Date: 2023-10-03
+Version: 03d8df0f8d9c51cacea632053ce2c387c41d5aaa
+Date: 2023-10-10
 License: Apache 2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/tflite/src b/third_party/tflite/src
index 85a1b2f..03d8df0 160000
--- a/third_party/tflite/src
+++ b/third_party/tflite/src
@@ -1 +1 @@
-Subproject commit 85a1b2f83ce8075b9f1ca23ed6857784ede9965c
+Subproject commit 03d8df0f8d9c51cacea632053ce2c387c41d5aaa
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 08a4f17..4e91a54 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 08a4f176de99034a3089ce1a6ff48797fa4213ff
+Subproject commit 4e91a54a0767cf596a407e9bc0933e4bbc66e8d3
diff --git a/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf b/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf
index 7160fcdca..23dc153bb 100644
--- a/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf
+++ b/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf
Binary files differ
diff --git a/third_party/win_virtual_display/driver/Driver.cpp b/third_party/win_virtual_display/driver/Driver.cpp
index 288fbfb3..c00f8fa 100644
--- a/third_party/win_virtual_display/driver/Driver.cpp
+++ b/third_party/win_virtual_display/driver/Driver.cpp
@@ -12,30 +12,22 @@
 
 #include <algorithm>
 
-#pragma region SampleMonitors
-
-namespace {
-}  // namespace
-
-#pragma endregion
-
 #pragma region EventDeclaration
 
 extern "C" DRIVER_INITIALIZE DriverEntry;
 
-EVT_WDF_DRIVER_DEVICE_ADD IddSampleDeviceAdd;
-EVT_WDF_DEVICE_D0_ENTRY IddSampleDeviceD0Entry;
+EVT_WDF_DRIVER_DEVICE_ADD EvtWdfDriverDeviceAdd;
+EVT_WDF_DEVICE_D0_ENTRY EvtWdfDeviceD0Entry;
 
-EVT_IDD_CX_ADAPTER_INIT_FINISHED IddSampleAdapterInitFinished;
-EVT_IDD_CX_ADAPTER_COMMIT_MODES IddSampleAdapterCommitModes;
+EVT_IDD_CX_ADAPTER_INIT_FINISHED EvtIddCxAdapterInitFinished;
+EVT_IDD_CX_ADAPTER_COMMIT_MODES EvtIddCxAdapterCommitModes;
 
-EVT_IDD_CX_PARSE_MONITOR_DESCRIPTION IddSampleParseMonitorDescription;
-EVT_IDD_CX_MONITOR_GET_DEFAULT_DESCRIPTION_MODES
-IddSampleMonitorGetDefaultModes;
-EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES IddSampleMonitorQueryModes;
+EVT_IDD_CX_PARSE_MONITOR_DESCRIPTION EvtIddCxParseMonitorDescription;
+EVT_IDD_CX_MONITOR_GET_DEFAULT_DESCRIPTION_MODES EvtIddCxMonitorGetDefaultModes;
+EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES EvtIddCxMonitorQueryModes;
 
-EVT_IDD_CX_MONITOR_ASSIGN_SWAPCHAIN IddSampleMonitorAssignSwapChain;
-EVT_IDD_CX_MONITOR_UNASSIGN_SWAPCHAIN IddSampleMonitorUnassignSwapChain;
+EVT_IDD_CX_MONITOR_ASSIGN_SWAPCHAIN EvtIddCxMonitorAssignSwapChain;
+EVT_IDD_CX_MONITOR_UNASSIGN_SWAPCHAIN EvtIddCxMonitorUnassignSwapChain;
 
 struct IndirectDeviceContextWrapper {
   display::test::IndirectDeviceContext* pContext;
@@ -84,7 +76,7 @@
   WDF_OBJECT_ATTRIBUTES Attributes;
   WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
 
-  WDF_DRIVER_CONFIG_INIT(&Config, IddSampleDeviceAdd);
+  WDF_DRIVER_CONFIG_INIT(&Config, EvtWdfDriverDeviceAdd);
 
   Status = WdfDriverCreate(pDriverObject, pRegistryPath, &Attributes, &Config,
                            WDF_NO_HANDLE);
@@ -98,17 +90,17 @@
 }
 
 _Use_decl_annotations_ NTSTATUS
-IddSampleDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit) {
-  TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "IddSampleDeviceAdd");
+EvtWdfDriverDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit) {
+  TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "EvtWdfDriverDeviceAdd");
 
   NTSTATUS Status = STATUS_SUCCESS;
   WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks;
 
   UNREFERENCED_PARAMETER(Driver);
 
-  // Register for power callbacks - in this sample only power-on is needed
+  // Register for power callbacks - in this driver only power-on is needed
   WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks);
-  PnpPowerCallbacks.EvtDeviceD0Entry = IddSampleDeviceD0Entry;
+  PnpPowerCallbacks.EvtDeviceD0Entry = EvtWdfDeviceD0Entry;
   WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &PnpPowerCallbacks);
 
   IDD_CX_CLIENT_CONFIG IddConfig;
@@ -116,18 +108,17 @@
 
   // If the driver wishes to handle custom IoDeviceControl requests, it's
   // necessary to use this callback since IddCx redirects IoDeviceControl
-  // requests to an internal queue. This sample does not need this.
-  // IddConfig.EvtIddCxDeviceIoControl = IddSampleIoDeviceControl;
+  // requests to an internal queue. This driver does not require this.
+  // IddConfig.EvtIddCxDeviceIoControl = IoDeviceControl;
 
-  IddConfig.EvtIddCxAdapterInitFinished = IddSampleAdapterInitFinished;
-  IddConfig.EvtIddCxParseMonitorDescription = IddSampleParseMonitorDescription;
+  IddConfig.EvtIddCxAdapterInitFinished = EvtIddCxAdapterInitFinished;
+  IddConfig.EvtIddCxParseMonitorDescription = EvtIddCxParseMonitorDescription;
   IddConfig.EvtIddCxMonitorGetDefaultDescriptionModes =
-      IddSampleMonitorGetDefaultModes;
-  IddConfig.EvtIddCxMonitorQueryTargetModes = IddSampleMonitorQueryModes;
-  IddConfig.EvtIddCxAdapterCommitModes = IddSampleAdapterCommitModes;
-  IddConfig.EvtIddCxMonitorAssignSwapChain = IddSampleMonitorAssignSwapChain;
-  IddConfig.EvtIddCxMonitorUnassignSwapChain =
-      IddSampleMonitorUnassignSwapChain;
+      EvtIddCxMonitorGetDefaultModes;
+  IddConfig.EvtIddCxMonitorQueryTargetModes = EvtIddCxMonitorQueryModes;
+  IddConfig.EvtIddCxAdapterCommitModes = EvtIddCxAdapterCommitModes;
+  IddConfig.EvtIddCxMonitorAssignSwapChain = EvtIddCxMonitorAssignSwapChain;
+  IddConfig.EvtIddCxMonitorUnassignSwapChain = EvtIddCxMonitorUnassignSwapChain;
 
   Status = IddCxDeviceInitConfig(pDeviceInit, &IddConfig);
   if (!NT_SUCCESS(Status)) {
@@ -180,29 +171,29 @@
 
   for (int i = 0; i < driver_properties.monitor_count; i++) {
     TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "Checking for display #%d", i);
-    display::test::IndirectSampleMonitor indirect_sample_monitor;
+    display::test::IndirectMonitor indirect_monitor;
     auto mode = driver_properties.requested_modes[i];
-    display::test::Edid edid(indirect_sample_monitor.pEdidBlock.data());
+    display::test::Edid edid(indirect_monitor.pEdidBlock.data());
     bool success =
         edid.GetTimingEntry(0)->SetMode(mode.width, mode.height, mode.vSync);
     if (!success) {
       TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "SetMode() unsuccessful");
     }
     edid.UpdateChecksum();
-    indirect_sample_monitor.pEdidBlock = edid.getEdidBlock();
+    indirect_monitor.pEdidBlock = edid.getEdidBlock();
     TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER,
                 "Width (Modified EDID,Chosen Mode) (Inside "
-                "IddSampleDeviceAdd): %ld, %hu",
+                "EvtWdfDriverDeviceAdd): %ld, %hu",
                 edid.GetTimingEntry(0)->GetWidth(), mode.width);
-    indirect_sample_monitor.pModeList.push_back(mode);
-    pContext->pContext->sample_monitors.push_back(indirect_sample_monitor);
+    indirect_monitor.pModeList.push_back(mode);
+    pContext->pContext->monitors.push_back(indirect_monitor);
   }
 
   return Status;
 }
 
 _Use_decl_annotations_ NTSTATUS
-IddSampleDeviceD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState) {
+EvtWdfDeviceD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState) {
   UNREFERENCED_PARAMETER(PreviousState);
 
   // This function is called by WDF to start the device in the fully-on power
@@ -249,9 +240,10 @@
       IDDCX_TRANSMISSION_TYPE_WIRED_OTHER;
 
   // Declare your device strings for telemetry (required)
-  AdapterCaps.EndPointDiagnostics.pEndPointFriendlyName = L"IddSample Device";
-  AdapterCaps.EndPointDiagnostics.pEndPointManufacturerName = L"Microsoft";
-  AdapterCaps.EndPointDiagnostics.pEndPointModelName = L"IddSample Model";
+  AdapterCaps.EndPointDiagnostics.pEndPointFriendlyName = L"IDD Virtual Device";
+  AdapterCaps.EndPointDiagnostics.pEndPointManufacturerName =
+      L"IDD Virtual Manufacturer";
+  AdapterCaps.EndPointDiagnostics.pEndPointModelName = L"IDD Virtual Model";
 
   // Declare your hardware and firmware versions (required)
   IDDCX_ENDPOINT_VERSION Version = {};
@@ -300,7 +292,7 @@
   WDF_OBJECT_ATTRIBUTES Attr;
   WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectMonitorContextWrapper);
 
-  // In the sample driver, we report a monitor right away but a real driver
+  // In this driver, we report a monitor right away but a real driver
   // would do this when a monitor connection event occurs
   IDDCX_MONITOR_INFO MonitorInfo = {};
   MonitorInfo.Size = sizeof(MonitorInfo);
@@ -309,19 +301,19 @@
 
   MonitorInfo.MonitorDescription.Size = sizeof(MonitorInfo.MonitorDescription);
   MonitorInfo.MonitorDescription.Type = IDDCX_MONITOR_DESCRIPTION_TYPE_EDID;
-  if (ConnectorIndex >= sample_monitors.size()) {
+  if (ConnectorIndex >= monitors.size()) {
     MonitorInfo.MonitorDescription.DataSize = 0;
     MonitorInfo.MonitorDescription.pData = nullptr;
   } else {
     MonitorInfo.MonitorDescription.DataSize = Edid::kBlockSize;
     MonitorInfo.MonitorDescription.pData =
-        (sample_monitors[ConnectorIndex].pEdidBlock.data());
+        (monitors[ConnectorIndex].pEdidBlock.data());
   }
 
   TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "ConnectorIndex: %d",
               ConnectorIndex);
 
-  display::test::Edid edid1(sample_monitors[ConnectorIndex].pEdidBlock.data());
+  display::test::Edid edid1(monitors[ConnectorIndex].pEdidBlock.data());
   TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER,
               "Width (Modified EDID) (Inside FinishInit): %ld",
               edid1.GetTimingEntry(0)->GetWidth());
@@ -331,7 +323,7 @@
   // container ID if the monitor is not permanently attached to the display
   // adapter device object. The container ID is typically made unique for each
   // monitor and can be used to associate the monitor with other devices, like
-  // audio or input devices. In this sample we generate a random container ID
+  // audio or input devices. In this case we generate a random container ID
   // GUID, but it's best practice to choose a stable container ID for a unique
   // monitor or to use "this" device's container ID for a permanent/integrated
   // monitor.
@@ -356,9 +348,9 @@
     pMonitorContextWrapper->pContext =
         new IndirectMonitorContext(MonitorCreateOut.MonitorObject);
 
-    if (ConnectorIndex < sample_monitors.size()) {
+    if (ConnectorIndex < monitors.size()) {
       pMonitorContextWrapper->pContext->default_mode_list =
-          sample_monitors[ConnectorIndex].pModeList;
+          monitors[ConnectorIndex].pModeList;
     }
 
     // Tell the OS that the monitor has been plugged in
@@ -402,16 +394,16 @@
 #pragma region DDI Callbacks
 
 _Use_decl_annotations_ NTSTATUS
-IddSampleAdapterInitFinished(IDDCX_ADAPTER AdapterObject,
-                             const IDARG_IN_ADAPTER_INIT_FINISHED* pInArgs) {
+EvtIddCxAdapterInitFinished(IDDCX_ADAPTER AdapterObject,
+                            const IDARG_IN_ADAPTER_INIT_FINISHED* pInArgs) {
   // This is called when the OS has finished setting up the adapter for use by
   // the IddCx driver. It's now possible to report attached monitors.
 
   auto* pDeviceContextWrapper =
       WdfObjectGet_IndirectDeviceContextWrapper(AdapterObject);
   if (NT_SUCCESS(pInArgs->AdapterInitStatus)) {
-    for (DWORD i = 0;
-         i < pDeviceContextWrapper->pContext->sample_monitors.size(); i++) {
+    for (DWORD i = 0; i < pDeviceContextWrapper->pContext->monitors.size();
+         i++) {
       pDeviceContextWrapper->pContext->FinishInit(i);
     }
   }
@@ -420,12 +412,12 @@
 }
 
 _Use_decl_annotations_ NTSTATUS
-IddSampleAdapterCommitModes(IDDCX_ADAPTER AdapterObject,
-                            const IDARG_IN_COMMITMODES* pInArgs) {
+EvtIddCxAdapterCommitModes(IDDCX_ADAPTER AdapterObject,
+                           const IDARG_IN_COMMITMODES* pInArgs) {
   UNREFERENCED_PARAMETER(AdapterObject);
   UNREFERENCED_PARAMETER(pInArgs);
 
-  // For the sample, do nothing when modes are picked - the swap-chain is taken
+  // Do nothing when modes are picked - the swap-chain is taken
   // care of by IddCx
 
   // ==============================
@@ -438,9 +430,9 @@
   return STATUS_SUCCESS;
 }
 
-_Use_decl_annotations_ NTSTATUS IddSampleParseMonitorDescription(
-    const IDARG_IN_PARSEMONITORDESCRIPTION* pInArgs,
-    IDARG_OUT_PARSEMONITORDESCRIPTION* pOutArgs) {
+_Use_decl_annotations_ NTSTATUS
+EvtIddCxParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION* pInArgs,
+                                IDARG_OUT_PARSEMONITORDESCRIPTION* pOutArgs) {
   // ==============================
   // TODO: In a real driver, this function would be called to generate monitor
   // modes for an EDID by parsing it. In this driver, the client's requested
@@ -448,22 +440,18 @@
   // EDID.
   // ==============================
   TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER,
-              "Inside IddSampleParseMonitorDescription");
+              "Inside ParseMonitorDescription");
 
   pOutArgs->MonitorModeBufferOutputCount =
-      display::test::IndirectSampleMonitor::kModeListLength;
+      display::test::IndirectMonitor::kModeListLength;
 
   if (pInArgs->MonitorModeBufferInputCount <
-      display::test::IndirectSampleMonitor::kModeListLength) {
+      display::test::IndirectMonitor::kModeListLength) {
     // Return success if there was no buffer, since the caller was only asking
     // for a count of modes
     return (pInArgs->MonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL
                                                       : STATUS_SUCCESS;
   } else {
-    // In the sample driver, we have reported some static information about
-    // connected monitors Check which of the reported monitors this call is for
-    // by comparing it to the pointer of our known EDID blocks.
-
     if (pInArgs->MonitorDescription.DataSize !=
         display::test::Edid::kBlockSize) {
       return STATUS_INVALID_PARAMETER;
@@ -505,11 +493,10 @@
   }
 }
 
-_Use_decl_annotations_ NTSTATUS IddSampleMonitorGetDefaultModes(
+_Use_decl_annotations_ NTSTATUS EvtIddCxMonitorGetDefaultModes(
     IDDCX_MONITOR MonitorObject,
     const IDARG_IN_GETDEFAULTDESCRIPTIONMODES* pInArgs,
     IDARG_OUT_GETDEFAULTDESCRIPTIONMODES* pOutArgs) {
-
   // ==============================
   // TODO: In a real driver, this function would be called to generate monitor
   // modes for a monitor with no EDID. Drivers should report modes that are
@@ -554,9 +541,9 @@
 }
 
 _Use_decl_annotations_ NTSTATUS
-IddSampleMonitorQueryModes(IDDCX_MONITOR MonitorObject,
-                           const IDARG_IN_QUERYTARGETMODES* pInArgs,
-                           IDARG_OUT_QUERYTARGETMODES* pOutArgs) {
+EvtIddCxMonitorQueryModes(IDDCX_MONITOR MonitorObject,
+                          const IDARG_IN_QUERYTARGETMODES* pInArgs,
+                          IDARG_OUT_QUERYTARGETMODES* pOutArgs) {
   UNREFERENCED_PARAMETER(MonitorObject);
   std::vector<IDDCX_TARGET_MODE> TargetModes;
 
@@ -566,7 +553,7 @@
   // available set of modes for a given output as the intersection of monitor
   // modes with target modes.
 
-  TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "IddSampleMonitorQueryModes");
+  TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "MonitorQueryModes");
 
   TargetModes.push_back(
       display::test::Methods::CreateIddCxTargetMode(3840, 2160, 60));
@@ -599,8 +586,8 @@
 }
 
 _Use_decl_annotations_ NTSTATUS
-IddSampleMonitorAssignSwapChain(IDDCX_MONITOR MonitorObject,
-                                const IDARG_IN_SETSWAPCHAIN* pInArgs) {
+EvtIddCxMonitorAssignSwapChain(IDDCX_MONITOR MonitorObject,
+                               const IDARG_IN_SETSWAPCHAIN* pInArgs) {
   auto* pMonitorContextWrapper =
       WdfObjectGet_IndirectMonitorContextWrapper(MonitorObject);
   pMonitorContextWrapper->pContext->AssignSwapChain(
@@ -610,7 +597,7 @@
 }
 
 _Use_decl_annotations_ NTSTATUS
-IddSampleMonitorUnassignSwapChain(IDDCX_MONITOR MonitorObject) {
+EvtIddCxMonitorUnassignSwapChain(IDDCX_MONITOR MonitorObject) {
   auto* pMonitorContextWrapper =
       WdfObjectGet_IndirectMonitorContextWrapper(MonitorObject);
   pMonitorContextWrapper->pContext->UnassignSwapChain();
diff --git a/third_party/win_virtual_display/driver/Driver.h b/third_party/win_virtual_display/driver/Driver.h
index 8290e1e..6dea2346 100644
--- a/third_party/win_virtual_display/driver/Driver.h
+++ b/third_party/win_virtual_display/driver/Driver.h
@@ -16,9 +16,8 @@
 #include "Trace.h"
 
 namespace display::test {
-/// <summary>
-/// Provides a sample implementation of an indirect display driver.
-/// </summary>
+
+// Contains data and handles related to a single device (WDFDEVICE) object.
 class IndirectDeviceContext {
  public:
   IndirectDeviceContext(_In_ WDFDEVICE WdfDevice);
@@ -27,13 +26,14 @@
   void InitAdapter();
   void FinishInit(UINT ConnectorIndex);
 
-  std::vector<IndirectSampleMonitor> sample_monitors;
+  std::vector<IndirectMonitor> monitors;
 
  protected:
   WDFDEVICE m_WdfDevice;
   IDDCX_ADAPTER m_Adapter;
 };
 
+// Contains data and handles related to a single monitor (IDDCX_MONITOR) object.
 class IndirectMonitorContext {
  public:
   IndirectMonitorContext(_In_ IDDCX_MONITOR Monitor);
diff --git a/third_party/win_virtual_display/driver/IndirectMonitor.h b/third_party/win_virtual_display/driver/IndirectMonitor.h
index 79c597b..d2e59d9 100644
--- a/third_party/win_virtual_display/driver/IndirectMonitor.h
+++ b/third_party/win_virtual_display/driver/IndirectMonitor.h
@@ -17,7 +17,7 @@
 
 namespace display::test {
 // Represents a virtual monitor, encapsulates an EDID and modes.
-struct IndirectSampleMonitor {
+struct IndirectMonitor {
   static constexpr size_t kModeListLength = 1;
   // Modified EDID from Dell S2719DGF
   std::array<unsigned char, Edid::kBlockSize> pEdidBlock = {
diff --git a/third_party/win_virtual_display/driver/SwapChainProcessor.cpp b/third_party/win_virtual_display/driver/SwapChainProcessor.cpp
index 97cccd8..03359c9c 100644
--- a/third_party/win_virtual_display/driver/SwapChainProcessor.cpp
+++ b/third_party/win_virtual_display/driver/SwapChainProcessor.cpp
@@ -113,12 +113,12 @@
       // We have finished processing this frame hence we release the reference
       // on it. If the driver forgets to release the reference to the surface,
       // it will be leaked which results in the surfaces being left around after
-      // swapchain is destroyed. NOTE: Although in this sample we release
-      // reference to the surface here; the driver still owns the
-      // Buffer.MetaData.pSurface surface until
-      // IddCxSwapChainReleaseAndAcquireBuffer returns S_OK and gives us a new
-      // frame, a driver may want to use the surface in future to re-encode the
-      // desktop for better quality if there is no new frame for a while
+      // swapchain is destroyed. NOTE: Although we release reference to the
+      // surface here; the driver still owns the Buffer.MetaData.pSurface
+      // surface until IddCxSwapChainReleaseAndAcquireBuffer returns S_OK and
+      // gives us a new frame, a driver may want to use the surface in future
+      // to re-encode the desktop for better quality if there is no new frame
+      // for a while
       AcquiredBuffer.Reset();
 
       // Indicate to OS that we have finished inital processing of the frame, it
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index e383075..54e69a01 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -231,6 +231,10 @@
     "META": {"sizes": {"includes": [5]}},
     "includes": [2880],
   },
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/web_app_install/resources.grd": {
+    "META": {"sizes": {"includes": [5]}},
+    "includes": [2890],
+  },
   "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/commander/resources.grd": {
     "META": {"sizes": {"includes": [15]}},
     "includes": [2900],
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 0cabf54..3c0cf68 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -1105,7 +1105,6 @@
       'android-webview-10-x86-rel-tests': 'android_release_trybot_x86_fastbuild_webview_trichrome_reclient',
       'android-webview-12-x64-dbg': 'android_debug_trybot_x64_webview_trichrome_webview_shell_reclient',
       'android-webview-13-x64-dbg': 'android_debug_trybot_x64_webview_trichrome_webview_shell_reclient',
-      'android-webview-nougat-arm64-dbg': 'android_release_trybot_arm64_webview_monochrome_reclient',
       'android-webview-oreo-arm64-dbg': 'android_release_trybot_arm64_webview_monochrome_reclient',
       'android-webview-pie-arm64-dbg': 'android_release_trybot_arm64_webview_monochrome_reclient',
       'android-webview-pie-x86-wpt-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient',
@@ -1121,7 +1120,6 @@
       'android_cronet': 'android_cronet_release_trybot_arm_no_neon_reclient',
       'android_n5x_swarming_dbg': 'android_debug_trybot_arm64_reclient',
       'android_optional_gpu_tests_rel': 'gpu_tests_android_release_trybot_reclient',
-      'android_unswarmed_pixel_aosp': 'android_debug_trybot_arm64_reclient',
       'gpu-fyi-cq-android-arm64': 'gpu_tests_android_release_trybot_arm64_reclient',
       'gpu-fyi-try-android-m-nexus-5x-64': 'gpu_tests_android_release_trybot_arm64_reclient',
       'gpu-fyi-try-android-nvidia-shield-tv': 'gpu_tests_android_release_trybot_reclient',
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.android.json b/tools/mb/mb_config_expectations/tryserver.chromium.android.json
index ce46663..2b9a83a 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.android.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.android.json
@@ -1272,23 +1272,6 @@
       "use_remoteexec": true
     }
   },
-  "android-webview-nougat-arm64-dbg": {
-    "gn_args": {
-      "dcheck_always_on": true,
-      "debuggable_apks": false,
-      "ffmpeg_branding": "Chrome",
-      "is_component_build": false,
-      "is_debug": false,
-      "proprietary_codecs": true,
-      "strip_debug_info": true,
-      "symbol_level": 0,
-      "system_webview_package_name": "com.google.android.apps.chrome",
-      "target_cpu": "arm64",
-      "target_os": "android",
-      "use_dummy_lastchange": true,
-      "use_remoteexec": true
-    }
-  },
   "android-webview-oreo-arm64-dbg": {
     "gn_args": {
       "dcheck_always_on": true,
@@ -1548,20 +1531,6 @@
       "use_static_angle": true
     }
   },
-  "android_unswarmed_pixel_aosp": {
-    "gn_args": {
-      "debuggable_apks": false,
-      "ffmpeg_branding": "Chrome",
-      "is_component_build": true,
-      "is_debug": true,
-      "proprietary_codecs": true,
-      "symbol_level": 1,
-      "target_cpu": "arm64",
-      "target_os": "android",
-      "use_dummy_lastchange": true,
-      "use_remoteexec": true
-    }
-  },
   "gpu-fyi-cq-android-arm64": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 7d3aa41..1744217d 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -17550,6 +17550,36 @@
   </description>
 </action>
 
+<action name="LinkCapturingAcceptedFromInfoBar">
+  <owner>dmurph@google.com</owner>
+  <owner>desktop-pwas-team@google.com</owner>
+  <description>
+    Recorded when the user accepts the info bar in an app browser to turn on
+    link capturing for that app. This only shows if the app doesn't have link
+    capturing enabled, and the user launched the app via the intent picker.
+  </description>
+</action>
+
+<action name="LinkCapturingCancelledFromInfoBar">
+  <owner>dmurph@google.com</owner>
+  <owner>desktop-pwas-team@google.com</owner>
+  <description>
+    Recorded when the user cancels the info bar in an app browser offering to
+    turn on link capturing for that app. This only shows if the app doesn't have
+    link capturing enabled, and the user launched the app via the intent picker.
+  </description>
+</action>
+
+<action name="LinkCapturingIgnoredFromInfoBar">
+  <owner>dmurph@google.com</owner>
+  <owner>desktop-pwas-team@google.com</owner>
+  <description>
+    Recorded when the user ignores the info bar in an app browser offering to
+    turn on link capturing for that app. This only shows if the app doesn't have
+    link capturing enabled, and the user launched the app via the intent picker.
+  </description>
+</action>
+
 <action name="LinkNavigationOpenedInForegroundTab">
   <owner>meiliang@chromium.org</owner>
   <owner>sbirch@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b09b54d9..6a93437 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -33916,6 +33916,7 @@
   <int value="1164" label="ProfileReauthPrompt"/>
   <int value="1165" label="RelatedWebsiteSetsEnabled"/>
   <int value="1166" label="DeviceExtendedFkeysModifier"/>
+  <int value="1167" label="UnaffiliatedDeviceArcAllowed"/>
 </enum>
 
 <enum name="EnterprisePoliciesSources">
@@ -63437,6 +63438,7 @@
   <int value="-835242361" label="OmniboxAdaptiveSuggestionsCount:enabled"/>
   <int value="-834661509" label="ModalPermissionPrompts:disabled"/>
   <int value="-834234595" label="BorealisProvision:enabled"/>
+  <int value="-833024559" label="AuxiliarySearchDonation:enabled"/>
   <int value="-832806243" label="QuickActionSearchWidgetAndroid:disabled"/>
   <int value="-832780530" label="SecurePaymentConfirmationDebug:enabled"/>
   <int value="-832561975" label="enable-picture-in-picture"/>
@@ -64269,6 +64271,7 @@
   <int value="-416660617" label="EnforceTLS13Downgrade:disabled"/>
   <int value="-415186532" label="AndroidSiteSettingsUIRefresh:enabled"/>
   <int value="-414900505" label="ScrollCapture:enabled"/>
+  <int value="-414477658" label="DefaultBucketUsesRelaxedDurability:disabled"/>
   <int value="-414398582" label="UpcomingFollowFeatures:disabled"/>
   <int value="-413779344" label="SyncAutofillWalletUsageData:disabled"/>
   <int value="-413562235" label="MessagesForAndroidUpdatePassword:disabled"/>
@@ -64937,6 +64940,7 @@
   <int value="-85706353" label="VirtualDesksGestures:enabled"/>
   <int value="-85704140" label="ImageServiceSuggestPoweredImages:disabled"/>
   <int value="-83431306" label="FSPsInRecents:enabled"/>
+  <int value="-83386867" label="NtpTabResumptionModule:enabled"/>
   <int value="-82880083" label="CaptureModeDemoTools:enabled"/>
   <int value="-82530769" label="WebXRPlaneDetection:enabled"/>
   <int value="-82328138"
@@ -65046,6 +65050,7 @@
   <int value="-35528548" label="LensImageFormatOptimizations:disabled"/>
   <int value="-35388407" label="AshNewSystemMenu:disabled"/>
   <int value="-35256214" label="InterestFeedNoticeCardAutoDismiss:enabled"/>
+  <int value="-35002051" label="DefaultBucketUsesRelaxedDurability:enabled"/>
   <int value="-33240310" label="AppShimNotificationAttribution:enabled"/>
   <int value="-32712825" label="CrOSEnforceSystemAec:disabled"/>
   <int value="-32385086" label="NtpRecipeTasksModule:disabled"/>
@@ -66340,6 +66345,7 @@
   <int value="606723570" label="SharingUseDeviceInfo:disabled"/>
   <int value="606834606" label="force-color-profile"/>
   <int value="606969417" label="DiscoverApp:enabled"/>
+  <int value="608405849" label="WebAuthenticationFilterGooglePasskeys:enabled"/>
   <int value="608761130" label="PrintSaveToDrive:enabled"/>
   <int value="609112512" label="touch-selection-strategy"/>
   <int value="609568740" label="ImprovedSemanticsActivityIndicators:disabled"/>
@@ -66366,6 +66372,7 @@
   <int value="623112705"
       label="IPH_KeyboardAccessoryPaymentVirtualCard:disabled"/>
   <int value="623512796" label="EnableWifiQos:enabled"/>
+  <int value="623671543" label="AuxiliarySearchDonation:disabled"/>
   <int value="623728853" label="OsSettingsTestChromeRefresh:enabled"/>
   <int value="623772100" label="EnableIncognitoWindowCounter:disabled"/>
   <int value="624317932" label="print-pdf-as-image"/>
@@ -68103,6 +68110,7 @@
   <int value="1467494310" label="JavaScriptExperimentalSharedMemory:enabled"/>
   <int value="1467583815" label="AVIF:disabled"/>
   <int value="1469407485" label="disable-accelerated-2d-canvas"/>
+  <int value="1470134259" label="NtpTabResumptionModule:disabled"/>
   <int value="1471169381" label="kWebSQLAccess:enabled"/>
   <int value="1471491886"
       label="AutofillOfferToSaveCardWithSameLastFour:enabled"/>
@@ -68708,6 +68716,8 @@
   <int value="1770189877" label="ConfirmNtpSuggestionRemovals:enabled"/>
   <int value="1771548551" label="DisableKeepaliveFetch:enabled"/>
   <int value="1772454319" label="enable-storage-manager"/>
+  <int value="1772618273"
+      label="WebAuthenticationFilterGooglePasskeys:disabled"/>
   <int value="1774991770" label="SafetyCheckPermissions:enabled"/>
   <int value="1775397180" label="kFastPairHID:disabled"/>
   <int value="1775475563" label="malware-interstitial-v3"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 61b2430d..93397ae 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -404,6 +404,7 @@
     ambient setting (slide show, video, etc) has a different initialization
     process. This is emitted each time ash tries to launch the ambient UI.
   </summary>
+  <token key="Settings" variants="AmbientUiSettings"/>
 </histogram>
 
 <histogram name="Ash.AmbientMode.LottieAnimationSmoothness.{Settings}"
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml
index 3de3eba3..3a3b20c 100644
--- a/tools/metrics/histograms/metadata/cookie/histograms.xml
+++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -722,7 +722,7 @@
 </histogram>
 
 <histogram name="Cookie.PartitionedCookieCount.{NonceType}" units="cookies"
-    expires_after="2023-10-22">
+    expires_after="2024-02-25">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 6373462a..297d6a2 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2528,198 +2528,137 @@
   </summary>
 </histogram>
 
-<histogram name="Media.EME.CdmStorageManager.DatabaseOpenError.Incognito"
+<histogram name="Media.EME.CdmStorageManager.DatabaseOpenError.{ProfileType}"
     enum="CdmStorageOpenError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from opening the CdmStorageDatabase.
-    Recorded on every open from an Incognito profile.
+    Recorded on every open from an {ProfileType} profile.
   </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
 <histogram
-    name="Media.EME.CdmStorageManager.DatabaseOpenError.Incognito.Migration"
+    name="Media.EME.CdmStorageManager.DatabaseOpenError.{ProfileType}.Migration"
     enum="CdmStorageOpenError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from opening the CdmStorageDatabase.
-    Recorded on every open from an Incognito profile when
+    Recorded on every open from an {ProfileType} profile when
     'kCdmStorageDatabaseMigration' is enabled.
   </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
-<histogram name="Media.EME.CdmStorageManager.DatabaseOpenError.NotIncognito"
-    enum="CdmStorageOpenError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from opening the CdmStorageDatabase.
-    Recorded on every open from a non-Incognito profile.
-  </summary>
-</histogram>
-
-<histogram
-    name="Media.EME.CdmStorageManager.DatabaseOpenError.NotIncognito.Migration"
-    enum="CdmStorageOpenError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from opening the CdmStorageDatabase.
-    Recorded on every open from a non-Incognito profile when
-    'kCdmStorageDatabaseMigration' is enabled.
-  </summary>
-</histogram>
-
-<histogram name="Media.EME.CdmStorageManager.DeleteDatabaseError.Incognito"
+<histogram name="Media.EME.CdmStorageManager.DeleteDatabaseError.{ProfileType}"
     enum="BooleanError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from the DeleteDatabase function. Recorded
-    after every call of DeleteDatabase on Incognito profile.
+    after every call of DeleteDatabase on {ProfileType} profile.
   </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
-<histogram name="Media.EME.CdmStorageManager.DeleteDatabaseError.NotIncognito"
-    enum="BooleanError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from the DeleteDatabase function. Recorded
-    after every call of DeleteDatabase on non-Incognito profile.
-  </summary>
-</histogram>
-
-<histogram name="Media.EME.CdmStorageManager.DeleteFileError.Incognito"
+<histogram name="Media.EME.CdmStorageManager.DeleteFileError.{ProfileType}"
     enum="BooleanError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from the DeleteFile function. Recorded
-    after every call of DeleteFile on Incognito profile.
+    after every call of DeleteFile on {ProfileType} profile.
   </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
 <histogram
-    name="Media.EME.CdmStorageManager.DeleteFileError.Incognito.Migration"
+    name="Media.EME.CdmStorageManager.DeleteFileError.{ProfileType}.Migration"
     enum="BooleanError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from the DeleteFile function. Recorded
-    after every call of DeleteFile on Incognito profile when
+    after every call of DeleteFile on {ProfileType} profile when
     'kCdmStorageDatabaseMigration' is enabled.
   </summary>
-</histogram>
-
-<histogram name="Media.EME.CdmStorageManager.DeleteFileError.NotIncognito"
-    enum="BooleanError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from the DeleteFile function. Recorded
-    after every call of DeleteFile on non-Incognito profile.
-  </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
 <histogram
-    name="Media.EME.CdmStorageManager.DeleteFileError.NotIncognito.Migration"
-    enum="BooleanError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from the DeleteFile function. Recorded
-    after every call of DeleteFile on non-Incognito profile when
-    'kCdmStorageDatabaseMigration' is enabled.
-  </summary>
-</histogram>
-
-<histogram
-    name="Media.EME.CdmStorageManager.DeleteForStorageKeyError.Incognito"
+    name="Media.EME.CdmStorageManager.DeleteForStorageKeyError.{ProfileType}"
     enum="BooleanError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from the DeleteForStorageKey function.
-    Recorded after every call of DeleteForStorageKey on Incognito profile.
+    Recorded after every call of DeleteForStorageKey on {ProfileType} profile.
   </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
-<histogram
-    name="Media.EME.CdmStorageManager.DeleteForStorageKeyError.NotIncognito"
-    enum="BooleanError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from the DeleteForStorageKey function.
-    Recorded after every call of DeleteForStorageKey on non-Incognito profile.
-  </summary>
-</histogram>
-
-<histogram name="Media.EME.CdmStorageManager.ReadFileError.Incognito"
+<histogram name="Media.EME.CdmStorageManager.ReadFileError.{ProfileType}"
     enum="BooleanError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from the ReadFile function. Recorded after
-    every call of ReadFile on Incognito profile.
+    every call of ReadFile on {ProfileType} profile.
   </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
-<histogram name="Media.EME.CdmStorageManager.ReadFileError.NotIncognito"
-    enum="BooleanError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from the ReadFile function. Recorded after
-    every call of ReadFile on non-Incognito profile.
-  </summary>
-</histogram>
-
-<histogram name="Media.EME.CdmStorageManager.WriteFileError.Incognito"
+<histogram name="Media.EME.CdmStorageManager.WriteFileError.{ProfileType}"
     enum="BooleanError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from the WriteFile function. Recorded
-    after every call of WriteFile on Incognito profile.
+    after every call of WriteFile on {ProfileType} profile.
   </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
 <histogram
-    name="Media.EME.CdmStorageManager.WriteFileError.Incognito.Migration"
+    name="Media.EME.CdmStorageManager.WriteFileError.{ProfileType}.Migration"
     enum="BooleanError" expires_after="2024-08-11">
   <owner>vpasupathy@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
     This UMA logs overall error rates from the WriteFile function. Recorded
-    after every call of WriteFile on Incognito profile when
+    after every call of WriteFile on {ProfileType} profile when
     'kCdmStorageDatabaseMigration' is enabled.
   </summary>
-</histogram>
-
-<histogram name="Media.EME.CdmStorageManager.WriteFileError.NotIncognito"
-    enum="BooleanError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from the WriteFile function. Recorded
-    after every call of WriteFile on non-Incognito profile.
-  </summary>
-</histogram>
-
-<histogram
-    name="Media.EME.CdmStorageManager.WriteFileError.NotIncognito.Migration"
-    enum="BooleanError" expires_after="2024-08-11">
-  <owner>vpasupathy@chromium.org</owner>
-  <owner>media-dev-uma@chromium.org</owner>
-  <summary>
-    This UMA logs overall error rates from the WriteFile function. Recorded
-    after every call of WriteFile on non-Incognito profile when
-    'kCdmStorageDatabaseMigration' is enabled.
-  </summary>
+  <token key="ProfileType">
+    <variant name="Incognito"/>
+    <variant name="NonIncognito"/>
+  </token>
 </histogram>
 
 <histogram name="Media.EME.CrosCdmType" enum="CrosCdmType"
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 3e65947..4706e1f4 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -5577,7 +5577,7 @@
 </histogram>
 
 <histogram name="Net.SSLRenegotiationInfoSupported" enum="BooleanSupported"
-    expires_after="2023-11-20">
+    expires_after="2024-11-20">
   <owner>davidben@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index a07e7efa..a4b51f1 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -435,4 +435,5 @@
  <item id="report_check_in" added_in_milestone="119" content_hash_code="02080b2e" os_list="chromeos" file_path="chromeos/ash/components/report/device_metrics/use_case/use_case.cc" />
  <item id="plus_address_reservation" added_in_milestone="119" content_hash_code="02835001" os_list="linux,windows,android,chromeos" file_path="components/plus_addresses/plus_address_client.cc" />
  <item id="plus_address_confirmation" added_in_milestone="119" content_hash_code="04783158" os_list="linux,windows,android,chromeos" file_path="components/plus_addresses/plus_address_client.cc" />
+ <item id="customize_chrome_page_handler" added_in_milestone="120" content_hash_code="003c50db" os_list="linux,windows,chromeos" file_path="chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc" />
 </annotations>
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml
index b74dd2a..3924f4b 100644
--- a/tools/traffic_annotation/summary/grouping.xml
+++ b/tools/traffic_annotation/summary/grouping.xml
@@ -291,6 +291,7 @@
       <annotation id="iwa_update_discovery_web_bundle"/>
       <annotation id="almanac_launcher_app"/>
       <annotation id="ip_protection_service_get_proxy_config"/>
+      <annotation id="customize_chrome_page_handler"/>
     </sender>
   </group>
   <group name="Admin Features" hidden="true">
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index b2a2d212..08304d99 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -328,7 +328,8 @@
 // milestones.
 BASE_FEATURE(kEyeDropper,
              "EyeDropper",
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS)
              base::FEATURE_ENABLED_BY_DEFAULT
 #else
              base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index bc18ce34..ea52a61b 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1199,6 +1199,15 @@
 };
 
 /**
+ * Whether the new directory tree flag is enabled.
+ * @returns {boolean}
+ */
+util.isNewDirectoryTreeEnabled = () => {
+  return loadTimeData.valueExists('NEW_DIRECTORY_TREE') &&
+      loadTimeData.getBoolean('NEW_DIRECTORY_TREE');
+};
+
+/**
  * Retrieves all entries inside the given |rootEntry|.
  * @param {!DirectoryEntry} rootEntry
  * @param {function(!Array<!Entry>)} entriesCallback Called when some chunk of
diff --git a/ui/file_manager/file_manager/foreground/js/actions_controller.js b/ui/file_manager/file_manager/foreground/js/actions_controller.js
index 7d5fd5d..19dfeeed 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_controller.js
@@ -76,7 +76,7 @@
 
     // Attach listeners to non-user events which will only update the in-memory
     // ActionsModel.
-    if (util.isFilesAppExperimental()) {
+    if (util.isNewDirectoryTreeEnabled()) {
       this.ui_.directoryTree.addEventListener(
           XfTree.events.TREE_SELECTION_CHANGED,
           this.onNavigationListSelectionChanged_.bind(this), true);
diff --git a/ui/file_manager/file_manager/foreground/js/crostini_controller.js b/ui/file_manager/file_manager/foreground/js/crostini_controller.js
index e076b2b..60722d9 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/crostini_controller.js
@@ -69,7 +69,7 @@
       crostiniNavigationModelItem = null;
       getStore().dispatch(removeUiEntry({key: crostiniPlaceHolderKey}));
     }
-    if (!util.isFilesAppExperimental()) {
+    if (!util.isNewDirectoryTreeEnabled()) {
       this.directoryTree_.dataModel.linuxFilesItem =
           crostiniNavigationModelItem;
       // Redraw the tree to ensure 'Linux files' is added/removed.
diff --git a/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js b/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js
index 9ee4c7ba..2a47767a 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js
@@ -182,7 +182,7 @@
 
       // Put the new name in the .label element before detaching the
       // <input> to prevent showing the old name.
-      if (util.isFilesAppExperimental()) {
+      if (util.isNewDirectoryTreeEnabled()) {
         this.currentDirectoryItem_.label = newName;
       } else {
         this.getLabelElement_().textContent = newName;
@@ -198,7 +198,7 @@
         return;
       }
 
-      if (!util.isFilesAppExperimental()) {
+      if (!util.isNewDirectoryTreeEnabled()) {
         this.currentDirectoryItem_.entry = newEntry;
         this.currentDirectoryItem_.updateSubDirectories(/* recursive= */ true);
       }
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 404f3d9..2ee4c1a0 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -1257,7 +1257,7 @@
     const directoryTree = /** @type {DirectoryTree} */
         (this.dialogDom_.querySelector('#directory-tree'));
 
-    if (util.isFilesAppExperimental()) {
+    if (util.isNewDirectoryTreeEnabled()) {
       const treeContainer = directoryTree.parentElement;
       directoryTree.remove();
       const directoryTreeContainer = new DirectoryTreeContainer(
@@ -1572,7 +1572,7 @@
 
     // If there is no target select MyFiles by default.
     if (!nextCurrentDirEntry) {
-      if (util.isFilesAppExperimental()) {
+      if (util.isNewDirectoryTreeEnabled()) {
         const myFiles = getMyFiles(this.store_.getState());
         nextCurrentDirEntry = myFiles.myFilesEntry;
       } else if (this.ui_.directoryTree.dataModel.myFilesModel_) {
@@ -1759,7 +1759,7 @@
 
     this.updateOfficePrefs_(prefs);
 
-    if (redraw && !util.isFilesAppExperimental()) {
+    if (redraw && !util.isNewDirectoryTreeEnabled()) {
       this.ui_.directoryTree.redraw(false);
     }
   }
@@ -1829,14 +1829,14 @@
             new TrashRootEntry());
       }
       this.store_.dispatch(addUiEntry({entry: this.fakeTrashItem_.entry}));
-      if (!util.isFilesAppExperimental()) {
+      if (!util.isNewDirectoryTreeEnabled()) {
         this.ui_.directoryTree.dataModel.fakeTrashItem = this.fakeTrashItem_;
       }
       return;
     }
 
     this.store_.dispatch(removeUiEntry({key: trashRootKey}));
-    if (!util.isFilesAppExperimental()) {
+    if (!util.isNewDirectoryTreeEnabled()) {
       this.ui_.directoryTree.dataModel.fakeTrashItem = null;
     }
     this.navigateAwayFromDisabledRoot_(this.fakeTrashItem_);
@@ -1859,12 +1859,12 @@
         this.fakeDriveItem_.disabled = this.volumeManager_.isDisabled(
             VolumeManagerCommon.VolumeType.DRIVE);
       }
-      if (!util.isFilesAppExperimental()) {
+      if (!util.isNewDirectoryTreeEnabled()) {
         this.ui_.directoryTree.dataModel.fakeDriveItem = this.fakeDriveItem_;
       }
       return;
     }
-    if (!util.isFilesAppExperimental()) {
+    if (!util.isNewDirectoryTreeEnabled()) {
       this.ui_.directoryTree.dataModel.fakeDriveItem = null;
     }
     this.navigateAwayFromDisabledRoot_(this.fakeDriveItem_);
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index a5c8c345..ab7805f 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -133,7 +133,7 @@
 
   // The event target could still be a descendant of a DirectoryItem element
   // (e.g. the eject button).
-  if (util.isFilesAppExperimental()) {
+  if (util.isNewDirectoryTreeEnabled()) {
     // Handle eject button in the new directory tree.
     if (element.classList.contains('root-eject')) {
       const treeItem = element.closest('xf-tree-item');
@@ -276,7 +276,7 @@
 CommandUtil.createVolumeSwitchCommand = index =>
     new (class extends FilesCommand {
       execute(event, fileManager) {
-        if (util.isFilesAppExperimental()) {
+        if (util.isNewDirectoryTreeEnabled()) {
           const items = fileManager.ui.directoryTree.items;
           if (items[index - 1]?.entry) {
             getStore().dispatch(
@@ -1023,7 +1023,7 @@
 
                 // Select new directory and start rename operation.
                 if (executedFromDirectoryTree) {
-                  if (util.isFilesAppExperimental()) {
+                  if (util.isNewDirectoryTreeEnabled()) {
                     // The above `targetDirectory.getDirectory` call will create
                     // a new directory, the new directory's file watcher handler
                     // will re-read the parent directory and the new tree item
diff --git a/ui/file_manager/file_manager/foreground/js/guest_os_controller.js b/ui/file_manager/file_manager/foreground/js/guest_os_controller.js
index 070a09a..628af4b 100644
--- a/ui/file_manager/file_manager/foreground/js/guest_os_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/guest_os_controller.js
@@ -84,7 +84,7 @@
       return navigationModelItem;
     });
 
-    if (!util.isFilesAppExperimental()) {
+    if (!util.isNewDirectoryTreeEnabled()) {
       this.directoryTree_.dataModel.guestOsPlaceholders =
           newGuestOsPlaceholders;
       // Redraw the tree to ensure any newly added/removed roots are
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index 93def32..dd59c35 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -618,7 +618,7 @@
    * @suppress {checkTypes} closure can't cast Element to XfTree.
    */
   initDirectoryTree(directoryTree) {
-    if (util.isFilesAppExperimental()) {
+    if (util.isNewDirectoryTreeEnabled()) {
       this.directoryTreeContainer =
           /** @type {!DirectoryTreeContainer} */ (directoryTree);
       this.directoryTree =
@@ -701,7 +701,7 @@
         ListContainer.ListType.UNINITIALIZED) {
       this.listContainer.currentView.relayout();
     }
-    if (!util.isFilesAppExperimental() && this.directoryTree) {
+    if (!util.isNewDirectoryTreeEnabled() && this.directoryTree) {
       this.directoryTree.relayout();
     }
   }
diff --git a/ui/file_manager/integration_tests/file_manager/drive_specific.js b/ui/file_manager/integration_tests/file_manager/drive_specific.js
index fd8caa4..34a05eb8 100644
--- a/ui/file_manager/integration_tests/file_manager/drive_specific.js
+++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -1724,10 +1724,10 @@
 
 /**
  * Tests that when bulk pinning is enabled the queued state is shown for all
- * files that the PinManager is tracking but has not yet pinned.
+ * files that the PinningManager is tracking but has not yet pinned.
  */
-testcase.driveAllItemsShouldBeQueuedIfTrackedByPinManager = async () => {
-  // Stop the PinManager from pinning files.
+testcase.driveAllItemsShouldBeQueuedIfTrackedByPinningManager = async () => {
+  // Stop the PinningManager from pinning files.
   await sendTestMessage({name: 'setBulkPinningShouldPinFiles', enabled: false});
 
   // Add a single empty file and load Files app up at the Drive root.
diff --git a/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js b/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js
index e5c494e5..c4ad59d5 100644
--- a/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js
+++ b/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js
@@ -43,7 +43,7 @@
    */
   static async create(appId, remoteCall) {
     const useNewTree =
-        await sendTestMessage({name: 'isFilesExperimentalEnabled'}) === 'true';
+        await sendTestMessage({name: 'isNewDirectoryTreeEnabled'}) === 'true';
     const directoryTree =
         new DirectoryTreePageObject(appId, remoteCall, useNewTree);
     remoteCall.waitForElement(appId, directoryTree.rootSelector);
diff --git a/ui/file_manager/integration_tests/file_manager/toolbar.js b/ui/file_manager/integration_tests/file_manager/toolbar.js
index ac9eb7d..beed086 100644
--- a/ui/file_manager/integration_tests/file_manager/toolbar.js
+++ b/ui/file_manager/integration_tests/file_manager/toolbar.js
@@ -503,7 +503,7 @@
 
   // Force the bulk pinning manager to check for free space again (this
   // currently is done on a 60s poll).
-  await sendTestMessage({name: 'forcePinManagerSpaceCheck'});
+  await sendTestMessage({name: 'forcePinningManagerSpaceCheck'});
   await remoteCall.waitForElement(appId, '#cloud-button[hidden]');
 };
 
diff --git a/ui/file_manager/integration_tests/remote_call.js b/ui/file_manager/integration_tests/remote_call.js
index 1215b0a3..c0afd607 100644
--- a/ui/file_manager/integration_tests/remote_call.js
+++ b/ui/file_manager/integration_tests/remote_call.js
@@ -1026,7 +1026,7 @@
   /**
    * Wait for the underlying bulk pinning manager to enter the specified stage.
    * @param {string} want The stage the bulk pinning is expected to be in. This
-   *     is a string relating to the stage defined in the `PinManager`.
+   *     is a string relating to the stage defined in the `PinningManager`.
    */
   async waitForBulkPinningStage(want) {
     const caller = getCaller();
diff --git a/ui/message_center/views/notification_view_base_unittest.cc b/ui/message_center/views/notification_view_base_unittest.cc
index 3ac2f26..e3c3cee 100644
--- a/ui/message_center/views/notification_view_base_unittest.cc
+++ b/ui/message_center/views/notification_view_base_unittest.cc
@@ -1017,7 +1017,9 @@
   // Now construct a mouse click event 2 pixel inside from the bottom.
   gfx::Point cursor_location(notification_view()->size().width() / 2,
                              notification_view()->size().height() - 2);
-  generator.MoveMouseTo(cursor_location);
+  gfx::Point cursor_in_screen =
+      views::View::ConvertPointToScreen(notification_view(), cursor_location);
+  generator.MoveMouseTo(cursor_in_screen);
   generator.ClickLeftButton();
 
   EXPECT_TRUE(delegate_->clicked());
@@ -1041,7 +1043,9 @@
   // Now construct a mouse click event 2 pixel inside from the bottom.
   gfx::Point cursor_location(notification_view()->size().width() / 2,
                              notification_view()->size().height() - 2);
-  generator.MoveMouseTo(cursor_location);
+  gfx::Point cursor_in_screen =
+      views::View::ConvertPointToScreen(notification_view(), cursor_location);
+  generator.MoveMouseTo(cursor_in_screen);
   generator.ClickLeftButton();
 
   EXPECT_TRUE(delegate_->clicked());
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index 18722961..4203c528 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -50,9 +50,22 @@
     scoped_refptr<ColorProviderKey::ThemeInitializerSupplier> custom_theme,
     bool use_custom_frame) const {
   ui::ColorProviderKey key;
-  key.color_mode = (GetDefaultSystemColorScheme() == ColorScheme::kDark)
-                       ? ColorProviderKey::ColorMode::kDark
-                       : ColorProviderKey::ColorMode::kLight;
+
+  switch (GetDefaultSystemColorScheme()) {
+    case ColorScheme::kDark:
+      key.color_mode = ColorProviderKey::ColorMode::kDark;
+      break;
+    case ColorScheme::kLight:
+      key.color_mode = ColorProviderKey::ColorMode::kLight;
+      break;
+    case ColorScheme::kPlatformHighContrast:
+      key.color_mode = GetPreferredColorScheme() == PreferredColorScheme::kDark
+                           ? ColorProviderKey::ColorMode::kDark
+                           : ColorProviderKey::ColorMode::kLight;
+      break;
+    default:
+      NOTREACHED_NORETURN();
+  }
   key.contrast_mode = UserHasContrastPreference()
                           ? ColorProviderKey::ContrastMode::kHigh
                           : ColorProviderKey::ContrastMode::kNormal;
diff --git a/ui/native_theme/native_theme_win_unittest.cc b/ui/native_theme/native_theme_win_unittest.cc
index e31d5e1..722d2796 100644
--- a/ui/native_theme/native_theme_win_unittest.cc
+++ b/ui/native_theme/native_theme_win_unittest.cc
@@ -9,6 +9,7 @@
 
 namespace ui {
 
+using ColorMode = ColorProviderKey::ColorMode;
 using PrefScheme = NativeTheme::PreferredColorScheme;
 using SystemThemeColor = NativeTheme::SystemThemeColor;
 
@@ -19,6 +20,10 @@
 
   ~TestNativeThemeWin() override = default;
 
+  ColorMode GetColorMode() const {
+    return GetColorProviderKey(/*custom_theme=*/nullptr).color_mode;
+  }
+
   // NativeTheme:
   void SetSystemColor(SystemThemeColor system_color, SkColor color) {
     system_colors_[system_color] = color;
@@ -131,4 +136,22 @@
   EXPECT_EQ(theme.GetPlatformHighContrastColorScheme(), HCColorScheme::kNone);
 }
 
+TEST(NativeThemeWinTest, TestColorProviderKeyColorMode) {
+  TestNativeThemeWin theme;
+
+  theme.set_forced_colors(false);
+  theme.set_use_dark_colors(true);
+  EXPECT_EQ(theme.GetColorMode(), ColorMode::kDark);
+
+  theme.set_use_dark_colors(false);
+  EXPECT_EQ(theme.GetColorMode(), ColorMode::kLight);
+
+  theme.set_forced_colors(true);
+  theme.set_preferred_color_scheme(PrefScheme::kDark);
+  EXPECT_EQ(theme.GetColorMode(), ColorMode::kDark);
+
+  theme.set_preferred_color_scheme(PrefScheme::kLight);
+  EXPECT_EQ(theme.GetColorMode(), ColorMode::kLight);
+}
+
 }  // namespace ui
diff --git a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.h b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.h
index 3a933cc..9f95db6 100644
--- a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.h
+++ b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.h
@@ -12,7 +12,6 @@
 VIEWS_EXPORT
 @interface MenuControllerCocoaDelegateImpl
     : NSObject <MenuControllerCocoaDelegate>
-- (void)setAnchorRect:(gfx::Rect)rect;
 @end
 
 #endif  // UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_COCOA_DELEGATE_IMPL_H_
diff --git a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm
index 05de57a3..5e5f12d 100644
--- a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm
+++ b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm
@@ -121,24 +121,32 @@
 // --- Private API begin ---
 
 // In macOS 13 and earlier, the internals of menus are handled by HI Toolbox,
-// and the bridge to that code is NSCarbonMenuImpl. Starting with macOS 14, the
-// internals of menus are in NSCocoaMenuImpl. Abstract away into a protocol the
-// (one) common method that this code uses that is present on both Impl classes.
-@protocol CrNSMenuImpl <NSObject>
-@optional
+// and the bridge to that code is NSCarbonMenuImpl. While in reality this is a
+// class, abstract its method that is used by this code into a protocol.
+@protocol CrNSCarbonMenuImpl <NSObject>
+
+// Highlights the menu item at the provided index.
 - (void)highlightItemAtIndex:(NSInteger)index;
+
 @end
 
 @interface NSMenu (Impl)
-- (id<CrNSMenuImpl>)_menuImpl;
+
+// Returns the impl. (If called on macOS 14 this would return a subclass of
+// NSCocoaMenuImpl, but private API use is not needed on macOS 14.)
+- (id<CrNSCarbonMenuImpl>)_menuImpl;
+
+// Returns the bounds of the entire menu in screen coordinate space. Available
+// on both Carbon and Cocoa impls, but always (incorrectly) returns a zero
+// origin with the Cocoa impl. Therefore, do not use with macOS 14 or later.
 - (CGRect)_boundsIfOpen;
+
 @end
 
 // --- Private API end ---
 
 @implementation MenuControllerCocoaDelegateImpl {
   NSMutableArray* __strong _menuObservers;
-  gfx::Rect _anchorRect;
 }
 
 - (instancetype)init {
@@ -154,10 +162,6 @@
   }
 }
 
-- (void)setAnchorRect:(gfx::Rect)rect {
-  _anchorRect = rect;
-}
-
 - (void)controllerWillAddItem:(NSMenuItem*)menuItem
                     fromModel:(ui::MenuModel*)model
                       atIndex:(size_t)index
@@ -191,101 +195,110 @@
 }
 
 - (void)controllerWillAddMenu:(NSMenu*)menu fromModel:(ui::MenuModel*)model {
-  absl::optional<size_t> alerted_index;
+  absl::optional<size_t> alertedIndex;
 
-  // This list will be copied into callback blocks later if it's non-empty, but
-  // since it's fairly small that's not a big deal.
-  std::vector<ui::ElementIdentifier> element_ids;
+  // A map containing elements that need to be tracked, mapping from their
+  // identifiers to their indexes in the menu.
+  std::map<ui::ElementIdentifier, NSInteger> elementIds;
 
   for (size_t i = 0; i < model->GetItemCount(); ++i) {
     if (model->IsAlertedAt(i)) {
-      DCHECK(!alerted_index.has_value());
-      alerted_index = i;
+      CHECK(!alertedIndex.has_value())
+          << "Mac menu code can only alert for one item in a menu";
+      alertedIndex = i;
     }
     const ui::ElementIdentifier identifier = model->GetElementIdentifierAt(i);
     if (identifier) {
-      element_ids.push_back(identifier);
+      elementIds.emplace(identifier, base::checked_cast<NSInteger>(i));
     }
   }
 
-  if (alerted_index.has_value() || !element_ids.empty()) {
-    auto shown_callback = ^(NSNotification* note) {
-      NSMenu* const menu_obj = note.object;
-      if (alerted_index.has_value()) {
-        if ([menu respondsToSelector:@selector(_menuImpl)]) {
-          id<CrNSMenuImpl> menuImpl = [menu_obj _menuImpl];
-          if ([menuImpl respondsToSelector:@selector(highlightItemAtIndex:)]) {
-            const auto index =
-                base::checked_cast<NSInteger>(alerted_index.value());
-            [menuImpl highlightItemAtIndex:index];
-          }
+  if (alertedIndex.has_value() || !elementIds.empty()) {
+    __block bool menuShown = false;
+    auto shownCallback = ^(NSNotification* note) {
+      if (@available(macOS 14.0, *)) {
+        // This early return handles two cases.
+        //
+        // 1. If this window isn't the window implementing the menu, this call
+        //    to get the frame will return an empty rect. Return, as this would
+        //    be the wrong window.
+        //
+        // 2. When the notification first fires, the layout isn't complete and
+        //    the menu item bounds will be reported to have a width of 10. If
+        //    the width is too small, early return, as the callback will happen
+        //    again, that time with the correct bounds.
+        if (menu.numberOfItems &&
+            NSWidth([menu itemAtIndex:0].accessibilityFrame) < 20) {
+          return;
         }
       }
 
-      // This situation is broken.
-      //
-      // First, NSMenuDidBeginTrackingNotification is the best way to get called
-      // right before the menu is shown, but at the moment of the call, the menu
-      // isn't open yet. Second, to make things worse, the implementation of
-      // -_boundsIfOpen *tries* to return an NSZeroRect if the menu isn't open
-      // yet but fails to detect it correctly, and instead falls over and
-      // returns a bogus bounds. Fortunately, those bounds are broken in a
-      // predictable way, so that situation can be detected. Don't even bother
-      // trying to make the -_boundsIfOpen call on the notification; there's no
-      // point.
-      //
-      // However, it takes just one trip through the main loop for the menu to
-      // appear and the -_boundsIfOpen call to work.
-      dispatch_after(
-          dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC),
-          dispatch_get_main_queue(), ^{
-            // Even though all supported macOS releases have `-_boundsIfOpen`,
-            // because it's not official API, retain the fallback code written
-            // for earlier versions of macOSes.
-            //
-            // The fallback bounds are intentionally twice as wide as they
-            // should be because even though we could check the RTL bit and
-            // guess whether the menu should appear to the left or right of the
-            // anchor, if the anchor is near one side of the screen the menu
-            // could end up on the other side.
-            gfx::Rect screen_rect = self->_anchorRect;
-            CGSize menu_size = [menu_obj size];
-            screen_rect.Inset(gfx::Insets::TLBR(
-                0, -menu_size.width, -menu_size.height, -menu_size.width));
-            if ([menu_obj respondsToSelector:@selector(_boundsIfOpen)]) {
-              CGRect bounds = [menu_obj _boundsIfOpen];
-              // A broken bounds for a menu that isn't
-              // actually yet open looks like: {{zeroish,
-              // main display height}, {zeroish, zeroish}}.
-              auto is_zeroish = [](CGFloat f) { return f >= 0 && f < 0.00001; };
-              if (is_zeroish(bounds.origin.x) && bounds.origin.y > 300 &&
-                  is_zeroish(bounds.size.width) &&
-                  is_zeroish(bounds.size.height)) {
-                // FYI, this never actually happens.
-                LOG(ERROR) << "Get menu bounds failed.";
-              } else {
-                screen_rect = gfx::ScreenRectFromNSRect(bounds);
-              }
-            }
+      // The notification may fire more than once; only process the first
+      // time.
+      if (menuShown) {
+        return;
+      }
+      menuShown = true;
 
-            for (ui::ElementIdentifier element_id : element_ids) {
-              ui::ElementTrackerMac::GetInstance()->NotifyMenuItemShown(
-                  menu_obj, element_id, screen_rect);
-            }
-          });
+      if (alertedIndex.has_value()) {
+        const auto index = base::checked_cast<NSInteger>(alertedIndex.value());
+        if (@available(macOS 14.0, *)) {
+          [menu itemAtIndex:index].accessibilitySelected = true;
+        } else {
+          [menu._menuImpl highlightItemAtIndex:index];
+        }
+      }
+
+      if (@available(macOS 14.0, *)) {
+        for (auto [elementId, index] : elementIds) {
+          NSRect frame = [menu itemAtIndex:index].accessibilityFrame;
+          ui::ElementTrackerMac::GetInstance()->NotifyMenuItemShown(
+              menu, elementId, gfx::ScreenRectFromNSRect(frame));
+        }
+      } else {
+        // macOS 13 and earlier use the old Carbon Menu Manager, and getting the
+        // bounds of menus is pretty wackadoodle.
+        //
+        // Even though with macOS 11 through macOS 13 watching for
+        // NSWindowDidOrderOnScreenAndFinishAnimatingNotification would work to
+        // guarantee that the menu is on the screen and can be queried for size,
+        // with macOS 10.15, there's no involvement from Cocoa, so there's no
+        // good notification that the menu window was shown. Therefore, rely on
+        // NSMenuDidBeginTrackingNotification, but then spin the event loop
+        // once. This practically guarantees that the menu is on screen and can
+        // be queried for size.
+        dispatch_after(
+            dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC),
+            dispatch_get_main_queue(), ^{
+              gfx::Rect bounds = gfx::ScreenRectFromNSRect(menu._boundsIfOpen);
+              for (auto [elementId, index] : elementIds) {
+                ui::ElementTrackerMac::GetInstance()->NotifyMenuItemShown(
+                    menu, elementId, bounds);
+              }
+            });
+      };
     };
 
-    [_menuObservers
-        addObject:[NSNotificationCenter.defaultCenter
-                      addObserverForName:NSMenuDidBeginTrackingNotification
-                                  object:menu
-                                   queue:nil
-                              usingBlock:shown_callback]];
+    if (@available(macOS 14.0, *)) {
+      NSString* notificationName =
+          @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification";
+      [_menuObservers addObject:[NSNotificationCenter.defaultCenter
+                                    addObserverForName:notificationName
+                                                object:nil
+                                                 queue:nil
+                                            usingBlock:shownCallback]];
+    } else {
+      [_menuObservers
+          addObject:[NSNotificationCenter.defaultCenter
+                        addObserverForName:NSMenuDidBeginTrackingNotification
+                                    object:menu
+                                     queue:nil
+                                usingBlock:shownCallback]];
+    }
   }
 
-  if (!element_ids.empty()) {
-    auto hidden_callback = ^(NSNotification* note) {
-      NSMenu* const menu_obj = note.object;
+  if (!elementIds.empty()) {
+    auto hiddenCallback = ^(NSNotification* note) {
       // We expect to see the following order of events:
       // - element shown
       // - element activated (optional)
@@ -297,9 +310,9 @@
       dispatch_after(
           dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC),
           dispatch_get_main_queue(), ^{
-            for (ui::ElementIdentifier element_id : element_ids) {
+            for (auto [elementId, index] : elementIds) {
               ui::ElementTrackerMac::GetInstance()->NotifyMenuItemHidden(
-                  menu_obj, element_id);
+                  menu, elementId);
             }
           });
     };
@@ -309,7 +322,7 @@
                       addObserverForName:NSMenuDidEndTrackingNotification
                                   object:menu
                                    queue:nil
-                              usingBlock:hidden_callback]];
+                              usingBlock:hiddenCallback]];
   }
 }
 
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index c3c80f6..a7a82c6 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -215,7 +215,6 @@
 
   closing_event_time_ = base::TimeTicks();
   running_ = true;
-  [menu_delegate_ setAnchorRect:bounds];
 
   // Ensure the UI can update while the menu is fading out.
   base::ScopedPumpMessagesInPrivateModes pump_private;
diff --git a/v8 b/v8
index faa4cfb..c57efa1 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit faa4cfb4e3db1580859487805253f952286c9887
+Subproject commit c57efa129901e286f562dccac8c5e77b9517b1fd