diff --git a/DEPS b/DEPS
index 48f3259..81c9d7a 100644
--- a/DEPS
+++ b/DEPS
@@ -241,7 +241,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:81e5cdad29bb4c7aaad98c843637513db3155b0d',
+  'luci_go': 'git_revision:36cf4b54527c49aca7ed3023995a081e14f1852a',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -304,15 +304,15 @@
   # 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': 'a25977da8a2451c0d53c581068b180c2e9621cc6',
+  'skia_revision': 'da5034f9d117ac2bc6ee62af6530e114c874d443',
   # 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': '199c484c7503cb392116ca8b0e62149b06733cbf',
+  'v8_revision': 'd0578efe564af5dbf3c8b39e6c78cbed301775aa',
   # 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': 'e5671e16b83ff26b25c2a831ff9cdc3930f8c06d',
+  'angle_revision': '660e4a7c0d4f919b58a7ef22903aad2efabefa1d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -331,7 +331,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:11.20230124.2.1',
+  'fuchsia_version': 'version:11.20230125.1.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -383,7 +383,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': '84175b83e49abab730cd167d1dbe68442295555f',
+  'devtools_frontend_revision': '25650e0d5d2db67fc0e1b670dd81023775124b41',
   # 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.
@@ -419,7 +419,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'c744a23d77d53b8e8e7b9d5c7d7439e2622034da',
+  'dawn_revision': '2cf9764e450fa31846943764ec5e3c518615cf1d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -455,7 +455,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'cros_components_revision': '64d107c35744760124f2b6353d9309cee2c71767',
+  'cros_components_revision': '5e449ecf7311cba83cdcfc1b2ae449f40d22f29e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -467,7 +467,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libunwind_revision':    'bb5988e15c56d4742574fc880c51ae104d5421b7',
+  'libunwind_revision':    'e95b94b74d26f8387d4fb03a687a2fab0ed8e91c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -770,12 +770,12 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    'bfce84bcff9a9a84cf368739dfeb65490ef562d2',
+    'fe129212b094323fe75657a1cc566554d0e23de9',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + 'e1c456ba79168ef658572d4603dd44301b7a8a63',
+    'url': Var('chromium_git') + '/website.git' + '@' + '03e9daab0fdba4143e91afb7d8b7ee6c881c3f73',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -959,7 +959,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '7VfhAMGn11-gxhQIPatt8IpN533nojeeDldry00N7foC',
+          'version': 'aYKU5k2YMftLAo4DCcErxGnD4lv2Mumfhrh8DR_wAnIC',
       },
     ],
     'condition': 'checkout_android',
@@ -1210,7 +1210,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '1167631ca6cabf9ffc52c7774da14ee7c9662fc4',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '4a9880edc819ab88d1a7ffc67a73c2616538b575',
     'condition': 'checkout_src_internal',
   },
 
@@ -1800,7 +1800,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@a888e09ec585efd4e81d62609866eced92dac509',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@71bd1907ea2f4e3d03f9fee926bb6cab5b8a6a2b',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1837,10 +1837,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'b38a15b4485587d016eb2ca1bf3531292a870f14',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'ad8abf400d8d23fb04bdcf1f654bccb6625db7b4',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'e2c29c520a4e489c93953a8ed0ae290d4adbd0b2',
+    Var('webrtc_git') + '/src.git' + '@' + 'cc1c932f104196022f907e034b88266c1bdaaf4e',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1867,7 +1867,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'MyiVNjXOgp4UALQCkynT8FIIE1dUun9865DmSTPvY74C',
+          'version': 'bOyplOZW_1JEVFUYAKgbKGWaIlUNmN1YWkzd5HXMjbMC',
         },
       ],
       'dep_type': 'cipd',
@@ -1877,7 +1877,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': 'LafRj2L3lxlukI7brcSm4q7utsj7P4fdgDLNqpbx0QcC',
+          'version': 'eBpAa_OebMnB2kWt7jt2enLuznrQvGveRaHpV1a3y1AC',
         },
       ],
       'dep_type': 'cipd',
@@ -1899,7 +1899,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-arm64',
-          'version': 'r0BKwIKC3SOVOFW8X04QsWZty0hrjyylHg1hng-befgC',
+          'version': 'BUfxeGjbFbRJh3xW3sHUYhB0CNMviWBhCtud4vytIrEC',
         },
       ],
       'dep_type': 'cipd',
@@ -1910,7 +1910,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@705330c39b600b6a84389848e51b3114a1dc4dad',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@024bd0d0d5a44a4b6dca4c5c412f1dd86b30c95b',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc
index 3d3ea28..9475c08 100644
--- a/ash/accelerators/debug_commands.cc
+++ b/ash/accelerators/debug_commands.cc
@@ -198,7 +198,7 @@
 }
 
 void HandleToggleVideoConferenceCameraTrayIcon() {
-  if (!ash::features::IsVcControlsUiEnabled()) {
+  if (!ash::features::IsVideoConferenceEnabled()) {
     return;
   }
 
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.cc b/ash/capture_mode/capture_mode_demo_tools_controller.cc
index a080e8a..cfccb09 100644
--- a/ash/capture_mode/capture_mode_demo_tools_controller.cc
+++ b/ash/capture_mode/capture_mode_demo_tools_controller.cc
@@ -164,7 +164,9 @@
 }
 
 void CaptureModeDemoToolsController::RefreshBounds() {
-  key_combo_widget_->SetBounds(CalculateKeyComboWidgetBounds());
+  if (key_combo_widget_) {
+    key_combo_widget_->SetBounds(CalculateKeyComboWidgetBounds());
+  }
 }
 
 void CaptureModeDemoToolsController::OnTouchEvent(
diff --git a/ash/capture_mode/capture_mode_demo_tools_unittests.cc b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
index 605f740..42add24 100644
--- a/ash/capture_mode/capture_mode_demo_tools_unittests.cc
+++ b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "ash/accelerators/keyboard_code_util.h"
+#include "ash/accessibility/magnifier/docked_magnifier_controller.h"
 #include "ash/capture_mode/capture_mode_bar_view.h"
 #include "ash/capture_mode/capture_mode_constants.h"
 #include "ash/capture_mode/capture_mode_controller.h"
@@ -741,6 +742,26 @@
   VerifyKeyComboWidgetPosition();
 }
 
+// Tests that there is no crash when work area changed after starting a video
+// recording with demo tools enabled. Docked mananifier is used as an example to
+// trigger the work area change.
+TEST_F(CaptureModeDemoToolsTest, WorkAreaChangeTest) {
+  CaptureModeController* controller = StartCaptureSession(
+      CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
+  controller->EnableDemoTools(true);
+  StartVideoRecordingImmediately();
+  EXPECT_TRUE(controller->is_recording_in_progress());
+  CaptureModeDemoToolsController* demo_tools_controller =
+      GetCaptureModeDemoToolsController();
+  EXPECT_TRUE(demo_tools_controller);
+  CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller);
+
+  auto* docked_magnifier_controller =
+      Shell::Get()->docked_magnifier_controller();
+  docked_magnifier_controller->SetEnabled(/*enabled=*/true);
+  controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
+}
+
 // Tests that the metrics that record if a recording starts with demo tools
 // feature enabled are recorded correctly in a capture session both in clamshell
 // and tablet mode.
diff --git a/ash/components/arc/arc_features.cc b/ash/components/arc/arc_features.cc
index 77067049..c464eb6 100644
--- a/ash/components/arc/arc_features.cc
+++ b/ash/components/arc/arc_features.cc
@@ -82,6 +82,11 @@
              "ArcEnablePerVmCoreScheduling",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Enables use of new endpoint for fetching ARC sign-in token.
+BASE_FEATURE(kEnableTokenBootstrapEndpoint,
+             "ArcEnableTokenBootstrapEndpoint",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Controls whether to use ARC TTS caching to optimize ARC boot.
 BASE_FEATURE(kEnableTTSCaching,
              "ArcEnableTTSCaching",
diff --git a/ash/components/arc/arc_features.h b/ash/components/arc/arc_features.h
index e6eb73e9..715241b 100644
--- a/ash/components/arc/arc_features.h
+++ b/ash/components/arc/arc_features.h
@@ -24,6 +24,7 @@
 BASE_DECLARE_FEATURE(kEnableArcVmDataMigration);
 BASE_DECLARE_FEATURE(kEnableLazyWebViewInit);
 BASE_DECLARE_FEATURE(kEnablePerVmCoreScheduling);
+BASE_DECLARE_FEATURE(kEnableTokenBootstrapEndpoint);
 BASE_DECLARE_FEATURE(kEnableTTSCaching);
 BASE_DECLARE_FEATURE(kEnableTTSCacheSetup);
 BASE_DECLARE_FEATURE(kEnableUnifiedAudioFocusFeature);
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 2f502ba..2885e60 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -965,11 +965,30 @@
              "FloatingWorkspace",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Maximum delay to wait for restoring Floating Workspace after login.
+constexpr base::FeatureParam<base::TimeDelta>
+    kFloatingWorkspaceMaxTimeAvaliableForRestoreAfterLogin{
+        &kFloatingWorkspace, "MaxTimeAvailableForRestoreAfterLogin",
+        base::Seconds(3)};
+
 // Enables or disables Floating Workspace V2 feature on ChromeOS
 BASE_FEATURE(kFloatingWorkspaceV2,
              "FloatingWorkspaceV2",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Maximum delay to wait for restoring Floating Workspace V2 after login.
+constexpr base::FeatureParam<base::TimeDelta>
+    kFloatingWorkspaceV2MaxTimeAvaliableForRestoreAfterLogin{
+        &kFloatingWorkspaceV2, "MaxTimeAvailableForRestoreAfterLoginV2",
+        base::Seconds(15)};
+
+// Time interval to capture current desk as desk template and upload template to
+// server.
+constexpr base::FeatureParam<base::TimeDelta>
+    kFloatingWorkspaceV2PeriodicJobIntervalInSeconds{
+        &kFloatingWorkspaceV2, "PeriodicJobIntervalInSeconds",
+        base::Seconds(30)};
+
 // If enabled, makes the Projector app use server side speech
 // recognition instead of on-device speech recognition.
 BASE_FEATURE(kForceEnableServerSideSpeechRecognitionForDev,
@@ -1752,21 +1771,16 @@
 // Controls whether the quick dim prototype is enabled.
 BASE_FEATURE(kQuickDim, "QuickDim", base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Controls whether the vc background blur is enabled.
-BASE_FEATURE(kVCBackgroundBlur,
-             "VCBackgroundBlur",
+// Controls whether the video conference feature is enabled.
+BASE_FEATURE(kVideoConference,
+             "VideoConference",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Controls whether the vc background replace is enabled.
-BASE_FEATURE(kVCBackgroundReplace,
+BASE_FEATURE(kVcBackgroundReplace,
              "VCBackgroundReplace",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Controls whether the vc portrait relighting is enabled.
-BASE_FEATURE(kVCPortraitRelighting,
-             "VCPortraitRelighting",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Enables or disables fingerprint quick unlock.
 BASE_FEATURE(kQuickUnlockFingerprint,
              "QuickUnlockFingerprint",
@@ -2087,9 +2101,6 @@
              "UserActivityPrediction",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Enable or disable the ChromeOS video conferencing controls UI.
-BASE_FEATURE(kVcControlsUi, "VcControlsUi", base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Enable or disable the fake effects for ChromeOS video conferencing controls
 // UI. Only meaningful in the emulator.
 BASE_FEATURE(kVcControlsUiFakeEffects,
@@ -3200,20 +3211,13 @@
   return base::FeatureList::IsEnabled(kUseStorkSmdsServerAddress);
 }
 
-bool IsVCBackgroundBlurEnabled() {
-  return base::FeatureList::IsEnabled(kVCBackgroundBlur);
+bool IsVideoConferenceEnabled() {
+  return base::FeatureList::IsEnabled(kVideoConference);
 }
 
-bool IsVCBackgroundReplaceEnabled() {
-  return base::FeatureList::IsEnabled(kVCBackgroundReplace);
-}
-
-bool IsVCPortraitRelightingEnabled() {
-  return base::FeatureList::IsEnabled(kVCPortraitRelighting);
-}
-
-bool IsVcControlsUiEnabled() {
-  return base::FeatureList::IsEnabled(kVcControlsUi);
+bool IsVcBackgroundReplaceEnabled() {
+  return base::FeatureList::IsEnabled(kVcBackgroundReplace) &&
+         IsVideoConferenceEnabled();
 }
 
 bool IsVcControlsUiFakeEffectsEnabled() {
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 13c6647..2f2adf39 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -290,7 +290,16 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kFirstPartyVietnameseInput);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFloatingWorkspace);
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::FeatureParam<base::TimeDelta>
+    kFloatingWorkspaceMaxTimeAvaliableForRestoreAfterLogin;
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFloatingWorkspaceV2);
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::FeatureParam<base::TimeDelta>
+    kFloatingWorkspaceV2MaxTimeAvaliableForRestoreAfterLogin;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::FeatureParam<base::TimeDelta>
+    kFloatingWorkspaceV2PeriodicJobIntervalInSeconds;
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEcheLauncher);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEcheLauncherListView);
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -501,9 +510,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kPromiseIcons);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQsRevamp);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQuickDim);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVCBackgroundBlur);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVCBackgroundReplace);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVCPortraitRelighting);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVideoConference);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVcBackgroundReplace);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQuickUnlockFingerprint);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQuickUnlockPinAutosubmit);
 // TODO(crbug.com/1104164) - Remove this once most users have their preferences
@@ -592,7 +600,6 @@
 BASE_DECLARE_FEATURE(kUseStorkSmdsServerAddress);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kUseWallpaperStagingUrl);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kUserActivityPrediction);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVcControlsUi);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVcControlsUiFakeEffects);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kVirtualKeyboardBorderedKey);
@@ -883,10 +890,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseAuthsessionForWebAuthNEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseLoginShelfWidgetEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseStorkSmdsServerAddressEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVCBackgroundBlurEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVCBackgroundReplaceEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVCPortraitRelightingEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVcControlsUiEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVideoConferenceEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVcBackgroundReplaceEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVcControlsUiFakeEffectsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsViewPpdEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWallpaperFastRefreshEnabled();
diff --git a/ash/shell.cc b/ash/shell.cc
index 6eb8e1a..3957c09 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -1308,7 +1308,7 @@
     camera_effects_controller_ = std::make_unique<CameraEffectsController>();
   }
 
-  if (features::IsVcControlsUiEnabled()) {
+  if (features::IsVideoConferenceEnabled()) {
     audio_effects_controller_ = std::make_unique<AudioEffectsController>();
   }
 
diff --git a/ash/system/audio/audio_effects_controller_unittest.cc b/ash/system/audio/audio_effects_controller_unittest.cc
index 0ef46e7..b6f4a40 100644
--- a/ash/system/audio/audio_effects_controller_unittest.cc
+++ b/ash/system/audio/audio_effects_controller_unittest.cc
@@ -29,7 +29,7 @@
 
   // NoSessionAshTestBase:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures({features::kVcControlsUi}, {});
+    scoped_feature_list_.InitWithFeatures({features::kVideoConference}, {});
 
     // Here we have to create the global instance of `CrasAudioHandler` before
     // `FakeVideoConferenceTrayController`, so we do it here and not in
diff --git a/ash/system/camera/camera_effects_controller.cc b/ash/system/camera/camera_effects_controller.cc
index 40c6f83..34f99fd 100644
--- a/ash/system/camera/camera_effects_controller.cc
+++ b/ash/system/camera/camera_effects_controller.cc
@@ -138,21 +138,16 @@
   }
 }
 
+// TODO(b/265586822): this should be eventually detected from hardware support.
 bool CameraEffectsController::IsCameraEffectsSupported(
     cros::mojom::CameraEffect effect) {
   switch (effect) {
-    case cros::mojom::CameraEffect::kBackgroundBlur:
-      return features::IsVCBackgroundBlurEnabled();
-    case cros::mojom::CameraEffect::kBackgroundReplace:
-      return features::IsVCBackgroundReplaceEnabled();
-    case cros::mojom::CameraEffect::kPortraitRelight:
-      return features::IsVCPortraitRelightingEnabled();
-
-    // returns if any effects is supported for kNone.
     case cros::mojom::CameraEffect::kNone:
-      return features::IsVCBackgroundBlurEnabled() ||
-             features::IsVCBackgroundReplaceEnabled() ||
-             features::IsVCPortraitRelightingEnabled();
+    case cros::mojom::CameraEffect::kBackgroundBlur:
+    case cros::mojom::CameraEffect::kPortraitRelight:
+      return features::IsVideoConferenceEnabled();
+    case cros::mojom::CameraEffect::kBackgroundReplace:
+      return features::IsVcBackgroundReplaceEnabled();
   }
 }
 
@@ -373,7 +368,7 @@
 
 bool CameraEffectsController::IsEffectControlAvailable(
     cros::mojom::CameraEffect effect /* = cros::mojom::CameraEffect::kNone*/) {
-  if (!ash::features::IsVcControlsUiEnabled()) {
+  if (!ash::features::IsVideoConferenceEnabled()) {
     return false;
   }
 
diff --git a/ash/system/camera/camera_effects_controller_unittest.cc b/ash/system/camera/camera_effects_controller_unittest.cc
index 9a9c071..48f0128 100644
--- a/ash/system/camera/camera_effects_controller_unittest.cc
+++ b/ash/system/camera/camera_effects_controller_unittest.cc
@@ -38,9 +38,7 @@
   // NoSessionAshTestBase:
   void SetUp() override {
     scoped_feature_list_.InitWithFeatures(
-        {features::kVcControlsUi, features::kVCBackgroundBlur,
-         features::kVCBackgroundReplace, features::kVCPortraitRelighting},
-        {});
+        {features::kVideoConference, features::kVcBackgroundReplace}, {});
 
     // Here we have to create the global instance of `CrasAudioHandler` before
     // `FakeVideoConferenceTrayController`, so we do it here and not in
@@ -127,34 +125,24 @@
        IsCameraEffectsSupportedShouldBeConsistentWithFlags) {
   {
     base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({}, {features::kVCBackgroundBlur});
+    scoped_feature_list.InitWithFeatures({}, {features::kVideoConference});
     EXPECT_FALSE(CameraEffectsController::IsCameraEffectsSupported(
         cros::mojom::CameraEffect::kBackgroundBlur));
     EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kBackgroundBlur));
+    EXPECT_FALSE(CameraEffectsController::IsCameraEffectsSupported(
+        cros::mojom::CameraEffect::kPortraitRelight));
+    EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
+        cros::mojom::CameraEffect::kPortraitRelight));
   }
 
   {
     base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({features::kVCBackgroundBlur}, {});
+    scoped_feature_list.InitWithFeatures({features::kVideoConference}, {});
     EXPECT_TRUE(CameraEffectsController::IsCameraEffectsSupported(
         cros::mojom::CameraEffect::kBackgroundBlur));
     EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kBackgroundBlur));
-  }
-
-  {
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({}, {features::kVCPortraitRelighting});
-    EXPECT_FALSE(CameraEffectsController::IsCameraEffectsSupported(
-        cros::mojom::CameraEffect::kPortraitRelight));
-    EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
-        cros::mojom::CameraEffect::kPortraitRelight));
-  }
-
-  {
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({features::kVCPortraitRelighting}, {});
     EXPECT_TRUE(CameraEffectsController::IsCameraEffectsSupported(
         cros::mojom::CameraEffect::kPortraitRelight));
     EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
@@ -163,7 +151,7 @@
 
   {
     base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({}, {features::kVCBackgroundReplace});
+    scoped_feature_list.InitWithFeatures({}, {features::kVcBackgroundReplace});
     EXPECT_FALSE(CameraEffectsController::IsCameraEffectsSupported(
         cros::mojom::CameraEffect::kBackgroundReplace));
     EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
@@ -172,7 +160,7 @@
 
   {
     base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({features::kVCBackgroundReplace}, {});
+    scoped_feature_list.InitWithFeatures({features::kVcBackgroundReplace}, {});
     EXPECT_TRUE(CameraEffectsController::IsCameraEffectsSupported(
         cros::mojom::CameraEffect::kBackgroundReplace));
     EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
diff --git a/ash/system/scheduled_feature/scheduled_feature_unittest.cc b/ash/system/scheduled_feature/scheduled_feature_unittest.cc
index 837ccb7..37b480d 100644
--- a/ash/system/scheduled_feature/scheduled_feature_unittest.cc
+++ b/ash/system/scheduled_feature/scheduled_feature_unittest.cc
@@ -508,7 +508,15 @@
 // Tests that changing the custom start and end times, in such a way that
 // shouldn't change the current status, only updates the timer but doesn't
 // change the status.
-TEST_F(ScheduledFeatureTest, ChangingStartTimesThatDontChangeTheStatus) {
+// TODO(crbug.com/1410064): Fix test failure and re-enable on ChromeOS.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_ChangingStartTimesThatDontChangeTheStatus \
+  DISABLED_ChangingStartTimesThatDontChangeTheStatus
+#else
+#define MAYBE_ChangingStartTimesThatDontChangeTheStatus \
+  ChangingStartTimesThatDontChangeTheStatus
+#endif
+TEST_F(ScheduledFeatureTest, MAYBE_ChangingStartTimesThatDontChangeTheStatus) {
   //       16:00        18:00         22:00
   // <----- + ----------- + ----------- + ----->
   //        |             |             |
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index 6172a46..6404367 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -124,9 +124,10 @@
   virtual_keyboard_tray_ = AddTrayButton(std::make_unique<VirtualKeyboardTray>(
       shelf_, TrayBackgroundViewCatalogName::kVirtualKeyboardStatusArea));
 
-  if (features::IsVcControlsUiEnabled())
+  if (features::IsVideoConferenceEnabled()) {
     video_conference_tray_ =
         AddTrayButton(std::make_unique<VideoConferenceTray>(shelf_));
+  }
 
   stop_recording_button_tray_ =
       AddTrayButton(std::make_unique<StopRecordingButtonTray>(shelf_));
diff --git a/ash/system/video_conference/bubble/bubble_view_unittest.cc b/ash/system/video_conference/bubble/bubble_view_unittest.cc
index a62dbe8a..6d145b0b 100644
--- a/ash/system/video_conference/bubble/bubble_view_unittest.cc
+++ b/ash/system/video_conference/bubble/bubble_view_unittest.cc
@@ -7,8 +7,10 @@
 #include "ash/constants/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shelf/shelf.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/icon_button.h"
+#include "ash/system/camera/camera_effects_controller.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/unified/unified_system_tray.h"
@@ -30,7 +32,7 @@
 
   // AshTestBase:
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(features::kVcControlsUi);
+    scoped_feature_list_.InitAndEnableFeature(features::kVideoConference);
 
     // Here we have to create the global instance of `CrasAudioHandler` before
     // `FakeVideoConferenceTrayController`, so we do it here and not do it in
@@ -55,6 +57,14 @@
 
     // Make the video conference tray visible for testing.
     video_conference_tray()->SetVisiblePreferred(true);
+
+    // For historical reason, all BubbleViewTest tests are written with the
+    // assumption that CameraEffectsController is not registered to the
+    // EffectsManager by default. It is not the case anymore since we removed
+    // the old Flags. The fix for that is easy: we just need to manually
+    // unregister CameraEffectsController in these tests.
+    controller()->effects_manager().UnregisterDelegate(
+        Shell::Get()->camera_effects_controller());
   }
 
   void TearDown() override {
diff --git a/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc b/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc
index 1f99cac..2c15f81 100644
--- a/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc
+++ b/ash/system/video_conference/bubble/return_to_app_panel_unittest.cc
@@ -70,7 +70,7 @@
 
   // AshTestBase:
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(features::kVcControlsUi);
+    scoped_feature_list_.InitAndEnableFeature(features::kVideoConference);
 
     // Here we have to create the global instance of `CrasAudioHandler` before
     // `FakeVideoConferenceTrayController`, so we do it here and not do it in
diff --git a/ash/system/video_conference/video_conference_tray_unittest.cc b/ash/system/video_conference/video_conference_tray_unittest.cc
index 80cb3aa..423cc441 100644
--- a/ash/system/video_conference/video_conference_tray_unittest.cc
+++ b/ash/system/video_conference/video_conference_tray_unittest.cc
@@ -26,7 +26,7 @@
 
   // AshTestBase:
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(features::kVcControlsUi);
+    scoped_feature_list_.InitAndEnableFeature(features::kVideoConference);
 
     // Here we have to create the global instance of `CrasAudioHandler` before
     // `FakeVideoConferenceTrayController`, so we do it here and not do it in
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index af6721e..3b7e039 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -320,6 +320,8 @@
   auto widget = std::make_unique<views::Widget>();
   widget->set_focus_on_creation(false);
   widget->Init(std::move(params));
+  // Turn off default widget animations.
+  widget->SetVisibilityAnimationTransition(views::Widget::ANIMATE_NONE);
 
   aura::Window* window = widget->GetNativeWindow();
   window->parent()->StackChildAtBottom(window);
diff --git a/base/allocator/partition_allocator/BUILD.gn b/base/allocator/partition_allocator/BUILD.gn
index 5476c272..c3064d9 100644
--- a/base/allocator/partition_allocator/BUILD.gn
+++ b/base/allocator/partition_allocator/BUILD.gn
@@ -425,7 +425,7 @@
     "ENABLE_POINTER_COMPRESSION=$enable_pointer_compression_support",
     "ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=$enable_shadow_metadata",
 
-    "STARSCAN=$use_starscan",
+    "USE_STARSCAN=$use_starscan",
 
     "ENABLE_PKEYS=$enable_pkeys",
   ]
diff --git a/base/allocator/partition_allocator/memory_reclaimer.cc b/base/allocator/partition_allocator/memory_reclaimer.cc
index 49f19a63..dc7b3e4 100644
--- a/base/allocator/partition_allocator/memory_reclaimer.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer.cc
@@ -10,9 +10,9 @@
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
 namespace partition_alloc {
 
@@ -66,7 +66,7 @@
   //
   // Lastly decommit empty slot spans and lastly try to discard unused pages at
   // the end of the remaining active slots.
-#if PA_CONFIG(STARSCAN_ENABLE_STARSCAN_ON_RECLAIM) && BUILDFLAG(STARSCAN)
+#if PA_CONFIG(STARSCAN_ENABLE_STARSCAN_ON_RECLAIM) && BUILDFLAG(USE_STARSCAN)
   {
     using PCScan = internal::PCScan;
     const auto invocation_mode = flags & PurgeFlags::kAggressiveReclaim
@@ -75,7 +75,7 @@
     PCScan::PerformScanIfNeeded(invocation_mode);
   }
 #endif  // PA_CONFIG(STARSCAN_ENABLE_STARSCAN_ON_RECLAIM) &&
-        // BUILDFLAG(STARSCAN)
+        // BUILDFLAG(USE_STARSCAN)
 
 #if PA_CONFIG(THREAD_CACHE_SUPPORTED)
   // Don't completely empty the thread cache outside of low memory situations,
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 5a633ee..67bda522 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -22,9 +22,9 @@
 #include "base/allocator/partition_allocator/partition_root.h"
 #include "base/allocator/partition_allocator/partition_stats.h"
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
 namespace partition_alloc {
 
@@ -105,9 +105,9 @@
 #if BUILDFLAG(ENABLE_PKEYS)
   internal::PartitionAddressSpace::UninitPkeyPoolForTesting();
 #endif
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   internal::PCScan::UninitForTesting();  // IN-TEST
-#endif                                   // BUILDFLAG(STARSCAN)
+#endif
 #if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 #if PA_CONFIG(HAS_64_BITS_POINTERS)
   internal::PartitionAddressSpace::UninitForTesting();
diff --git a/base/allocator/partition_allocator/partition_alloc_config.h b/base/allocator/partition_allocator/partition_alloc_config.h
index 4abf110..387f6047 100644
--- a/base/allocator/partition_allocator/partition_alloc_config.h
+++ b/base/allocator/partition_allocator/partition_alloc_config.h
@@ -40,7 +40,7 @@
 #endif
 
 // PCScan supports 64 bits only and is disabled outside Chromium.
-#if PA_CONFIG(HAS_64_BITS_POINTERS) && BUILDFLAG(STARSCAN)
+#if PA_CONFIG(HAS_64_BITS_POINTERS) && BUILDFLAG(USE_STARSCAN)
 #define PA_CONFIG_ALLOW_PCSCAN() 1
 #else
 #define PA_CONFIG_ALLOW_PCSCAN() 0
@@ -92,7 +92,7 @@
 #endif  // PA_CONFIG(HAS_64_BITS_POINTERS) &&
         // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID))
 
-#if PA_CONFIG(HAS_64_BITS_POINTERS) && BUILDFLAG(STARSCAN)
+#if PA_CONFIG(HAS_64_BITS_POINTERS) && BUILDFLAG(USE_STARSCAN)
 // Use card table to avoid races for PCScan configuration without safepoints.
 // The card table provides the guaranteee that for a marked card the underling
 // super-page is fully initialized.
@@ -100,7 +100,7 @@
 #else
 // The card table is permanently disabled for 32-bit.
 #define PA_CONFIG_STARSCAN_USE_CARD_TABLE() 0
-#endif  // PA_CONFIG(HAS_64_BITS_POINTERS) && BUILDFLAG(STARSCAN)
+#endif  // PA_CONFIG(HAS_64_BITS_POINTERS) && BUILDFLAG(USE_STARSCAN)
 
 #if PA_CONFIG(STARSCAN_USE_CARD_TABLE) && !PA_CONFIG(ALLOW_PCSCAN)
 #error "Card table can only be used when *Scan is allowed"
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 284aacb..67bb9e60 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -37,9 +37,9 @@
 #include "base/allocator/partition_allocator/tagging.h"
 #include "build/build_config.h"
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
 namespace partition_alloc::internal {
 
@@ -792,7 +792,7 @@
       (is_direct_mapped()
            ? 0
            : ReservedTagBitmapSize() + ReservedFreeSlotBitmapSize());
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   PA_DCHECK(SuperPageStateBitmapAddr(super_page) == state_bitmap);
   const size_t state_bitmap_reservation_size =
       root->IsQuarantineAllowed() ? ReservedStateBitmapSize() : 0;
@@ -804,7 +804,7 @@
   uintptr_t payload = state_bitmap + state_bitmap_reservation_size;
 #else
   uintptr_t payload = state_bitmap;
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
   root->next_partition_page = payload;
   root->next_partition_page_end = root->next_super_page - PartitionPageSize();
@@ -914,7 +914,7 @@
   // sure to register the super-page after it has been fully initialized.
   // Otherwise, the concurrent scanner may try to access |extent->root| which
   // could be not initialized yet.
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   if (root->IsQuarantineEnabled()) {
     {
       ScopedSyscallTimer timer{root};
@@ -925,7 +925,7 @@
     }
     PCScan::RegisterNewSuperPage(root, super_page);
   }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
 #if BUILDFLAG(USE_FREESLOT_BITMAP)
   // Commit the pages for freeslot bitmap.
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index d14663a..7f0bfd9f 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -32,9 +32,9 @@
 #include "base/allocator/partition_allocator/tagging.h"
 #include "build/build_config.h"
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
 #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
 #include "base/allocator/partition_allocator/partition_ref_count.h"
@@ -90,10 +90,10 @@
          (extent->number_of_consecutive_super_pages * kSuperPageSize);
 }
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 using AllocationStateMap =
     StateBitmap<kSuperPageSize, kSuperPageAlignment, kAlignment>;
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
 // Metadata of the slot span.
 //
@@ -450,7 +450,7 @@
       PartitionSuperPageToMetadataArea<thread_safe>(super_page));
 }
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 
 // Size that should be reserved for state bitmap (if present) inside a super
 // page. Elements of a super page are partition-page-aligned, hence the returned
@@ -489,7 +489,7 @@
   return 0ull;
 }
 
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
 // Returns the address of the tag bitmap of the `super_page`. Caller must ensure
 // that bitmap exists.
@@ -916,7 +916,7 @@
   next_slot_span = nullptr;
 }
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 // Returns the state bitmap from an address within a normal-bucket super page.
 // It's the caller's responsibility to ensure that the bitmap exists.
 PA_ALWAYS_INLINE AllocationStateMap* StateBitmapFromAddr(uintptr_t address) {
@@ -924,7 +924,7 @@
   uintptr_t super_page = address & kSuperPageBaseMask;
   return SuperPageStateBitmap(super_page);
 }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
 // Iterates over all slot spans in a super-page. |Callback| must return true if
 // early return is needed.
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index 40deaa4..9ccdad3 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -33,9 +33,9 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/mac/mac_util.h"
 #endif  // PA_CONFIG(ENABLE_MAC11_MALLOC_SIZE_HACK) && BUILDFLAG(IS_APPLE)
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
 #if BUILDFLAG(IS_WIN)
 #include <windows.h>
@@ -906,13 +906,13 @@
     PA_CHECK(!flags.allow_aligned_alloc || !flags.extras_offset);
 
     flags.quarantine_mode =
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
         (opts.quarantine == PartitionOptions::Quarantine::kDisallowed
              ? QuarantineMode::kAlwaysDisabled
              : QuarantineMode::kDisabledByDefault);
 #else
         QuarantineMode::kAlwaysDisabled;
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
     // We mark the sentinel slot span as free to make sure it is skipped by our
     // logic to find a new active slot span.
@@ -1291,7 +1291,7 @@
 void PartitionRoot<thread_safe>::PurgeMemory(int flags) {
   {
     ::partition_alloc::internal::ScopedGuard guard{lock_};
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
     // Avoid purging if there is PCScan task currently scheduled. Since pcscan
     // takes snapshot of all allocated pages, decommitting pages here (even
     // under the lock) is racy.
@@ -1299,7 +1299,7 @@
     if (PCScan::IsInProgress()) {
       return;
     }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
     if (flags & PurgeFlags::kDecommitEmptySlotSpans) {
       DecommitEmptySlotSpans();
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index badc7a88..4d2c78a 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -72,10 +72,10 @@
 #include "base/allocator/partition_allocator/thread_cache.h"
 #include "build/build_config.h"
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
 #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
 // We use this to make MEMORY_TOOL_REPLACES_ALLOCATOR behave the same for max
 // size as other alloc code.
@@ -247,9 +247,9 @@
   using SuperPageExtentEntry =
       internal::PartitionSuperPageExtentEntry<thread_safe>;
   using DirectMapExtent = internal::PartitionDirectMapExtent<thread_safe>;
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   using PCScan = internal::PCScan;
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 
   enum class QuarantineMode : uint8_t {
     kAlwaysDisabled,
@@ -1310,7 +1310,7 @@
   }
 #endif  // PA_CONFIG(ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   // TODO(bikineev): Change the condition to PA_LIKELY once PCScan is enabled by
   // default.
   if (PA_UNLIKELY(root->ShouldQuarantine(object))) {
@@ -1322,7 +1322,7 @@
       return;
     }
   }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
   root->FreeNoHooksImmediate(object, slot_span, slot_start);
 }
@@ -1375,7 +1375,7 @@
   }
 #endif
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   // TODO(bikineev): Change the condition to PA_LIKELY once PCScan is enabled by
   // default.
   if (PA_UNLIKELY(IsQuarantineEnabled())) {
@@ -1384,7 +1384,7 @@
       internal::StateBitmapFromAddr(slot_start)->Free(slot_start);
     }
   }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
   // TODO(keishi): Add PA_LIKELY when brp is fully enabled as |brp_enabled| will
@@ -1931,7 +1931,7 @@
   uintptr_t slot_start = 0;
   size_t slot_size;
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   const bool is_quarantine_enabled = IsQuarantineEnabled();
   // PCScan safepoint. Call before trying to allocate from cache.
   // TODO(bikineev): Change the condition to PA_LIKELY once PCScan is enabled by
@@ -1939,7 +1939,7 @@
   if (PA_UNLIKELY(is_quarantine_enabled)) {
     PCScan::JoinScanIfNeeded();
   }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
   auto* thread_cache = GetOrCreateThreadCache();
 
@@ -2085,7 +2085,7 @@
   }
 #endif  // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   // TODO(bikineev): Change the condition to PA_LIKELY once PCScan is enabled by
   // default.
   if (PA_UNLIKELY(is_quarantine_enabled)) {
@@ -2094,7 +2094,7 @@
       internal::StateBitmapFromAddr(slot_start)->Allocate(slot_start);
     }
   }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 
   return object;
 }
diff --git a/base/android/unguessable_token_android.cc b/base/android/unguessable_token_android.cc
index 39f62679..448daee 100644
--- a/base/android/unguessable_token_android.cc
+++ b/base/android/unguessable_token_android.cc
@@ -20,7 +20,8 @@
                                       static_cast<jlong>(low));
 }
 
-base::UnguessableToken UnguessableTokenAndroid::FromJavaUnguessableToken(
+absl::optional<base::UnguessableToken>
+UnguessableTokenAndroid::FromJavaUnguessableToken(
     JNIEnv* env,
     const JavaRef<jobject>& token) {
   const uint64_t high = static_cast<uint64_t>(
@@ -29,7 +30,7 @@
       Java_UnguessableToken_getLowForSerialization(env, token));
   DCHECK(high);
   DCHECK(low);
-  return base::UnguessableToken::Deserialize(high, low);
+  return base::UnguessableToken::Deserialize2(high, low);
 }
 
 ScopedJavaLocalRef<jobject>
diff --git a/base/android/unguessable_token_android.h b/base/android/unguessable_token_android.h
index 0f2a7873..07fc350 100644
--- a/base/android/unguessable_token_android.h
+++ b/base/android/unguessable_token_android.h
@@ -22,7 +22,7 @@
       const base::UnguessableToken& token);
 
   // Create a native UnguessableToken from Java UnguessableToken |token|.
-  static base::UnguessableToken FromJavaUnguessableToken(
+  static absl::optional<base::UnguessableToken> FromJavaUnguessableToken(
       JNIEnv* env,
       const JavaRef<jobject>& token);
 
diff --git a/base/android/unguessable_token_android_unittest.cc b/base/android/unguessable_token_android_unittest.cc
index 7d06c5b..0a399ec0 100644
--- a/base/android/unguessable_token_android_unittest.cc
+++ b/base/android/unguessable_token_android_unittest.cc
@@ -18,10 +18,11 @@
       base::UnguessableToken::CreateForTesting(high, low);
   ScopedJavaLocalRef<jobject> jtoken =
       UnguessableTokenAndroid::Create(env, token);
-  base::UnguessableToken result =
+  absl::optional<base::UnguessableToken> result =
       UnguessableTokenAndroid::FromJavaUnguessableToken(env, jtoken);
 
-  EXPECT_EQ(token, result);
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(token, result.value());
 }
 
 TEST(UnguessableTokenAndroid, ParcelAndUnparcel) {
@@ -34,10 +35,11 @@
       UnguessableTokenAndroid::Create(env, token);
   ScopedJavaLocalRef<jobject> jtoken_clone =
       UnguessableTokenAndroid::ParcelAndUnparcelForTesting(env, jtoken);
-  base::UnguessableToken token_clone =
+  absl::optional<base::UnguessableToken> token_clone =
       UnguessableTokenAndroid::FromJavaUnguessableToken(env, jtoken_clone);
 
-  EXPECT_EQ(token, token_clone);
+  ASSERT_TRUE(token_clone.has_value());
+  EXPECT_EQ(token, token_clone.value());
 }
 
 }  // namespace android
diff --git a/base/memory/nonscannable_memory.cc b/base/memory/nonscannable_memory.cc
index 5221af1..6d27403 100644
--- a/base/memory/nonscannable_memory.cc
+++ b/base/memory/nonscannable_memory.cc
@@ -13,9 +13,9 @@
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 #include "base/allocator/partition_alloc_features.h"
 #include "base/allocator/partition_allocator/shim/allocator_shim_default_dispatch_to_partition_alloc.h"
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
 namespace base {
@@ -37,14 +37,14 @@
 
 template <bool Quarantinable>
 void* NonScannableAllocatorImpl<Quarantinable>::Alloc(size_t size) {
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   // TODO(bikineev): Change to LIKELY once PCScan is enabled by default.
   if (UNLIKELY(pcscan_enabled_.load(std::memory_order_acquire))) {
     PA_DCHECK(allocator_.get());
     return allocator_->root()->AllocWithFlagsNoHooks(
         0, size, partition_alloc::PartitionPageSize());
   }
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
   // Otherwise, dispatch to default partition.
   return allocator_shim::internal::PartitionAllocMalloc::Allocator()
       ->AllocWithFlagsNoHooks(0, size, partition_alloc::PartitionPageSize());
@@ -57,7 +57,7 @@
 
 template <bool Quarantinable>
 void NonScannableAllocatorImpl<Quarantinable>::NotifyPCScanEnabled() {
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   allocator_.reset(partition_alloc::internal::MakePCScanMetadata<
                    partition_alloc::PartitionAllocator>());
   allocator_->init({
@@ -75,7 +75,7 @@
     partition_alloc::internal::PCScan::RegisterNonScannableRoot(
         allocator_->root());
   pcscan_enabled_.store(true, std::memory_order_release);
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 }
 
 template class NonScannableAllocatorImpl<true>;
diff --git a/base/memory/nonscannable_memory.h b/base/memory/nonscannable_memory.h
index 757a5110..3da7e05a 100644
--- a/base/memory/nonscannable_memory.h
+++ b/base/memory/nonscannable_memory.h
@@ -16,9 +16,9 @@
 
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 #include "base/allocator/partition_allocator/partition_alloc.h"
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/metadata_allocator.h"
-#endif  // BUILDFLAG(STARSCAN)
+#endif
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
 // This file contains allocation/deallocation functions for memory that doesn't
@@ -47,13 +47,13 @@
   // Returns PartitionRoot corresponding to the allocator, or nullptr if the
   // allocator is not enabled.
   partition_alloc::ThreadSafePartitionRoot* root() {
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
     if (!allocator_.get())
       return nullptr;
     return allocator_->root();
 #else
     return nullptr;
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
   }
 
   void NotifyPCScanEnabled();
@@ -65,12 +65,12 @@
   NonScannableAllocatorImpl();
   ~NonScannableAllocatorImpl();
 
-#if BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_STARSCAN)
   std::unique_ptr<partition_alloc::PartitionAllocator,
                   partition_alloc::internal::PCScanMetadataDeleter>
       allocator_;
   std::atomic_bool pcscan_enabled_{false};
-#endif  // BUILDFLAG(STARSCAN)
+#endif  // BUILDFLAG(USE_STARSCAN)
 };
 
 extern template class NonScannableAllocatorImpl<true>;
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 5cd66ac..cb08288 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -44,7 +44,7 @@
 #include <sys/resource.h>
 #endif
 
-#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
 #include "base/allocator/partition_allocator/starscan/stack/stack.h"
 #endif
@@ -78,7 +78,7 @@
       base::DisallowSingleton();
 
 #if !BUILDFLAG(IS_NACL)
-#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
     partition_alloc::internal::PCScan::NotifyThreadCreated(
         partition_alloc::internal::GetStackPointer());
 #endif
@@ -92,7 +92,7 @@
     // where they were created. This explicitly sets the priority of all new
     // threads.
     PlatformThread::SetCurrentThreadType(thread_params->thread_type);
-#endif
+#endif  //  !BUILDFLAG(IS_NACL)
   }
 
   ThreadIdNameManager::GetInstance()->RegisterThread(
@@ -106,7 +106,7 @@
       PlatformThread::CurrentId());
 
 #if !BUILDFLAG(IS_NACL) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
-    BUILDFLAG(STARSCAN)
+    BUILDFLAG(USE_STARSCAN)
   partition_alloc::internal::PCScan::NotifyThreadDestroyed();
 #endif
 
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index db94a93..73e9a08 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -31,7 +31,7 @@
 
 #include <windows.h>
 
-#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
 #include "base/allocator/partition_allocator/starscan/pcscan.h"
 #include "base/allocator/partition_allocator/starscan/stack/stack.h"
 #endif
@@ -110,7 +110,7 @@
                                 FALSE,
                                 DUPLICATE_SAME_ACCESS);
 
-#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
   partition_alloc::internal::PCScan::NotifyThreadCreated(
       partition_alloc::internal::GetStackPointer());
 #endif
@@ -131,7 +131,7 @@
                                                    PlatformThread::CurrentId());
   }
 
-#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(STARSCAN)
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
   partition_alloc::internal::PCScan::NotifyThreadDestroyed();
 #endif
 
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 031c2f20..ef3285ae 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -2080,7 +2080,7 @@
 }
 
 config("default_stack_frames") {
-  if (is_posix || is_fuchsia) {
+  if (!is_win) {
     if (enable_frame_pointers) {
       cflags = [ "-fno-omit-frame-pointer" ]
 
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 082d34b..4738ee8 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -173,18 +173,18 @@
 
 # Determine whether to enable or disable frame pointers, based on the platform
 # and build arguments.
-# TODO(crbug.com/1052397): Consider changing is_chromeos_ash to is_chromeos after
-# lacros-chrome switches to target_os="chromeos".
 if (is_chromeos) {
   # ChromeOS generally prefers frame pointers, to support CWP.
   # However, Clang does not currently generate usable frame pointers in ARM
   # 32-bit builds (https://bugs.llvm.org/show_bug.cgi?id=18505) so disable them
   # there to avoid the unnecessary overhead.
   enable_frame_pointers = current_cpu != "arm"
-} else if (is_apple || is_linux || is_chromeos) {
+} else if (is_apple || is_linux) {
   enable_frame_pointers = true
 } else if (is_win) {
   # 64-bit Windows ABI doesn't support frame pointers.
+  # NOTE: This setting is actually not used in the BUILD.gn for Windows,
+  # but it still reflects correctly that we don't emit frame pointers on x64.
   if (current_cpu == "x64") {
     enable_frame_pointers = false
   } else {
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index c52adb4..d245135 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-11.20230124.3.1
+11.20230125.0.1
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index e29ca3f..e21a244 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -244,6 +244,7 @@
   libc6
   libcairo2
   libcap2
+  libcgi-session-perl
   libcups2
   libdrm2
   libegl1
diff --git a/chrome/VERSION b/chrome/VERSION
index 4f6f04a..455d0010 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=111
 MINOR=0
-BUILD=5559
+BUILD=5560
 PATCH=0
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index f1ac0ac218..cfcf144 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-111.0.5550.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-111.0.5557.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index f4db2fe0..89328d2 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -7406,9 +7406,24 @@
       <message name="IDS_BOOKMARK_FOLDER_CHILD_COUNT" desc="Text description for the number of children of a bookmark folder">
         {NUM_BOOKMARKS, plural, =1 {1 bookmark} other {# bookmarks}}
       </message>
+      <message name="IDS_BOOKMARKS_EDIT_MOVE_TO_ANOTHER_FOLDER" desc="Tooltip for the button in the bookmarks side panel bulk edit mode that allows the user to move the selected bookmarks to a different folder.">
+        Move to another folder
+      </message>
       <message name="IDS_BOOKMARKS_EDIT_MORE" desc="Tooltip for the menu button in the bookmarks side panel bulk edit mode that shows more actions the user can take on selected bookmarks.">
         More
       </message>
+      <message name="IDS_BOOKMARKS_EDIT_MOVE_TO" desc="Title for the bookmarks side panel edit dialog when there are multiple selected bookmarks">
+        Move to…
+      </message>
+      <message name="IDS_BOOKMARKS_EDIT_NEW_FOLDER" desc="Label for the button to add a new folder in the bookmarks side panel edit dialog">
+        New Folder
+      </message>
+      <message name="IDS_BOOKMARKS_EDIT_CANCEL" desc="Label for the button to close the bookmarks side panel edit dialog">
+        Cancel
+      </message>
+      <message name="IDS_BOOKMARKS_EDIT_SAVE" desc="Label for the button to save changes from the bookmarks side panel edit dialog">
+        Save
+      </message>
       <message name="IDS_BOOKMARK_DELETION_COUNT" desc="Text description for the number of deleted bookmarks">
         {NUM_BOOKMARKS, plural, =1 {1 bookmark deleted} other {# bookmarks deleted}}
       </message>
@@ -7424,6 +7439,9 @@
       <message name="IDS_BOOKMARKS_RENAME" desc="Label for the rename bookmarks menu option">
         Rename
       </message>
+      <message name="IDS_BOOKMARKS_URL_FOLDER_DESCRIPTION" desc="Description for a bookmark that includes its URL and parent folder">
+        <ph name="URL">$1<ex>www.google.com</ex></ph> - <ph name="FOLDER">$2<ex>Bookmarks Bar</ex></ph>
+      </message>
 
       <!-- Read Anything strings -->
       <!-- TODO(crbug.com/1266555): Add final strings and make them translateable. -->
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_CANCEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_CANCEL.png.sha1
new file mode 100644
index 0000000..f25da24
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_CANCEL.png.sha1
@@ -0,0 +1 @@
+fe5b327c457d6a3192928c3b35fdd90e5e8e8463
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_MOVE_TO.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_MOVE_TO.png.sha1
new file mode 100644
index 0000000..f25da24
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_MOVE_TO.png.sha1
@@ -0,0 +1 @@
+fe5b327c457d6a3192928c3b35fdd90e5e8e8463
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_MOVE_TO_ANOTHER_FOLDER.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_MOVE_TO_ANOTHER_FOLDER.png.sha1
new file mode 100644
index 0000000..6c6588f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_MOVE_TO_ANOTHER_FOLDER.png.sha1
@@ -0,0 +1 @@
+57c9ca09e43e40316ea3cbea3d011385594deeba
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_NEW_FOLDER.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_NEW_FOLDER.png.sha1
new file mode 100644
index 0000000..f25da24
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_NEW_FOLDER.png.sha1
@@ -0,0 +1 @@
+fe5b327c457d6a3192928c3b35fdd90e5e8e8463
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_SAVE.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_SAVE.png.sha1
new file mode 100644
index 0000000..f25da24
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_EDIT_SAVE.png.sha1
@@ -0,0 +1 @@
+fe5b327c457d6a3192928c3b35fdd90e5e8e8463
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_URL_FOLDER_DESCRIPTION.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_URL_FOLDER_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..2736f29
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_URL_FOLDER_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+e133d3c1dfd037adddda2e1dd4dfd7fdeb4d3216
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 310552e..8bccbad3 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2762,43 +2762,6 @@
     {"(128dip)", kLargeFaviconFromGoogle128,
      std::size(kLargeFaviconFromGoogle128), nullptr}};
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurLowest[] = {
-    {"blur_level", "lowest"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurLight[] = {
-    {"blur_level", "light"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurMedium[] = {
-    {"blur_level", "medium"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurHeavy[] = {
-    {"blur_level", "heavy"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurMaximum[] = {
-    {"blur_level", "maximum"},
-};
-
-const FeatureEntry::FeatureVariation kVCBackgroundBlurVariations[] = {
-    {"Lowest Blur", kVCBackgroundBlurLowest, std::size(kVCBackgroundBlurLowest),
-     nullptr},
-    {"Light Blur", kVCBackgroundBlurLight, std::size(kVCBackgroundBlurLight),
-     nullptr},
-    {"Medium Blur", kVCBackgroundBlurMedium, std::size(kVCBackgroundBlurMedium),
-     nullptr},
-    {"Heavy Blur", kVCBackgroundBlurHeavy, std::size(kVCBackgroundBlurHeavy),
-     nullptr},
-    {"Maximum Blur", kVCBackgroundBlurMaximum,
-     std::size(kVCBackgroundBlurMaximum), nullptr},
-};
-
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 #if BUILDFLAG(IS_ANDROID)
 const FeatureEntry::FeatureParam kGridTabSwitcherForTabletsPolished[] = {
     {"enable_launch_polish", "true"}};
@@ -8429,19 +8392,13 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-    {"vc-background-blur", flag_descriptions::kVCBackgroundBlurName,
-     flag_descriptions::kVCBackgroundBlurDescription, kOsCrOS,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(ash::features::kVCBackgroundBlur,
-                                    kVCBackgroundBlurVariations,
-                                    "VCBackgroundBlur")},
+    {"video-conference", flag_descriptions::kVideoConferenceName,
+     flag_descriptions::kVideoConferenceDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kVideoConference)},
 
-    {"vc-background-replace", flag_descriptions::kVCBackgroundReplaceName,
-     flag_descriptions::kVCBackgroundReplaceDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kVCBackgroundReplace)},
-
-    {"vc-portrait-relighting", flag_descriptions::kVCPortraitRelightingName,
-     flag_descriptions::kVCPortraitRelightingDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kVCPortraitRelighting)},
+    {"vc-background-replace", flag_descriptions::kVcBackgroundReplaceName,
+     flag_descriptions::kVcBackgroundReplaceDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kVcBackgroundReplace)},
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -9151,9 +9108,6 @@
      flag_descriptions::kHoldingSpaceSuggestionsName,
      flag_descriptions::kHoldingSpaceSuggestionsDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kHoldingSpaceSuggestions)},
-    {"vc-controls-ui", flag_descriptions::kVcControlsUiName,
-     flag_descriptions::kVcControlsUiDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kVcControlsUi)},
     {"enable-16-desks", flag_descriptions::kDesks16Name,
      flag_descriptions::kDesks16Description, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kEnable16Desks)},
diff --git a/chrome/browser/accessibility/live_caption_surface.cc b/chrome/browser/accessibility/live_caption_surface.cc
index 79315e2..29e0e77 100644
--- a/chrome/browser/accessibility/live_caption_surface.cc
+++ b/chrome/browser/accessibility/live_caption_surface.cc
@@ -4,10 +4,6 @@
 
 #include "chrome/browser/accessibility/live_caption_surface.h"
 
-#include <memory>
-#include <string>
-#include <utility>
-
 #include "base/functional/callback_forward.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
@@ -113,8 +109,8 @@
   }
 }
 
-std::string LiveCaptionSurface::GetSessionId() const {
-  return session_id_.ToString();
+base::UnguessableToken LiveCaptionSurface::session_id() const {
+  return session_id_;
 }
 
 }  // namespace captions
diff --git a/chrome/browser/accessibility/live_caption_surface.h b/chrome/browser/accessibility/live_caption_surface.h
index 1279f17c..8f9ca89 100644
--- a/chrome/browser/accessibility/live_caption_surface.h
+++ b/chrome/browser/accessibility/live_caption_surface.h
@@ -5,9 +5,6 @@
 #ifndef CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_SURFACE_H_
 #define CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_SURFACE_H_
 
-#include <memory>
-#include <string>
-
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -58,8 +55,8 @@
   void MediaEffectivelyFullscreenChanged(bool is_fullscreen) override;
   void PrimaryPageChanged(content::Page& page) override;
 
-  // Returns a unique string identifier for the current web contents.
-  std::string GetSessionId() const;
+  // Returns a unique identifier for the current web contents.
+  base::UnguessableToken session_id() const;
 
  private:
   friend content::WebContentsUserData<LiveCaptionSurface>;
diff --git a/chrome/browser/accessibility/live_caption_surface_browsertest.cc b/chrome/browser/accessibility/live_caption_surface_browsertest.cc
index 66d2597..cb1e942 100644
--- a/chrome/browser/accessibility/live_caption_surface_browsertest.cc
+++ b/chrome/browser/accessibility/live_caption_surface_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/path_service.h"
 #include "base/test/bind.h"
+#include "base/unguessable_token.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -240,14 +241,12 @@
 
   // The session IDs of the two surfaces should be different because they
   // represent different web contents.
-  const std::string init_id_1 = surface_1->GetSessionId();
-  EXPECT_NE("", init_id_1);
-  EXPECT_NE("", surface_2->GetSessionId());
-  EXPECT_NE(init_id_1, surface_2->GetSessionId());
+  const base::UnguessableToken init_id_1 = surface_1->session_id();
+  EXPECT_NE(init_id_1, surface_2->session_id());
 
   // Navigating a tab shouldn't change its session ID.
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kAboutBlankUrl));
-  EXPECT_EQ(init_id_1, surface_1->GetSessionId());
+  EXPECT_EQ(init_id_1, surface_1->session_id());
 }
 
 // Test that a surface reports the end of live caption sessions.
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.cc
index 8c341567..51caaf9 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.cc
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.cc
@@ -14,11 +14,9 @@
 
 namespace {
 
-// Endpoint for requesting app duplicate data. Local server link is being used
-// since endpoint is not hooked up to OnePlatform yet.
-// TODO(b/264961456): update to One Platform url when endpoint is deployed.
+// Endpoint for requesting app duplicate data on the ChromeOS Almanac API.
 constexpr char kAppDeduplicationOnePlatformEndpoint[] =
-    "http://localhost:9876/v1/deduplicate";
+    "https://chromeosalmanac-pa.googleapis.com/v1/deduplicate";
 
 // Maximum size of App Deduplication Response is 1MB, current size of file at
 // initial launch (v1 of deduplication endpoint is) ~6KB.
@@ -75,6 +73,8 @@
   // A POST request is sent with an override to GET due to server requirements.
   resource_request->method = "POST";
   resource_request->headers.SetHeader("X-HTTP-Method-Override", "GET");
+  resource_request->headers.SetHeader("X-Goog-Api-Key",
+                                      google_apis::GetAPIKey());
 
   resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 
diff --git a/chrome/browser/ash/app_list/search/ranking/ftrl_ranker.cc b/chrome/browser/ash/app_list/search/ranking/ftrl_ranker.cc
index 8e7a736..e6db56b 100644
--- a/chrome/browser/ash/app_list/search/ranking/ftrl_ranker.cc
+++ b/chrome/browser/ash/app_list/search/ranking/ftrl_ranker.cc
@@ -30,6 +30,8 @@
                        CategoriesList& categories) {
   for (auto& ranker : rankers_)
     ranker->Start(query, results, categories);
+
+  ftrl_->Clear();
 }
 
 void FtrlRanker::Train(const LaunchData& launch) {
diff --git a/chrome/browser/ash/app_list/search/search_controller.cc b/chrome/browser/ash/app_list/search/search_controller.cc
index d2b889b..7795a217 100644
--- a/chrome/browser/ash/app_list/search/search_controller.cc
+++ b/chrome/browser/ash/app_list/search/search_controller.cc
@@ -90,7 +90,15 @@
 
   burn_in_controller_->Start();
 
+  // TODO(b/266468933): This logging is limited to a short maximum query
+  // length. Add another metric which measures the bucket count of query length,
+  // with no maximum.
   ash::RecordLauncherIssuedSearchQueryLength(query.length());
+  // Limit query length, for efficiency reasons in matching query to texts.
+  const std::u16string truncated_query =
+      query.length() > kMaxAllowedQueryLength
+          ? query.substr(0, kMaxAllowedQueryLength)
+          : query;
 
   // Clear all search results but preserve zero-state results.
   ClearNonZeroStateResults(results_);
@@ -102,14 +110,14 @@
   }
 
   categories_ = CreateAllCategories();
-  ranker_manager_->Start(query, results_, categories_);
+  ranker_manager_->Start(truncated_query, results_, categories_);
 
   session_start_ = base::Time::Now();
-  last_query_ = query;
+  last_query_ = truncated_query;
 
   // Search all providers.
   for (const auto& provider : providers_) {
-    provider->Start(query);
+    provider->Start(truncated_query);
   }
 }
 
diff --git a/chrome/browser/ash/app_list/search/search_controller.h b/chrome/browser/ash/app_list/search/search_controller.h
index 75848fcb..e1dc608 100644
--- a/chrome/browser/ash/app_list/search/search_controller.h
+++ b/chrome/browser/ash/app_list/search/search_controller.h
@@ -40,6 +40,9 @@
 class SearchSessionMetricsManager;
 class SearchProvider;
 
+// Long queries will be truncated down to this length.
+constexpr int kMaxAllowedQueryLength = 500;
+
 // A controller that collects queries from the AppListClient, dispatches them to
 // search providers, then ranks and publishes the results to the AppListModel.
 // Many methods are virtual for testing.
diff --git a/chrome/browser/ash/app_list/search/search_controller_unittest.cc b/chrome/browser/ash/app_list/search/search_controller_unittest.cc
index 4ca9e6e..3419089 100644
--- a/chrome/browser/ash/app_list/search/search_controller_unittest.cc
+++ b/chrome/browser/ash/app_list/search/search_controller_unittest.cc
@@ -151,6 +151,14 @@
   TestRankerManager* ranker_manager_{nullptr};
 };
 
+// Tests that long queries are truncated to the maximum allowed query length.
+TEST_F(SearchControllerTest, TruncateLongQuery) {
+  std::u16string long_query(kMaxAllowedQueryLength + 1, u'a');
+  search_controller_->StartSearch(long_query);
+  EXPECT_EQ(search_controller_->get_query(),
+            long_query.substr(0, kMaxAllowedQueryLength));
+}
+
 // Tests that best matches are ordered first, and categories are ignored when
 // ranking within best match.
 TEST_F(SearchControllerTest, BestMatchesOrderedAboveOtherResults) {
diff --git a/chrome/browser/ash/app_list/search/util/ftrl_optimizer.cc b/chrome/browser/ash/app_list/search/util/ftrl_optimizer.cc
index 89a5689..64d04a2 100644
--- a/chrome/browser/ash/app_list/search/util/ftrl_optimizer.cc
+++ b/chrome/browser/ash/app_list/search/util/ftrl_optimizer.cc
@@ -48,6 +48,10 @@
 
 FtrlOptimizer::~FtrlOptimizer() {}
 
+void FtrlOptimizer::Clear() {
+  last_expert_scores_.clear();
+}
+
 std::vector<double> FtrlOptimizer::Score(
     std::vector<std::string>&& items,
     std::vector<std::vector<double>>&& expert_scores) {
@@ -62,15 +66,14 @@
   DCHECK_EQ(expert_scores.size(), num_experts);
   DCHECK_GE(weights.size(), 0);
   DCHECK_EQ(static_cast<size_t>(weights.size()), num_experts);
-  for (size_t i = 0; i < num_experts; ++i) {
-    const auto& scores_i = expert_scores[i];
-    DCHECK_EQ(scores_i.size(), num_items);
-    for (size_t j = 0; j < num_items; ++j)
-      result[j] += weights[i] * scores_i[j];
-  }
+  for (size_t i = 0; i < num_items; ++i) {
+    last_expert_scores_[items[i]] = {};
 
-  last_expert_scores_ = std::move(expert_scores);
-  last_items_ = std::move(items);
+    for (size_t j = 0; j < num_experts; ++j) {
+      result[i] += weights[j] * expert_scores[j][i];
+      last_expert_scores_[items[i]].emplace_back(expert_scores[j][i]);
+    }
+  }
 
   return result;
 }
@@ -79,8 +82,9 @@
   // If |last_items_| is empty, experts had no chance at prediction and we
   // should early exit. This could happen if |proto_| finishes initializing
   // after Score but before Train.
-  if (!proto_.initialized() || last_items_.empty())
+  if (!proto_.initialized() || last_expert_scores_.empty()) {
     return;
+  }
 
   // Compute the loss of each expert and update weights.
   auto& weights = *proto_->mutable_weights();
@@ -100,32 +104,32 @@
 
 double FtrlOptimizer::Loss(size_t expert, const std::string& item) {
   size_t num_experts = params_.num_experts;
-  size_t num_items = last_items_.size();
+  size_t num_items = last_expert_scores_.size();
 
   DCHECK_GT(num_items, 0u);
-  DCHECK_EQ(last_expert_scores_.size(), num_experts);
   DCHECK_LT(expert, num_experts);
 
   // Find the score of the launched item.
-  auto& scores = last_expert_scores_[expert];
-  double score = 0.0;
-  DCHECK_EQ(scores.size(), last_items_.size());
-  for (size_t i = 0; i < scores.size(); ++i) {
-    if (last_items_[i] == item)
-      score = scores[i];
+  double score = {0.0};
+
+  if (last_expert_scores_.find(item) != last_expert_scores_.end()) {
+    DCHECK_EQ(last_expert_scores_[item].size(), num_experts);
+    score = last_expert_scores_[item][expert];
   }
 
   // Find the rank of the item, ie. the number of items with higher score.
   size_t rank = 0;
-  for (size_t i = 0; i < scores.size(); ++i) {
-    if (scores[i] > score)
+
+  for (const auto& scores : last_expert_scores_) {
+    if (scores.second[expert] > score) {
       ++rank;
+    }
   }
 
   // The loss is linear in the |rank|. A loss of 1.0 means |item| wasn't
   // included at all.
-  DCHECK(!scores.empty());
-  return static_cast<double>(rank) / scores.size();
+  DCHECK(!last_expert_scores_.empty());
+  return static_cast<double>(rank) / last_expert_scores_.size();
 }
 
 void FtrlOptimizer::OnProtoRead(ReadStatus status) {
diff --git a/chrome/browser/ash/app_list/search/util/ftrl_optimizer.h b/chrome/browser/ash/app_list/search/util/ftrl_optimizer.h
index 0231954..c87614f 100644
--- a/chrome/browser/ash/app_list/search/util/ftrl_optimizer.h
+++ b/chrome/browser/ash/app_list/search/util/ftrl_optimizer.h
@@ -69,6 +69,8 @@
   FtrlOptimizer(const FtrlOptimizer&) = delete;
   FtrlOptimizer& operator=(const FtrlOptimizer&) = delete;
 
+  void Clear();
+
   // Score the given |items| using the given |scores| from experts. The outer
   // vector of |scores| must be Params.num_experts long, with inner vectors the
   // same length as |items|.
@@ -84,12 +86,10 @@
 
   Params params_;
 
-  // The items most recently passed to |Score|.
-  std::vector<std::string> last_items_;
-  // For each expert (outer vector) the scores returned by that expert for the
-  // content of |last_items_|. The inner vector will be the same size as
-  // |last_items_|.
-  std::vector<std::vector<double>> last_expert_scores_;
+  // For each result id it matched a vector that contains result from
+  // different experts. The vector size will equal the number of experts,
+  // and the scores are always in the same order of experts.
+  std::map<std::string, std::vector<double>> last_expert_scores_;
 
   PersistentProto<FtrlOptimizerProto> proto_;
 
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
index dba1610..42a5bdb 100644
--- a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
@@ -619,7 +619,7 @@
 IN_PROC_BROWSER_TEST_P(ArcAuthServiceTest, SuccessfulBackgroundFetch) {
   base::HistogramTester histogram_tester;
   SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
-  test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
+  test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
                                          GetFakeAuthTokenResponse());
 
   base::RunLoop run_loop;
@@ -654,13 +654,13 @@
           case 0:
             // Reply with broken PAC script state.
             test_url_loader_factory()->AddResponse(
-                GURL(arc::kAuthTokenExchangeEndPoint),
+                GURL(arc::kTokenBootstrapEndPoint),
                 network::mojom::URLResponseHead::New(), "response", status);
             break;
           case 1:
             // Reply with the auth token.
-            test_url_loader_factory()->AddResponse(
-                arc::kAuthTokenExchangeEndPoint, GetFakeAuthTokenResponse());
+            test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
+                                                   GetFakeAuthTokenResponse());
             break;
           default:
             NOTREACHED();
@@ -693,7 +693,7 @@
                        ReAuthenticatePrimaryAccountSucceeds) {
   base::HistogramTester tester;
   SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
-  test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
+  test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
                                          GetFakeAuthTokenResponse());
 
   base::RunLoop run_loop;
@@ -723,15 +723,15 @@
   auth_instance().RequestAccountInfo(kFakeUserName, run_loop.QuitClosure());
 
   EXPECT_TRUE(
-      test_url_loader_factory()->IsPending(arc::kAuthTokenExchangeEndPoint));
+      test_url_loader_factory()->IsPending(arc::kTokenBootstrapEndPoint));
   test_url_loader_factory()->SimulateResponseForPendingRequest(
-      arc::kAuthTokenExchangeEndPoint, std::string(), net::HTTP_UNAUTHORIZED);
+      arc::kTokenBootstrapEndPoint, std::string(), net::HTTP_UNAUTHORIZED);
 
   // Should retry auth token exchange request
   EXPECT_TRUE(
-      test_url_loader_factory()->IsPending(arc::kAuthTokenExchangeEndPoint));
+      test_url_loader_factory()->IsPending(arc::kTokenBootstrapEndPoint));
   test_url_loader_factory()->SimulateResponseForPendingRequest(
-      arc::kAuthTokenExchangeEndPoint, GetFakeAuthTokenResponse());
+      arc::kTokenBootstrapEndPoint, GetFakeAuthTokenResponse());
   run_loop.Run();
 
   ASSERT_TRUE(auth_instance().account_info());
@@ -744,7 +744,7 @@
                        ReAuthenticatePrimaryAccountFailsForInvalidAccount) {
   base::HistogramTester tester;
   SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
-  test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
+  test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
                                          std::string() /* response */,
                                          net::HTTP_UNAUTHORIZED);
 
@@ -765,7 +765,7 @@
   // Add a Secondary Account.
   SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
   SeedAccountInfo(kSecondaryAccountEmail);
-  test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
+  test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
                                          GetFakeAuthTokenResponse());
 
   base::RunLoop run_loop;
@@ -793,7 +793,7 @@
   // Add a Secondary Account.
   SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
   SeedAccountInfo(kSecondaryAccountEmail);
-  test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
+  test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
                                          std::string() /* response */,
                                          net::HTTP_UNAUTHORIZED);
 
@@ -815,7 +815,7 @@
   base::HistogramTester tester;
   const AccountInfo account_info = SetupGaiaAccount(kSecondaryAccountEmail);
   SetInvalidRefreshTokenForAccount(account_info.account_id);
-  test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
+  test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
                                          std::string() /* response */,
                                          net::HTTP_UNAUTHORIZED);
 
@@ -1278,7 +1278,7 @@
 IN_PROC_BROWSER_TEST_P(ArcAuthServiceTest, ChildAccountFetch) {
   SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
   EXPECT_TRUE(profile()->IsChild());
-  test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
+  test_url_loader_factory()->AddResponse(arc::kTokenBootstrapEndPoint,
                                          GetFakeAuthTokenResponse());
 
   base::RunLoop run_loop;
diff --git a/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc
index cee06cc..534c765 100644
--- a/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc
+++ b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "ash/components/arc/arc_features.h"
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/json/json_string_value_serializer.h"
 #include "base/json/json_writer.h"
@@ -43,6 +45,10 @@
 constexpr char kDeviceType[] = "device_type";
 constexpr char kDeviceTypeArc[] = "arc_plus_plus";
 constexpr char kLoginScopedToken[] = "login_scoped_token";
+constexpr char kClientId[] = "client_id";
+constexpr char kClientIdArc[] =
+    "1070009224336-sdh77n7uot3oc99ais00jmuft6sk2fg9.apps.googleusercontent.com";
+constexpr char kRefreshToken[] = "refresh_token";
 constexpr char kGetAuthCodeKey[] = "Content-Type";
 constexpr char kGetAuthCodeValue[] = "application/json; charset=utf-8";
 constexpr char kContentTypeJSON[] = "application/json";
@@ -60,6 +66,9 @@
 const char kAuthTokenExchangeEndPoint[] =
     "https://www.googleapis.com/oauth2/v4/ExchangeToken";
 
+const char kTokenBootstrapEndPoint[] =
+    "https://oauthtokenbootstrap.googleapis.com/v1/tokenbootstrap";
+
 ArcBackgroundAuthCodeFetcher::ArcBackgroundAuthCodeFetcher(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     Profile* profile,
@@ -119,13 +128,22 @@
     return;
   }
 
+  bool use_new_endpoint =
+      base::FeatureList::IsEnabled(arc::kEnableTokenBootstrapEndpoint);
+
   user_manager::KnownUser known_user(g_browser_process->local_state());
   const std::string device_id = known_user.GetDeviceId(
       multi_user_util::GetAccountIdFromProfile(profile_));
   DCHECK(!device_id.empty());
 
   base::Value::Dict request_data;
-  request_data.Set(kLoginScopedToken, token_info.token);
+  if (use_new_endpoint) {
+    request_data.Set(kRefreshToken, token_info.token);
+    request_data.Set(kClientId, kClientIdArc);
+  } else {
+    // TODO(b/264416977): Remove this code path after M112
+    request_data.Set(kLoginScopedToken, token_info.token);
+  }
   request_data.Set(kDeviceType, kDeviceTypeArc);
   request_data.Set(kDeviceId, device_id);
   std::string request_string;
@@ -142,9 +160,18 @@
           "account setup. This is also triggered when the Google Play Store "
           "detects that current credentials are revoked or invalid and "
           "requests extra authorization code for the account re-sign in."
-        data: "Device id and access token."
+        data: "Device id, access token, and hardcoded client id."
         destination: GOOGLE_OWNED_SERVICE
+        internal {
+          contacts {
+            email: "arc-core@google.com"
+          }
         }
+        user_data {
+          type: ACCESS_TOKEN
+        }
+        last_reviewed: "2023-01-24"
+      }
       policy {
         cookies_allowed: NO
         setting:
@@ -154,7 +181,12 @@
         policy_exception_justification: "Not implemented."
   })");
   auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url = GURL(kAuthTokenExchangeEndPoint);
+  if (use_new_endpoint) {
+    resource_request->url = GURL(kTokenBootstrapEndPoint);
+  } else {
+    // TODO(b/264416977): Remove this code path after M112
+    resource_request->url = GURL(kAuthTokenExchangeEndPoint);
+  }
   resource_request->load_flags = net::LOAD_DISABLE_CACHE |
                                  net::LOAD_BYPASS_CACHE |
                                  (bypass_proxy_ ? net::LOAD_BYPASS_PROXY : 0);
diff --git a/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h
index e5049e5..a78ed202 100644
--- a/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h
+++ b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h
@@ -29,7 +29,7 @@
 namespace arc {
 
 // Exposed for testing.
-extern const char kAuthTokenExchangeEndPoint[];
+extern const char kTokenBootstrapEndPoint[];
 
 // The instance is not reusable, so for each Fetch(), the instance must be
 // re-created. Deleting the instance cancels inflight operation.
@@ -88,7 +88,7 @@
   // Account on Chrome OS.
   const bool is_primary_account_;
 
-  // Indicates if the request to `kAuthTokenExchangeEndPoint` which fetches the
+  // Indicates if the request to `kTokenBootstrapEndPoint` which fetches the
   // auth code to be used for Google Play Store sign-in should bypass the proxy.
   // Currently we only set the value to true if the network is configured to use
   // a mandatory PAC script which is broken or not reachable.
diff --git a/chrome/browser/ash/bruschetta/DEPS b/chrome/browser/ash/bruschetta/DEPS
new file mode 100644
index 0000000..10464cb
--- /dev/null
+++ b/chrome/browser/ash/bruschetta/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  # Give bruschetta_util access to the Bruschetta Installer.
+  "+chrome/browser/ui/views",
+]
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.cc b/chrome/browser/ash/bruschetta/bruschetta_util.cc
index 4d83a4e..1f52457 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_util.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_util.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/ash/bruschetta/bruschetta_pref_names.h"
 #include "chrome/browser/ash/guest_os/guest_os_pref_names.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/views/bruschetta/bruschetta_installer_view.h"
 #include "components/prefs/pref_service.h"
 
 namespace bruschetta {
@@ -90,4 +91,8 @@
   return value != nullptr;
 }
 
+void RunInstaller(Profile* profile, const guest_os::GuestId& guest_id) {
+  BruschettaInstallerView::Show(profile, guest_id);
+}
+
 }  // namespace bruschetta
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.h b/chrome/browser/ash/bruschetta/bruschetta_util.h
index e66682f1..2de13b0 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_util.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_util.h
@@ -10,6 +10,8 @@
 
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+class Profile;
+
 namespace bruschetta {
 
 extern const char kToolsDlc[];
@@ -56,6 +58,9 @@
 // Returns true if Bruschetta is installed.
 bool IsInstalled(Profile* profile, const guest_os::GuestId& guest_id);
 
+// Runs the GUI installer.
+void RunInstaller(Profile* profile, const guest_os::GuestId& guest_id);
+
 }  // namespace bruschetta
 
 #endif  // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_UTIL_H_
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index 40181bd5..98b70c6 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -1007,7 +1007,7 @@
       crosapi::LacrosDataBackwardMigrationModePolicyObserver>();
 
   // Only creates VideoConferenceAppServiceClient if VcControlsUi is enabled.
-  if (features::IsVcControlsUiEnabled()) {
+  if (features::IsVideoConferenceEnabled()) {
     vc_app_service_client_ =
         std::make_unique<VideoConferenceAppServiceClient>();
   }
@@ -1406,7 +1406,7 @@
 
   multi_capture_notification_ = std::make_unique<MultiCaptureNotification>();
 
-  if (features::IsVcControlsUiEnabled()) {
+  if (features::IsVideoConferenceEnabled()) {
     video_conference_manager_client_ =
         std::make_unique<video_conference::VideoConferenceManagerClientImpl>();
   }
diff --git a/chrome/browser/ash/crosapi/browser_loader.cc b/chrome/browser/ash/crosapi/browser_loader.cc
index 1e00e00..71055bc 100644
--- a/chrome/browser/ash/crosapi/browser_loader.cc
+++ b/chrome/browser/ash/crosapi/browser_loader.cc
@@ -226,7 +226,7 @@
 
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&CheckRegisteredMayBlock, component_manager_),
+      base::BindOnce(&IsInstalledMayBlock, GetLacrosComponentName()),
       base::BindOnce(&BrowserLoader::OnLoadSelection,
                      weak_factory_.GetWeakPtr(), std::move(callback)));
 }
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc
index 8a2feb07..f65349e 100644
--- a/chrome/browser/ash/crosapi/crosapi_util.cc
+++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -587,7 +587,7 @@
 
   params->extension_keep_list = extensions::BuildExtensionKeeplistInitParam();
 
-  params->vc_controls_ui_enabled = ash::features::IsVcControlsUiEnabled();
+  params->vc_controls_ui_enabled = ash::features::IsVideoConferenceEnabled();
 
   params->standalone_browser_app_service_blocklist =
       extensions::BuildStandaloneBrowserAppServiceBlockListInitParam();
diff --git a/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc b/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc
index a73eca3..94db91f 100644
--- a/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc
+++ b/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc
@@ -131,7 +131,7 @@
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_{
-      ash::features::kVcControlsUi};
+      ash::features::kVideoConference};
 };
 
 // Tests |VideoConferenceManagerAsh| api calls don't crash. Tests calls over
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc
index 6675dc2..772711f 100644
--- a/chrome/browser/ash/drive/drive_integration_service.cc
+++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -1074,7 +1074,7 @@
   }
 
   if (ash::features::IsDriveFsBulkPinningEnabled()) {
-    pin_manager_ = std::make_unique<drivefs::pinning::DriveFsPinManager>(
+    pin_manager_ = std::make_unique<drivefs::pinning::PinManager>(
         profile_->GetPath(), GetDriveFsInterface());
     GetDriveFsHost()->AddObserver(pin_manager_.get());
     ToggleBulkPinning();
diff --git a/chrome/browser/ash/drive/drive_integration_service.h b/chrome/browser/ash/drive/drive_integration_service.h
index ea8c088..d0a3035 100644
--- a/chrome/browser/ash/drive/drive_integration_service.h
+++ b/chrome/browser/ash/drive/drive_integration_service.h
@@ -178,8 +178,8 @@
   // Returns the DriveFsHost if it is enabled.
   drivefs::DriveFsHost* GetDriveFsHost() const;
 
-  // Returns the `DriveFsPinManager` iff DriveFS is mounted.
-  drivefs::pinning::DriveFsPinManager* GetPinManager() const {
+  // Returns the PinManager if DriveFS is mounted and bulk-pinning is enabled.
+  drivefs::pinning::PinManager* GetPinManager() const {
     return pin_manager_.get();
   }
 
@@ -415,7 +415,7 @@
 
   std::unique_ptr<DriveFsHolder> drivefs_holder_;
   std::unique_ptr<PreferenceWatcher> preference_watcher_;
-  std::unique_ptr<drivefs::pinning::DriveFsPinManager> pin_manager_;
+  std::unique_ptr<drivefs::pinning::PinManager> pin_manager_;
   int drivefs_total_failures_count_ = 0;
   int drivefs_consecutive_failures_count_ = 0;
   bool remount_when_online_ = false;
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc
index e6fab92..159fb77b 100644
--- a/chrome/browser/ash/file_manager/file_tasks.cc
+++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -65,7 +65,7 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "components/drive/drive_api_util.h"
-#include "components/prefs/pref_registry_simple.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/services/app_service/public/cpp/app_launch_util.h"
@@ -452,9 +452,11 @@
 ResultingTasks::ResultingTasks() = default;
 ResultingTasks::~ResultingTasks() = default;
 
-void RegisterProfilePrefs(PrefRegistrySimple* registry) {
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterDictionaryPref(prefs::kDefaultHandlersForFileExtensions);
-  registry->RegisterBooleanPref(prefs::kOfficeSetupComplete, false);
+  registry->RegisterBooleanPref(
+      prefs::kOfficeSetupComplete, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterBooleanPref(prefs::kOfficeFilesAlwaysMove, false);
 }
 
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h
index 23f044e6..cc5fa8a 100644
--- a/chrome/browser/ash/file_manager/file_tasks.h
+++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -101,7 +101,6 @@
 #include "base/functional/callback_forward.h"
 #include "chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
-#include "components/prefs/pref_registry_simple.h"
 #include "url/gurl.h"
 
 using storage::FileSystemURL;
@@ -117,6 +116,10 @@
 class FileSystemURL;
 }
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
 namespace file_manager::file_tasks {
 
 extern const char kActionIdView[];
@@ -278,7 +281,7 @@
 };
 
 // Registers profile prefs related to file_manager.
-void RegisterProfilePrefs(PrefRegistrySimple*);
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable*);
 
 // Update the default file handler for the given sets of suffixes and MIME
 // types.
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_service.cc b/chrome/browser/ash/floating_workspace/floating_workspace_service.cc
index cd04bb3..2ead01c 100644
--- a/chrome/browser/ash/floating_workspace/floating_workspace_service.cc
+++ b/chrome/browser/ash/floating_workspace/floating_workspace_service.cc
@@ -32,21 +32,6 @@
 
 namespace ash {
 
-// Max time floating workspace service can wait after user login.
-// After that even a more recent foreign session change is detected
-// restore will not take place.
-// TODO(b/263417467): let the following parameters be controlled by Finch or
-// policy override.
-constexpr base::TimeDelta kMaxTimeAvaliableForRestoreAfterLogin =
-    base::Seconds(3);
-
-constexpr base::TimeDelta kMaxTimeAvaliableForRestoreAfterLoginV2 =
-    base::Seconds(15);
-
-// Time interval to capture current desk as desk template
-// and upload template to server.
-constexpr base::TimeDelta kPeriodicJobIntervalInSeconds = base::Seconds(30);
-
 // Static
 FloatingWorkspaceService* FloatingWorkspaceService::GetForProfile(
     Profile* profile) {
@@ -118,7 +103,9 @@
   if (!should_run_restore_)
     return;
   if (base::TimeTicks::Now() >
-      initialization_timestamp_ + kMaxTimeAvaliableForRestoreAfterLogin) {
+      initialization_timestamp_ +
+          ash::features::kFloatingWorkspaceMaxTimeAvaliableForRestoreAfterLogin
+              .Get()) {
     // No need to restore any remote session 3 seconds (TBD) after login.
     should_run_restore_ = false;
     return;
@@ -138,7 +125,8 @@
         base::BindOnce(
             &FloatingWorkspaceService::TryRestoreMostRecentlyUsedSession,
             weak_pointer_factory_.GetWeakPtr()),
-        kMaxTimeAvaliableForRestoreAfterLogin);
+        ash::features::kFloatingWorkspaceMaxTimeAvaliableForRestoreAfterLogin
+            .Get());
     should_run_restore_ = false;
     return;
   }
@@ -250,8 +238,10 @@
 }
 
 void FloatingWorkspaceService::StartCaptureAndUploadActiveDesk() {
-  timer_.Start(FROM_HERE, kPeriodicJobIntervalInSeconds, this,
-               &FloatingWorkspaceService::CaptureAndUploadActiveDesk);
+  timer_.Start(
+      FROM_HERE,
+      ash::features::kFloatingWorkspaceV2PeriodicJobIntervalInSeconds.Get(),
+      this, &FloatingWorkspaceService::CaptureAndUploadActiveDesk);
 }
 
 void FloatingWorkspaceService::StopCaptureAndUploadActiveDesk() {
@@ -274,7 +264,9 @@
 
   // Check if template has been downloaded after 15 seconds (TBD).
   if (base::TimeTicks::Now() >
-      initialization_timestamp_ + kMaxTimeAvaliableForRestoreAfterLoginV2) {
+      initialization_timestamp_ +
+          ash::features::
+              kFloatingWorkspaceV2MaxTimeAvaliableForRestoreAfterLogin.Get()) {
     // No need to restore any remote session 15 seconds (TBD) after login.
     should_run_restore_ = false;
     return;
diff --git a/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc b/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc
index e809de0..e69b3ecb 100644
--- a/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc
+++ b/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc
@@ -232,7 +232,7 @@
   VideoConferenceAppServiceClient* client_ = nullptr;
 
   base::test::ScopedFeatureList scoped_feature_list_{
-      ash::features::kVcControlsUi};
+      ash::features::kVideoConference};
 };
 
 IN_PROC_BROWSER_TEST_F(VideoConferenceAppServiceClientTest, GetAppName) {
diff --git a/chrome/browser/ash/video_conference/video_conference_manager_ash.cc b/chrome/browser/ash/video_conference/video_conference_manager_ash.cc
index 8e28f3b..dd3bb216a 100644
--- a/chrome/browser/ash/video_conference/video_conference_manager_ash.cc
+++ b/chrome/browser/ash/video_conference/video_conference_manager_ash.cc
@@ -133,7 +133,7 @@
     NotifyDeviceUsedWhileDisabledCallback callback) {
   // TODO(crbug.com/1368284): Remove this conditional check once it becomes
   // possible to enable ash features in lacros browsertests.
-  if (ash::features::IsVcControlsUiEnabled()) {
+  if (ash::features::IsVideoConferenceEnabled()) {
     GetTrayController()->HandleDeviceUsedWhileDisabled(std::move(device),
                                                        app_name);
   }
@@ -166,7 +166,7 @@
 void VideoConferenceManagerAsh::SendUpdatedState() {
   // TODO(crbug.com/1368284): Remove this conditional check once it becomes
   // possible to enable ash features in lacros browsertests.
-  if (ash::features::IsVcControlsUiEnabled()) {
+  if (ash::features::IsVideoConferenceEnabled()) {
     GetTrayController()->UpdateWithMediaState(GetAggregatedState());
   }
 }
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index c555948..4ebc6bbf 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -343,6 +343,7 @@
 #include "media/mojo/mojom/renderer_extensions.mojom.h"
 #include "media/mojo/mojom/speech_recognition.mojom.h"  // nogncheck
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chrome/browser/accessibility/live_caption_surface.h"
 #include "chromeos/crosapi/mojom/speech_recognition.mojom.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 #endif  // BUILDFLAG(ENABLE_SPEECH_SERVICE)
@@ -637,15 +638,50 @@
 void BindSpeechRecognitionRecognizerClientHandler(
     content::RenderFrameHost* frame_host,
     mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient>
-        receiver) {
+        client_receiver) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  // On LaCrOS, forward to Ash.
+
+  // Hold a client-browser interface just long enough to bootstrap a remote
+  // recognizer client.
+  mojo::Remote<media::mojom::SpeechRecognitionClientBrowserInterface>
+      interface_remote;
+  auto* service = chromeos::LacrosService::Get();
+  if (!service || !service->IsAvailable<crosapi::mojom::SpeechRecognition>()) {
+    return;
+  }
+  service->GetRemote<crosapi::mojom::SpeechRecognition>()
+      ->BindSpeechRecognitionClientBrowserInterface(
+          interface_remote.BindNewPipeAndPassReceiver());
+
+  // Grab the per-web-contents logic on our end to drive the remote client.
+  auto* surface = captions::LiveCaptionSurface::GetOrCreateForWebContents(
+      content::WebContents::FromRenderFrameHost(frame_host));
+  mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface_remote;
+  mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
+      surface_client_receiver;
+  surface->BindToSurfaceClient(
+      surface_remote.InitWithNewPipeAndPassReceiver(),
+      surface_client_receiver.InitWithNewPipeAndPassRemote());
+
+  // Populate static info to send to the client.
+  auto metadata = media::mojom::SpeechRecognitionSurfaceMetadata::New();
+  metadata->session_id = surface->session_id();
+
+  // Bootstrap the recognizer client.
+  interface_remote->BindRecognizerToRemoteClient(
+      std::move(client_receiver), std::move(surface_client_receiver),
+      std::move(surface_remote), std::move(metadata));
+#else
   Profile* profile = Profile::FromBrowserContext(
       frame_host->GetProcess()->GetBrowserContext());
   PrefService* profile_prefs = profile->GetPrefs();
   if (profile_prefs->GetBoolean(prefs::kLiveCaptionEnabled) &&
       captions::IsLiveCaptionFeatureSupported()) {
-    captions::LiveCaptionSpeechRecognitionHost::Create(frame_host,
-                                                       std::move(receiver));
+    captions::LiveCaptionSpeechRecognitionHost::Create(
+        frame_host, std::move(client_receiver));
   }
+#endif
 }
 
 void BindMediaFoundationRendererNotifierHandler(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 4c10f39..08151a8 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/accessibility/accessibility_labels_service.h"
 #include "chrome/browser/accessibility/accessibility_labels_service_factory.h"
 #include "chrome/browser/after_startup_task_utils.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/bluetooth/chrome_bluetooth_delegate_impl_client.h"
 #include "chrome/browser/browser_about_handler.h"
 #include "chrome/browser/browser_features.h"
@@ -400,6 +401,7 @@
 #include "chrome/browser/ash/system_extensions/system_extensions_provider.h"
 #include "chrome/browser/speech/tts_chromeos.h"
 #include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h"
+#include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chromeos/ash/services/network_health/public/cpp/network_health_helper.h"
 #include "chromeos/crosapi/cpp/lacros_startup_state.h"
@@ -408,6 +410,7 @@
 #include "components/user_manager/user_manager.h"
 #include "services/service_manager/public/mojom/interface_provider_spec.mojom.h"
 #include "storage/browser/file_system/external_mount_points.h"
+#include "ui/display/screen.h"
 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "chrome/browser/chrome_browser_main_linux.h"
 #elif BUILDFLAG(IS_ANDROID)
@@ -7360,6 +7363,27 @@
         ash::NewWindowDelegate::Disposition::kNewForegroundTab);
     return true;
   }
+
+  // If Lacros is the only browser, we intercept any WebUI URLs that would be
+  // opened in a regular browser window. We open these with the OsUrlHandler SWA
+  // instead, which will load them in an app window.
+  Profile* profile = Profile::FromBrowserContext(opener->GetBrowserContext());
+  bool should_open_in_ash_app =
+      !crosapi::browser_util::IsAshWebBrowserEnabled() &&
+      opener->GetWebUI() != nullptr &&
+      ChromeWebUIControllerFactory::GetInstance()->CanHandleUrl(url) &&
+      !ash::GetCapturingSystemAppForURL(profile, url);
+  if (should_open_in_ash_app) {
+    ash::SystemAppLaunchParams launch_params;
+    launch_params.url = url;
+    int64_t display_id =
+        display::Screen::GetScreen()->GetDisplayForNewWindows().id();
+    ash::LaunchSystemWebAppAsync(
+        ProfileManager::GetPrimaryUserProfile(),
+        ash::SystemWebAppType::OS_URL_HANDLER, launch_params,
+        std::make_unique<apps::WindowInfo>(display_id));
+    return true;
+  }
 #endif
   return false;
 }
diff --git a/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc b/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
index a1f0422..4a057a3d2 100644
--- a/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
+++ b/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
@@ -24,7 +24,6 @@
 
 namespace {
 const int kWasmPageSize = 1 << 16;
-}  // namespace
 
 // Web platform security features are implemented by content/ and blink/.
 // However, since ContentBrowserClientImpl::LogWebFeatureForCurrentPage() is
@@ -158,6 +157,20 @@
   base::test::ScopedFeatureList features_;
 };
 
+// Return the child of `parent`.
+// Precondition: the number of children must be one.
+content::RenderFrameHost* GetChild(content::RenderFrameHost& parent) {
+  content::RenderFrameHost* child_rfh = nullptr;
+  parent.ForEachRenderFrameHost([&](content::RenderFrameHost* rfh) {
+    if (&parent == rfh->GetParent()) {
+      CHECK(!child_rfh) << "Multiple children found";
+      child_rfh = rfh;
+    }
+  });
+  CHECK(child_rfh) << "No children found";
+  return child_rfh;
+}
+
 // Check the kCrossOriginOpenerPolicyReporting feature usage. No header => 0
 // count.
 IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
@@ -2025,6 +2038,61 @@
   CheckHistogramCount("Navigation.BlobUrl.Sandboxed", false, 1);
 }
 
+using SameDocumentCrossOriginInitiatorTest =
+    ChromeWebPlatformSecurityMetricsBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(SameDocumentCrossOriginInitiatorTest, SameOrigin) {
+  const GURL parent_url = https_server().GetURL("a.test", "/empty.html");
+  const GURL child_url = https_server().GetURL("a.test", "/empty.html");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), parent_url));
+  LoadIFrame(child_url);
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 0);
+  EXPECT_TRUE(content::ExecJs(
+      web_contents(), "document.querySelector('iframe').src += '#foo';"));
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(SameDocumentCrossOriginInitiatorTest, SameSite) {
+  const GURL parent_url = https_server().GetURL("a.a.test", "/empty.html");
+  const GURL child_url = https_server().GetURL("b.a.test", "/empty.html");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), parent_url));
+  LoadIFrame(child_url);
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 0);
+  EXPECT_TRUE(content::ExecJs(
+      web_contents(), "document.querySelector('iframe').src += '#foo';"));
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+  // TODO(https://crbug.com/1408429) It seems the initiator origin is wrong,
+  // e.g. `child_url` instead of `parent_url`, causing the metrics not to be
+  // recorded.
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(SameDocumentCrossOriginInitiatorTest, CrossOrigin) {
+  const GURL parent_url = https_server().GetURL("a.test", "/empty.html");
+  const GURL child_url = https_server().GetURL("b.test", "/empty.html");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), parent_url));
+  LoadIFrame(child_url);
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 0);
+  EXPECT_TRUE(content::ExecJs(
+      web_contents(), "document.querySelector('iframe').src += '#foo';"));
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(SameDocumentCrossOriginInitiatorTest,
+                       SameOriginInitiated) {
+  const GURL parent_url = https_server().GetURL("a.test", "/empty.html");
+  const GURL child_url = https_server().GetURL("b.test", "/empty.html");
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), parent_url));
+  LoadIFrame(child_url);
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 0);
+  EXPECT_TRUE(
+      content::ExecJs(GetChild(*(web_contents()->GetPrimaryMainFrame())),
+                      "location.href += '#foo';"));
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+  CheckCounter(WebFeature::kSameDocumentCrossOriginInitiator, 0);
+}
+
 // TODO(arthursonzogni): Add basic test(s) for the WebFeatures:
 // [ ] CrossOriginOpenerPolicySameOrigin
 // [ ] CrossOriginOpenerPolicySameOriginAllowPopups
@@ -2032,3 +2100,5 @@
 //
 // Added by:
 // https://chromium-review.googlesource.com/c/chromium/src/+/2122140
+
+}  // namespace
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 1608940..cb587ba 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -7029,24 +7029,9 @@
     "expiry_milestone": 110
   },
   {
-    "name": "vc-background-blur",
-    "owners": [ "shafron", "skyostil", "charleszhao", "jmpollock" ],
-    "expiry_milestone": 115
-  },
-  {
     "name": "vc-background-replace",
     "owners": [ "shafron", "skyostil", "charleszhao", "jmpollock" ],
-    "expiry_milestone": 115
-  },
-  {
-    "name": "vc-controls-ui",
-    "owners": [ "rtinkoff", "cros-status-area-eng@google.com" ],
-    "expiry_milestone": 117
-  },
-  {
-    "name": "vc-portrait-relighting",
-    "owners": [ "shafron", "skyostil", "charleszhao", "jmpollock" ],
-    "expiry_milestone": 115
+    "expiry_milestone": 120
   },
   {
     "name": "verbose-logging-in-nacl",
@@ -7055,6 +7040,11 @@
     "expiry_milestone": 128
   },
   {
+    "name": "video-conference",
+    "owners": [ "shafron", "newcomer", "charleszhao", "jmpollock" ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "video-tutorials",
     "owners": [ "shaktisahu"],
     "expiry_milestone": 102
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9a2dd5b..356b0636 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3096,20 +3096,15 @@
     "webpages and apps to consume alt+click. When disabled the legacy "
     "behavior of remapping alt+click to right click will remain unchanged.";
 
-const char kVCBackgroundBlurName[] = "Enable vc background blur";
-const char kVCBackgroundBlurDescription[] =
-    "Enables background blur feature for video conferencing on chromebooks.";
+const char kVideoConferenceName[] = "Enable video conference features";
+const char kVideoConferenceDescription[] =
+    "Enables all features for ChromeOS built-in video conferencing UI.";
 
-const char kVCBackgroundReplaceName[] = "Enable vc background replacement";
-const char kVCBackgroundReplaceDescription[] =
+const char kVcBackgroundReplaceName[] = "Enable vc background replacement";
+const char kVcBackgroundReplaceDescription[] =
     "Enables background replacement feature for video conferencing on "
     "chromebooks. THIS WILL OVERRIDE BACKGROUND BLUR.";
 
-const char kVCPortraitRelightingName[] = "Enable vc portrait relighting";
-const char kVCPortraitRelightingDescription[] =
-    "Enables portrait relighting feature for video conferencing on "
-    "chromebooks. THIS WILL OVERRIDE BACKGROUND BLUR & REPLACE.";
-
 const char kV8VmFutureName[] = "Future V8 VM features";
 const char kV8VmFutureDescription[] =
     "This enables upcoming and experimental V8 VM features. "
@@ -6508,10 +6503,6 @@
     "Enables promise icons in the Launcher and Shelf (if the app is pinned) "
     "for app installations.";
 
-const char kVcControlsUiName[] = "Video conferencing controls UI";
-const char kVcControlsUiDescription[] =
-    "Enables the built-in video conference controls UI";
-
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // ============================================================================
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c95b68a7..0a17954 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1759,14 +1759,11 @@
 extern const char kUseSearchClickForRightClickName[];
 extern const char kUseSearchClickForRightClickDescription[];
 
-extern const char kVCBackgroundBlurName[];
-extern const char kVCBackgroundBlurDescription[];
+extern const char kVideoConferenceName[];
+extern const char kVideoConferenceDescription[];
 
-extern const char kVCBackgroundReplaceName[];
-extern const char kVCBackgroundReplaceDescription[];
-
-extern const char kVCPortraitRelightingName[];
-extern const char kVCPortraitRelightingDescription[];
+extern const char kVcBackgroundReplaceName[];
+extern const char kVcBackgroundReplaceDescription[];
 
 extern const char kV8VmFutureName[];
 extern const char kV8VmFutureDescription[];
@@ -3780,9 +3777,6 @@
 
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-extern const char kVcControlsUiName[];
-extern const char kVcControlsUiDescription[];
-
 // ============================================================================
 // Don't just add flags to the end, put them in the right section in
 // alphabetical order. See top instructions for more.
diff --git a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_dropdown_v4.xml b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_dropdown_v4.xml
index ecf34be..b73826698 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_dropdown_v4.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_dropdown_v4.xml
@@ -13,32 +13,36 @@
     android:layout_height="match_parent"
     android:orientation="vertical">
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_consent_learn_more_bullet_one"
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_consent_learn_more_bullet_two"
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_consent_learn_more_bullet_three"
         android:layout_marginBottom="@dimen/list_item_default_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_consent_learn_more_link"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
 </LinearLayout>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_v4.xml b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_v4.xml
index b893faf..6171055f 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_v4.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_consent_eea_v4.xml
@@ -76,17 +76,19 @@
                     android:gravity="center"
                     style="@style/TextAppearance.Headline.Primary" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_marginBottom="@dimen/list_item_default_margin"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_consent_description_1"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_consent_description_2"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
                 <ImageView
@@ -97,11 +99,12 @@
                     android:adjustViewBounds="true"
                     android:importantForAccessibility="no" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_marginBottom="@dimen/list_item_default_margin"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_consent_description_3"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
                 <LinearLayout
@@ -134,10 +137,11 @@
                     android:layout_height="wrap_content"
                     android:visibility="gone" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_consent_description_4"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
             </LinearLayout>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_dropdown_v4.xml b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_dropdown_v4.xml
index 02c9574..2c4eff2 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_dropdown_v4.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_dropdown_v4.xml
@@ -20,25 +20,28 @@
         android:text="@string/privacy_sandbox_m1_notice_eea_learn_more_heading_1"
         style="@style/TextAppearance.TextMediumThick.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_notice_eea_learn_more_bullet_one"
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_notice_eea_learn_more_bullet_two"
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_notice_eea_learn_more_bullet_three"
         android:layout_marginBottom="@dimen/list_item_default_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
     <TextView
@@ -48,18 +51,20 @@
         android:text="@string/privacy_sandbox_m1_notice_eea_learn_more_heading_2"
         style="@style/TextAppearance.TextMediumThick.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_eea_learn_more_description"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_eea_learn_more_description_android"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
 </LinearLayout>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_v4.xml b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_v4.xml
index 1a70e322..9c4193a6 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_v4.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_eea_v4.xml
@@ -55,10 +55,11 @@
                     android:gravity="center"
                     style="@style/TextAppearance.Headline.Primary" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_notice_eea_description_1"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
                 <ImageView
@@ -69,18 +70,20 @@
                     android:adjustViewBounds="true"
                     android:importantForAccessibility="no" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:id="@+id/privacy_sandbox_m1_notice_eea_bullet_one"
                     android:layout_marginBottom="@dimen/list_item_default_margin"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:id="@+id/privacy_sandbox_m1_notice_eea_bullet_two"
                     android:layout_marginBottom="@dimen/list_item_default_margin"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
                 <LinearLayout
@@ -113,12 +116,13 @@
                     android:layout_height="wrap_content"
                     android:visibility="gone" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_marginBottom="@dimen/privacy_sandbox_notice_margin_bottom"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_gravity="center_vertical"
                     android:text="@string/privacy_sandbox_m1_notice_eea_description_2"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
             </LinearLayout>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_dropdown_v4.xml b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_dropdown_v4.xml
index a832911..073f4bd 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_dropdown_v4.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_dropdown_v4.xml
@@ -20,39 +20,44 @@
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_heading_1"
         style="@style/TextAppearance.TextMediumThick.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_description_1"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_notice_row_learn_more_bullet_one"
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/privacy_sandbox_m1_notice_row_learn_more_bullet_two"
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_description_2"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_description_3"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
     <TextView
@@ -62,25 +67,28 @@
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_heading_2"
         style="@style/TextAppearance.TextMediumThick.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_description_4"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_description_android"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:layout_marginBottom="@dimen/promo_between_text_margin"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/privacy_sandbox_m1_notice_row_learn_more_description_5"
+        app:leading="@dimen/text_size_medium_leading"
         style="@style/TextAppearance.TextMedium.Secondary" />
 
 </LinearLayout>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_v4.xml b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_v4.xml
index c6b5edd..52cadd0 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_v4.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/layout/privacy_sandbox_notice_row_v4.xml
@@ -55,17 +55,19 @@
                     android:gravity="center"
                     style="@style/TextAppearance.Headline.Primary" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_marginBottom="@dimen/list_item_default_margin"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_notice_row_description_1"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_notice_row_description_2"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
                 <ImageView
@@ -76,11 +78,12 @@
                     android:adjustViewBounds="true"
                     android:importantForAccessibility="no" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_marginBottom="@dimen/list_item_default_margin"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_notice_row_description_3"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
                 <LinearLayout
@@ -113,11 +116,12 @@
                     android:layout_height="wrap_content"
                     android:visibility="gone" />
 
-                <TextView
+                <org.chromium.ui.widget.TextViewWithLeading
                     android:layout_marginBottom="@dimen/privacy_sandbox_notice_margin_bottom"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/privacy_sandbox_m1_notice_row_description_4"
+                    app:leading="@dimen/text_size_medium_leading"
                     style="@style/TextAppearance.TextMedium.Secondary" />
 
             </LinearLayout>
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index a9567b88..c3350ad6f 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -1703,8 +1703,12 @@
 }
 
 void RenderViewContextMenu::AppendSearchWebForImageItems() {
-  if (!params_.has_image_contents)
+  // TODO(b/266624865): Image Search items do not function correctly when
+  // |GetBrowser| returns nullptr, as is the case for a context menu in the
+  // side panel, so for now we do not append image items in that case.
+  if (!GetBrowser() || !params_.has_image_contents) {
     return;
+  }
 
   TemplateURLService* service =
       TemplateURLServiceFactory::GetForProfile(GetProfile());
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
index e819aa6..dad1f58 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
@@ -1104,6 +1104,24 @@
   EXPECT_FALSE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_SEARCHLENSFORIMAGE));
 }
 
+// Verify that the Lens Image Search menu item is disabled when there is the
+// Browser is NULL (b/266624865).
+TEST_F(RenderViewContextMenuPrefsTest, LensImageSearchNoBrowser) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(lens::features::kLensStandalone);
+  SetUserSelectedDefaultSearchProvider("https://www.google.com",
+                                       /*supports_image_search=*/true);
+  content::ContextMenuParams params = CreateParams(MenuItem::IMAGE);
+  params.has_image_contents = true;
+  TestRenderViewContextMenu menu(*web_contents()->GetPrimaryMainFrame(),
+                                 params);
+  menu.SetBrowser(nullptr);
+  menu.Init();
+
+  EXPECT_FALSE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE));
+  EXPECT_FALSE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_SEARCHLENSFORIMAGE));
+}
+
 // Verify that the Lens Image Search menu item is enabled on image content
 TEST_F(RenderViewContextMenuPrefsTest, LensImageSearchEnabled) {
   base::test::ScopedFeatureList features;
diff --git a/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts b/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts
index b291cd93..c4bb082 100644
--- a/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts
+++ b/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts
@@ -12,6 +12,12 @@
       idList: string[], dragNodeIndex: number, isFromTouch: boolean, x: number,
       y: number): void;
   removeTrees(idList: string[]): Promise<void>;
+  canPaste(parentId: string): Promise<boolean>;
+  openInNewWindow(idList: string[], incognito: boolean): void;
+  openInNewTab(id: string, active: boolean): void;
+  cut(idList: string[]): Promise<void>;
+  paste(parentId: string, selectedIdList?: string[]): Promise<void>;
+  copy(idList: string[]): Promise<void>;
 }
 
 export class BookmarkManagerApiProxyImpl implements BookmarkManagerApiProxy {
@@ -32,6 +38,31 @@
     return chrome.bookmarkManagerPrivate.removeTrees(idList);
   }
 
+  canPaste(parentId: string) {
+    return chrome.bookmarkManagerPrivate.canPaste(parentId);
+  }
+
+  openInNewWindow(idList: string[], incognito: boolean) {
+    return chrome.bookmarkManagerPrivate.openInNewWindow(idList, incognito);
+  }
+
+  openInNewTab(id: string, active: boolean) {
+    return chrome.bookmarkManagerPrivate.openInNewTab(id, active);
+  }
+
+  cut(idList: string[]) {
+    return chrome.bookmarkManagerPrivate.cut(idList);
+  }
+
+  paste(parentId: string, selectedIdList?: string[]) {
+    return chrome.bookmarkManagerPrivate.paste(parentId, selectedIdList);
+  }
+
+  copy(idList: string[]) {
+    return chrome.bookmarkManagerPrivate.copy(idList);
+  }
+
+
   static getInstance(): BookmarkManagerApiProxy {
     return instance || (instance = new BookmarkManagerApiProxyImpl());
   }
diff --git a/chrome/browser/resources/bookmarks/command_manager.ts b/chrome/browser/resources/bookmarks/command_manager.ts
index cadd355..5358685 100644
--- a/chrome/browser/resources/bookmarks/command_manager.ts
+++ b/chrome/browser/resources/bookmarks/command_manager.ts
@@ -328,7 +328,7 @@
       }
       case Command.COPY: {
         const idList = Array.from(itemIds);
-        chrome.bookmarkManagerPrivate.copy(idList).then(() => {
+        BookmarkManagerApiProxyImpl.getInstance().copy(idList).then(() => {
           let labelPromise: Promise<string>;
           if (idList.length === 1) {
             labelPromise =
@@ -406,13 +406,13 @@
         }));
         break;
       case Command.CUT:
-        chrome.bookmarkManagerPrivate.cut(Array.from(itemIds));
+        BookmarkManagerApiProxyImpl.getInstance().cut(Array.from(itemIds));
         break;
       case Command.PASTE:
         const selectedFolder = state.selectedFolder;
         const selectedItems = state.selection.items;
         trackUpdatedItems();
-        chrome.bookmarkManagerPrivate
+        BookmarkManagerApiProxyImpl.getInstance()
             .paste(selectedFolder, Array.from(selectedItems))
             .then(highlightUpdatedItems);
         break;
@@ -512,14 +512,16 @@
     const openBookmarkIdsCallback = function() {
       const incognito = command === Command.OPEN_INCOGNITO;
       if (command === Command.OPEN_NEW_WINDOW || incognito) {
-        chrome.bookmarkManagerPrivate.openInNewWindow(ids, incognito);
+        BookmarkManagerApiProxyImpl.getInstance().openInNewWindow(
+            ids, incognito);
       } else {
         if (command === Command.OPEN) {
-          chrome.bookmarkManagerPrivate.openInNewTab(
+          BookmarkManagerApiProxyImpl.getInstance().openInNewTab(
               ids.shift()!, /*active=*/ true);
         }
         ids.forEach(function(id) {
-          chrome.bookmarkManagerPrivate.openInNewTab(id, /*active=*/ false);
+          BookmarkManagerApiProxyImpl.getInstance().openInNewTab(
+              id, /*active=*/ false);
         });
       }
     };
@@ -672,20 +674,6 @@
     return loadTimeData.getStringF(caseOther, ids.length);
   }
 
-  private getCommandSublabel_(command: Command): string {
-    const multipleNodes = this.menuIds_.size > 1 ||
-        this.containsMatchingNode_(this.menuIds_, function(node) {
-          return !node.url;
-        });
-    switch (command) {
-      case Command.OPEN_NEW_TAB:
-        const ids = this.expandIds_(this.menuIds_);
-        return multipleNodes && ids.length > 0 ? String(ids.length) : '';
-      default:
-        return '';
-    }
-  }
-
   private computeMenuCommands_(): Command[] {
     switch (this.menuSource_) {
       case MenuSource.ITEM:
@@ -770,9 +758,10 @@
   }
 
   private updateCanPaste_(targetId: string): Promise<void> {
-    return chrome.bookmarkManagerPrivate.canPaste(targetId).then(result => {
-      this.canPaste_ = result;
-    });
+    return BookmarkManagerApiProxyImpl.getInstance().canPaste(targetId).then(
+        result => {
+          this.canPaste_ = result;
+        });
   }
 
   ////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/resources/side_panel/bookmarks/BUILD.gn b/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
index abc721a..b4ace9d 100644
--- a/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
+++ b/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
@@ -23,6 +23,7 @@
     "commerce/shopping_list.ts",
     "power_bookmark_row.ts",
     "power_bookmarks_context_menu.ts",
+    "power_bookmarks_edit_dialog.ts",
     "power_bookmarks_list.ts",
   ]
 
diff --git a/chrome/browser/resources/side_panel/bookmarks/icons.html b/chrome/browser/resources/side_panel/bookmarks/icons.html
index 709ce74..fef3e06 100644
--- a/chrome/browser/resources/side_panel/bookmarks/icons.html
+++ b/chrome/browser/resources/side_panel/bookmarks/icons.html
@@ -19,6 +19,9 @@
       <g id="format-list" viewBox="0 0 24 24">
         <path d="M3 6c0-.83.67-1.5 1.5-1.5S6 5.17 6 6s-.67 1.5-1.5 1.5S3 6.83 3 6Zm0 6c0-.83.67-1.5 1.5-1.5S6 11.17 6 12s-.67 1.5-1.5 1.5S3 12.83 3 12Zm1.5 4.5c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5S6 18.82 6 18s-.67-1.5-1.5-1.5ZM21 19H8v-2h13v2ZM8 13h13v-2H8v2Zm0-6V5h13v2H8Z"></path>
       </g>
+      <g id="move" viewBox="0 0 24 24">
+        <path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2Zm0 12H4V8h16v10Zm-8.01-9-1.41 1.41L12.16 12H8v2h4.16l-1.59 1.59L11.99 17 16 13.01 11.99 9Z"></path>
+      </g>
       <g id="price-tracking">
         <path d="M12 11.333v-4c0-2.046-1.087-3.76-3-4.213v-.453c0-.554-.447-1-1-1-.554 0-1 .446-1 1v.453c-1.907.453-3 2.16-3 4.213v4H2.666v1.334h10.667v-1.334H12Zm-1.334 0H5.333v-4c0-1.653 1.007-3 2.667-3s2.666 1.347 2.666 3v4ZM8 14.667c.733 0 1.333-.6 1.333-1.334H6.666c0 .734.6 1.334 1.334 1.334Zm6.666-7.334h-1.333c0-1.826-.82-3.46-2.107-4.56l.94-.94c1.527 1.347 2.5 3.307 2.5 5.5Zm-9.893-4.56-.94-.94c-1.527 1.347-2.5 3.307-2.5 5.5h1.333c0-1.826.82-3.46 2.107-4.56Z"></path>
       </g>
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.html b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.html
new file mode 100644
index 0000000..a4b42cd6
--- /dev/null
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.html
@@ -0,0 +1,64 @@
+<style include="cr-shared-style">
+  :host {
+    --cr-dialog-body-padding-horizontal: 16px;
+    --cr-dialog-title-slot-padding-start: 16px;
+    --cr-dialog-width: 300px;
+  }
+
+  .body {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+  }
+
+  .button-row {
+    font-size: 12px;
+    justify-content: space-between;
+  }
+
+  .folder-header {
+    color: var(--cr-primary-text-color);
+    font-size: 14px;
+    font-weight: 500;
+  }
+
+  .folder-row {
+    display: flex;
+    width: auto;
+  }
+
+  .folder-selector {
+    border: 1px solid var(--scrollable-border-color);
+    border-radius: 2px;
+    height: 160px;
+  }
+</style>
+
+<cr-dialog id="dialog">
+  <div slot="title">$i18n{editMoveFolderTo}</div>
+  <div slot="body" class="body">
+    <div class="folder-header">
+      <template is="dom-if" if="[[activeFolder_]]" restamp>
+        TODO: Back Button
+      </template>
+      [[getActiveFolderTitle_(activeFolder_)]]
+    </div>
+    <div id="folder-selector" class="folder-selector">
+      <iron-list scroll-target="folder-selector"
+          items="[[getShownFolders_(activeFolder_, topLevelBookmarks_)]]">
+        <template>
+          <div class="folder-row">TODO: Folder row</div>
+        </template>
+      </iron-list>
+    </div>
+  </div>
+  <div class="button-row" slot="button-container">
+    <cr-button on-click="onNewFolder_">$i18n{editNewFolder}</cr-button>
+    <div>
+      <cr-button on-click="onCancel_">$i18n{editCancel}</cr-button>
+      <cr-button class="action-button cr-button-gap" on-click="onSave_">
+        $i18n{editSave}
+      </cr-button>
+    </div>
+  </div>
+</cr-dialog>
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.ts
new file mode 100644
index 0000000..baa969f
--- /dev/null
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.ts
@@ -0,0 +1,115 @@
+// 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 '../strings.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
+import 'chrome://resources/cr_elements/cr_shared_style.css.js';
+import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
+
+import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
+import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './power_bookmarks_edit_dialog.html.js';
+
+export interface PowerBookmarksEditDialogElement {
+  $: {
+    dialog: CrDialogElement,
+  };
+}
+
+function isFolder(node: chrome.bookmarks.BookmarkTreeNode) {
+  return !node.url;
+}
+
+export class PowerBookmarksEditDialogElement extends PolymerElement {
+  static get is() {
+    return 'power-bookmarks-edit-dialog';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      topLevelBookmarks_: {
+        type: Array,
+        value: () => [],
+      },
+
+      selectedBookmarks_: {
+        type: Array,
+        value: () => [],
+      },
+
+      selectedFolder_: {
+        type: Object,
+        value: null,
+      },
+
+      activeFolder_: {
+        type: Object,
+        value: null,
+      },
+    };
+  }
+
+  private topLevelBookmarks_: chrome.bookmarks.BookmarkTreeNode[];
+  private selectedBookmarks_: chrome.bookmarks.BookmarkTreeNode[];
+  private selectedFolder_: chrome.bookmarks.BookmarkTreeNode|undefined;
+  private activeFolder_: chrome.bookmarks.BookmarkTreeNode|undefined;
+
+  showDialog(
+      activeFolder: chrome.bookmarks.BookmarkTreeNode|undefined,
+      topLevelBookmarks: chrome.bookmarks.BookmarkTreeNode[],
+      selectedBookmarks: chrome.bookmarks.BookmarkTreeNode[]) {
+    this.activeFolder_ = activeFolder;
+    this.topLevelBookmarks_ = topLevelBookmarks;
+    this.selectedBookmarks_ = selectedBookmarks;
+    this.$.dialog.showModal();
+  }
+
+  private getActiveFolderTitle_() {
+    if (this.activeFolder_ &&
+        this.activeFolder_.id !== loadTimeData.getString('otherBookmarksId') &&
+        this.activeFolder_.id !== loadTimeData.getString('mobileBookmarksId')) {
+      return this.activeFolder_!.title;
+    } else {
+      return loadTimeData.getString('allBookmarks');
+    }
+  }
+
+  private getShownFolders_(): chrome.bookmarks.BookmarkTreeNode[] {
+    if (this.activeFolder_ && this.activeFolder_.children) {
+      return this.activeFolder_.children!.filter(isFolder);
+    } else if (!this.activeFolder_ && this.topLevelBookmarks_) {
+      return this.topLevelBookmarks_.filter(isFolder);
+    }
+    assertNotReached('No bookmarks to display in edit menu');
+  }
+
+  private onNewFolder_() {
+    // TODO
+  }
+
+  private onCancel_() {
+    this.$.dialog.close();
+  }
+
+  private onSave_() {
+    // TODO
+    this.$.dialog.close();
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'power-bookmarks-edit-dialog': PowerBookmarksEditDialogElement;
+  }
+}
+
+customElements.define(
+    PowerBookmarksEditDialogElement.is, PowerBookmarksEditDialogElement);
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
index 257eff2..fffc0478 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
@@ -144,7 +144,7 @@
     <iron-list items="[[shownBookmarks_]]" scroll-target="bookmarks">
       <template>
         <power-bookmark-row id="bookmark-[[item.id]]" bookmark="[[item]]"
-            description= "[[getBookmarkDescription_(item,
+            description="[[getBookmarkDescription_(item,
                             compactDescriptions_.*, expandedDescriptions_.*,
                             compact_)]]"
             compact="[[compact_]]" trailing-icon="cr:more-vert"
@@ -202,6 +202,11 @@
           title="$i18n{tooltipDelete}" aria-label="$i18n{tooltipDelete}"
           on-click="onDeleteClicked_">
       </cr-icon-button>
+      <cr-icon-button iron-icon="bookmarks:move"
+          disabled="[[!selectedBookmarks_.length]]"
+          title="$i18n{tooltipMove}" aria-label="$i18n{tooltipMove}"
+          on-click="onMoveClicked_">
+      </cr-icon-button>
       <cr-icon-button iron-icon="cr:more-vert"
           disabled="[[!selectedBookmarks_.length]]"
           title="$i18n{tooltipMore}" aria-label="$i18n{tooltipMore}"
@@ -221,7 +226,7 @@
     </button>
   </template>
   <hr>
-  <button class="dropdown-item" on-click="onVisualViewClicked_">
+  <button id="visualView" class="dropdown-item" on-click="onVisualViewClicked_">
     <iron-icon icon="cr:check" invisible$="[[compact_]]"></iron-icon>
     $i18n{visualView}
   </button>
@@ -231,6 +236,8 @@
   </button>
 </cr-action-menu>
 
+<power-bookmarks-edit-dialog id="editDialog"></power-bookmarks-edit-dialog>
+
 <cr-lazy-render id="contextMenu">
   <template>
     <power-bookmarks-context-menu
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
index b793a6c..f85b2b751 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
@@ -7,6 +7,8 @@
 import './icons.html.js';
 import './power_bookmarks_context_menu.js';
 import './power_bookmark_row.js';
+import './power_bookmarks_context_menu.js';
+import './power_bookmarks_edit_dialog.js';
 import '//bookmarks-side-panel.top-chrome/shared/sp_empty_state.js';
 import '//bookmarks-side-panel.top-chrome/shared/sp_filter_chip.js';
 import '//bookmarks-side-panel.top-chrome/shared/sp_footer.js';
@@ -34,6 +36,7 @@
 import {ActionSource} from './bookmarks.mojom-webui.js';
 import {BookmarksApiProxy, BookmarksApiProxyImpl} from './bookmarks_api_proxy.js';
 import {PowerBookmarksContextMenuElement} from './power_bookmarks_context_menu.js';
+import {PowerBookmarksEditDialogElement} from './power_bookmarks_edit_dialog.js';
 import {getTemplate} from './power_bookmarks_list.html.js';
 import {Label, PowerBookmarksService} from './power_bookmarks_service.js';
 
@@ -47,6 +50,7 @@
     deletionToast: CrLazyRenderElement<CrToastElement>,
     powerBookmarksContainer: HTMLElement,
     sortMenu: CrActionMenuElement,
+    editDialog: PowerBookmarksEditDialogElement,
   };
 }
 
@@ -293,14 +297,28 @@
     if (this.compact_) {
       return this.get(`compactDescriptions_.${bookmark.id}`);
     } else {
-      return this.get(`expandedDescriptions_.${bookmark.id}`);
+      const url = this.get(`expandedDescriptions_.${bookmark.id}`);
+      if (this.searchQuery_ && url && bookmark.parentId) {
+        const parentFolder =
+            this.bookmarksService_.findBookmarkWithId(bookmark.parentId);
+        const folderLabel = this.getFolderLabel_(parentFolder);
+        return loadTimeData.getStringF(
+            'urlFolderDescription', url, folderLabel);
+      } else {
+        return url;
+      }
     }
   }
 
-  private getFolderLabel_(): string {
-    const activeFolder = this.getActiveFolder_();
-    if (activeFolder) {
-      return activeFolder!.title;
+  private getActiveFolderLabel_(): string {
+    return this.getFolderLabel_(this.getActiveFolder_());
+  }
+
+  private getFolderLabel_(folder: chrome.bookmarks.BookmarkTreeNode|
+                          undefined): string {
+    if (folder && folder.id !== loadTimeData.getString('otherBookmarksId') &&
+        folder.id !== loadTimeData.getString('mobileBookmarksId')) {
+      return folder!.title;
     } else {
       return loadTimeData.getString('allBookmarks');
     }
@@ -514,6 +532,14 @@
     this.$.deletionToast.get().hide();
   }
 
+  private onMoveClicked_(event: MouseEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.$.editDialog.showDialog(
+        this.getActiveFolder_(), this.bookmarksService_.getTopLevelBookmarks(),
+        this.selectedBookmarks_);
+  }
+
   private onEditMenuClicked_(event: MouseEvent) {
     event.preventDefault();
     event.stopPropagation();
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_service.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_service.ts
index 7181016b..d7a43b4 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_service.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_service.ts
@@ -117,6 +117,21 @@
   }
 
   /**
+   * Returns a list of all root bookmark folders.
+   */
+  getFolders() {
+    return this.folders_;
+  }
+
+  /**
+   * Returns a list of all bookmarks defaulted to if no filter criteria are
+   * provided.
+   */
+  getTopLevelBookmarks() {
+    return this.filterBookmarks(undefined, 0, undefined, []);
+  }
+
+  /**
    * Returns a list of bookmarks and folders filtered by the provided criteria.
    */
   filterBookmarks(
@@ -135,9 +150,12 @@
                   folder.children!));
       shownBookmarks = topLevelBookmarks;
     }
+    if (searchQuery) {
+      shownBookmarks = this.applySearchQuery_(searchQuery!, shownBookmarks);
+    }
     shownBookmarks = shownBookmarks.filter(
         (b: chrome.bookmarks.BookmarkTreeNode) =>
-            this.nodeMatchesContentFilters_(b, labels, searchQuery));
+            this.nodeMatchesContentFilters_(b, labels));
     const sortChangedPosition =
         this.sortBookmarks(shownBookmarks, activeSortIndex);
     if (sortChangedPosition) {
@@ -345,20 +363,41 @@
     }
   }
 
+  // Return an array that includes folder and all its descendants.
+  private expandFolder_(folder: chrome.bookmarks.BookmarkTreeNode):
+      chrome.bookmarks.BookmarkTreeNode[] {
+    let expanded: chrome.bookmarks.BookmarkTreeNode[] = [folder];
+    if (folder.children) {
+      folder.children.forEach((child: chrome.bookmarks.BookmarkTreeNode) => {
+        expanded = expanded.concat(this.expandFolder_(child));
+      });
+    }
+    return expanded;
+  }
+
+  private applySearchQuery_(
+      searchQuery: string,
+      shownBookmarks: chrome.bookmarks.BookmarkTreeNode[]) {
+    let searchSpace: chrome.bookmarks.BookmarkTreeNode[] = [];
+    // Search space should include all descendants of the shown bookmarks, in
+    // addition to the shown bookmarks themselves.
+    shownBookmarks.forEach((bookmark: chrome.bookmarks.BookmarkTreeNode) => {
+      searchSpace = searchSpace.concat(this.expandFolder_(bookmark));
+    });
+    return searchSpace.filter(
+        (bookmark: chrome.bookmarks.BookmarkTreeNode) =>
+            (bookmark.title &&
+             bookmark.title.toLocaleLowerCase().includes(searchQuery)) ||
+            (bookmark.url &&
+             bookmark.url.toLocaleLowerCase().includes(searchQuery)));
+  }
+
   private nodeMatchesContentFilters_(
-      bookmark: chrome.bookmarks.BookmarkTreeNode, labels: Label[],
-      searchQuery: string|undefined): boolean {
+      bookmark: chrome.bookmarks.BookmarkTreeNode, labels: Label[]): boolean {
     // Price tracking label
     if (labels[0] && labels[0]!.active &&
         !this.productInfos_.has(bookmark.id)) {
       return false;
-    } else if (
-        searchQuery &&
-        !(bookmark.title &&
-          bookmark.title.toLocaleLowerCase().includes(searchQuery!)) &&
-        !(bookmark.url &&
-          bookmark.url.toLocaleLowerCase().includes(searchQuery!))) {
-      return false;
     }
     return true;
   }
diff --git a/chrome/browser/resources/side_panel/customize_chrome/cards.html b/chrome/browser/resources/side_panel/customize_chrome/cards.html
index 262964b..952ad12 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/cards.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/cards.html
@@ -65,7 +65,7 @@
   </cr-toggle>
 </div>
 <div id="cards">
-  <iron-collapse opened="[[show_]]">
+  <iron-collapse opened="[[show_]]" no-animation="[[!initialized_]]">
     <hr>
     <template is="dom-repeat" items="[[modules_]]">
       <div class="card">
diff --git a/chrome/browser/resources/side_panel/customize_chrome/cards.ts b/chrome/browser/resources/side_panel/customize_chrome/cards.ts
index 20c90b72..ced990b 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/cards.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/cards.ts
@@ -51,6 +51,11 @@
         type: Boolean,
         value: false,
       },
+
+      initialized_: {
+        type: Boolean,
+        value: false,
+      },
     };
   }
 
@@ -65,6 +70,7 @@
   private setModulesSettingsListenerId_: number|null = null;
   private discountCheckbox_: boolean;
   private discountCheckboxEligible_: boolean;
+  private initialized_: boolean;
 
   constructor() {
     super();
@@ -81,6 +87,7 @@
                   this.show_ = visible;
                   this.managedByPolicy_ = managed;
                   this.modules_ = modulesSettings;
+                  this.initialized_ = true;
                 });
     this.pageHandler_.updateModulesSettings();
   }
diff --git a/chrome/browser/resources/side_panel/customize_chrome/shortcuts.html b/chrome/browser/resources/side_panel/customize_chrome/shortcuts.html
index e17786e..2519601d 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/shortcuts.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/shortcuts.html
@@ -51,7 +51,7 @@
     checked="[[show_]]" on-change="onShowShortcutsToggleChange_"></cr-toggle>
 </div>
 <div id="options">
-  <iron-collapse opened="[[show_]]">
+  <iron-collapse opened="[[show_]]" no-animation="[[!initialized_]]">
     <hr>
     <cr-radio-group id="shortcutsRadioSelection" disabled="[[!show_]]"
       selected="[[shortcutsRadioSelection_]]"
diff --git a/chrome/browser/resources/side_panel/customize_chrome/shortcuts.ts b/chrome/browser/resources/side_panel/customize_chrome/shortcuts.ts
index eacbd14e..7ff710a 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/shortcuts.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/shortcuts.ts
@@ -44,12 +44,17 @@
         computed: 'computeShortcutsRadioSelection_(customLinksEnabled_)',
       },
       show_: Boolean,
+      initialized_: {
+        type: Boolean,
+        value: false,
+      },
     };
   }
 
   private customLinksEnabled_: boolean;
   private shortcutsRadioSelection_: string|undefined = undefined;
   private show_: boolean;
+  private initialized_: boolean;
 
   private setMostVisitedSettingsListenerId_: number|null = null;
 
@@ -69,6 +74,7 @@
             (customLinksEnabled: boolean, shortcutsVisible: boolean) => {
               this.customLinksEnabled_ = customLinksEnabled;
               this.show_ = shortcutsVisible;
+              this.initialized_ = true;
             });
     this.pageHandler_.updateMostVisitedSettings();
   }
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface.cc b/chrome/browser/speech/speech_recognition_client_browser_interface.cc
index 21ce2da..cf11aaa 100644
--- a/chrome/browser/speech/speech_recognition_client_browser_interface.cc
+++ b/chrome/browser/speech/speech_recognition_client_browser_interface.cc
@@ -7,7 +7,12 @@
 #include <memory>
 
 #include "base/feature_list.h"
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+#include "chrome/browser/accessibility/live_caption_controller_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/live_caption/live_caption_controller.h"
+#include "components/live_caption/live_caption_ui_remote_driver.h"
 #include "components/live_caption/pref_names.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
@@ -22,6 +27,7 @@
     SpeechRecognitionClientBrowserInterface(content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
   profile_prefs_ = profile->GetPrefs();
+  controller_ = captions::LiveCaptionControllerFactory::GetForProfile(profile);
 
   pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
   pref_change_registrar_->Init(profile_prefs_);
@@ -59,6 +65,22 @@
   OnSpeechRecognitionAvailabilityChanged();
 }
 
+void SpeechRecognitionClientBrowserInterface::BindRecognizerToRemoteClient(
+    mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient>
+        client_receiver,
+    mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
+        surface_client_receiver,
+    mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface_remote,
+    media::mojom::SpeechRecognitionSurfaceMetadataPtr metadata) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  ui_drivers_.Add(
+      std::make_unique<captions::LiveCaptionUiRemoteDriver>(
+          controller_, std::move(surface_client_receiver),
+          std::move(surface_remote), metadata->session_id.ToString()),
+      std::move(client_receiver));
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+}
+
 void SpeechRecognitionClientBrowserInterface::OnSodaInstalled(
     speech::LanguageCode language_code) {
   if (!prefs::IsLanguageCodeForLiveCaption(language_code, profile_prefs_))
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface.h b/chrome/browser/speech/speech_recognition_client_browser_interface.h
index c6890fd..a444043 100644
--- a/chrome/browser/speech/speech_recognition_client_browser_interface.h
+++ b/chrome/browser/speech/speech_recognition_client_browser_interface.h
@@ -12,10 +12,15 @@
 #include "media/mojo/mojom/speech_recognition.mojom.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
+#include "mojo/public/cpp/bindings/unique_receiver_set.h"
 
 class PrefChangeRegistrar;
 class PrefService;
 
+namespace captions {
+class LiveCaptionController;
+}  // namespace captions
+
 namespace content {
 class BrowserContext;
 }  // namespace content
@@ -43,6 +48,13 @@
   void BindSpeechRecognitionBrowserObserver(
       mojo::PendingRemote<media::mojom::SpeechRecognitionBrowserObserver>
           pending_remote) override;
+  void BindRecognizerToRemoteClient(
+      mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient>
+          client_receiver,
+      mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
+          host_receiver,
+      mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> origin_remote,
+      media::mojom::SpeechRecognitionSurfaceMetadataPtr metadata) override;
 
   // SodaInstaller::Observer:
   void OnSodaInstalled(speech::LanguageCode language_code) override;
@@ -63,8 +75,12 @@
   mojo::ReceiverSet<media::mojom::SpeechRecognitionClientBrowserInterface>
       speech_recognition_client_browser_interface_;
 
+  mojo::UniqueReceiverSet<media::mojom::SpeechRecognitionRecognizerClient>
+      ui_drivers_;
+
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
   raw_ptr<PrefService> profile_prefs_;
+  raw_ptr<captions::LiveCaptionController> controller_;
 };
 
 }  // namespace speech
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc b/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc
index 1a218bc7..241240d9 100644
--- a/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc
+++ b/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/speech/speech_recognition_client_browser_interface_factory.h"
 
 #include "base/no_destructor.h"
+#include "build/build_config.h"
+#include "chrome/browser/accessibility/live_caption_controller_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/speech/speech_recognition_client_browser_interface.h"
 
@@ -30,7 +32,11 @@
           "SpeechRecognitionClientBrowserInterface",
           // Incognito profiles should use their own instance of the browser
           // context.
-          ProfileSelections::BuildForRegularAndIncognito()) {}
+          ProfileSelections::BuildForRegularAndIncognito()) {
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+  DependsOn(::captions::LiveCaptionControllerFactory::GetInstance());
+#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
+}
 
 SpeechRecognitionClientBrowserInterfaceFactory::
     ~SpeechRecognitionClientBrowserInterfaceFactory() = default;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index ed1bf6d..e6221c4f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2252,8 +2252,6 @@
       "ash/back_gesture_contextual_nudge_delegate.h",
       "ash/browser_data_migration_error_dialog.cc",
       "ash/browser_data_migration_error_dialog.h",
-      "ash/bruschetta_delegate.cc",
-      "ash/bruschetta_delegate.h",
       "ash/calendar/calendar_client_impl.cc",
       "ash/calendar/calendar_client_impl.h",
       "ash/calendar/calendar_keyed_service.cc",
diff --git a/chrome/browser/ui/ash/bruschetta_delegate.cc b/chrome/browser/ui/ash/bruschetta_delegate.cc
deleted file mode 100644
index 7778e9f..0000000
--- a/chrome/browser/ui/ash/bruschetta_delegate.cc
+++ /dev/null
@@ -1,12 +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/ui/ash/bruschetta_delegate.h"
-
-#include "chrome/browser/ui/views/bruschetta/bruschetta_installer_view.h"
-
-void RunBruschettaInstaller(Profile* profile,
-                            const guest_os::GuestId& guest_id) {
-  BruschettaInstallerView::Show(profile, guest_id);
-}
diff --git a/chrome/browser/ui/ash/bruschetta_delegate.h b/chrome/browser/ui/ash/bruschetta_delegate.h
deleted file mode 100644
index 70de5a5a..0000000
--- a/chrome/browser/ui/ash/bruschetta_delegate.h
+++ /dev/null
@@ -1,15 +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_UI_ASH_BRUSCHETTA_DELEGATE_H_
-#define CHROME_BROWSER_UI_ASH_BRUSCHETTA_DELEGATE_H_
-
-#include "chrome/browser/ash/guest_os/guest_id.h"
-
-class Profile;
-
-void RunBruschettaInstaller(Profile* profile,
-                            const guest_os::GuestId& guest_id);
-
-#endif  // CHROME_BROWSER_UI_ASH_BRUSCHETTA_DELEGATE_H_
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index 79ac7bd2..b2f029f 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -158,7 +158,7 @@
   // constructed. The video conferencing views will observe and have their own
   // reference to this controller, and will assume it exists for as long as they
   // themselves exist.
-  if (ash::features::IsVcControlsUiEnabled()) {
+  if (ash::features::IsVideoConferenceEnabled()) {
     // `VideoConferenceTrayController` relies on audio and camera services to
     // function properly, so we will use the fake version when system bus is not
     // available so that this works on linux-chromeos and unit tests.
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index bb3800c..6edf5cf 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -77,6 +77,14 @@
     "ts-ps3-notice-settings";
 constexpr char kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeLearnMore[] =
     "ts-ps3-notice-learn-more";
+constexpr char kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentAccept[] =
+    "ts-ps4-consent-accept";
+constexpr char kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentDecline[] =
+    "ts-ps4-consent-decline";
+constexpr char kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeOk[] =
+    "ts-ps4-notice-ok";
+constexpr char kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeSettings[] =
+    "ts-ps4-notice-settings";
 constexpr char kHatsSurveyTriggerTrustSafetyPrivacySettings[] =
     "ts-privacy-settings";
 constexpr char kHatsSurveyTriggerTrustSafetyTrustedSurface[] =
@@ -95,6 +103,14 @@
     "ts-v2-trusted-surface";
 constexpr char kHatsSurveyTriggerTrustSafetyV2PrivacyGuide[] =
     "ts-v2-privacy-guide";
+constexpr char kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentAccept[] =
+    "ts-v2-ps4-consent-accept";
+constexpr char kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentDecline[] =
+    "ts-v2-ps4-consent-decline";
+constexpr char kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeOk[] =
+    "ts-v2-ps4-notice-ok";
+constexpr char kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeSettings[] =
+    "ts-v2-ps4-notice-settings";
 
 constexpr char kHatsNextSurveyTriggerIDTesting[] =
     "HLpeYy5Av0ugnJ3q1cK0XzzA8UHv";
@@ -270,6 +286,28 @@
               .Get(),
       std::vector<std::string>{"Stable channel", "3P cookies blocked",
                                "Privacy Sandbox enabled"});
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurvey,
+      kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentAccept,
+      features::kTrustSafetySentimentSurveyPrivacySandbox4ConsentAcceptTriggerId
+          .Get());
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurvey,
+      kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentDecline,
+      features::
+          kTrustSafetySentimentSurveyPrivacySandbox4ConsentDeclineTriggerId
+              .Get());
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurvey,
+      kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeOk,
+      features::kTrustSafetySentimentSurveyPrivacySandbox4NoticeOkTriggerId
+          .Get());
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurvey,
+      kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeSettings,
+      features::
+          kTrustSafetySentimentSurveyPrivacySandbox4NoticeSettingsTriggerId
+              .Get());
 
   // Trust & Safety Sentiment surveys - Version 2.
   survey_configs.emplace_back(
@@ -299,6 +337,29 @@
       &features::kTrustSafetySentimentSurveyV2,
       kHatsSurveyTriggerTrustSafetyV2PrivacyGuide,
       features::kTrustSafetySentimentSurveyV2PrivacyGuideTriggerId.Get());
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurveyV2,
+      kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentAccept,
+      features::
+          kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentAcceptTriggerId
+              .Get());
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurveyV2,
+      kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentDecline,
+      features::
+          kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentDeclineTriggerId
+              .Get());
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurveyV2,
+      kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeOk,
+      features::kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeOkTriggerId
+          .Get());
+  survey_configs.emplace_back(
+      &features::kTrustSafetySentimentSurveyV2,
+      kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeSettings,
+      features::
+          kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeSettingsTriggerId
+              .Get());
 
   // Autofill surveys.
   survey_configs.emplace_back(&features::kAutofillAddressSurvey,
diff --git a/chrome/browser/ui/hats/hats_service.h b/chrome/browser/ui/hats/hats_service.h
index 1ce172c..aa61c01 100644
--- a/chrome/browser/ui/hats/hats_service.h
+++ b/chrome/browser/ui/hats/hats_service.h
@@ -61,6 +61,10 @@
 extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeOk[];
 extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeSettings[];
 extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeLearnMore[];
+extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentAccept[];
+extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentDecline[];
+extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeOk[];
+extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeSettings[];
 extern const char kHatsSurveyTriggerTrustSafetyPrivacySettings[];
 extern const char kHatsSurveyTriggerTrustSafetyTrustedSurface[];
 extern const char kHatsSurveyTriggerTrustSafetyTransactions[];
@@ -70,6 +74,12 @@
 extern const char kHatsSurveyTriggerTrustSafetyV2SafetyCheck[];
 extern const char kHatsSurveyTriggerTrustSafetyV2TrustedSurface[];
 extern const char kHatsSurveyTriggerTrustSafetyV2PrivacyGuide[];
+extern const char kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentAccept[];
+extern const char
+    kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentDecline[];
+extern const char kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeOk[];
+extern const char
+    kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeSettings[];
 extern const char kHatsSurveyTriggerWhatsNew[];
 
 // The Trigger ID for a test HaTS Next survey which is available for testing
diff --git a/chrome/browser/ui/hats/trust_safety_sentiment_service.cc b/chrome/browser/ui/hats/trust_safety_sentiment_service.cc
index 90aa57ac..fede869 100644
--- a/chrome/browser/ui/hats/trust_safety_sentiment_service.cc
+++ b/chrome/browser/ui/hats/trust_safety_sentiment_service.cc
@@ -66,95 +66,8 @@
              : features::kTrustSafetySentimentSurveyNtpVisitsMaxRange.Get();
 }
 
-std::string GetHatsTriggerForFeatureArea(
-    TrustSafetySentimentService::FeatureArea feature_area) {
-  if (base::FeatureList::IsEnabled(features::kTrustSafetySentimentSurveyV2)) {
-    switch (feature_area) {
-      case (TrustSafetySentimentService::FeatureArea::kTrustedSurface):
-        return kHatsSurveyTriggerTrustSafetyV2TrustedSurface;
-      case (TrustSafetySentimentService::FeatureArea::kSafetyCheck):
-        return kHatsSurveyTriggerTrustSafetyV2SafetyCheck;
-      case (TrustSafetySentimentService::FeatureArea::kPasswordCheck):
-        return kHatsSurveyTriggerTrustSafetyV2PasswordCheck;
-      case (TrustSafetySentimentService::FeatureArea::kBrowsingData):
-        return kHatsSurveyTriggerTrustSafetyV2BrowsingData;
-      case (TrustSafetySentimentService::FeatureArea::kPrivacyGuide):
-        return kHatsSurveyTriggerTrustSafetyV2PrivacyGuide;
-      case (TrustSafetySentimentService::FeatureArea::kControlGroup):
-        return kHatsSurveyTriggerTrustSafetyV2ControlGroup;
-      default:
-        NOTREACHED();
-        return "";
-    }
-  }
-  switch (feature_area) {
-    case (TrustSafetySentimentService::FeatureArea::kPrivacySettings):
-      return kHatsSurveyTriggerTrustSafetyPrivacySettings;
-    case (TrustSafetySentimentService::FeatureArea::kTrustedSurface):
-      return kHatsSurveyTriggerTrustSafetyTrustedSurface;
-    case (TrustSafetySentimentService::FeatureArea::kTransactions):
-      return kHatsSurveyTriggerTrustSafetyTransactions;
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3ConsentAccept):
-      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3ConsentAccept;
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3ConsentDecline):
-      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3ConsentDecline;
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3NoticeDismiss):
-      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeDismiss;
-    case (TrustSafetySentimentService::FeatureArea::kPrivacySandbox3NoticeOk):
-      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeOk;
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3NoticeSettings):
-      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeSettings;
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3NoticeLearnMore):
-      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeLearnMore;
-    default:
-      NOTREACHED();
-      return "";
-  }
-}
-
-// Checks that this feature is valid for the current version.
-bool VersionCheck(TrustSafetySentimentService::FeatureArea feature_area) {
-  bool isV2 =
-      base::FeatureList::IsEnabled(features::kTrustSafetySentimentSurveyV2);
-  switch (feature_area) {
-    // Version 1 only
-    case (TrustSafetySentimentService::FeatureArea::kPrivacySettings):
-    case (TrustSafetySentimentService::FeatureArea::kTransactions):
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3ConsentAccept):
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3ConsentDecline):
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3NoticeDismiss):
-    case (TrustSafetySentimentService::FeatureArea::kPrivacySandbox3NoticeOk):
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3NoticeSettings):
-    case (TrustSafetySentimentService::FeatureArea::
-              kPrivacySandbox3NoticeLearnMore):
-      return isV2 == false;
-    // Version 2 only
-    case (TrustSafetySentimentService::FeatureArea::kSafetyCheck):
-    case (TrustSafetySentimentService::FeatureArea::kPasswordCheck):
-    case (TrustSafetySentimentService::FeatureArea::kBrowsingData):
-    case (TrustSafetySentimentService::FeatureArea::kPrivacyGuide):
-    case (TrustSafetySentimentService::FeatureArea::kControlGroup):
-      return isV2 == true;
-    // Both Versions
-    case (TrustSafetySentimentService::FeatureArea::kTrustedSurface):
-      return true;
-    default:
-      NOTREACHED();
-      return false;
-  }
-}
-
 bool ProbabilityCheck(TrustSafetySentimentService::FeatureArea feature_area) {
-  if (!VersionCheck(feature_area)) {
+  if (!TrustSafetySentimentService::VersionCheck(feature_area)) {
     return false;
   }
 
@@ -560,6 +473,9 @@
   TriggerOccurred(feature_area, product_specific_data);
 }
 
+void TrustSafetySentimentService::InteractedWithPrivacySandbox4(
+    FeatureArea feature_area) {}
+
 void TrustSafetySentimentService::OnOffTheRecordProfileCreated(
     Profile* off_the_record) {
   // Only interested in the primary OTR profile i.e. the one used for incognito
@@ -677,3 +593,124 @@
   return base::Time::Now() - trigger.occurred_time < GetMinTimeToPrompt() ||
          trigger.remaining_ntps_to_open > 0;
 }
+
+// static
+bool TrustSafetySentimentService::VersionCheck(
+    TrustSafetySentimentService::FeatureArea feature_area) {
+  bool isV2 =
+      base::FeatureList::IsEnabled(features::kTrustSafetySentimentSurveyV2);
+  switch (feature_area) {
+    // Version 1 only
+    case (TrustSafetySentimentService::FeatureArea::kPrivacySettings):
+    case (TrustSafetySentimentService::FeatureArea::kTransactions):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3ConsentAccept):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3ConsentDecline):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3NoticeDismiss):
+    case (TrustSafetySentimentService::FeatureArea::kPrivacySandbox3NoticeOk):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3NoticeSettings):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3NoticeLearnMore):
+      return isV2 == false;
+    // Version 2 only
+    case (TrustSafetySentimentService::FeatureArea::kSafetyCheck):
+    case (TrustSafetySentimentService::FeatureArea::kPasswordCheck):
+    case (TrustSafetySentimentService::FeatureArea::kBrowsingData):
+    case (TrustSafetySentimentService::FeatureArea::kPrivacyGuide):
+    case (TrustSafetySentimentService::FeatureArea::kControlGroup):
+      return isV2 == true;
+    // Both Versions
+    case (TrustSafetySentimentService::FeatureArea::kTrustedSurface):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox4ConsentAccept):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox4ConsentDecline):
+    case (TrustSafetySentimentService::FeatureArea::kPrivacySandbox4NoticeOk):
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox4NoticeSettings):
+      return true;
+    // None
+    case (TrustSafetySentimentService::FeatureArea::kIneligible):
+      return false;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+// static
+std::string TrustSafetySentimentService::GetHatsTriggerForFeatureArea(
+    TrustSafetySentimentService::FeatureArea feature_area) {
+  if (base::FeatureList::IsEnabled(features::kTrustSafetySentimentSurveyV2)) {
+    switch (feature_area) {
+      case (TrustSafetySentimentService::FeatureArea::kTrustedSurface):
+        return kHatsSurveyTriggerTrustSafetyV2TrustedSurface;
+      case (TrustSafetySentimentService::FeatureArea::kSafetyCheck):
+        return kHatsSurveyTriggerTrustSafetyV2SafetyCheck;
+      case (TrustSafetySentimentService::FeatureArea::kPasswordCheck):
+        return kHatsSurveyTriggerTrustSafetyV2PasswordCheck;
+      case (TrustSafetySentimentService::FeatureArea::kBrowsingData):
+        return kHatsSurveyTriggerTrustSafetyV2BrowsingData;
+      case (TrustSafetySentimentService::FeatureArea::kPrivacyGuide):
+        return kHatsSurveyTriggerTrustSafetyV2PrivacyGuide;
+      case (TrustSafetySentimentService::FeatureArea::kControlGroup):
+        return kHatsSurveyTriggerTrustSafetyV2ControlGroup;
+      case (TrustSafetySentimentService::FeatureArea::
+                kPrivacySandbox4ConsentAccept):
+        return kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentAccept;
+      case (TrustSafetySentimentService::FeatureArea::
+                kPrivacySandbox4ConsentDecline):
+        return kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4ConsentDecline;
+      case (TrustSafetySentimentService::FeatureArea::kPrivacySandbox4NoticeOk):
+        return kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeOk;
+      case (TrustSafetySentimentService::FeatureArea::
+                kPrivacySandbox4NoticeSettings):
+        return kHatsSurveyTriggerTrustSafetyV2PrivacySandbox4NoticeSettings;
+      default:
+        NOTREACHED();
+        return "";
+    }
+  }
+  switch (feature_area) {
+    case (TrustSafetySentimentService::FeatureArea::kPrivacySettings):
+      return kHatsSurveyTriggerTrustSafetyPrivacySettings;
+    case (TrustSafetySentimentService::FeatureArea::kTrustedSurface):
+      return kHatsSurveyTriggerTrustSafetyTrustedSurface;
+    case (TrustSafetySentimentService::FeatureArea::kTransactions):
+      return kHatsSurveyTriggerTrustSafetyTransactions;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3ConsentAccept):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3ConsentAccept;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3ConsentDecline):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3ConsentDecline;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3NoticeDismiss):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeDismiss;
+    case (TrustSafetySentimentService::FeatureArea::kPrivacySandbox3NoticeOk):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeOk;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3NoticeSettings):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeSettings;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox3NoticeLearnMore):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeLearnMore;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox4ConsentAccept):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentAccept;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox4ConsentDecline):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox4ConsentDecline;
+    case (TrustSafetySentimentService::FeatureArea::kPrivacySandbox4NoticeOk):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeOk;
+    case (TrustSafetySentimentService::FeatureArea::
+              kPrivacySandbox4NoticeSettings):
+      return kHatsSurveyTriggerTrustSafetyPrivacySandbox4NoticeSettings;
+    default:
+      NOTREACHED();
+      return "";
+  }
+}
diff --git a/chrome/browser/ui/hats/trust_safety_sentiment_service.h b/chrome/browser/ui/hats/trust_safety_sentiment_service.h
index c25bc6b..c698208b 100644
--- a/chrome/browser/ui/hats/trust_safety_sentiment_service.h
+++ b/chrome/browser/ui/hats/trust_safety_sentiment_service.h
@@ -116,13 +116,27 @@
     kBrowsingData = 12,
     kPrivacyGuide = 13,
     kControlGroup = 14,
-    kMaxValue = kControlGroup,
+    kPrivacySandbox4ConsentAccept = 15,
+    kPrivacySandbox4ConsentDecline = 16,
+    kPrivacySandbox4NoticeOk = 17,
+    kPrivacySandbox4NoticeSettings = 18,
+    kMaxValue = kPrivacySandbox4NoticeSettings,
   };
 
   // Called when the user interacts with Privacy Sandbox 3, |feature_area|
   // specifies what type of interaction occurred.
   virtual void InteractedWithPrivacySandbox3(FeatureArea feature_area);
 
+  virtual void InteractedWithPrivacySandbox4(FeatureArea feature_area);
+
+  // Checks that this feature area is valid for the current version.
+  static bool VersionCheck(
+      TrustSafetySentimentService::FeatureArea feature_area);
+
+  // Gets the HaTS trigger for a feature area.
+  static std::string GetHatsTriggerForFeatureArea(
+      TrustSafetySentimentService::FeatureArea feature_area);
+
  private:
   friend class TrustSafetySentimentServiceTest;
   FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
diff --git a/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc b/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc
index f66bd62..a5cdf49a 100644
--- a/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc
+++ b/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc
@@ -69,6 +69,10 @@
     std::string privacy_sandbox_3_notice_dismiss_probability = "0.1";
     std::string privacy_sandbox_3_notice_ok_probability = "0.4";
     std::string privacy_sandbox_3_notice_settings_probability = "0.7";
+    std::string privacy_sandbox_4_consent_accept_probability = "0.01";
+    std::string privacy_sandbox_4_consent_decline_probability = "0.1";
+    std::string privacy_sandbox_4_notice_ok_probability = "0.1";
+    std::string privacy_sandbox_4_notice_settings_probability = "0.1";
     std::string privacy_settings_trigger_id = "privacy-settings-test";
     std::string trusted_surface_trigger_id = "trusted-surface-test";
     std::string transactions_trigger_id = "transactions-test";
@@ -82,6 +86,14 @@
         "privacy-sandbox-3-ok-dismiss";
     std::string privacy_sandbox_3_notice_settings_trigger_id =
         "privacy-sandbox-3-settings-dismiss";
+    std::string privacy_sandbox_4_consent_accept_trigger_id =
+        "privacy-sandbox-4-consent-accept";
+    std::string privacy_sandbox_4_consent_decline_trigger_id =
+        "privacy-sandbox-4-consent-decline";
+    std::string privacy_sandbox_4_notice_ok_trigger_id =
+        "privacy-sandbox-4-notice-ok";
+    std::string privacy_sandbox_4_notice_settings_trigger_id =
+        "privacy-sandbox-4-notice-settings";
     std::string transactions_password_manager_time = "20s";
   };
 
@@ -108,6 +120,14 @@
              params.privacy_sandbox_3_notice_ok_probability},
             {"privacy-sandbox-3-notice-settings-probability",
              params.privacy_sandbox_3_notice_settings_probability},
+            {"privacy-sandbox-4-consent-accept-probability",
+             params.privacy_sandbox_4_consent_accept_probability},
+            {"privacy-sandbox-4-consent-decline-probability",
+             params.privacy_sandbox_4_consent_decline_probability},
+            {"privacy-sandbox-4-notice-ok-probability",
+             params.privacy_sandbox_4_notice_ok_probability},
+            {"privacy-sandbox-4-notice-settings-probability",
+             params.privacy_sandbox_4_notice_settings_probability},
             {"privacy-settings-trigger-id", params.privacy_settings_trigger_id},
             {"trusted-surface-trigger-id", params.trusted_surface_trigger_id},
             {"transactions-trigger-id", params.transactions_trigger_id},
@@ -121,6 +141,14 @@
              params.privacy_sandbox_3_notice_ok_trigger_id},
             {"privacy-sandbox-3-notice-settings-trigger-id",
              params.privacy_sandbox_3_notice_settings_trigger_id},
+            {"privacy-sandbox-4-consent-accept-trigger-id",
+             params.privacy_sandbox_4_consent_accept_trigger_id},
+            {"privacy-sandbox-4-consent-decline-trigger-id",
+             params.privacy_sandbox_4_consent_decline_trigger_id},
+            {"privacy-sandbox-4-notice-ok-trigger-id",
+             params.privacy_sandbox_4_notice_ok_trigger_id},
+            {"privacy-sandbox-4-notice-settings-trigger-id",
+             params.privacy_sandbox_4_notice_settings_trigger_id},
             {"transactions-password-manager-time",
              params.transactions_password_manager_time},
         });
@@ -139,12 +167,24 @@
     std::string safety_check_probability = "0.4";
     std::string trusted_surface_probability = "0.4";
     std::string privacy_guide_probability = "0.4";
+    std::string privacy_sandbox_4_consent_accept_probability = "0.01";
+    std::string privacy_sandbox_4_consent_decline_probability = "0.1";
+    std::string privacy_sandbox_4_notice_ok_probability = "0.1";
+    std::string privacy_sandbox_4_notice_settings_probability = "0.1";
     std::string browsing_data_trigger_id = "browsing-data-test";
     std::string control_group_trigger_id = "control-group-test";
     std::string password_check_trigger_id = "password-check-test";
     std::string safety_check_trigger_id = "safety-check-test";
     std::string trusted_surface_trigger_id = "trusted-surface-test";
     std::string privacy_guide_trigger_id = "privacy-guide-test";
+    std::string privacy_sandbox_4_consent_accept_trigger_id =
+        "privacy-sandbox-4-consent-accept";
+    std::string privacy_sandbox_4_consent_decline_trigger_id =
+        "privacy-sandbox-4-consent-decline";
+    std::string privacy_sandbox_4_notice_ok_trigger_id =
+        "privacy-sandbox-4-notice-ok";
+    std::string privacy_sandbox_4_notice_settings_trigger_id =
+        "privacy-sandbox-4-notice-settings";
   };
 
   void SetupFeatureParametersV2(FeatureParamsV2 params) {
@@ -163,12 +203,28 @@
             {"safety-check-probability", params.safety_check_probability},
             {"trusted-surface-probability", params.trusted_surface_probability},
             {"privacy-guide-probability", params.privacy_guide_probability},
+            {"privacy-sandbox-4-consent-accept-probability",
+             params.privacy_sandbox_4_consent_accept_probability},
+            {"privacy-sandbox-4-consent-decline-probability",
+             params.privacy_sandbox_4_consent_decline_probability},
+            {"privacy-sandbox-4-notice-ok-probability",
+             params.privacy_sandbox_4_notice_ok_probability},
+            {"privacy-sandbox-4-notice-settings-probability",
+             params.privacy_sandbox_4_notice_settings_probability},
             {"browsing-data-trigger-id", params.browsing_data_trigger_id},
             {"control-group-trigger-id", params.control_group_trigger_id},
             {"password-check-trigger-id", params.password_check_trigger_id},
             {"safety-check-trigger-id", params.safety_check_trigger_id},
             {"trusted-surface-trigger-id", params.trusted_surface_trigger_id},
             {"privacy-guide-trigger-id", params.privacy_guide_trigger_id},
+            {"privacy-sandbox-4-consent-accept-trigger-id",
+             params.privacy_sandbox_4_consent_accept_trigger_id},
+            {"privacy-sandbox-4-consent-decline-trigger-id",
+             params.privacy_sandbox_4_consent_decline_trigger_id},
+            {"privacy-sandbox-4-notice-ok-trigger-id",
+             params.privacy_sandbox_4_notice_ok_trigger_id},
+            {"privacy-sandbox-4-notice-settings-trigger-id",
+             params.privacy_sandbox_4_notice_settings_trigger_id},
         });
   }
 
@@ -821,6 +877,38 @@
                   {TrustSafetySentimentService::FeatureArea::kPrivacySettings});
 }
 
+TEST_F(TrustSafetySentimentServiceTest, AllFeatureAreasCorrectVersions) {
+  // Assert that for every feature area there is the correct version(s) and
+  // survey trigger id.
+  FeatureParams paramsv1;
+  SetupFeatureParameters(paramsv1);
+  for (int enum_value = 0;
+       enum_value <=
+       static_cast<int>(TrustSafetySentimentService::FeatureArea::kMaxValue);
+       ++enum_value) {
+    auto feature_area =
+        static_cast<TrustSafetySentimentService::FeatureArea>(enum_value);
+    if (TrustSafetySentimentService::VersionCheck(feature_area)) {
+      EXPECT_NE("", TrustSafetySentimentService::GetHatsTriggerForFeatureArea(
+                        feature_area));
+    }
+  }
+  feature_list()->Reset();
+  FeatureParamsV2 paramsv2;
+  SetupFeatureParametersV2(paramsv2);
+  for (int enum_value = 0;
+       enum_value <=
+       static_cast<int>(TrustSafetySentimentService::FeatureArea::kMaxValue);
+       ++enum_value) {
+    auto feature_area =
+        static_cast<TrustSafetySentimentService::FeatureArea>(enum_value);
+    if (TrustSafetySentimentService::VersionCheck(feature_area)) {
+      EXPECT_NE("", TrustSafetySentimentService::GetHatsTriggerForFeatureArea(
+                        feature_area));
+    }
+  }
+}
+
 TEST_F(TrustSafetySentimentServiceTest, Eligibility_V1FeatureWhileV2Enabled) {
   // A survey from V1 only is not shown because V2 is enabled.
   FeatureParams params;
diff --git a/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc b/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc
index 79962543f..ba3cd57 100644
--- a/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc
+++ b/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h"
 #include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h"
@@ -14,6 +15,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/privacy_sandbox/privacy_sandbox_features.h"
 #include "components/sync/test/test_sync_service.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test.h"
@@ -106,13 +108,46 @@
 
 class PrivacySandboxPromptHelperTestWithParam
     : public PrivacySandboxPromptHelperTest,
-      public testing::WithParamInterface<bool> {
-  PrivacySandboxService::PromptType TestPromptType() override {
-    // Setup consent / notice based on testing parameter. Helper behavior should
-    // be identical regardless of which type of prompt is required.
-    return GetParam() ? PrivacySandboxService::PromptType::kConsent
-                      : PrivacySandboxService::PromptType::kNotice;
+      public testing::WithParamInterface<PrivacySandboxService::PromptType> {
+ public:
+  void SetUpInProcessBrowserTestFixture() override {
+    test_prompt_type_ = GetParam();
+    switch (test_prompt_type_) {
+      case PrivacySandboxService::PromptType::kNone:
+        [[fallthrough]];
+      case PrivacySandboxService::PromptType::kNotice:
+        [[fallthrough]];
+      case PrivacySandboxService::PromptType::kConsent: {
+        feature_list_.InitWithFeatures(
+            /*enabled_features=*/{privacy_sandbox::kPrivacySandboxSettings3},
+            /*disabled_features=*/{privacy_sandbox::kPrivacySandboxSettings4});
+        break;
+      }
+      case PrivacySandboxService::PromptType::kM1Consent:
+        [[fallthrough]];
+      case PrivacySandboxService::PromptType::kM1NoticeROW:
+        [[fallthrough]];
+      case PrivacySandboxService::PromptType::kM1NoticeEEA: {
+        feature_list_.InitWithFeatures(
+            /*enabled_features=*/{privacy_sandbox::kPrivacySandboxSettings4},
+            /*disabled_features=*/{privacy_sandbox::kPrivacySandboxSettings3});
+        break;
+      }
+    }
+
+    PrivacySandboxPromptHelperTest::SetUpInProcessBrowserTestFixture();
   }
+
+ private:
+  PrivacySandboxService::PromptType TestPromptType() override {
+    // Setup appropriate prompt type based on testing parameter. Helper
+    // behavior should be "identical" regardless of which type of prompt is
+    // required.
+    return test_prompt_type_;
+  }
+
+  PrivacySandboxService::PromptType test_prompt_type_;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_P(PrivacySandboxPromptHelperTestWithParam,
@@ -296,6 +331,11 @@
       static_cast<base::HistogramBase::Sample>(base::Hash("about:blank")), 1);
 }
 
-INSTANTIATE_TEST_SUITE_P(PrivacySandboxPromptHelperTestWithParamInstance,
-                         PrivacySandboxPromptHelperTestWithParam,
-                         testing::Bool());
+INSTANTIATE_TEST_SUITE_P(
+    PrivacySandboxPromptHelperTestWithParamInstance,
+    PrivacySandboxPromptHelperTestWithParam,
+    testing::Values(PrivacySandboxService::PromptType::kM1Consent,
+                    PrivacySandboxService::PromptType::kM1NoticeEEA,
+                    PrivacySandboxService::PromptType::kM1NoticeROW,
+                    PrivacySandboxService::PromptType::kConsent,
+                    PrivacySandboxService::PromptType::kNotice));
diff --git a/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.cc b/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.cc
index d8885f9c..d54d3a79 100644
--- a/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.cc
+++ b/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.cc
@@ -221,11 +221,16 @@
   return !update_new_tab_button_callback_.is_null();
 }
 
-bool LensUnifiedSidePanelView::HandleContextMenu(
-    content::RenderFrameHost& render_frame_host,
-    const content::ContextMenuParams& params) {
-  // Disable context menu.
-  return true;
+content::WebContents* LensUnifiedSidePanelView::OpenURLFromTab(
+    content::WebContents* source,
+    const content::OpenURLParams& params) {
+  if (lens::features::GetEnableContextMenuInLensSidePanel()) {
+    // Use |OpenURL| so that we create a new tab rather than trying to open
+    // this link in the side panel.
+    return browser_view_->browser()->OpenURL(params);
+  } else {
+    return content::WebContentsDelegate::OpenURLFromTab(source, params);
+  }
 }
 
 void LensUnifiedSidePanelView::OpenUrl(const content::OpenURLParams& params) {
@@ -246,6 +251,13 @@
     bool renderer_initiated) {
   content::OpenURLParams params(url, referrer, disposition, transition,
                                 renderer_initiated);
+  if (lens::features::GetEnableContextMenuInLensSidePanel() &&
+      started_from_context_menu) {
+    // Link clicks initiated from the context menu will be handled by
+    // |OpenURLFromTab|.
+    return;
+  }
+
   // If the navigation is initiated by the renderer process, we must set an
   // initiator origin.
   if (renderer_initiated)
diff --git a/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.h b/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.h
index 134274fb..34023b2 100644
--- a/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.h
+++ b/chrome/browser/ui/views/side_panel/lens/lens_unified_side_panel_view.h
@@ -84,8 +84,9 @@
                            bool renderer_initiated) override;
 
   // content::WebContentsDelegate:
-  bool HandleContextMenu(content::RenderFrameHost& render_frame_host,
-                         const content::ContextMenuParams& params) override;
+  content::WebContents* OpenURLFromTab(
+      content::WebContents* source,
+      const content::OpenURLParams& params) override;
 
   raw_ptr<BrowserView> browser_view_;
   raw_ptr<views::Separator> separator_;
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
index d28a01f..e837ee6 100644
--- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
+++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
@@ -361,14 +361,14 @@
   BrowserList::RemoveObserver(this);
 }
 
-Browser* BrowserWaiter::AwaitAdded() {
-  added_run_loop_.Run();
+Browser* BrowserWaiter::AwaitAdded(const base::Location& location) {
+  added_run_loop_.Run(location);
   return added_browser_;
 }
 
-Browser* BrowserWaiter::AwaitRemoved() {
+Browser* BrowserWaiter::AwaitRemoved(const base::Location& location) {
   if (!removed_browser_)
-    removed_run_loop_.Run();
+    removed_run_loop_.Run(location);
   return removed_browser_;
 }
 
@@ -395,8 +395,8 @@
 
 UpdateAwaiter::~UpdateAwaiter() = default;
 
-void UpdateAwaiter::AwaitUpdate() {
-  run_loop_.Run();
+void UpdateAwaiter::AwaitUpdate(const base::Location& location) {
+  run_loop_.Run(location);
 }
 
 void UpdateAwaiter::OnWebAppManifestUpdated(const AppId& app_id,
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h
index b5cde1b..dcd319e 100644
--- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h
+++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_WEB_APPLICATIONS_TEST_WEB_APP_BROWSERTEST_UTIL_H_
 
 #include "base/functional/callback.h"
+#include "base/location.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
@@ -123,8 +124,10 @@
   explicit BrowserWaiter(Browser* filter = nullptr);
   ~BrowserWaiter() override;
 
-  Browser* AwaitAdded();
-  Browser* AwaitRemoved();
+  Browser* AwaitAdded(
+      const base::Location& location = base::Location::Current());
+  Browser* AwaitRemoved(
+      const base::Location& location = base::Location::Current());
 
   // BrowserListObserver:
   void OnBrowserAdded(Browser* browser) override;
@@ -147,7 +150,7 @@
  public:
   explicit UpdateAwaiter(WebAppInstallManager& install_manager);
   ~UpdateAwaiter() override;
-  void AwaitUpdate();
+  void AwaitUpdate(const base::Location& location = base::Location::Current());
 
   // WebAppInstallManagerObserver:
   void OnWebAppManifestUpdated(const AppId& app_id,
diff --git a/chrome/browser/ui/webui/ash/drive_internals_ui.cc b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
index d9141118..ef62815 100644
--- a/chrome/browser/ui/webui/ash/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
@@ -69,7 +69,7 @@
 
 using content::BrowserThread;
 using drive::DriveIntegrationService;
-using drivefs::pinning::DriveFsPinManager;
+using drivefs::pinning::PinManager;
 
 constexpr char kKey[] = "key";
 constexpr char kValue[] = "value";
@@ -248,11 +248,11 @@
 
 // Class to handle messages from chrome://drive-internals.
 class DriveInternalsWebUIHandler : public content::WebUIMessageHandler,
-                                   public DriveFsPinManager::Observer {
+                                   public PinManager::Observer {
  public:
   ~DriveInternalsWebUIHandler() override {
     if (pin_manager_) {
-      VLOG(1) << "DriveInternalsWebUIHandler dropped before DriveFsPinManager";
+      VLOG(1) << "DriveInternalsWebUIHandler dropped before PinManager";
       pin_manager_->RemoveObserver(this);
     }
   }
@@ -628,12 +628,12 @@
 
   void OnDrop() override {
     if (pin_manager_) {
-      VLOG(1) << "DriveFsPinManager dropped before DriveInternalsWebUIHandler";
+      VLOG(1) << "PinManager dropped before DriveInternalsWebUIHandler";
       pin_manager_ = nullptr;
     }
   }
 
-  void OnProgress(const drivefs::pinning::SetupProgress& progress) override {
+  void OnProgress(const drivefs::pinning::Progress& progress) override {
     using drivefs::pinning::HumanReadableSize;
 
     base::Value::Dict d;
@@ -971,7 +971,7 @@
   }
 
   // DriveFS bulk-pinning manager.
-  base::raw_ptr<DriveFsPinManager> pin_manager_ = nullptr;
+  base::raw_ptr<PinManager> pin_manager_ = nullptr;
 
   // The last event sent to the JavaScript side.
   int last_sent_event_id_ = -1;
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 0d41270..f427364 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -1471,7 +1471,7 @@
         GURL(chrome::kChromeUIBluetoothPairingURL),
         GURL(ash::kChromeUICameraAppURL), GURL(chrome::kOsUIComponentsURL),
         GURL(chrome::kChromeUICrashesUrl), GURL(chrome::kOsUICrashesURL),
-        GURL(chrome::kOsUICreditsURL),
+        GURL(chrome::kChromeUICreditsURL), GURL(chrome::kOsUICreditsURL),
         GURL(chrome::kChromeUIBorealisCreditsURL),
         GURL(chrome::kChromeUICloudUploadURL),
         GURL(chrome::kChromeUICrostiniCreditsURL),
@@ -1515,7 +1515,8 @@
         GURL(chrome::kOsUISettingsURL), GURL(chrome::kOsUISignInInternalsURL),
         GURL(chrome::kChromeUISlowURL), GURL(chrome::kChromeUISmbShareURL),
         GURL(chrome::kOsUISyncInternalsURL), GURL(chrome::kOsUISysInternalsUrl),
-        GURL(chrome::kOsUITermsURL), GURL(chrome::kChromeUIUserImageURL),
+        GURL(chrome::kChromeUITermsURL), GURL(chrome::kOsUITermsURL),
+        GURL(chrome::kChromeUIUserImageURL), GURL(chrome::kChromeUIVersionURL),
         GURL(chrome::kOsUIVersionURL), GURL(chrome::kChromeUIVmUrl),
         GURL(chrome::kOsUISystemURL), GURL(chrome::kOsUIHelpAppURL),
         GURL(chrome::kOsUINetExportURL),
diff --git a/chrome/browser/ui/webui/settings/ash/crostini_handler.cc b/chrome/browser/ui/webui/settings/ash/crostini_handler.cc
index ea01f28e..33dfe48 100644
--- a/chrome/browser/ui/webui/settings/ash/crostini_handler.cc
+++ b/chrome/browser/ui/webui/settings/ash/crostini_handler.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/ash/bruschetta_delegate.h"
 #include "chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_dialog.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
@@ -958,8 +957,8 @@
 void CrostiniHandler::HandleRequestBruschettaInstallerView(
     const base::Value::List& args) {
   AllowJavascript();
-  RunBruschettaInstaller(Profile::FromWebUI(web_ui()),
-                         bruschetta::GetBruschettaAlphaId());
+  bruschetta::RunInstaller(Profile::FromWebUI(web_ui()),
+                           bruschetta::GetBruschettaAlphaId());
 }
 
 }  // namespace ash::settings
diff --git a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc
index 6f76428..c97aa4f 100644
--- a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc
+++ b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc
@@ -55,6 +55,7 @@
       {"tooltipClose", IDS_CLOSE},
       {"tooltipDelete", IDS_DELETE},
       {"tooltipMore", IDS_BOOKMARKS_EDIT_MORE},
+      {"tooltipMove", IDS_BOOKMARKS_EDIT_MOVE_TO_ANOTHER_FOLDER},
       {"shoppingListFolderTitle", IDS_SIDE_PANEL_TRACKED_PRODUCTS},
       {"shoppingListTrackPriceButtonDescription",
        IDS_PRICE_TRACKING_TRACK_PRODUCT_ACCESSIBILITY},
@@ -97,6 +98,11 @@
       {"menuRename", IDS_BOOKMARKS_RENAME},
       {"newFolderTitle", IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME},
       {"undoBookmarkDeletion", IDS_UNDO_BOOKMARK_DELETION},
+      {"urlFolderDescription", IDS_BOOKMARKS_URL_FOLDER_DESCRIPTION},
+      {"editMoveFolderTo", IDS_BOOKMARKS_EDIT_MOVE_TO},
+      {"editNewFolder", IDS_BOOKMARKS_EDIT_NEW_FOLDER},
+      {"editCancel", IDS_BOOKMARKS_EDIT_CANCEL},
+      {"editSave", IDS_BOOKMARKS_EDIT_SAVE},
   };
   for (const auto& str : kLocalizedStrings)
     webui::AddLocalizedString(source, str.name, str.id);
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index f7a0853..eb9dd14 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1674583178-43dc267feb9c224b991b95353ff06412d93cd4ab.profdata
+chrome-mac-arm-main-1674626180-20a40fc31ff63f4a0c2c8d23d54b09e5f9cbccf7.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 72975b1..373c9217e 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1674583178-085f4af72137a90124942d46542505081e2220be.profdata
+chrome-mac-main-1674626180-4cd6a2c3d4a6d3297156651844ac51d3aa634472.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 0daaef4..a22c247 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1674593924-95ed30299224a880202fed77445e1b3e6658639d.profdata
+chrome-win32-main-1674604749-3ca2650cdd0404ebd362226c4505692ecfa31579.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index fe9ab5c..aee578267 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1674593924-f777fe92383f1af52434ef5e8fb8064a41f75d60.profdata
+chrome-win64-main-1674626180-1f4f82d9f6fac67836dc4d3c3d29011b0eee86ab.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 7114c1a..04c1e39 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -1143,6 +1143,22 @@
     kTrustSafetySentimentSurveyPrivacySandbox3NoticeLearnMoreProbability{
         &kTrustSafetySentimentSurvey,
         "privacy-sandbox-3-notice-learn-more-probability", 0.2};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentAcceptProbability{
+        &kTrustSafetySentimentSurvey,
+        "privacy-sandbox-4-consent-accept-probability", 0.0};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentDeclineProbability{
+        &kTrustSafetySentimentSurvey,
+        "privacy-sandbox-4-consent-decline-probability", 0.0};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeOkProbability{
+        &kTrustSafetySentimentSurvey, "privacy-sandbox-4-notice-ok-probability",
+        0.0};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeSettingsProbability{
+        &kTrustSafetySentimentSurvey,
+        "privacy-sandbox-4-notice-settings-probability", 0.0};
 // The HaTS trigger IDs, which determine which survey is delivered from the HaTS
 // backend.
 const base::FeatureParam<std::string>
@@ -1178,6 +1194,22 @@
     kTrustSafetySentimentSurveyPrivacySandbox3NoticeLearnMoreTriggerId{
         &kTrustSafetySentimentSurvey,
         "privacy-sandbox-3-notice-learn-more-trigger-id", ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentAcceptTriggerId{
+        &kTrustSafetySentimentSurvey,
+        "privacy-sandbox-4-consent-accept-trigger-id", ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentDeclineTriggerId{
+        &kTrustSafetySentimentSurvey,
+        "privacy-sandbox-4-consent-decline-trigger-id", ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeOkTriggerId{
+        &kTrustSafetySentimentSurvey, "privacy-sandbox-4-notice-ok-trigger-id",
+        ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeSettingsTriggerId{
+        &kTrustSafetySentimentSurvey,
+        "privacy-sandbox-4-notice-settings-trigger-id", ""};
 // The time the user must remain on settings after interacting with a privacy
 // setting to be considered.
 const base::FeatureParam<base::TimeDelta>
@@ -1248,6 +1280,22 @@
 const base::FeatureParam<double>
     kTrustSafetySentimentSurveyV2PrivacyGuideProbability{
         &kTrustSafetySentimentSurveyV2, "privacy-guide-probability", 0.0};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentAcceptProbability{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-consent-accept-probability", 0.0};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentDeclineProbability{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-consent-decline-probability", 0.0};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeOkProbability{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-notice-ok-probability", 0.0};
+const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeSettingsProbability{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-notice-settings-probability", 0.0};
 // The HaTS trigger IDs, which determine which survey is delivered from the HaTS
 // backend.
 const base::FeatureParam<std::string>
@@ -1268,6 +1316,22 @@
 const base::FeatureParam<std::string>
     kTrustSafetySentimentSurveyV2PrivacyGuideTriggerId{
         &kTrustSafetySentimentSurveyV2, "privacy-guide-trigger-id", ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentAcceptTriggerId{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-consent-accept-trigger-id", ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentDeclineTriggerId{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-consent-decline-trigger-id", ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeOkTriggerId{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-notice-ok-trigger-id", ""};
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeSettingsTriggerId{
+        &kTrustSafetySentimentSurveyV2,
+        "privacy-sandbox-4-notice-settings-trigger-id", ""};
 // The time the user must have the Trusted Surface bubble open to be considered.
 // Alternatively the user can interact with the bubble, in which case this time
 // is irrelevant.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index d403abc..cd3ec7a 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -644,6 +644,18 @@
 extern const base::FeatureParam<double>
     kTrustSafetySentimentSurveyPrivacySandbox3NoticeLearnMoreProbability;
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentAcceptProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentDeclineProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeOkProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeSettingsProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::FeatureParam<std::string>
     kTrustSafetySentimentSurveyPrivacySettingsTriggerId;
 COMPONENT_EXPORT(CHROME_FEATURES)
@@ -671,6 +683,18 @@
 extern const base::FeatureParam<std::string>
     kTrustSafetySentimentSurveyPrivacySandbox3NoticeLearnMoreTriggerId;
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentAcceptTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4ConsentDeclineTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeOkTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyPrivacySandbox4NoticeSettingsTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::FeatureParam<base::TimeDelta>
     kTrustSafetySentimentSurveyPrivacySettingsTime;
 COMPONENT_EXPORT(CHROME_FEATURES)
@@ -717,6 +741,18 @@
 extern const base::FeatureParam<double>
     kTrustSafetySentimentSurveyV2PrivacyGuideProbability;
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentAcceptProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentDeclineProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeOkProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<double>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeSettingsProbability;
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::FeatureParam<std::string>
     kTrustSafetySentimentSurveyV2BrowsingDataTriggerId;
 COMPONENT_EXPORT(CHROME_FEATURES)
@@ -735,6 +771,18 @@
 extern const base::FeatureParam<std::string>
     kTrustSafetySentimentSurveyV2PrivacyGuideTriggerId;
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentAcceptTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4ConsentDeclineTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeOkTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string>
+    kTrustSafetySentimentSurveyV2PrivacySandbox4NoticeSettingsTriggerId;
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::FeatureParam<base::TimeDelta>
     kTrustSafetySentimentSurveyV2TrustedSurfaceTime;
 
diff --git a/chrome/test/data/webui/bookmarks/BUILD.gn b/chrome/test/data/webui/bookmarks/BUILD.gn
index 693cd23..fa2dd80 100644
--- a/chrome/test/data/webui/bookmarks/BUILD.gn
+++ b/chrome/test/data/webui/bookmarks/BUILD.gn
@@ -11,7 +11,7 @@
     "actions_test.ts",
     "app_test.ts",
     "bookmarks_focus_test.js",
-    "command_manager_test.js",
+    "command_manager_test.ts",
     "dialog_focus_manager_test.ts",
     "dnd_manager_test.ts",
     "edit_dialog_test.ts",
@@ -46,6 +46,7 @@
     "//tools/typescript/definitions/chrome_event.d.ts",
     "//tools/typescript/definitions/runtime.d.ts",
     "//tools/typescript/definitions/tabs.d.ts",
+    "//tools/typescript/definitions/windows.d.ts",
   ]
   ts_deps = [ "//chrome/browser/resources/bookmarks:build_ts" ]
 }
diff --git a/chrome/test/data/webui/bookmarks/command_manager_test.js b/chrome/test/data/webui/bookmarks/command_manager_test.ts
similarity index 66%
rename from chrome/test/data/webui/bookmarks/command_manager_test.js
rename to chrome/test/data/webui/bookmarks/command_manager_test.ts
index 06eaf44..3228513f 100644
--- a/chrome/test/data/webui/bookmarks/command_manager_test.js
+++ b/chrome/test/data/webui/bookmarks/command_manager_test.ts
@@ -2,41 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {BookmarksCommandManagerElement, Command, createBookmark, DialogFocusManager, getDisplayedList, MenuSource, selectFolder} from 'chrome://bookmarks/bookmarks.js';
+import {BookmarkManagerApiProxyImpl, BookmarksApiProxyImpl, BookmarksCommandManagerElement, BookmarksFolderNodeElement, BookmarksItemElement, BookmarksListElement, Command, createBookmark, DialogFocusManager, getDisplayedList, MenuSource, selectFolder, SelectFolderAction, SelectItemsAction, setDebouncerForTesting} from 'chrome://bookmarks/bookmarks.js';
 import {isMac} from 'chrome://resources/js/platform.js';
 import {pressAndReleaseKeyOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 
+import {TestBookmarkManagerApiProxy} from './test_bookmark_manager_api_proxy.js';
+import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js';
 import {TestCommandManager} from './test_command_manager.js';
 import {TestStore} from './test_store.js';
 import {createFolder, createItem, customClick, findFolderNode, normalizeIterable, replaceBody, testTree} from './test_util.js';
 
 suite('<bookmarks-command-manager>', function() {
-  let commandManager;
-  let testCommandManager;
-  let store;
-  let lastCommand;
-  let lastCommandIds;
-  let bmpCopyFunction;
-  let bmpCutFunction;
-  let bmpPasteFunction;
-
-  suiteSetup(function() {
-    // Overwrite bookmarkManagerPrivate APIs which will crash if called with
-    // fake data.
-    bmpCopyFunction = chrome.bookmarkManagerPrivate.copy;
-    bmpPasteFunction = chrome.bookmarkManagerPrivate.paste;
-    bmpCutFunction = chrome.bookmarkManagerPrivate.cut;
-    chrome.bookmarkManagerPrivate.copy = function() {};
-    chrome.bookmarkManagerPrivate.removeTrees = function() {};
-  });
-
-  suiteTeardown(function() {
-    chrome.bookmarkManagerPrivate.copy = bmpCopyFunction;
-    chrome.bookmarkManagerPrivate.paste = bmpPasteFunction;
-    chrome.bookmarkManagerPrivate.cut = bmpCutFunction;
-  });
+  let commandManager: BookmarksCommandManagerElement;
+  let testCommandManager: TestCommandManager;
+  let store: TestStore;
+  let bookmarkManagerProxy: TestBookmarkManagerApiProxy;
 
   setup(function() {
     const bulkChildren = [];
@@ -78,12 +61,19 @@
               [
                 createFolder('21', []),
               ]),
-          createFolder('3', bulkChildren),
-          createFolder('4', [], {unmodifiable: 'managed'})),
+          createFolder('3', bulkChildren), createFolder('4', [], {
+            unmodifiable: chrome.bookmarks.BookmarkTreeNodeUnmodifiable.MANAGED,
+          })),
       selectedFolder: '1',
     });
     store.replaceSingleton();
 
+    const bookmarksProxy = new TestBookmarksApiProxy();
+    BookmarksApiProxyImpl.setInstance(bookmarksProxy);
+
+    bookmarkManagerProxy = new TestBookmarkManagerApiProxy();
+    BookmarkManagerApiProxyImpl.setInstance(bookmarkManagerProxy);
+
     testCommandManager = new TestCommandManager();
     commandManager = testCommandManager.getCommandManager();
     replaceBody(commandManager);
@@ -98,14 +88,18 @@
     commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     flush();
 
-    const commandHidden = {};
-    commandManager.root.querySelectorAll('.dropdown-item').forEach(element => {
-      commandHidden[element.getAttribute('command')] = element.hidden;
-    });
+    const commandHidden: {[key: string]: boolean} = {};
+    commandManager.shadowRoot!.querySelectorAll<HTMLElement>('.dropdown-item')
+        .forEach(element => {
+          commandHidden[element.getAttribute('command')!] = element.hidden;
+        });
 
     // With a folder and an item selected, the only available context menu item
     // is 'Delete'.
+    assertTrue(commandHidden[Command.EDIT] !== undefined);
     assertTrue(commandHidden[Command.EDIT]);
+
+    assertTrue(commandHidden[Command.DELETE] !== undefined);
     assertFalse(commandHidden[Command.DELETE]);
   });
 
@@ -115,21 +109,21 @@
     store.data.selection.items = new Set(['13']);
     store.notifyObservers();
 
-    pressAndReleaseKeyOn(document.body, '', [], key);
+    pressAndReleaseKeyOn(document.body, 0, [], key);
     testCommandManager.assertLastCommand(Command.EDIT, ['13']);
 
     // Doesn't trigger when multiple items are selected.
     store.data.selection.items = new Set(['11', '13']);
     store.notifyObservers();
 
-    pressAndReleaseKeyOn(document.body, '', [], key);
+    pressAndReleaseKeyOn(document.body, 0, [], key);
     testCommandManager.assertLastCommand(null);
 
     // Doesn't trigger when nothing is selected.
     store.data.selection.items = new Set();
     store.notifyObservers();
 
-    pressAndReleaseKeyOn(document.body, '', [], key);
+    pressAndReleaseKeyOn(document.body, 0, [], key);
     testCommandManager.assertLastCommand(null);
   });
 
@@ -149,30 +143,17 @@
     testCommandManager.assertLastCommand(Command.COPY, ['11', '13']);
   });
 
-  test('sublabels are shown', function() {
-    store.data.selection.items = new Set(['14']);
-    store.notifyObservers();
-
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
-    assertEquals('2', commandManager.getCommandSublabel_(Command.OPEN_NEW_TAB));
-  });
-
-  test('cut/paste commands trigger', function() {
-    let lastCut;
-    let lastPaste;
-    chrome.bookmarkManagerPrivate.cut = (idList) => {
-      lastCut = idList.sort();
-    };
-    chrome.bookmarkManagerPrivate.paste = (selectedFolder) => {
-      lastPaste = selectedFolder;
-    };
-
+  test('cut/paste commands trigger', async function() {
     store.data.selection.items = new Set(['11', '13']);
     store.notifyObservers();
 
     document.dispatchEvent(new Event('cut'));
+    const lastCut = (await bookmarkManagerProxy.whenCalled('cut')).sort();
     assertDeepEquals(['11', '13'], lastCut);
+
+    setDebouncerForTesting();
     document.dispatchEvent(new Event('paste'));
+    const lastPaste = await bookmarkManagerProxy.whenCalled('paste');
     assertEquals('1', lastPaste);
   });
 
@@ -182,24 +163,24 @@
     const redoModifier = isMac ? ['meta', 'shift'] : 'ctrl';
     const redoKey = isMac ? 'Z' : 'y';
 
-    pressAndReleaseKeyOn(document.body, '', undoModifier, undoKey);
+    pressAndReleaseKeyOn(document.body, 0, undoModifier, undoKey);
     testCommandManager.assertLastCommand(Command.UNDO);
 
-    pressAndReleaseKeyOn(document.body, '', redoModifier, redoKey);
+    pressAndReleaseKeyOn(document.body, 0, redoModifier, redoKey);
     testCommandManager.assertLastCommand(Command.REDO);
   });
 
   test('undo triggered when bookmarks-toolbar element has focus', function() {
     const element = document.createElement('bookmarks-toolbar');
     document.body.appendChild(element);
-    pressAndReleaseKeyOn(element, '', isMac ? 'meta' : 'ctrl', 'z');
+    pressAndReleaseKeyOn(element, 0, isMac ? 'meta' : 'ctrl', 'z');
     testCommandManager.assertLastCommand(Command.UNDO);
   });
 
   test('undo not triggered when most other elements have focus', function() {
     const element = document.createElement('div');
     document.body.appendChild(element);
-    pressAndReleaseKeyOn(element, '', isMac ? 'meta' : 'ctrl', 'z');
+    pressAndReleaseKeyOn(element, 0, isMac ? 'meta' : 'ctrl', 'z');
     testCommandManager.assertLastCommand(null);
   });
 
@@ -208,7 +189,7 @@
     const input = document.createElement('input');
     toolbar.appendChild(input);
     document.body.appendChild(toolbar);
-    pressAndReleaseKeyOn(input, '', isMac ? 'meta' : 'ctrl', 'z');
+    pressAndReleaseKeyOn(input, 0, isMac ? 'meta' : 'ctrl', 'z');
     testCommandManager.assertLastCommand(null);
   });
 
@@ -219,10 +200,12 @@
     commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     flush();
 
-    const showInFolderItem = commandManager.root.querySelector(
-        `[command='${Command.SHOW_IN_FOLDER}']`);
+    const showInFolderItem =
+        commandManager.shadowRoot!.querySelector<HTMLElement>(
+            `[command='${Command.SHOW_IN_FOLDER}']`);
 
     // Show in folder hidden when search is inactive.
+    assertTrue(!!showInFolderItem);
     assertTrue(showInFolderItem.hidden);
 
     // Show in Folder visible when search is active.
@@ -247,44 +230,31 @@
 
     // Executing the command selects the parent folder.
     commandManager.handle(Command.SHOW_IN_FOLDER, new Set(['12']));
+    assertTrue(!!store.lastAction);
     assertEquals('select-folder', store.lastAction.name);
-    assertEquals('1', store.lastAction.id);
+    assertEquals('1', (store.lastAction as SelectFolderAction).id);
   });
 
-  test('does not delete children at same time as ancestor', function() {
-    let lastDelete = null;
-    chrome.bookmarkManagerPrivate.removeTrees = function(idArray) {
-      lastDelete = idArray.sort();
-    };
-
+  test('does not delete children at same time as ancestor', async function() {
     const parentAndChildren = new Set(['11', '12', '111', '1221']);
     assertTrue(commandManager.canExecute(Command.DELETE, parentAndChildren));
     commandManager.handle(Command.DELETE, parentAndChildren);
 
+    const lastDelete = await bookmarkManagerProxy.whenCalled('removeTrees');
+
     assertDeepEquals(['11', '12'], lastDelete);
   });
 
-  test('expandIds_ expands one level of IDs', function() {
-    let ids = commandManager.expandIds_(new Set(['1']));
-    assertDeepEquals(['13'], ids);
-
-    ids = commandManager.expandIds_(new Set(['11', '12', '13']));
-    assertDeepEquals(['111', '121', '13'], ids);
-  });
-
-  test('shift-enter opens URLs in new window', function() {
+  test('shift-enter opens URLs in new window', async function() {
     store.data.selection.items = new Set(['12', '13']);
     store.notifyObservers();
 
-    let lastCreate;
-    chrome.windows.create = function(createConfig) {
-      lastCreate = createConfig;
-    };
-
     pressAndReleaseKeyOn(document.body, 13, 'shift', 'Enter');
+    const [ids, incognito] =
+        await bookmarkManagerProxy.whenCalled('openInNewWindow');
     testCommandManager.assertLastCommand(Command.OPEN_NEW_WINDOW, ['12', '13']);
-    assertDeepEquals(['http://121/', 'http://13/'], lastCreate.url);
-    assertFalse(lastCreate.incognito);
+    assertDeepEquals(['121', '13'], ids);
+    assertFalse(incognito);
   });
 
   test('shift-enter does not trigger enter commands', function() {
@@ -297,34 +267,28 @@
     testCommandManager.assertLastCommand(Command.OPEN_NEW_WINDOW);
   });
 
-  test('opening many items causes a confirmation dialog', function() {
-    let lastCreate = null;
-    chrome.windows.create = function(createConfig) {
-      lastCreate = createConfig;
-    };
-
+  test('opening many items causes a confirmation dialog', async function() {
     const items = new Set(['3']);
     assertTrue(commandManager.canExecute(Command.OPEN_NEW_WINDOW, items));
 
     commandManager.handle(Command.OPEN_NEW_WINDOW, items);
-    // No window should be created right away.
-    assertEquals(null, lastCreate);
 
     const dialog = commandManager.$.openDialog.getIfExists();
+    assertTrue(!!dialog);
     assertTrue(dialog.open);
 
     // Pressing 'cancel' should not open the window.
-    dialog.querySelector('.cancel-button').click();
+    dialog.querySelector<HTMLElement>('.cancel-button')!.click();
     assertFalse(dialog.open);
-    assertEquals(null, lastCreate);
 
     commandManager.handle(Command.OPEN_NEW_WINDOW, items);
     assertTrue(dialog.open);
 
     // Pressing 'yes' will open all the URLs.
-    dialog.querySelector('.action-button').click();
+    dialog.querySelector<HTMLElement>('.action-button')!.click();
+    const [ids] = await bookmarkManagerProxy.whenCalled('openInNewWindow');
     assertFalse(dialog.open);
-    assertEquals(20, lastCreate.url.length);
+    assertEquals(20, ids.length);
   });
 
   test('cannot execute "Open in New Tab" on folders with no items', function() {
@@ -336,17 +300,22 @@
     commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     flush();
 
-    const commandItem = {};
-    commandManager.root.querySelectorAll('.dropdown-item').forEach(element => {
-      commandItem[element.getAttribute('command')] = element;
-    });
+    const commandItem: {[key: string]: HTMLButtonElement} = {};
+    commandManager.shadowRoot!
+        .querySelectorAll<HTMLButtonElement>('.dropdown-item')
+        .forEach(element => {
+          commandItem[element.getAttribute('command')!] = element;
+        });
 
+    assertTrue(!!commandItem[Command.OPEN_NEW_TAB]);
     assertTrue(commandItem[Command.OPEN_NEW_TAB].disabled);
     assertFalse(commandItem[Command.OPEN_NEW_TAB].hidden);
 
+    assertTrue(!!commandItem[Command.OPEN_NEW_WINDOW]);
     assertTrue(commandItem[Command.OPEN_NEW_WINDOW].disabled);
     assertFalse(commandItem[Command.OPEN_NEW_WINDOW].hidden);
 
+    assertTrue(!!commandItem[Command.OPEN_INCOGNITO]);
     assertTrue(commandItem[Command.OPEN_INCOGNITO].disabled);
     assertFalse(commandItem[Command.OPEN_INCOGNITO].hidden);
   });
@@ -365,7 +334,7 @@
 
     // No divider line should be visible when only 'Open' commands are enabled.
     commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
-    commandManager.root.querySelectorAll('hr').forEach(element => {
+    commandManager.shadowRoot!.querySelectorAll('hr').forEach(element => {
       assertTrue(element.hidden);
     });
   });
@@ -382,10 +351,12 @@
     assertFalse(commandManager.canExecute(Command.DELETE, items));
 
     commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
-    const commandItem = {};
-    commandManager.root.querySelectorAll('.dropdown-item').forEach(element => {
-      commandItem[element.getAttribute('command')] = element;
-    });
+    const commandItem: {[key: string]: HTMLElement} = {};
+    commandManager.shadowRoot!.querySelectorAll<HTMLElement>('.dropdown-item')
+        .forEach(element => {
+          commandItem[element.getAttribute('command')!] = element;
+        });
+    assertTrue(!!commandItem[Command.EDIT]);
     commandItem[Command.EDIT].click();
     testCommandManager.assertLastCommand(null);
   });
@@ -397,11 +368,11 @@
     store.notifyObservers();
 
     const editKey = isMac ? 'Enter' : 'F2';
-    pressAndReleaseKeyOn(document.body, '', '', editKey);
+    pressAndReleaseKeyOn(document.body, 0, '', editKey);
     testCommandManager.assertLastCommand(Command.EDIT);
     assertTrue(DialogFocusManager.getInstance().hasOpenDialog());
 
-    pressAndReleaseKeyOn(document.body, '', '', 'Delete');
+    pressAndReleaseKeyOn(document.body, 0, '', 'Delete');
     testCommandManager.assertLastCommand(null);
   });
 
@@ -452,6 +423,7 @@
       parentId: '21',
       index: 0,
       url: 'https://www.example.com',
+      title: 'example',
     };
     store.dispatch(createBookmark(item1.id, item1));
     assertFalse(commandManager.canExecute(Command.SORT, new Set()));
@@ -461,6 +433,7 @@
       parentId: '21',
       index: 1,
       url: 'https://www.example.com',
+      title: 'example',
     };
     store.dispatch(createBookmark(item2.id, item2));
     assertTrue(commandManager.canExecute(Command.SORT, new Set()));
@@ -468,12 +441,12 @@
 });
 
 suite('<bookmarks-item> CommandManager integration', function() {
-  let list;
-  let items;
-  let commandManager;
-  let openedTabs;
-  let rootNode;
-  let store;
+  let list: BookmarksListElement;
+  let items: NodeListOf<BookmarksItemElement>;
+  let commandManager: BookmarksCommandManagerElement;
+  let rootNode: BookmarksFolderNodeElement;
+  let store: TestStore;
+  let bookmarkManagerProxy: TestBookmarkManagerApiProxy;
 
   setup(function() {
     store = new TestStore({
@@ -492,6 +465,8 @@
     });
     store.setReducersEnabled(true);
     store.replaceSingleton();
+    bookmarkManagerProxy = new TestBookmarkManagerApiProxy();
+    BookmarkManagerApiProxyImpl.setInstance(bookmarkManagerProxy);
 
     commandManager = document.createElement('bookmarks-command-manager');
 
@@ -504,123 +479,144 @@
     rootNode.depth = 0;
     document.body.appendChild(rootNode);
     flush();
+    document.body.appendChild(document.createElement('cr-toast-manager'));
 
-    items = list.root.querySelectorAll('bookmarks-item');
-
-
-    openedTabs = [];
-    chrome.tabs.create = function(createConfig) {
-      openedTabs.push(createConfig);
-    };
+    items = list.shadowRoot!.querySelectorAll<BookmarksItemElement>(
+        'bookmarks-item');
   });
 
-  function assertOpenedTabs(tabs) {
-    assertDeepEquals(tabs, openedTabs.map(createConfig => createConfig.url));
-  }
-
-  function simulateDoubleClick(element, config) {
+  function simulateDoubleClick(element: HTMLElement, config?: MouseEventInit) {
     config = config || {};
     customClick(element, config);
     config.detail = 2;
     customClick(element, config);
   }
 
-  function simulateMiddleClick(element, config) {
+  function simulateMiddleClick(element: HTMLElement, config?: MouseEventInit) {
     config = config || {};
     config.button = 1;
     customClick(element, config, 'auxclick');
   }
 
   test('double click opens folders in bookmark manager', function() {
-    simulateDoubleClick(items[0]);
+    simulateDoubleClick(items[0]!);
     assertEquals(store.data.selectedFolder, '11');
   });
 
-  test('double click opens items in foreground tab', function() {
-    simulateDoubleClick(items[1]);
-    assertOpenedTabs(['http://12/']);
+  test('double click opens items in foreground tab', async function() {
+    simulateDoubleClick(items[1]!);
+
+    const [id, active] = await bookmarkManagerProxy.whenCalled('openInNewTab');
+
+    assertEquals('12', id);
+    assertTrue(active);
   });
 
   test('shift-double click opens full selection', function() {
     // Shift-double click works because the first click event selects the range
     // of items, then the second doubleclick event opens that whole selection.
-    customClick(items[0]);
-    simulateDoubleClick(items[1], {shiftKey: true});
+    const item1 = items[0];
+    const item2 = items[1];
 
-    assertOpenedTabs(['http://111/', 'http://12/']);
+    assertTrue(!!item1);
+    assertTrue(!!item2);
+
+    customClick(item1);
+    simulateDoubleClick(item2, {shiftKey: true});
+
+    const [id1] = bookmarkManagerProxy.getArgs('openInNewTab')[0];
+    const [id2] = bookmarkManagerProxy.getArgs('openInNewTab')[1];
+
+    assertDeepEquals(['11', '12'], [id1, id2]);
   });
 
   test('control-double click opens full selection', function() {
-    customClick(items[0]);
-    simulateDoubleClick(items[2], {ctrlKey: true});
+    const item1 = items[0];
+    const item2 = items[2];
 
-    assertOpenedTabs(['http://111/', 'http://13/']);
+    assertTrue(!!item1);
+    assertTrue(!!item2);
+
+    customClick(item1);
+    simulateDoubleClick(item2, {ctrlKey: true});
+
+    const [id1] = bookmarkManagerProxy.getArgs('openInNewTab')[0];
+    const [id2] = bookmarkManagerProxy.getArgs('openInNewTab')[1];
+
+    assertDeepEquals(['11', '13'], [id1, id2]);
   });
 
-  test('middle-click opens clicked item in new tab', function() {
+  test('middle-click opens clicked item in new tab', async function() {
+    const item1 = items[1];
+    const item2 = items[2];
+
+    assertTrue(!!item1);
+    assertTrue(!!item2);
+
     // Select multiple items.
-    customClick(items[1]);
-    customClick(items[2], {shiftKey: true});
+    customClick(item1);
+    customClick(item2, {shiftKey: true});
 
     // Only the middle-clicked item is opened.
-    simulateMiddleClick(items[2]);
-    assertDeepEquals(['13'], normalizeIterable(store.data.selection.items));
-    assertOpenedTabs(['http://13/']);
-    assertFalse(openedTabs[0].active);
+    simulateMiddleClick(item2);
+
+    const [id, active] = await bookmarkManagerProxy.whenCalled('openInNewTab');
+
+    assertEquals('13', id);
+    assertFalse(active);
   });
 
   test('middle-click does not open folders', function() {
-    simulateMiddleClick(items[0]);
+    const item = items[0];
+    assertTrue(!!item);
+
+    simulateMiddleClick(item);
+
     assertDeepEquals(['11'], normalizeIterable(store.data.selection.items));
-    assertOpenedTabs([]);
+    assertEquals(0, bookmarkManagerProxy.getCallCount('openInNewTab'));
   });
 
-  test('shift-middle click opens in foreground tab', function() {
-    simulateMiddleClick(items[1], {shiftKey: true});
-    assertOpenedTabs(['http://12/']);
-    assertTrue(openedTabs[0].active);
+  test('shift-middle click opens in foreground tab', async function() {
+    const item = items[1];
+    assertTrue(!!item);
+
+    simulateMiddleClick(item, {shiftKey: true});
+    const [id, active] = await bookmarkManagerProxy.whenCalled('openInNewTab');
+
+    assertEquals('12', id);
+    assertTrue(active);
   });
 
-  test('copy/cut/paste for folder nodes independent of selection', function() {
-    const bmpCopyFunction = chrome.bookmarkManagerPrivate.copy;
-    const bmpCutFunction = chrome.bookmarkManagerPrivate.cut;
+  test(
+      'copy/cut/paste for folder nodes independent of selection',
+      async function() {
+        const modifier = isMac ? 'meta' : 'ctrl';
 
-    let lastCut;
-    let lastCopy;
-    chrome.bookmarkManagerPrivate.copy = function(idList) {
-      lastCopy = idList.sort();
-    };
-    chrome.bookmarkManagerPrivate.cut = function(idList) {
-      lastCut = idList.sort();
-    };
+        store.data.selection.items = new Set(['12', '13']);
+        store.notifyObservers();
+        const targetNode = findFolderNode(rootNode, '11');
+        assertTrue(!!targetNode);
 
-    const modifier = isMac ? 'meta' : 'ctrl';
+        pressAndReleaseKeyOn(targetNode, 0, modifier, 'c');
+        const lastCopy = await bookmarkManagerProxy.whenCalled('copy');
+        assertDeepEquals(['11'], lastCopy);
 
-    store.data.selection.items = new Set(['12', '13']);
-    store.notifyObservers();
-    const targetNode = findFolderNode(rootNode, '11');
-    pressAndReleaseKeyOn(targetNode, '', modifier, 'c');
-    assertDeepEquals(['11'], lastCopy);
-
-    pressAndReleaseKeyOn(targetNode, '', modifier, 'x');
-    assertDeepEquals(['11'], lastCut);
-
-    chrome.bookmarkManagerPrivate.copy = bmpCopyFunction;
-    chrome.bookmarkManagerPrivate.cut = bmpCutFunction;
-  });
+        pressAndReleaseKeyOn(targetNode, 0, modifier, 'x');
+        const lastCut = await bookmarkManagerProxy.whenCalled('cut');
+        assertDeepEquals(['11'], lastCut);
+      });
 
   test('context menu disappears immediately on right click', async function() {
-    commandManager.updateCanPaste_ = function() {
-      this.canPaste_ = true;
-      return Promise.resolve();
-    };
+    bookmarkManagerProxy.setCanPaste(true);
 
-    customClick(items[0], {button: 1}, 'contextmenu');
+    customClick(items[0]!, {button: 1}, 'contextmenu');
     assertDeepEquals(['11'], normalizeIterable(store.data.selection.items));
 
     await flushTasks();
 
     const dropdown = commandManager.$.dropdown.getIfExists();
+    assertTrue(!!dropdown);
+
     const dialog = dropdown.getDialog();
     assertTrue(dropdown.open);
 
@@ -630,23 +626,20 @@
     // Ensure the dialog is the target even when clicking outside it, and send
     // a context menu event which should immediately dismiss the dialog,
     // allowing subsequent events to bubble through to elements below.
-    assertEquals(dropdown, commandManager.root.elementFromPoint(x, y));
-    assertEquals(dialog, dropdown.root.elementFromPoint(x, y));
+    assertEquals(dropdown, commandManager.shadowRoot!.elementFromPoint(x, y));
+    assertEquals(dialog, dropdown.shadowRoot!.elementFromPoint(x, y));
     customClick(dialog, {clientX: x, clientY: y, button: 1}, 'contextmenu');
     assertFalse(dropdown.open);
   });
 });
 
 suite('<bookmarks-command-manager> whole page integration', function() {
-  let store;
-  let commandManager;
+  let store: TestStore;
+  let commandManager: BookmarksCommandManagerElement;
+  let testFolderId: string;
 
-  let testFolderId;
-
-  function create(bookmark) {
-    return new Promise(function(resolve) {
-      chrome.bookmarks.create(bookmark, resolve);
-    });
+  function create(details: chrome.bookmarks.CreateDetails) {
+    return chrome.bookmarks.create(details);
   }
 
   suiteSetup(async function() {
@@ -667,6 +660,10 @@
   });
 
   setup(async function() {
+    const bookmarksProxy = new BookmarksApiProxyImpl();
+    BookmarksApiProxyImpl.setInstance(bookmarksProxy);
+    const bookmarkManagerProxy = new BookmarkManagerApiProxyImpl();
+    BookmarkManagerApiProxyImpl.setInstance(bookmarkManagerProxy);
     store = new TestStore({});
     store.replaceSingleton();
     store.setReducersEnabled(true);
@@ -683,13 +680,14 @@
 
   test('paste selects newly created items', async function() {
     const displayedIdsBefore = getDisplayedList(store.data);
+
     commandManager.handle(Command.SELECT_ALL, new Set());
     commandManager.handle(Command.COPY, new Set(displayedIdsBefore));
 
     store.expectAction('select-items');
     commandManager.handle(Command.PASTE, new Set());
-
-    const action = await store.waitForAction('select-items');
+    const action =
+        await store.waitForAction('select-items') as SelectItemsAction;
 
     const displayedIdsAfter = getDisplayedList(store.data);
     assertEquals(4, displayedIdsAfter.length);
@@ -705,7 +703,7 @@
     assertEquals(action.anchor, displayedIdsAfter[2]);
   });
 
-  suiteTeardown(function(done) {
-    chrome.bookmarks.removeTree(testFolderId, () => done());
+  suiteTeardown(function() {
+    return chrome.bookmarks.removeTree(testFolderId);
   });
 });
diff --git a/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts b/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts
index 7132110fe..c8df146 100644
--- a/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts
+++ b/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts
@@ -9,15 +9,26 @@
 export class TestBookmarkManagerApiProxy extends TestBrowserProxy implements
     BookmarkManagerApiProxy {
   onDragEnter = new FakeChromeEvent();
+  private canPaste_ = false;
 
   constructor() {
     super([
+      'canPaste',
+      'copy',
+      'cut',
       'drop',
-      'startDrag',
+      'openInNewTab',
+      'openInNewWindow',
+      'paste',
       'removeTrees',
+      'startDrag',
     ]);
   }
 
+  setCanPaste(canPaste: boolean) {
+    this.canPaste_ = canPaste;
+  }
+
   drop(parentId: string, index?: number) {
     this.methodCalled('drop', [parentId, index]);
     return Promise.resolve();
@@ -29,8 +40,36 @@
     this.methodCalled('startDrag', idList);
   }
 
-  removeTrees(_idList: string[]) {
-    this.methodCalled('removeTrees');
+  removeTrees(idList: string[]) {
+    this.methodCalled('removeTrees', idList);
+    return Promise.resolve();
+  }
+
+  canPaste(_parentId: string) {
+    this.methodCalled('canPaste');
+    return Promise.resolve(this.canPaste_);
+  }
+
+  openInNewWindow(idList: string[], incognito: boolean) {
+    this.methodCalled('openInNewWindow', [idList, incognito]);
+  }
+
+  openInNewTab(id: string, active: boolean) {
+    this.methodCalled('openInNewTab', [id, active]);
+  }
+
+  cut(idList: string[]) {
+    this.methodCalled('cut', idList);
+    return Promise.resolve();
+  }
+
+  paste(parentId: string, _selectedIdList?: string[]) {
+    this.methodCalled('paste', parentId);
+    return Promise.resolve();
+  }
+
+  copy(idList: string[]) {
+    this.methodCalled('copy', idList);
     return Promise.resolve();
   }
 }
diff --git a/chrome/test/data/webui/build_webui_tests.gni b/chrome/test/data/webui/build_webui_tests.gni
index 38768257..eb38ec2 100644
--- a/chrome/test/data/webui/build_webui_tests.gni
+++ b/chrome/test/data/webui/build_webui_tests.gni
@@ -19,6 +19,21 @@
   preprocess_dir = "${target_gen_dir}/preprocessed"
   tsc_dir = "${target_gen_dir}/tsc"
 
+  if (defined(invoker.static_files)) {
+    static_files_filter = [ "*.html" ]
+    static_files = filter_include(invoker.static_files, static_files_filter)
+    assert(static_files == invoker.static_files,
+           "Static files must be .html files")
+    preprocess_if_expr("preprocess_static_files") {
+      visibility = [ ":build_grdp" ]
+      defines = chrome_grit_defines
+      in_folder = "."
+      out_folder = preprocess_dir
+      in_files = static_files
+      out_manifest = "${target_gen_dir}/preprocess_static_files_manifest.json"
+    }
+  }
+
   preprocess_if_expr("preprocess") {
     visibility = [ ":build_ts" ]
     defines = chrome_grit_defines
@@ -60,6 +75,11 @@
     deps = [ ":build_ts" ]
     manifest_files =
         filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+    if (defined(invoker.static_files)) {
+      deps += [ ":preprocess_static_files" ]
+      manifest_files +=
+          [ "${target_gen_dir}/preprocess_static_files_manifest.json" ]
+    }
     resource_path_prefix = invoker.resource_path_prefix
   }
 }
diff --git a/chrome/test/data/webui/side_panel/BUILD.gn b/chrome/test/data/webui/side_panel/BUILD.gn
index 743ea90b..2d9c67a 100644
--- a/chrome/test/data/webui/side_panel/BUILD.gn
+++ b/chrome/test/data/webui/side_panel/BUILD.gn
@@ -12,9 +12,11 @@
     "bookmarks/bookmarks_drag_manager_test.ts",
     "bookmarks/bookmarks_list_interactive_ui_test.ts",
     "bookmarks/bookmarks_list_test.ts",
+    "bookmarks/power_bookmarks_edit_dialog_test.ts",
     "bookmarks/power_bookmarks_list_test.ts",
     "bookmarks/power_bookmarks_service_test.ts",
     "bookmarks/test_bookmarks_api_proxy.ts",
+    "bookmarks/test_power_bookmarks_delegate.ts",
     "bookmarks/commerce/shopping_list_test.ts",
     "bookmarks/commerce/test_shopping_list_api_proxy.ts",
     "reading_list/reading_list_app_test.ts",
diff --git a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_edit_dialog_test.ts b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_edit_dialog_test.ts
new file mode 100644
index 0000000..0d73f391
--- /dev/null
+++ b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_edit_dialog_test.ts
@@ -0,0 +1,114 @@
+// 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 'chrome://webui-test/mojo_webui_test_support.js';
+import 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_edit_dialog.js';
+
+import {BookmarksApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/bookmarks_api_proxy.js';
+import {PowerBookmarksEditDialogElement} from 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_edit_dialog.js';
+import {PowerBookmarksService} from 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_service.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
+import {assertEquals} from 'chrome://webui-test/chai_assert.js';
+
+import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js';
+import {TestPowerBookmarksDelegate} from './test_power_bookmarks_delegate.js';
+
+suite('SidePanelPowerBookmarksEditDialogTest', () => {
+  let powerBookmarksEditDialog: PowerBookmarksEditDialogElement;
+  let bookmarksApi: TestBookmarksApiProxy;
+  let delegate: TestPowerBookmarksDelegate;
+  let service: PowerBookmarksService;
+
+  const folders: chrome.bookmarks.BookmarkTreeNode[] = [
+    {
+      id: '2',
+      parentId: '0',
+      title: 'Other Bookmarks',
+      children: [
+        {
+          id: '3',
+          parentId: '2',
+          title: 'First child bookmark',
+          url: 'http://child/bookmark/1/',
+          dateAdded: 1,
+        },
+        {
+          id: '4',
+          parentId: '2',
+          title: 'Second child bookmark',
+          url: 'http://child/bookmark/2/',
+          dateAdded: 3,
+        },
+        {
+          id: '5',
+          parentId: '2',
+          title: 'Child folder',
+          dateAdded: 2,
+          children: [
+            {
+              id: '6',
+              parentId: '5',
+              title: 'Nested bookmark',
+              url: 'http://nested/bookmark/',
+              dateAdded: 4,
+            },
+          ],
+        },
+      ],
+    },
+  ];
+
+  setup(async () => {
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+
+    bookmarksApi = new TestBookmarksApiProxy();
+    bookmarksApi.setFolders(JSON.parse(JSON.stringify(folders)));
+    BookmarksApiProxyImpl.setInstance(bookmarksApi);
+
+    delegate = new TestPowerBookmarksDelegate();
+    service = new PowerBookmarksService(delegate);
+    service.startListening();
+
+    loadTimeData.overrideValues({
+      allBookmarks: 'All Bookmarks',
+    });
+
+    powerBookmarksEditDialog =
+        document.createElement('power-bookmarks-edit-dialog');
+    document.body.appendChild(powerBookmarksEditDialog);
+
+    await delegate.whenCalled('onBookmarksLoaded');
+  });
+
+  test('ShowsCorrectRowCount', async () => {
+    const topLevelBookmarks = service.getTopLevelBookmarks();
+    powerBookmarksEditDialog.showDialog(
+        undefined,
+        topLevelBookmarks,
+        [topLevelBookmarks[0]!],
+    );
+
+    const ironList =
+        powerBookmarksEditDialog.shadowRoot!.querySelector('iron-list');
+    const rows = ironList!.items!;
+
+    assertEquals(rows.length, 1);
+  });
+
+  test('ShowsActiveFolderName', () => {
+    const topLevelBookmarks = service.getTopLevelBookmarks();
+    powerBookmarksEditDialog.showDialog(
+        undefined,
+        topLevelBookmarks,
+        [topLevelBookmarks[0]!],
+    );
+
+    const titleElement =
+        powerBookmarksEditDialog.shadowRoot!.querySelector('.folder-header');
+    assertEquals(
+        titleElement!.textContent!.includes(
+            loadTimeData.getString('allBookmarks')),
+        true);
+  });
+});
diff --git a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts
index 36cf4311..4c470689 100644
--- a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts
+++ b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts
@@ -82,6 +82,7 @@
     powerBookmarksList = document.createElement('power-bookmarks-list');
     document.body.appendChild(powerBookmarksList);
 
+    await bookmarksApi.whenCalled('getFolders');
     await flushTasks();
   });
 
@@ -93,8 +94,6 @@
   });
 
   test('DefaultsToSortByNewest', () => {
-    flush();
-
     const bookmarkElements = getBookmarkElements(powerBookmarksList);
     // All folders should come first
     assertEquals(bookmarkElements[0]!.id, 'bookmark-5');
@@ -207,4 +206,60 @@
     assertEquals(
         1, (newFolder as PowerBookmarkRowElement).bookmark.children!.length);
   });
+
+  test('SetsCompactDescription', async () => {
+    const bookmarkElements = getBookmarkElements(powerBookmarksList);
+    const folderElement = bookmarkElements[0]!;
+    assertEquals(folderElement.id, 'bookmark-5');
+
+    const descriptionElement =
+        folderElement.shadowRoot!.getElementById('description');
+    const pluralString =
+        await PluralStringProxyImpl.getInstance().getPluralString('foo', 1);
+    assertEquals(descriptionElement!.textContent!.includes(pluralString), true);
+  });
+
+  test('SetsExpandedDescription', () => {
+    const menu =
+        powerBookmarksList.shadowRoot!.querySelector('cr-action-menu')!;
+    menu.showAt(powerBookmarksList);
+    const visualViewButton: HTMLElement = menu.querySelector('#visualView')!;
+    visualViewButton.click();
+
+    const bookmarkElements = getBookmarkElements(powerBookmarksList);
+    const folderElement = bookmarkElements[1]!;
+    assertEquals(folderElement.id, 'bookmark-4');
+
+    const descriptionElement =
+        folderElement.shadowRoot!.getElementById('description');
+    const expandedDescription = 'child';
+    assertEquals(
+        descriptionElement!.textContent!.includes(expandedDescription), true);
+  });
+
+  test('SetsExpandedSearchResultDescription', () => {
+    const menu =
+        powerBookmarksList.shadowRoot!.querySelector('cr-action-menu')!;
+    menu.showAt(powerBookmarksList);
+    const visualViewButton: HTMLElement = menu.querySelector('#visualView')!;
+    visualViewButton.click();
+
+    const searchField = powerBookmarksList.shadowRoot!.querySelector(
+        'cr-toolbar-search-field')!;
+    searchField.$.searchInput.value = 'child bookmark';
+    searchField.onSearchTermInput();
+    searchField.onSearchTermSearch();
+
+    flush();
+
+    const bookmarkElements = getBookmarkElements(powerBookmarksList);
+    const folderElement = bookmarkElements[0]!;
+    assertEquals(folderElement.id, 'bookmark-4');
+
+    const descriptionElement =
+        folderElement.shadowRoot!.getElementById('description');
+    const expandedDescription = 'child - All Bookmarks';
+    assertEquals(
+        descriptionElement!.textContent!.includes(expandedDescription), true);
+  });
 });
diff --git a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts
index b09039cc0..9833590 100644
--- a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts
+++ b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts
@@ -11,65 +11,11 @@
 import {BookmarkProductInfo} from 'chrome://bookmarks-side-panel.top-chrome/shopping_list.mojom-webui.js';
 import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
 import {assertEquals} from 'chrome://webui-test/chai_assert.js';
-import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
 import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js';
 
 import {TestShoppingListApiProxy} from './commerce/test_shopping_list_api_proxy.js';
 import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js';
-
-class TestPowerBookmarksDelegate extends TestBrowserProxy {
-  constructor() {
-    super([
-      'setCurrentUrl',
-      'setCompactDescription',
-      'setExpandedDescription',
-      'onBookmarksLoaded',
-      'onBookmarkChanged',
-      'onBookmarkCreated',
-      'onBookmarkMoved',
-      'onBookmarkRemoved',
-    ]);
-  }
-
-  setCurrentUrl(url: string|undefined) {
-    this.methodCalled('setCurrentUrl', url);
-  }
-
-  setCompactDescription(
-      bookmark: chrome.bookmarks.BookmarkTreeNode, description: string) {
-    this.methodCalled('setCompactDescription', bookmark, description);
-  }
-
-  setExpandedDescription(
-      bookmark: chrome.bookmarks.BookmarkTreeNode, description: string) {
-    this.methodCalled('setExpandedDescription', bookmark, description);
-  }
-
-  onBookmarksLoaded() {
-    this.methodCalled('onBookmarksLoaded');
-  }
-
-  onBookmarkChanged(id: string, changedInfo: chrome.bookmarks.ChangeInfo) {
-    this.methodCalled('onBookmarkChanged', id, changedInfo);
-  }
-
-  onBookmarkCreated(
-      bookmark: chrome.bookmarks.BookmarkTreeNode,
-      parent: chrome.bookmarks.BookmarkTreeNode) {
-    this.methodCalled('onBookmarkCreated', bookmark, parent);
-  }
-
-  onBookmarkMoved(
-      bookmark: chrome.bookmarks.BookmarkTreeNode,
-      oldParent: chrome.bookmarks.BookmarkTreeNode,
-      newParent: chrome.bookmarks.BookmarkTreeNode) {
-    this.methodCalled('onBookmarkMoved', bookmark, oldParent, newParent);
-  }
-
-  onBookmarkRemoved(bookmark: chrome.bookmarks.BookmarkTreeNode) {
-    this.methodCalled('onBookmarkRemoved', bookmark);
-  }
-}
+import {TestPowerBookmarksDelegate} from './test_power_bookmarks_delegate.js';
 
 suite('SidePanelPowerBookmarksServiceTest', () => {
   let delegate: TestPowerBookmarksDelegate;
@@ -145,10 +91,11 @@
     delegate = new TestPowerBookmarksDelegate();
     service = new PowerBookmarksService(delegate);
     service.startListening();
+
+    await delegate.whenCalled('onBookmarksLoaded');
   });
 
   test('FiltersTopLevelBookmarks', () => {
-    assertEquals(1, delegate.getCallCount('onBookmarksLoaded'));
     const defaultBookmarks =
         service.filterBookmarks(undefined, 0, undefined, []);
     assertEquals(folders[0]!.children!.length, defaultBookmarks.length);
@@ -163,7 +110,7 @@
 
   test('FiltersBySearchQuery', () => {
     const searchBookmarks = service.filterBookmarks(undefined, 0, 'http', []);
-    assertEquals(searchBookmarks.length, 2);
+    assertEquals(searchBookmarks.length, 3);
   });
 
   test('FiltersByPriceTracking', () => {
diff --git a/chrome/test/data/webui/side_panel/bookmarks/test_power_bookmarks_delegate.ts b/chrome/test/data/webui/side_panel/bookmarks/test_power_bookmarks_delegate.ts
new file mode 100644
index 0000000..81e868bf
--- /dev/null
+++ b/chrome/test/data/webui/side_panel/bookmarks/test_power_bookmarks_delegate.ts
@@ -0,0 +1,59 @@
+// 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 {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
+
+export class TestPowerBookmarksDelegate extends TestBrowserProxy {
+  constructor() {
+    super([
+      'setCurrentUrl',
+      'setCompactDescription',
+      'setExpandedDescription',
+      'onBookmarksLoaded',
+      'onBookmarkChanged',
+      'onBookmarkCreated',
+      'onBookmarkMoved',
+      'onBookmarkRemoved',
+    ]);
+  }
+
+  setCurrentUrl(url: string|undefined) {
+    this.methodCalled('setCurrentUrl', url);
+  }
+
+  setCompactDescription(
+      bookmark: chrome.bookmarks.BookmarkTreeNode, description: string) {
+    this.methodCalled('setCompactDescription', bookmark, description);
+  }
+
+  setExpandedDescription(
+      bookmark: chrome.bookmarks.BookmarkTreeNode, description: string) {
+    this.methodCalled('setExpandedDescription', bookmark, description);
+  }
+
+  onBookmarksLoaded() {
+    this.methodCalled('onBookmarksLoaded');
+  }
+
+  onBookmarkChanged(id: string, changedInfo: chrome.bookmarks.ChangeInfo) {
+    this.methodCalled('onBookmarkChanged', id, changedInfo);
+  }
+
+  onBookmarkCreated(
+      bookmark: chrome.bookmarks.BookmarkTreeNode,
+      parent: chrome.bookmarks.BookmarkTreeNode) {
+    this.methodCalled('onBookmarkCreated', bookmark, parent);
+  }
+
+  onBookmarkMoved(
+      bookmark: chrome.bookmarks.BookmarkTreeNode,
+      oldParent: chrome.bookmarks.BookmarkTreeNode,
+      newParent: chrome.bookmarks.BookmarkTreeNode) {
+    this.methodCalled('onBookmarkMoved', bookmark, oldParent, newParent);
+  }
+
+  onBookmarkRemoved(bookmark: chrome.bookmarks.BookmarkTreeNode) {
+    this.methodCalled('onBookmarkRemoved', bookmark);
+  }
+}
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/cards_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/cards_test.ts
index feeae87..dc55741d 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/cards_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/cards_test.ts
@@ -299,4 +299,31 @@
           1, metrics.count('NewTabPage.Modules.Disabled', 'chrome_cart'));
     });
   });
+
+  test('only animates after initialization', async () => {
+    // Arrange.
+    customizeCards = document.createElement('customize-chrome-cards');
+    document.body.appendChild(customizeCards);
+
+    // Assert (no animation before initialize).
+    assertTrue(getCollapseElement().noAnimation!);
+
+    // Act (initialize).
+    callbackRouterRemote.setModulesSettings(
+        [{id: 'foo', name: 'Foo', enabled: true}], /*modulesManaged=*/ false,
+        /*modulesVisible=*/ true);
+    await callbackRouterRemote.$.flushForTesting();
+
+    // Assert (animation after initialize).
+    assertFalse(getCollapseElement().noAnimation!);
+
+    // Act (update).
+    callbackRouterRemote.setModulesSettings(
+        [{id: 'bar', name: 'Bar', enabled: true}], /*modulesManaged=*/ false,
+        /*modulesVisible=*/ true);
+    await callbackRouterRemote.$.flushForTesting();
+
+    // Assert (still animation after update).
+    assertFalse(getCollapseElement().noAnimation!);
+  });
 });
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/shortcuts_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/shortcuts_test.ts
index 6e750a38..20ef1763 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/shortcuts_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/shortcuts_test.ts
@@ -124,4 +124,31 @@
     assertFalse(customLinksEnabled);
     assertTrue(shortcutsVisible);
   });
+
+  test('only animates after initialization', async () => {
+    customizeShortcutsElement =
+        document.createElement('customize-chrome-shortcuts');
+    document.body.appendChild(customizeShortcutsElement);
+    const ironCollapse =
+        customizeShortcutsElement.shadowRoot!.querySelector('iron-collapse')!;
+
+    // No animation before initialize.
+    assertTrue(ironCollapse.noAnimation!);
+
+    // Initialize.
+    callbackRouterRemote.setMostVisitedSettings(
+        /*customLinksEnabled=*/ true, /*shortcutsVisible=*/ true);
+    await callbackRouterRemote.$.flushForTesting();
+
+    // Animation after initialize.
+    assertFalse(ironCollapse.noAnimation!);
+
+    // Update.
+    callbackRouterRemote.setMostVisitedSettings(
+        /*customLinksEnabled=*/ false, /*shortcutsVisible=*/ true);
+    await callbackRouterRemote.$.flushForTesting();
+
+    // Still animation after update.
+    assertFalse(ironCollapse.noAnimation!);
+  });
 });
diff --git a/chrome/test/data/webui/side_panel/side_panel_browsertest.js b/chrome/test/data/webui/side_panel/side_panel_browsertest.js
index 88c81e1..4269e61 100644
--- a/chrome/test/data/webui/side_panel/side_panel_browsertest.js
+++ b/chrome/test/data/webui/side_panel/side_panel_browsertest.js
@@ -29,6 +29,17 @@
   mocha.run();
 });
 
+var SidePanelPowerBookmarksEditDialogTest = class extends SidePanelBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://bookmarks-side-panel.top-chrome/test_loader.html?module=side_panel/bookmarks/power_bookmarks_edit_dialog_test.js';
+  }
+};
+
+TEST_F('SidePanelPowerBookmarksEditDialogTest', 'All', function() {
+  mocha.run();
+});
+
 var SidePanelPowerBookmarksListTest = class extends SidePanelBrowserTest {
   /** @override */
   get browsePreload() {
diff --git a/chrome/test/data/webui/whats_new/BUILD.gn b/chrome/test/data/webui/whats_new/BUILD.gn
index 78a362f..2b1c7e1 100644
--- a/chrome/test/data/webui/whats_new/BUILD.gn
+++ b/chrome/test/data/webui/whats_new/BUILD.gn
@@ -2,43 +2,26 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//tools/typescript/ts_library.gni")
-import("//ui/webui/resources/tools/generate_grd.gni")
+import("../build_webui_tests.gni")
 
 assert(!is_android)
 
-ts_library("build_ts") {
-  root_dir = "."
-  out_dir = "$target_gen_dir/tsc"
-  tsconfig_base = "tsconfig_base.json"
-  path_mappings = [
-    "chrome://whats-new/*|" +
-        rebase_path("$root_gen_dir/chrome/browser/resources/whats_new/tsc/*",
-                    target_gen_dir),
-    "chrome://webui-test/*|" +
-        rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*",
-                    target_gen_dir),
-  ]
-  in_files = [ "whats_new_app_test.ts" ]
-  deps = [
-    "..:build_ts",
-    "//chrome/browser/resources/whats_new:build_ts",
-  ]
-}
+build_webui_tests("build") {
+  resource_path_prefix = "whats_new"
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_whats_new"
-  out_grd = "$target_gen_dir/resources.grdp"
+  files = [
+    "whats_new_app_test.ts",
+    "test_with_command_3.ts",
+  ]
 
-  input_files_base_dir = rebase_path(".", "//")
-  input_files = [
+  static_files = [
     "test.html",
     "test_with_command_3.html",
-    "test_with_command_3.js",
   ]
 
-  deps = [ ":build_ts" ]
-  manifest_files =
-      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
-  resource_path_prefix = "whats_new"
+  ts_path_mappings =
+      [ "chrome://whats-new/*|" +
+        rebase_path("$root_gen_dir/chrome/browser/resources/whats_new/tsc/*",
+                    target_gen_dir) ]
+  ts_deps = [ "//chrome/browser/resources/whats_new:build_ts" ]
 }
diff --git a/chrome/test/data/webui/whats_new/test_with_command_3.html b/chrome/test/data/webui/whats_new/test_with_command_3.html
index 0a72933..e1af07f 100644
--- a/chrome/test/data/webui/whats_new/test_with_command_3.html
+++ b/chrome/test/data/webui/whats_new/test_with_command_3.html
@@ -3,5 +3,5 @@
 <body>
   <div>Test page for What's New iframe</div>
 </body>
-<script src="test_with_command_3.js"></script>
+<script type="module" src="test_with_command_3.js"></script>
 </html>
diff --git a/chrome/test/data/webui/whats_new/test_with_command_3.js b/chrome/test/data/webui/whats_new/test_with_command_3.ts
similarity index 74%
rename from chrome/test/data/webui/whats_new/test_with_command_3.js
rename to chrome/test/data/webui/whats_new/test_with_command_3.ts
index 40eaa15e9..2628e5f 100644
--- a/chrome/test/data/webui/whats_new/test_with_command_3.js
+++ b/chrome/test/data/webui/whats_new/test_with_command_3.ts
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {assertTrue} from 'chrome://webui-test/chai_assert.js';
+
 window.onload = function() {
+  assertTrue(!!window.top);
   window.top.postMessage(
       {'data': {'commandId': 3, 'clickInfo': {}}}, 'chrome://whats-new/');
 };
diff --git a/chrome/updater/app/app_install_win.cc b/chrome/updater/app/app_install_win.cc
index 1b70175..7a926dc 100644
--- a/chrome/updater/app/app_install_win.cc
+++ b/chrome/updater/app/app_install_win.cc
@@ -544,7 +544,7 @@
                       std::string install_args;
                       std::string install_data;
                       ReadInstallCommandFromManifest(
-                          cmd_line.GetSwitchValuePath(kOfflineDirSwitch),
+                          cmd_line.GetSwitchValueNative(kOfflineDirSwitch),
                           app_id,
                           GetInstallDataIndexFromAppArgsForCommandLine(cmd_line,
                                                                        app_id),
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index 1124427..d44a2c2 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -376,7 +376,7 @@
                                           const base::FilePath& exe_path,
                                           UpdaterScope install_scope,
                                           const std::wstring& app_id,
-                                          const base::FilePath& offline_dir,
+                                          const std::wstring& offline_dir_guid,
                                           bool is_silent_install) {
   auto launch_legacy_offline_install = [&]() -> base::Process {
     auto build_legacy_switch =
@@ -404,7 +404,7 @@
         L"{E85204C6-6F2F-40BF-9E6C-4952208BB977}",
 
         build_legacy_switch(updater::kOfflineDirSwitch),
-        base::CommandLine::QuoteForCommandLineToArgvW(offline_dir.value()),
+        base::CommandLine::QuoteForCommandLineToArgvW(offline_dir_guid),
 
         is_silent_install ? build_legacy_switch(updater::kSilentSwitch) : L"",
     };
@@ -427,7 +427,7 @@
     install_cmd.AppendSwitchASCII(updater::kSessionIdSwitch,
                                   "{E85204C6-6F2F-40BF-9E6C-4952208BB977}");
     install_cmd.AppendSwitchNative(updater::kOfflineDirSwitch,
-                                   offline_dir.value());
+                                   offline_dir_guid);
     if (is_silent_install)
       install_cmd.AppendSwitch(updater::kSilentSwitch);
 
@@ -1548,18 +1548,32 @@
       "  </app>\n"
       "</response>\n";
 
+  const std::wstring manifest_filename(L"OfflineManifest.gup");
+  const std::wstring cmd_exe_arbitrarily_named(L"arbitrarily_named_cmd.exe");
+  const std::string script_name("test_installer.bat");
+  const std::wstring offline_dir_guid(
+      L"{7B3A5597-DDEA-409B-B900-4C3D2A94A75C}");
   const HKEY root = UpdaterScopeToHKeyRoot(scope);
   const std::wstring app_client_state_key = GetAppClientStateKey(kTestAppID);
 
   EXPECT_TRUE(DeleteRegKey(root, app_client_state_key));
 
-  base::ScopedTempDir temp_dir;
-  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
-  const base::FilePath& offline_dir = temp_dir.GetPath();
+  const absl::optional<base::FilePath> updater_exe =
+      GetInstalledExecutablePath(scope);
+  ASSERT_TRUE(updater_exe.has_value());
+
+  const base::FilePath exe_dir(updater_exe->DirName());
+  const base::FilePath offline_dir(
+      exe_dir.Append(L"Offline").Append(offline_dir_guid));
+  const base::FilePath offline_app_dir(offline_dir.Append(kTestAppID));
+  const base::FilePath offline_app_scripts_dir(
+      offline_app_dir.Append(L"Scripts"));
+  ASSERT_TRUE(base::CreateDirectory(offline_app_scripts_dir));
 
   // Create a batch file as the installer script, which creates some registry
   // values as the installation artifacts.
-  base::FilePath installer_path = offline_dir.AppendASCII("test_installer.bat");
+  const base::FilePath batch_script_path(
+      offline_app_scripts_dir.AppendASCII(script_name));
 
   // Create a unique name for a shared event to be waited for in this process
   // and signaled in the offline installer process to confirm the installer
@@ -1567,7 +1581,7 @@
   test::EventHolder event_holder(test::CreateWaitableEventForTest());
 
   EXPECT_TRUE(base::WriteFile(
-      installer_path,
+      batch_script_path,
       [](UpdaterScope scope, const std::string& app_client_state_key,
          const std::wstring& event_name) -> std::string {
         const std::string reg_hive = IsSystemInstall(scope) ? "HKLM" : "HKCU";
@@ -1602,27 +1616,21 @@
   base::FilePath cmd_exe_path;
   ASSERT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd_exe_path));
   cmd_exe_path = cmd_exe_path.Append(L"cmd.exe");
-  ASSERT_TRUE(base::CopyFile(cmd_exe_path,
-                             offline_dir.Append(cmd_exe_path.BaseName())));
+  ASSERT_TRUE(base::CopyFile(
+      cmd_exe_path, offline_app_dir.Append(cmd_exe_arbitrarily_named)));
 
-  // Create manifest file.
-  base::FilePath manifest_path =
-      offline_dir.Append(FILE_PATH_LITERAL("OfflineManifest.gup"));
+  base::FilePath manifest_path = offline_dir.Append(manifest_filename);
   int64_t exe_size = 0;
   EXPECT_TRUE(base::GetFileSize(cmd_exe_path, &exe_size));
   const std::string manifest = base::StringPrintf(
-      kManifestFormat, kTestAppID, exe_size, installer_path.value().c_str());
+      kManifestFormat, kTestAppID, exe_size, batch_script_path.value().c_str());
   EXPECT_TRUE(base::WriteFile(manifest_path, manifest));
 
   // Trigger offline install.
-  const absl::optional<base::FilePath> updater_exe =
-      GetInstalledExecutablePath(scope);
-  ASSERT_TRUE(updater_exe.has_value());
-
-  ASSERT_TRUE(
-      LaunchOfflineInstallProcess(is_legacy_install, updater_exe.value(), scope,
-                                  kTestAppID, offline_dir, is_silent_install)
-          .IsValid());
+  ASSERT_TRUE(LaunchOfflineInstallProcess(
+                  is_legacy_install, updater_exe.value(), scope, kTestAppID,
+                  offline_dir_guid, is_silent_install)
+                  .IsValid());
 
   if (is_silent_install) {
     EXPECT_TRUE(WaitForUpdaterExit(scope));
diff --git a/chrome/updater/win/manifest_util.cc b/chrome/updater/win/manifest_util.cc
index 6081781..d721e49 100644
--- a/chrome/updater/win/manifest_util.cc
+++ b/chrome/updater/win/manifest_util.cc
@@ -85,29 +85,31 @@
 }  // namespace
 
 // TODO(crbug/1409111): Handle errors for offline dir or manifest errors.
-// TODO(crbug/1409111): Remove unneeded offline dir formats.
 void ReadInstallCommandFromManifest(
-    const base::FilePath& offline_dir_input,
+    const std::wstring& offline_dir_guid,
     const std::string& app_id,
     const std::string& install_data_index,
     update_client::ProtocolParser::Results& results,
     base::FilePath& installer_path,
     std::string& install_args,
     std::string& install_data) {
-  if (offline_dir_input.empty()) {
+  if (offline_dir_guid.empty()) {
     VLOG(1) << "Unexpected: offline install without an offline directory.";
     return;
   }
 
-  const bool is_offline_dir_relative = IsGuid(offline_dir_input.value());
-  const base::FilePath offline_dir =
-      is_offline_dir_relative ? [&offline_dir_input]() {
-        base::FilePath offline_dir;
-        return base::PathService::Get(base::DIR_EXE, &offline_dir)
-                   ? offline_dir.Append(L"Offline").Append(offline_dir_input)
-                   : base::FilePath();
-      }()
-                              : offline_dir_input;
+  if (!IsGuid(offline_dir_guid)) {
+    VLOG(1) << "Unexpected: offline directory needs to be a GUID: "
+            << offline_dir_guid;
+    return;
+  }
+
+  const base::FilePath offline_dir = [&offline_dir_guid]() {
+    base::FilePath offline_dir;
+    return base::PathService::Get(base::DIR_EXE, &offline_dir)
+               ? offline_dir.Append(L"Offline").Append(offline_dir_guid)
+               : base::FilePath();
+  }();
   if (offline_dir.empty()) {
     VLOG(1) << "Unexpected: offline directory empty.";
     return;
@@ -132,7 +134,7 @@
   }
 
   installer_path =
-      is_offline_dir_relative ? [&offline_dir, &app_id, &it]() {
+      [&offline_dir, &app_id, &it]() {
         const base::FilePath app_dir(offline_dir.AppendASCII(app_id));
         const base::FilePath path(app_dir.AppendASCII(it->manifest.run));
         return base::PathExists(path)
@@ -142,8 +144,7 @@
                          base::FileEnumerator::FolderSearchPolicy::ALL,
                          base::FileEnumerator::ErrorPolicy::IGNORE_ERRORS)
                          .Next();
-      }()
-                              : offline_dir.AppendASCII(it->manifest.run);
+      }();
   install_args = it->manifest.arguments;
 
   if (!install_data_index.empty()) {
diff --git a/chrome/updater/win/manifest_util.h b/chrome/updater/win/manifest_util.h
index 83113e0..4255a734 100644
--- a/chrome/updater/win/manifest_util.h
+++ b/chrome/updater/win/manifest_util.h
@@ -17,16 +17,17 @@
 
 // Parses the offline manifest file and extracts the app install command line.
 //
-// The function looks for the manifest file "OfflineManifest.gup" in
-// `offline_dir`, and falls back to "<app_id>.gup" in the same directory if
+// The function looks for the manifest file "OfflineManifest.gup" inside the
+// offline directory, and falls back to "<app_id>.gup" in the same directory if
 // needed.
 //
-// The offline dir can be specified as a relative path when it is in the format
-// "/offlinedir {GUID}". In this case:
-// * the actual offline directory is `{CURRENT_PROCESS_DIR}\Offline\{GUID}`,
-// * the offline manifest is
-// `{CURRENT_PROCESS_DIR}\Offline\{GUID}\OfflineManifest.gup`, and
-// * the installer is at
+// `offline_dir_guid`: the offline directory is specified on the command line as
+// a relative path in the format "/offlinedir {GUID}", where `{GUID}` is the
+// `offline_dir_guid` parameter.
+// * The actual offline directory is at `{CURRENT_PROCESS_DIR}\Offline\{GUID}`.
+// * The offline manifest is at
+// `{CURRENT_PROCESS_DIR}\Offline\{GUID}\OfflineManifest.gup`.
+// * The installer is at
 // `{CURRENT_PROCESS_DIR}\Offline\{GUID}\{app_id}\installer.exe`.
 //   * `installer.exe` may not correspond exactly to the value of the manifest's
 //   `run` attribute, so the code picks the first file it finds in the
@@ -46,7 +47,7 @@
 //                   installation, the text will be serialized to a file and
 //                   passed to the app installer.
 void ReadInstallCommandFromManifest(
-    const base::FilePath& offline_dir,
+    const std::wstring& offline_dir_guid,
     const std::string& app_id,
     const std::string& install_data_index,
     update_client::ProtocolParser::Results& results,
diff --git a/chrome/updater/win/manifest_util_unittest.cc b/chrome/updater/win/manifest_util_unittest.cc
index f4cbcf4..79848231 100644
--- a/chrome/updater/win/manifest_util_unittest.cc
+++ b/chrome/updater/win/manifest_util_unittest.cc
@@ -18,34 +18,11 @@
 namespace updater {
 
 TEST(ManifestUtil, ReadInstallCommandFromManifest) {
-  update_client::ProtocolParser::Results results;
-  base::FilePath installer_path;
-  std::string install_args;
-  std::string install_data;
-
-  base::FilePath offline_dir;
-  ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &offline_dir));
-  offline_dir = offline_dir.Append(FILE_PATH_LITERAL("updater"));
-
-  ReadInstallCommandFromManifest(
-      offline_dir, "{CDABE316-39CD-43BA-8440-6D1E0547AEE6}", "verboselogging",
-      results, installer_path, install_args, install_data);
-  EXPECT_EQ(installer_path, offline_dir.AppendASCII("my_installer.exe"));
-  EXPECT_EQ(install_args, "-baz");
-  EXPECT_EQ(install_data,
-            "{\n"
-            "        \"distribution\": {\n"
-            "          \"verbose_logging\": true\n"
-            "        }\n"
-            "      }");
-}
-
-TEST(ManifestUtil, ReadInstallCommandFromManifest_OfflineDirRelative) {
   const std::string app_id("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
   const std::wstring manifest_filename(L"OfflineManifest.gup");
   const std::wstring executable_name(L"my_installer.exe");
   const std::wstring executable_name_v2(L"random_named_my_installer.exe");
-  const base::FilePath offline_dir_relative(
+  const std::wstring offline_dir_guid(
       L"{7B3A5597-DDEA-409B-B900-4C3D2A94A75C}");
 
   base::FilePath exe_dir;
@@ -55,7 +32,7 @@
   ASSERT_TRUE(scoped_offline_base_dir.Set(exe_dir.Append(L"Offline")));
 
   const base::FilePath offline_dir(
-      scoped_offline_base_dir.GetPath().Append(offline_dir_relative));
+      scoped_offline_base_dir.GetPath().Append(offline_dir_guid));
 
   base::FilePath test_manifest;
   ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_manifest));
@@ -80,7 +57,7 @@
   std::string install_args;
   std::string install_data;
 
-  ReadInstallCommandFromManifest(offline_dir_relative, app_id, "verboselogging",
+  ReadInstallCommandFromManifest(offline_dir_guid, app_id, "verboselogging",
                                  results, installer_path, install_args,
                                  install_data);
   EXPECT_EQ(installer_path, expected_installer_path);
@@ -96,7 +73,7 @@
       offline_app_dir.Append(executable_name_v2));
   ASSERT_TRUE(base::Move(expected_installer_path, expected_installer_path_v2));
 
-  ReadInstallCommandFromManifest(offline_dir_relative, app_id, "verboselogging",
+  ReadInstallCommandFromManifest(offline_dir_guid, app_id, "verboselogging",
                                  results, installer_path, install_args,
                                  install_data);
   EXPECT_EQ(installer_path, expected_installer_path_v2);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 0ce2835..1a00fac 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-15324.0.0
\ No newline at end of file
+15326.0.0
\ No newline at end of file
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
index 74dc4bb6..80fb88d 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
@@ -26,8 +26,8 @@
 namespace drivefs::pinning {
 namespace {
 
-bool InProgress(const SetupStage stage) {
-  return stage > SetupStage::kNotStarted && stage < SetupStage::kSuccess;
+bool InProgress(const Stage stage) {
+  return stage > Stage::kNotStarted && stage < Stage::kSuccess;
 }
 
 int Percentage(const int64_t a, const int64_t b) {
@@ -44,7 +44,7 @@
 
 // Calls `base::SysInfo::AmountOfFreeDiskSpace` on a blocking thread.
 void GetFreeSpace(const base::FilePath& path,
-                  DriveFsPinManager::SpaceResult callback) {
+                  PinManager::SpaceResult callback) {
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock()},
       base::BindOnce(&base::SysInfo::AmountOfFreeDiskSpace, path),
@@ -136,8 +136,7 @@
 
 std::ostream& operator<<(std::ostream& out, Quoter<mojom::FileMetadata> q) {
   const mojom::FileMetadata& md = q.value;
-  return out << "{" << Quote(md.type) << " "
-             << DriveFsPinManager::StableId(md.stable_id)
+  return out << "{" << Quote(md.type) << " " << PinManager::Id(md.stable_id)
              << ", size: " << HumanReadableSize(md.size)
              << ", pinned: " << md.pinned << ", can_pin: "
              << (md.can_pin == mojom::FileMetadata::CanPinStatus::kOk)
@@ -148,9 +147,8 @@
 
 std::ostream& operator<<(std::ostream& out, Quoter<mojom::ItemEvent> q) {
   const mojom::ItemEvent& e = q.value;
-  return out << "{" << Quote(e.state) << " "
-             << DriveFsPinManager::StableId(e.stable_id) << " " << Quote(e.path)
-             << ", bytes_transferred: "
+  return out << "{" << Quote(e.state) << " " << PinManager::Id(e.stable_id)
+             << " " << Quote(e.path) << ", bytes_transferred: "
              << HumanReadableSize(e.bytes_transferred)
              << ", bytes_to_transfer: "
              << HumanReadableSize(e.bytes_to_transfer) << "}";
@@ -159,8 +157,8 @@
 std::ostream& operator<<(std::ostream& out, Quoter<mojom::FileChange> q) {
   const mojom::FileChange& change = q.value;
   return out << "{" << Quote(change.type) << " "
-             << DriveFsPinManager::StableId(change.stable_id) << " "
-             << Quote(change.path) << "}";
+             << PinManager::Id(change.stable_id) << " " << Quote(change.path)
+             << "}";
 }
 
 std::ostream& operator<<(std::ostream& out, Quoter<mojom::DriveError::Type> q) {
@@ -182,9 +180,8 @@
 
 std::ostream& operator<<(std::ostream& out, Quoter<mojom::DriveError> q) {
   const mojom::DriveError& e = q.value;
-  return out << "{" << Quote(e.type) << " "
-             << DriveFsPinManager::StableId(e.stable_id) << " " << Quote(e.path)
-             << "}";
+  return out << "{" << Quote(e.type) << " " << PinManager::Id(e.stable_id)
+             << " " << Quote(e.path) << "}";
 }
 
 // Rounds the given size to the next multiple of 4-KB.
@@ -205,7 +202,7 @@
 bool CanPinItem(const mojom::FileMetadata& metadata,
                 const base::FilePath& path) {
   using Type = mojom::FileMetadata::Type;
-  const auto id = DriveFsPinManager::StableId(metadata.stable_id);
+  const auto id = PinManager::Id(metadata.stable_id);
 
   if (metadata.type == Type::kDirectory) {
     VLOG(2) << "Skipped " << id << " " << Quote(path) << ": Directory";
@@ -238,8 +235,7 @@
 
 }  // namespace
 
-std::ostream& operator<<(std::ostream& out,
-                         const DriveFsPinManager::StableId id) {
+std::ostream& operator<<(std::ostream& out, const PinManager::Id id) {
   return out << "#" << static_cast<int64_t>(id);
 }
 
@@ -277,10 +273,10 @@
   return out << base::StringPrintf(" (%.*f %c)", precision, d, *unit);
 }
 
-std::ostream& operator<<(std::ostream& out, const SetupStage stage) {
+std::ostream& operator<<(std::ostream& out, const Stage stage) {
   switch (stage) {
-#define PRINT(s)         \
-  case SetupStage::k##s: \
+#define PRINT(s)    \
+  case Stage::k##s: \
     return out << #s;
     PRINT(NotStarted)
     PRINT(GettingFreeSpace)
@@ -294,27 +290,25 @@
 #undef PRINT
   }
 
-  return out << "SetupStage("
-             << static_cast<std::underlying_type_t<SetupStage>>(stage) << ")";
+  return out << "Stage(" << static_cast<std::underlying_type_t<Stage>>(stage)
+             << ")";
 }
 
-SetupProgress::SetupProgress() = default;
-SetupProgress::SetupProgress(const SetupProgress&) = default;
-SetupProgress& SetupProgress::operator=(const SetupProgress&) = default;
+Progress::Progress() = default;
+Progress::Progress(const Progress&) = default;
+Progress& Progress::operator=(const Progress&) = default;
 
 // TODO(b/261530666): This was chosen arbitrarily, this should be experimented
 // with and potentially made dynamic depending on feedback of the in progress
 // queue.
 constexpr base::TimeDelta kPeriodicRemovalInterval = base::Seconds(10);
 
-bool DriveFsPinManager::Add(const StableId id,
-                            const std::string& path,
-                            const int64_t size) {
+bool PinManager::Add(const Id id, const std::string& path, const int64_t size) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_GE(size, 0) << " for " << id << " " << Quote(path);
 
   const auto [it, ok] =
-      files_to_pin_.try_emplace(id, Progress{.path = path, .total = size});
+      files_to_pin_.try_emplace(id, File{.path = path, .total = size});
   DCHECK_EQ(id, it->first);
   if (!ok) {
     LOG_IF(ERROR, !ok) << "Cannot add " << id << " " << Quote(path)
@@ -333,9 +327,9 @@
   return true;
 }
 
-bool DriveFsPinManager::Remove(const StableId id,
-                               const std::string& path,
-                               int64_t transferred) {
+bool PinManager::Remove(const Id id,
+                        const std::string& path,
+                        int64_t transferred) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   const Files::iterator it = files_to_track_.find(id);
@@ -355,10 +349,10 @@
   return true;
 }
 
-bool DriveFsPinManager::Update(const StableId id,
-                               const std::string& path,
-                               const int64_t transferred,
-                               const int64_t total) {
+bool PinManager::Update(const Id id,
+                        const std::string& 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);
@@ -371,65 +365,65 @@
   return Update(*it, path, transferred, total);
 }
 
-bool DriveFsPinManager::Update(Files::value_type& entry,
-                               const std::string& path,
-                               int64_t transferred,
-                               int64_t total) {
+bool PinManager::Update(Files::value_type& entry,
+                        const std::string& path,
+                        int64_t transferred,
+                        int64_t total) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  auto& [id, progress] = entry;
+  auto& [id, file] = entry;
   bool modified = false;
 
-  if (path != progress.path) {
-    VLOG(1) << "Changed path of " << id << " " << Quote(progress.path) << " to "
+  if (path != file.path) {
+    VLOG(1) << "Changed path of " << id << " " << Quote(file.path) << " to "
             << Quote(path);
-    progress.path = path;
+    file.path = path;
     modified = true;
   }
 
-  if (!progress.in_progress) {
-    LOG_IF(ERROR, progress.transferred > 0)
+  if (!file.in_progress) {
+    LOG_IF(ERROR, file.transferred > 0)
         << "Queued " << id << " " << Quote(path) << " already has transferred "
-        << HumanReadableSize(progress.transferred);
+        << HumanReadableSize(file.transferred);
 
-    progress.in_progress = true;
+    file.in_progress = true;
     modified = true;
   }
 
-  if (transferred != progress.transferred && transferred >= 0) {
-    LOG_IF(ERROR, transferred < progress.transferred)
+  if (transferred != file.transferred && transferred >= 0) {
+    LOG_IF(ERROR, transferred < file.transferred)
         << "Progress went backwards from "
-        << HumanReadableSize(progress.transferred) << " to "
+        << HumanReadableSize(file.transferred) << " to "
         << HumanReadableSize(transferred) << " for " << id << " "
         << Quote(path);
-    progress_.pinned_bytes += transferred - progress.transferred;
-    progress.transferred = transferred;
+    progress_.pinned_bytes += transferred - file.transferred;
+    file.transferred = transferred;
     modified = true;
   }
 
-  if (total != progress.total && total >= 0) {
+  if (total != file.total && total >= 0) {
     LOG(ERROR) << "Changed expected size of " << id << " " << Quote(path)
-               << " from " << HumanReadableSize(progress.total) << " to "
+               << " from " << HumanReadableSize(file.total) << " to "
                << HumanReadableSize(total);
-    progress_.bytes_to_pin += total - progress.total;
+    progress_.bytes_to_pin += total - file.total;
     progress_.required_space +=
-        RoundToBlockSize(total) - RoundToBlockSize(progress.total);
-    progress.total = total;
+        RoundToBlockSize(total) - RoundToBlockSize(file.total);
+    file.total = total;
     modified = true;
   }
 
   return modified;
 }
 
-DriveFsPinManager::DriveFsPinManager(base::FilePath profile_path,
-                                     mojom::DriveFs* const drivefs)
+PinManager::PinManager(base::FilePath profile_path,
+                       mojom::DriveFs* const drivefs)
     : space_getter_(base::BindRepeating(&GetFreeSpace)),
       profile_path_(std::move(profile_path)),
       drivefs_(drivefs) {
   DCHECK(drivefs_);
 }
 
-DriveFsPinManager::~DriveFsPinManager() {
+PinManager::~PinManager() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!InProgress(progress_.stage)) << "Pin manager is " << progress_.stage;
   for (Observer& observer : observers_) {
@@ -438,7 +432,7 @@
   observers_.Clear();
 }
 
-void DriveFsPinManager::Start() {
+void PinManager::Start() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!InProgress(progress_.stage)) << "Pin manager is " << progress_.stage;
 
@@ -448,24 +442,24 @@
 
   VLOG(1) << "Calculating free space...";
   timer_ = base::ElapsedTimer();
-  progress_.stage = SetupStage::kGettingFreeSpace;
+  progress_.stage = Stage::kGettingFreeSpace;
   NotifyProgress();
 
   space_getter_.Run(
       profile_path_.AppendASCII("GCache"),
-      base::BindOnce(&DriveFsPinManager::OnFreeSpaceRetrieved, GetWeakPtr()));
+      base::BindOnce(&PinManager::OnFreeSpaceRetrieved, GetWeakPtr()));
 }
 
-void DriveFsPinManager::Stop() {
+void PinManager::Stop() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (InProgress(progress_.stage)) {
     VLOG(1) << "Stopping";
-    Complete(SetupStage::kStopped);
+    Complete(Stage::kStopped);
   }
 }
 
-void DriveFsPinManager::Enable(bool enabled) {
+void PinManager::Enable(bool enabled) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (enabled == InProgress(progress_.stage)) {
@@ -482,12 +476,12 @@
   }
 }
 
-void DriveFsPinManager::OnFreeSpaceRetrieved(const int64_t free_space) {
+void PinManager::OnFreeSpaceRetrieved(const int64_t free_space) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (free_space < 0) {
     LOG(ERROR) << "Cannot calculate free space";
-    return Complete(SetupStage::kCannotGetFreeSpace);
+    return Complete(Stage::kCannotGetFreeSpace);
   }
 
   progress_.free_space = free_space;
@@ -496,23 +490,23 @@
 
   VLOG(1) << "Calculating required space...";
   timer_ = base::ElapsedTimer();
-  progress_.stage = SetupStage::kListingFiles;
+  progress_.stage = Stage::kListingFiles;
   NotifyProgress();
 
   drivefs_->StartSearchQuery(search_query_.BindNewPipeAndPassReceiver(),
                              CreateMyDriveQuery());
   search_query_->GetNextPage(base::BindOnce(
-      &DriveFsPinManager::OnSearchResultForSizeCalculation, GetWeakPtr()));
+      &PinManager::OnSearchResultForSizeCalculation, GetWeakPtr()));
 }
 
-void DriveFsPinManager::OnSearchResultForSizeCalculation(
+void PinManager::OnSearchResultForSizeCalculation(
     const drive::FileError error,
     const absl::optional<std::vector<mojom::QueryItemPtr>> items) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (error != drive::FILE_ERROR_OK || !items) {
     LOG(ERROR) << "Cannot list files: " << error;
-    return Complete(SetupStage::kCannotListFiles);
+    return Complete(Stage::kCannotListFiles);
   }
 
   if (items->empty()) {
@@ -527,7 +521,7 @@
     const base::FilePath& path = item->path;
     DCHECK(item->metadata);
     const mojom::FileMetadata& md = *item->metadata;
-    const StableId id = StableId(md.stable_id);
+    const Id id = Id(md.stable_id);
     VLOG(3) << "Considering " << id << " " << Quote(path) << " " << Quote(md);
 
     if (!CanPinItem(md, item->path)) {
@@ -544,16 +538,16 @@
   NotifyProgress();
   DCHECK(search_query_);
   search_query_->GetNextPage(base::BindOnce(
-      &DriveFsPinManager::OnSearchResultForSizeCalculation, GetWeakPtr()));
+      &PinManager::OnSearchResultForSizeCalculation, GetWeakPtr()));
 }
 
-void DriveFsPinManager::Complete(const SetupStage stage) {
+void PinManager::Complete(const Stage stage) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!InProgress(stage));
 
   progress_.stage = stage;
   switch (stage) {
-    case SetupStage::kSuccess:
+    case Stage::kSuccess:
       LOG_IF(ERROR, progress_.failed_files > 0)
           << "Failed to pin " << progress_.failed_files << " files";
       VLOG(1) << "Pinned " << progress_.pinned_files << " files and downloaded "
@@ -564,7 +558,7 @@
       VLOG(1) << "Finished with success";
       break;
 
-    case SetupStage::kStopped:
+    case Stage::kStopped:
       VLOG(1) << "Stopped";
       break;
 
@@ -583,7 +577,7 @@
   }
 }
 
-void DriveFsPinManager::StartPinning() {
+void PinManager::StartPinning() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   VLOG(1) << "Calculated required space "
@@ -606,55 +600,53 @@
                << " is less than required space "
                << HumanReadableSize(progress_.required_space) << " + margin "
                << HumanReadableSize(margin);
-    return Complete(SetupStage::kNotEnoughSpace);
+    return Complete(Stage::kNotEnoughSpace);
   }
 
   if (!should_pin_) {
     VLOG(1) << "Should not pin files";
-    return Complete(SetupStage::kSuccess);
+    return Complete(Stage::kSuccess);
   }
 
   if (files_to_track_.empty() && files_to_pin_.empty()) {
     VLOG(1) << "Nothing to pin or track";
-    return Complete(SetupStage::kSuccess);
+    return Complete(Stage::kSuccess);
   }
 
   VLOG(1) << "Pinning and tracking "
           << (files_to_pin_.size() + files_to_track_.size()) << " files...";
   timer_ = base::ElapsedTimer();
-  progress_.stage = SetupStage::kSyncing;
+  progress_.stage = Stage::kSyncing;
   NotifyProgress();
 
   if (should_check_stalled_files_) {
     base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&DriveFsPinManager::CheckStalledFiles, GetWeakPtr()),
+        FROM_HERE, base::BindOnce(&PinManager::CheckStalledFiles, GetWeakPtr()),
         kPeriodicRemovalInterval);
   }
 
   PinSomeFiles();
 }
 
-void DriveFsPinManager::PinSomeFiles() {
+void PinManager::PinSomeFiles() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (files_to_track_.empty() && files_to_pin_.empty()) {
     VLOG(1) << "Nothing left to pin or track";
-    return Complete(SetupStage::kSuccess);
+    return Complete(Stage::kSuccess);
   }
 
   while (files_to_track_.size() < 50 && !files_to_pin_.empty()) {
     Files::node_type node = files_to_pin_.extract(files_to_pin_.begin());
     DCHECK(node);
-    const StableId id = node.key();
-    const Progress& progress = node.mapped();
-    const std::string& path = progress.path;
+    const Id id = node.key();
+    const File& file = node.mapped();
+    const std::string& path = file.path;
 
     VLOG(2) << "Pinning " << id << " " << Quote(path);
     drivefs_->SetPinnedByStableId(
         static_cast<int64_t>(id), true,
-        base::BindOnce(&DriveFsPinManager::OnFilePinned, GetWeakPtr(), id,
-                       path));
+        base::BindOnce(&PinManager::OnFilePinned, GetWeakPtr(), id, path));
 
     const Files::insert_return_type ir =
         files_to_track_.insert(std::move(node));
@@ -668,9 +660,9 @@
           << files_to_track_.size() << " files";
 }
 
-void DriveFsPinManager::OnFilePinned(const StableId id,
-                                     const std::string& path,
-                                     const drive::FileError status) {
+void PinManager::OnFilePinned(const Id id,
+                              const std::string& path,
+                              const drive::FileError status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (status != drive::FILE_ERROR_OK) {
@@ -686,85 +678,86 @@
   VLOG(1) << "Pinned " << id << " " << Quote(path);
 }
 
-void DriveFsPinManager::OnSyncingStatusUpdate(
-    const mojom::SyncingStatus& status) {
+void PinManager::OnSyncingStatusUpdate(const mojom::SyncingStatus& status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (progress_.stage != SetupStage::kSyncing) {
+  if (progress_.stage != Stage::kSyncing) {
     VLOG(2) << "Ignored syncing status update";
     return;
   }
 
   for (const mojom::ItemEventPtr& event : status.item_events) {
     DCHECK(event);
-    const StableId id = StableId(event->stable_id);
-    using State = mojom::ItemEvent::State;
-    switch (event->state) {
-      case State::kQueued:
-        // kQueued events come with a bytes_to_transfer field incorrectly set to
-        // zero (b/266462624). So we set it to -1 to ignore it.
-        event->bytes_to_transfer = -1;
-        [[fallthrough]];
-
-      case State::kInProgress:
-        if (Update(id, event->path, event->bytes_transferred,
-                   event->bytes_to_transfer)) {
-          VLOG(3) << Quote(event->state) << " " << id << " "
-                  << Quote(event->path) << ": " << Quote(*event);
-          VLOG_IF(2, !VLOG_IS_ON(3))
-              << Quote(event->state) << " " << id << " " << Quote(event->path);
-          progress_.useful_events++;
-          NotifyProgress();
-        } else {
-          VLOG(3) << "Duplicated event: " << Quote(*event);
-          progress_.duplicated_events++;
-        }
-        continue;
-
-      case State::kCompleted:
-        if (Remove(id, event->path)) {
-          VLOG(3) << "Synced " << id << " " << Quote(event->path) << ": "
-                  << Quote(*event);
-          VLOG_IF(2, !VLOG_IS_ON(3))
-              << "Synced " << id << " " << Quote(event->path);
-          progress_.useful_events++;
-          progress_.pinned_files++;
-          NotifyProgress();
-        } else {
-          VLOG(3) << "Duplicated event: " << Quote(*event);
-          progress_.duplicated_events++;
-        }
-        continue;
-
-      case State::kFailed:
-        if (Remove(id, event->path, 0)) {
-          LOG(ERROR) << Quote(event->state) << " " << id << " "
-                     << Quote(event->path) << ": " << Quote(*event);
-          progress_.failed_files++;
-          progress_.useful_events++;
-          NotifyProgress();
-        } else {
-          VLOG(3) << "Duplicated event: " << Quote(*event);
-          progress_.duplicated_events++;
-        }
-        continue;
+    if (OnSyncingEvent(*event)) {
+      progress_.useful_events++;
+      NotifyProgress();
+    } else {
+      progress_.duplicated_events++;
+      VLOG(3) << "Duplicated event: " << Quote(*event);
     }
-
-    LOG(ERROR) << "Unexpected event type: " << Quote(*event);
   }
 
   PinSomeFiles();
 }
 
-void DriveFsPinManager::OnUnmounted() {
+bool PinManager::OnSyncingEvent(mojom::ItemEvent& event) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  const Id id = Id(event.stable_id);
+  using State = mojom::ItemEvent::State;
+  switch (event.state) {
+    case State::kQueued:
+      // kQueued events come with a bytes_to_transfer field incorrectly set to
+      // zero (b/266462624). So we set it to -1 to ignore it.
+      event.bytes_to_transfer = -1;
+      [[fallthrough]];
+
+    case State::kInProgress:
+      if (!Update(id, event.path, event.bytes_transferred,
+                  event.bytes_to_transfer)) {
+        return false;
+      }
+
+      VLOG(3) << Quote(event.state) << " " << id << " " << Quote(event.path)
+              << ": " << Quote(event);
+      VLOG_IF(2, !VLOG_IS_ON(3))
+          << Quote(event.state) << " " << id << " " << Quote(event.path);
+      return true;
+
+    case State::kCompleted:
+      if (!Remove(id, event.path)) {
+        return false;
+      }
+
+      VLOG(3) << "Synced " << id << " " << Quote(event.path) << ": "
+              << Quote(event);
+      VLOG_IF(2, !VLOG_IS_ON(3)) << "Synced " << id << " " << Quote(event.path);
+      progress_.pinned_files++;
+      return true;
+
+    case State::kFailed:
+      if (!Remove(id, event.path, 0)) {
+        return false;
+      }
+
+      LOG(ERROR) << Quote(event.state) << " " << id << " " << Quote(event.path)
+                 << ": " << Quote(event);
+      progress_.failed_files++;
+      return true;
+  }
+
+  LOG(ERROR) << "Unexpected event type: " << Quote(event);
+  return false;
+}
+
+void PinManager::OnUnmounted() {
   LOG(ERROR) << "DriveFS got unmounted";
 }
 
-void DriveFsPinManager::OnFilesChanged(
-    const std::vector<mojom::FileChange>& changes) {
+void PinManager::OnFilesChanged(const std::vector<mojom::FileChange>& changes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (progress_.stage != SetupStage::kSyncing) {
+  if (progress_.stage != Stage::kSyncing) {
     for (const mojom::FileChange& change : changes) {
       VLOG(1) << "Ignored FileChange " << Quote(change);
     }
@@ -772,7 +765,7 @@
   }
 
   for (const mojom::FileChange& change : changes) {
-    const StableId id = StableId(change.stable_id);
+    const Id id = Id(change.stable_id);
     const Files::iterator it = files_to_track_.find(id);
     if (it == files_to_track_.end()) {
       VLOG(1) << "Ignored FileChange " << Quote(change);
@@ -781,68 +774,66 @@
 
     VLOG(1) << "Got FileChange " << Quote(change);
     DCHECK_EQ(it->first, id);
-    Progress& progress = it->second;
+    File& file = it->second;
 
     const std::string& path = change.path.value();
-    if (progress.path != path) {
-      LOG(ERROR) << "Changed path of " << id << " " << Quote(progress.path)
+    if (file.path != path) {
+      LOG(ERROR) << "Changed path of " << id << " " << Quote(file.path)
                  << " to " << Quote(path);
-      progress.path = path;
+      file.path = path;
     }
 
     VLOG(2) << "Checking changed " << id << " " << Quote(path);
     drivefs_->GetMetadataByStableId(
         static_cast<int64_t>(id),
-        base::BindOnce(&DriveFsPinManager::OnMetadataRetrieved, GetWeakPtr(),
-                       id, path));
+        base::BindOnce(&PinManager::OnMetadataRetrieved, GetWeakPtr(), id,
+                       path));
   }
 }
 
-void DriveFsPinManager::OnError(const mojom::DriveError& error) {
+void PinManager::OnError(const mojom::DriveError& error) {
   LOG(ERROR) << "Got DriveError " << Quote(error);
 }
 
-void DriveFsPinManager::NotifyProgress() {
+void PinManager::NotifyProgress() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (Observer& observer : observers_) {
     observer.OnProgress(progress_);
   }
 }
 
-void DriveFsPinManager::CheckStalledFiles() {
+void PinManager::CheckStalledFiles() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!should_check_stalled_files_) {
     return;
   }
 
-  for (const auto& [id, progress] : files_to_track_) {
-    if (!progress.in_progress) {
-      const std::string& path = progress.path;
+  for (const auto& [id, file] : files_to_track_) {
+    if (!file.in_progress) {
+      const std::string& path = file.path;
       VLOG(2) << "Checking unstarted " << id << " " << Quote(path);
       drivefs_->GetMetadataByStableId(
           static_cast<int64_t>(id),
-          base::BindOnce(&DriveFsPinManager::OnMetadataRetrieved, GetWeakPtr(),
-                         id, path));
+          base::BindOnce(&PinManager::OnMetadataRetrieved, GetWeakPtr(), id,
+                         path));
     }
   }
 
   base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&DriveFsPinManager::CheckStalledFiles, GetWeakPtr()),
+      FROM_HERE, base::BindOnce(&PinManager::CheckStalledFiles, GetWeakPtr()),
       kPeriodicRemovalInterval);
 
   PinSomeFiles();
 }
 
-void DriveFsPinManager::OnMetadataRetrieved(
-    const StableId id,
-    const std::string& path,
-    const drive::FileError error,
-    const mojom::FileMetadataPtr metadata) {
+void PinManager::OnMetadataRetrieved(const Id id,
+                                     const std::string& path,
+                                     const drive::FileError error,
+                                     const mojom::FileMetadataPtr metadata) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (progress_.stage != SetupStage::kSyncing) {
+  if (progress_.stage != Stage::kSyncing) {
     VLOG(1) << "Ignored metadata of " << id << " " << Quote(path);
     return;
   }
@@ -863,7 +854,7 @@
   }
 
   DCHECK(metadata);
-  DCHECK_EQ(id, StableId(metadata->stable_id));
+  DCHECK_EQ(id, Id(metadata->stable_id));
   VLOG(2) << "Got metadata for " << id << " " << Quote(path) << ": "
           << Quote(*metadata);
 
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.h b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
index 33d65b8..3113417 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.h
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
@@ -37,11 +37,10 @@
 // map are identified as being `available_offline` or 0 byte files.
 extern const base::TimeDelta kPeriodicRemovalInterval;
 
-// The `DriveFsPinManager` first undergoes a setup phase, where it audits the
-// current disk space, pins all available files (disk space willing) then moves
-// to monitoring. This enum represents the various stages the setup goes
-// through.
-enum class SetupStage {
+// The PinManager first undergoes a setup phase, where it audits the current
+// disk space, pins all available files (disk space willing) then moves to
+// monitoring. This enum represents the various stages the setup goes through.
+enum class Stage {
   // Initial stage.
   kNotStarted,
 
@@ -61,11 +60,11 @@
 };
 
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
-std::ostream& operator<<(std::ostream& out, SetupStage stage);
+std::ostream& operator<<(std::ostream& out, Stage stage);
 
 // When the manager is setting up, this struct maintains all the information
 // gathered.
-struct COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) SetupProgress {
+struct COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) Progress {
   // Number of free bytes on the stateful partition. Estimated at the beginning
   // of the setup process and left unchanged afterwards.
   int64_t free_space = 0;
@@ -100,11 +99,11 @@
   int32_t duplicated_events = 0;
 
   // Stage of the setup process.
-  SetupStage stage = SetupStage::kNotStarted;
+  Stage stage = Stage::kNotStarted;
 
-  SetupProgress();
-  SetupProgress(const SetupProgress&);
-  SetupProgress& operator=(const SetupProgress&);
+  Progress();
+  Progress(const Progress&);
+  Progress& operator=(const Progress&);
 };
 
 // Manages bulk pinning of items via DriveFS. This class handles the following:
@@ -113,15 +112,15 @@
 //  - 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) DriveFsPinManager
+class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) PinManager
     : public DriveFsHostObserver {
  public:
-  DriveFsPinManager(base::FilePath profile_path, mojom::DriveFs* drivefs);
+  PinManager(base::FilePath profile_path, mojom::DriveFs* drivefs);
 
-  DriveFsPinManager(const DriveFsPinManager&) = delete;
-  DriveFsPinManager& operator=(const DriveFsPinManager&) = delete;
+  PinManager(const PinManager&) = delete;
+  PinManager& operator=(const PinManager&) = delete;
 
-  ~DriveFsPinManager() override;
+  ~PinManager() override;
 
   // Starts up the manager, which will first search for any unpinned items and
   // pin them (within the users My drive) then turn to a "monitoring" phase
@@ -136,7 +135,7 @@
   void Enable(bool enabled);
 
   // Gets the current progress status.
-  SetupProgress GetProgress() const {
+  Progress GetProgress() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return progress_;
   }
@@ -145,9 +144,9 @@
   class Observer : public base::CheckedObserver {
    public:
     // Called when the setup progresses.
-    virtual void OnProgress(const SetupProgress& progress) {}
+    virtual void OnProgress(const Progress& progress) {}
 
-    // Called when the DriveFsPinManager is getting deleted.
+    // Called when the PinManager is getting deleted.
     virtual void OnDrop() {}
   };
 
@@ -160,6 +159,9 @@
     observers_.RemoveObserver(observer);
   }
 
+  // Processes a syncing status event. Returns true if the event was useful.
+  bool OnSyncingEvent(mojom::ItemEvent& event);
+
   // drivefs::DriveFsHostObserver
   void OnSyncingStatusUpdate(const mojom::SyncingStatus& status) override;
   void OnUnmounted() override;
@@ -167,9 +169,9 @@
   void OnError(const mojom::DriveError& error) override;
 
   // Stable ID provided by DriveFS.
-  enum class StableId : int64_t { kNone = 0 };
+  enum class Id : int64_t { kNone = 0 };
 
-  base::WeakPtr<DriveFsPinManager> GetWeakPtr() {
+  base::WeakPtr<PinManager> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
 
@@ -181,7 +183,7 @@
 
   // Sets the completion callback, which will be called once the initial pinning
   // has completed.
-  using CompletionCallback = base::OnceCallback<void(SetupStage)>;
+  using CompletionCallback = base::OnceCallback<void(Stage)>;
   void SetCompletionCallback(CompletionCallback f) {
     completion_callback_ = std::move(f);
   }
@@ -199,7 +201,7 @@
 
  private:
   // Struct keeping track of the progress of a file being synced.
-  struct Progress {
+  struct File {
     // Path inside the Drive folder.
     // TODO(b/265209836) Remove this field when not needed anymore.
     std::string path;
@@ -213,32 +215,32 @@
     // Have we received in-progress events for this file?
     bool in_progress = false;
 
-    friend std::ostream& operator<<(std::ostream& out, const Progress& p) {
+    friend std::ostream& operator<<(std::ostream& out, const File& p) {
       return out << "{transferred: " << HumanReadableSize(p.transferred)
                  << ", total: " << HumanReadableSize(p.total)
                  << ", in_progress: " << p.in_progress << "}";
     }
   };
 
-  using Files = std::map<StableId, Progress>;
+  using Files = std::map<Id, File>;
 
   // Adds an item to the files to pin.  Does nothing if an item with the same ID
   // already exists in files_to_pin_. Updates the total number of bytes to
   // transfer and the required space. Returns whether an item was actually
   // added.
-  bool Add(StableId id, const std::string& path, int64_t size);
+  bool Add(Id id, const std::string& path, int64_t size);
 
   // Removes an item from the map. Does nothing if the item is not in the map.
   // Updates the total number of bytes transferred so far. If `transferred` is
   // negative, use the total expected size. Returns whether an item was actually
   // removed.
-  bool Remove(StableId id, const std::string& path, int64_t transferred = -1);
+  bool Remove(Id id, const std::string& path, int64_t transferred = -1);
 
   // Updates an item in the map. Does nothing if the item is not in the map.
   // Updates the total number of bytes transferred so far. Updates the required
   // space. If `transferred` or `total` is negative, then the matching argument
   // is ignored. Returns whether anything has actually been updated.
-  bool Update(StableId id,
+  bool Update(Id id,
               const std::string& path,
               int64_t transferred,
               int64_t total);
@@ -260,7 +262,7 @@
 
   // When the pinning has finished, this ensures appropriate cleanup happens on
   // the underlying search query mojo connection.
-  void Complete(SetupStage stage);
+  void Complete(Stage stage);
 
   // Once the verification that the files to pin will not exceed available disk
   // space, the files to pin can be batch pinned.
@@ -270,9 +272,7 @@
   // emplaced. Note the file being pinned is just an update in drivefs, not the
   // actually completion of the file being downloaded, that is monitored via
   // `OnSyncingStatusUpdate`.
-  void OnFilePinned(StableId id,
-                    const std::string& path,
-                    drive::FileError status);
+  void OnFilePinned(Id id, const std::string& path, drive::FileError status);
 
   // Invoked at a regular interval to look at the map of in progress items and
   // ensure they are all still not available offline (i.e. still syncing). In
@@ -283,7 +283,7 @@
   // When an item goes to completed, it doesn't emit the final chunk of progress
   // nor it's final size, to ensure progress is adequately retrieved, this
   // method is used to get the total size to keep track of.
-  void OnMetadataRetrieved(StableId id,
+  void OnMetadataRetrieved(Id id,
                            const std::string& path,
                            drive::FileError error,
                            mojom::FileMetadataPtr metadata);
@@ -307,7 +307,7 @@
   SpaceGetter space_getter_;
   CompletionCallback completion_callback_;
 
-  SetupProgress progress_ GUARDED_BY_CONTEXT(sequence_checker_);
+  Progress progress_ GUARDED_BY_CONTEXT(sequence_checker_);
   base::ObserverList<Observer> observers_;
 
   const base::FilePath profile_path_;
@@ -319,15 +319,16 @@
   Files files_to_pin_ GUARDED_BY_CONTEXT(sequence_checker_);
   Files files_to_track_ GUARDED_BY_CONTEXT(sequence_checker_);
 
-  base::WeakPtrFactory<DriveFsPinManager> weak_ptr_factory_{this};
+  base::WeakPtrFactory<PinManager> 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);
 };
 
 COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
-std::ostream& operator<<(std::ostream& out, DriveFsPinManager::StableId id);
+std::ostream& operator<<(std::ostream& out, PinManager::Id id);
 
 }  // namespace drivefs::pinning
 
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
index 26267a78..64b2bba 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
@@ -5,6 +5,9 @@
 #include "chromeos/ash/components/drivefs/drivefs_pin_manager.h"
 
 #include <memory>
+#include <string>
+#include <utility>
+#include <vector>
 
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
@@ -24,15 +27,33 @@
 namespace drivefs::pinning {
 namespace {
 
-using ::base::test::RunClosure;
-using ::base::test::RunOnceCallback;
-using ::testing::_;
-using ::testing::AnyNumber;
-using ::testing::DoAll;
-using ::testing::Field;
-using ::testing::IsEmpty;
-using ::testing::Return;
-using ::testing::SizeIs;
+using base::BindOnce;
+using base::FilePath;
+using base::OnceCallback;
+using base::SequencedTaskRunner;
+using base::test::RunClosure;
+using base::test::RunOnceCallback;
+using drive::FileError;
+using mojom::FileMetadata;
+using mojom::FileMetadataPtr;
+using mojom::ItemEvent;
+using mojom::ItemEventPtr;
+using mojom::QueryItem;
+using mojom::QueryItemPtr;
+using mojom::SearchQuery;
+using mojom::SyncingStatus;
+using mojom::SyncingStatusPtr;
+using std::string;
+using std::vector;
+using testing::_;
+using testing::AnyNumber;
+using testing::DoAll;
+using testing::Field;
+using testing::IsEmpty;
+using testing::Return;
+using testing::SizeIs;
+
+using Id = PinManager::Id;
 
 // Shorthand way to represent drive files with the information that is relevant
 // for the pinning manager.
@@ -40,8 +61,8 @@
   static int64_t counter;
   int64_t stable_id = ++counter;
   int64_t size = 0;
-  base::FilePath path;
-  mojom::FileMetadata::Type type = mojom::FileMetadata::Type::kFile;
+  FilePath path;
+  FileMetadata::Type type = FileMetadata::Type::kFile;
   bool pinned = false;
   bool available_offline = false;
   // Whether to send a status update for this drive item. If false this will get
@@ -51,16 +72,15 @@
 
 int64_t DriveItem::counter = 0;
 
-mojom::FileMetadataPtr MakeMetadata(const bool available_offline,
-                                    const int64_t size) {
-  mojom::FileMetadataPtr md = mojom::FileMetadata::New();
+FileMetadataPtr MakeMetadata(const bool available_offline, const int64_t size) {
+  FileMetadataPtr md = FileMetadata::New();
   md->available_offline = available_offline;
   md->size = size;
   return md;
 }
 
-mojom::FileMetadataPtr MakeMetadata(const DriveItem& item) {
-  mojom::FileMetadataPtr md = mojom::FileMetadata::New();
+FileMetadataPtr MakeMetadata(const DriveItem& item) {
+  FileMetadataPtr md = FileMetadata::New();
   md->stable_id = item.stable_id;
   md->type = item.type;
   md->size = item.size;
@@ -70,16 +90,16 @@
   return md;
 }
 
-// An action that takes a `std::vector<DriveItem>` and is used to update the
-// items that are returned via the `GetNextPage` callback. These shorthand items
-// are converted to mojo types that represent the actual types returned.
-// NOTE: `arg0` in the below represents the pointer passed via parameters to the
+// An action that takes a `vector<DriveItem>` and is used to update the items
+// that are returned via the `GetNextPage` callback. These shorthand items are
+// converted to mojo types that represent the actual types returned. NOTE:
+// `arg0` in the below represents the pointer passed via parameters to the
 // `MOCK_METHOD` of `OnGetNextPage`.
 ACTION_P(PopulateSearchItems, items) {
-  std::vector<mojom::QueryItemPtr> result;
+  vector<QueryItemPtr> result;
   result.reserve(items.size());
   for (const DriveItem& item : items) {
-    mojom::QueryItemPtr p = mojom::QueryItem::New();
+    QueryItemPtr p = QueryItem::New();
     p->path = item.path;
     p->metadata = MakeMetadata(item);
     result.push_back(std::move(p));
@@ -91,11 +111,11 @@
 // `GetNextPage` query will return 0 items and this ensures the `MOCK_METHOD`
 // returns the appropriate type (instead of `absl::nullopt`).
 ACTION(PopulateNoSearchItems) {
-  *arg0 = std::vector<mojom::QueryItemPtr>();
+  *arg0 = vector<QueryItemPtr>();
 }
 
 class MockDriveFs : public mojom::DriveFsInterceptorForTesting,
-                    public mojom::SearchQuery {
+                    public SearchQuery {
  public:
   MockDriveFs() = default;
 
@@ -109,65 +129,56 @@
 
   MOCK_METHOD(void, OnStartSearchQuery, (const mojom::QueryParameters&));
 
-  void StartSearchQuery(mojo::PendingReceiver<mojom::SearchQuery> receiver,
+  void StartSearchQuery(mojo::PendingReceiver<SearchQuery> receiver,
                         mojom::QueryParametersPtr query_params) override {
     search_receiver_.reset();
     OnStartSearchQuery(*query_params);
     search_receiver_.Bind(std::move(receiver));
   }
 
-  MOCK_METHOD(drive::FileError,
+  MOCK_METHOD(FileError,
               OnGetNextPage,
-              (absl::optional<std::vector<mojom::QueryItemPtr>> * items));
+              (absl::optional<vector<QueryItemPtr>> * items));
 
   void GetNextPage(GetNextPageCallback callback) override {
-    absl::optional<std::vector<mojom::QueryItemPtr>> items;
+    absl::optional<vector<QueryItemPtr>> items;
     auto error = OnGetNextPage(&items);
-    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(callback), error, std::move(items)));
+    SequencedTaskRunner::GetCurrentDefault()->PostTask(
+        FROM_HERE, BindOnce(std::move(callback), error, std::move(items)));
   }
 
   MOCK_METHOD(void,
               SetPinned,
-              (const base::FilePath&,
-               bool,
-               base::OnceCallback<void(drive::FileError)>),
+              (const FilePath&, bool, OnceCallback<void(FileError)>),
               (override));
 
   MOCK_METHOD(void,
               SetPinnedByStableId,
-              (int64_t, bool, base::OnceCallback<void(drive::FileError)>),
+              (int64_t, bool, OnceCallback<void(FileError)>),
               (override));
 
-  MOCK_METHOD(
-      void,
-      GetMetadata,
-      (const base::FilePath&,
-       base::OnceCallback<void(drive::FileError, mojom::FileMetadataPtr)>),
-      (override));
+  MOCK_METHOD(void,
+              GetMetadata,
+              (const FilePath&, OnceCallback<void(FileError, FileMetadataPtr)>),
+              (override));
 
-  MOCK_METHOD(
-      void,
-      GetMetadataByStableId,
-      (int64_t,
-       base::OnceCallback<void(drive::FileError, mojom::FileMetadataPtr)>),
-      (override));
+  MOCK_METHOD(void,
+              GetMetadataByStableId,
+              (int64_t, OnceCallback<void(FileError, FileMetadataPtr)>),
+              (override));
 
  private:
-  mojo::Receiver<mojom::SearchQuery> search_receiver_{this};
+  mojo::Receiver<SearchQuery> search_receiver_{this};
 };
 
-class MockFreeSpace {
+class MockSpaceGetter {
  public:
-  MOCK_METHOD(void,
-              GetFreeSpace,
-              (const base::FilePath&, DriveFsPinManager::SpaceResult));
+  MOCK_METHOD(void, GetFreeSpace, (const FilePath&, PinManager::SpaceResult));
 };
 
-class MockObserver : public DriveFsPinManager::Observer {
+class MockObserver : public PinManager::Observer {
  public:
-  MOCK_METHOD(void, OnProgress, (const SetupProgress&), (override));
+  MOCK_METHOD(void, OnProgress, (const Progress&), (override));
   MOCK_METHOD(void, OnDrop, (), (override));
 };
 
@@ -186,17 +197,17 @@
     gcache_dir_ = temp_dir_.GetPath().Append("GCache");
   }
 
-  static mojom::SyncingStatusPtr MakeSyncingStatus(
-      const std::vector<DriveItem>& items,
-      mojom::ItemEvent::State state = mojom::ItemEvent::State::kQueued) {
-    mojom::SyncingStatusPtr status = mojom::SyncingStatus::New();
+  static SyncingStatusPtr MakeSyncingStatus(
+      const vector<DriveItem>& items,
+      ItemEvent::State state = ItemEvent::State::kQueued) {
+    SyncingStatusPtr status = SyncingStatus::New();
 
-    std::vector<mojom::ItemEventPtr> events;
+    vector<ItemEventPtr> events;
     for (const DriveItem& item : items) {
       if (item.pinned || !item.status_update) {
         continue;
       }
-      mojom::ItemEventPtr event = mojom::ItemEvent::New();
+      ItemEventPtr event = ItemEvent::New();
       event->stable_id = item.stable_id;
       event->path = item.path.value();
       event->state = state;
@@ -208,46 +219,45 @@
     return status;
   }
 
-  static void SetState(std::vector<mojom::ItemEventPtr>& events,
-                       const mojom::ItemEvent::State state) {
-    for (mojom::ItemEventPtr& event : events) {
+  static void SetState(vector<ItemEventPtr>& events,
+                       const ItemEvent::State state) {
+    for (ItemEventPtr& event : events) {
       DCHECK(event);
       event->state = state;
     }
   }
 
-  DriveFsPinManager::SpaceGetter GetSpaceGetter() {
-    return base::BindRepeating(&MockFreeSpace::GetFreeSpace,
-                               base::Unretained(&mock_free_space_));
+  PinManager::SpaceGetter GetSpaceGetter() {
+    return base::BindRepeating(&MockSpaceGetter::GetFreeSpace,
+                               base::Unretained(&space_getter_));
   }
 
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   base::ScopedTempDir temp_dir_;
-  base::FilePath gcache_dir_;
-  MockFreeSpace mock_free_space_;
-  MockDriveFs mock_drivefs_;
+  FilePath gcache_dir_;
+  MockSpaceGetter space_getter_;
+  MockDriveFs drivefs_;
 };
 
 // Tests DriveFsPinManagerTest::Add().
 TEST_F(DriveFsPinManagerTest, Add) {
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
-  manager.SetSpaceGetter(GetSpaceGetter());
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 0);
     EXPECT_EQ(progress.bytes_to_pin, 0);
     EXPECT_EQ(progress.required_space, 0);
   }
 
-  const DriveFsPinManager::StableId id1 = DriveFsPinManager::StableId(549);
-  const std::string path1 = "Path 1";
+  const Id id1 = Id(549);
+  const string path1 = "Path 1";
   const int64_t size1 = 698248964;
 
-  const DriveFsPinManager::StableId id2 = DriveFsPinManager::StableId(17);
-  const std::string path2 = "Path 2";
+  const Id id2 = Id(17);
+  const string path2 = "Path 2";
   const int64_t size2 = 78964533;
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
@@ -268,16 +278,16 @@
   {
     const auto it = manager.files_to_pin_.find(id1);
     ASSERT_NE(it, manager.files_to_pin_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path1);
-    EXPECT_EQ(progress.total, size1);
-    EXPECT_EQ(progress.transferred, 0);
-    EXPECT_FALSE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, size1);
+    EXPECT_EQ(file.transferred, 0);
+    EXPECT_FALSE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 0);
     EXPECT_EQ(progress.bytes_to_pin, size1);
@@ -292,16 +302,16 @@
   {
     const auto it = manager.files_to_pin_.find(id2);
     ASSERT_NE(it, manager.files_to_pin_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id2);
-    EXPECT_EQ(progress.path, path2);
-    EXPECT_EQ(progress.total, size2);
-    EXPECT_EQ(progress.transferred, 0);
-    EXPECT_FALSE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id2);
+    EXPECT_EQ(file.path, path2);
+    EXPECT_EQ(file.total, size2);
+    EXPECT_EQ(file.transferred, 0);
+    EXPECT_FALSE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 0);
     EXPECT_EQ(progress.bytes_to_pin, size1 + size2);
@@ -311,7 +321,7 @@
 
 // Tests DriveFsPinManagerTest::Update().
 TEST_F(DriveFsPinManagerTest, Update) {
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.pinned_bytes = 5000;
@@ -319,25 +329,25 @@
   manager.progress_.required_space = 20480;
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5000);
     EXPECT_EQ(progress.bytes_to_pin, 10000);
     EXPECT_EQ(progress.required_space, 20480);
   }
 
-  const DriveFsPinManager::StableId id1 = DriveFsPinManager::StableId(549);
-  const std::string path1 = "Path 1";
+  const Id id1 = Id(549);
+  const string path1 = "Path 1";
   const int64_t size1 = 2000;
 
-  const DriveFsPinManager::StableId id2 = DriveFsPinManager::StableId(17);
-  const std::string path2 = "Path 2";
+  const Id id2 = Id(17);
+  const string path2 = "Path 2";
   const int64_t size2 = 5000;
 
   // Put in place a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, DriveFsPinManager::Progress{.path = path1, .total = size1});
+        id1, PinManager::File{.path = path1, .total = size1});
     ASSERT_TRUE(ok);
   }
 
@@ -350,16 +360,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path1);
-    EXPECT_EQ(progress.total, size1);
-    EXPECT_EQ(progress.transferred, 0);
-    EXPECT_FALSE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, size1);
+    EXPECT_EQ(file.transferred, 0);
+    EXPECT_FALSE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5000);
     EXPECT_EQ(progress.bytes_to_pin, 10000);
@@ -373,16 +383,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path1);
-    EXPECT_EQ(progress.total, size1);
-    EXPECT_EQ(progress.transferred, 0);
-    EXPECT_TRUE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, size1);
+    EXPECT_EQ(file.transferred, 0);
+    EXPECT_TRUE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5000);
     EXPECT_EQ(progress.bytes_to_pin, 10000);
@@ -399,16 +409,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path1);
-    EXPECT_EQ(progress.total, size1);
-    EXPECT_EQ(progress.transferred, 0);
-    EXPECT_TRUE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, size1);
+    EXPECT_EQ(file.transferred, 0);
+    EXPECT_TRUE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5000);
     EXPECT_EQ(progress.bytes_to_pin, 10000);
@@ -422,16 +432,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path1);
-    EXPECT_EQ(progress.total, size2);
-    EXPECT_EQ(progress.transferred, 0);
-    EXPECT_TRUE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, size2);
+    EXPECT_EQ(file.transferred, 0);
+    EXPECT_TRUE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5000);
     EXPECT_EQ(progress.bytes_to_pin, 13000);
@@ -445,16 +455,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path1);
-    EXPECT_EQ(progress.total, size2);
-    EXPECT_EQ(progress.transferred, size1);
-    EXPECT_TRUE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, size2);
+    EXPECT_EQ(file.transferred, size1);
+    EXPECT_TRUE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 7000);
     EXPECT_EQ(progress.bytes_to_pin, 13000);
@@ -468,16 +478,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path2);
-    EXPECT_EQ(progress.total, size2);
-    EXPECT_EQ(progress.transferred, size1);
-    EXPECT_TRUE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path2);
+    EXPECT_EQ(file.total, size2);
+    EXPECT_EQ(file.transferred, size1);
+    EXPECT_TRUE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 7000);
     EXPECT_EQ(progress.bytes_to_pin, 13000);
@@ -491,16 +501,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path2);
-    EXPECT_EQ(progress.total, size2);
-    EXPECT_EQ(progress.transferred, 1000);
-    EXPECT_TRUE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path2);
+    EXPECT_EQ(file.total, size2);
+    EXPECT_EQ(file.transferred, 1000);
+    EXPECT_TRUE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 6000);
     EXPECT_EQ(progress.bytes_to_pin, 13000);
@@ -510,7 +520,7 @@
 
 // Tests DriveFsPinManagerTest::Remove().
 TEST_F(DriveFsPinManagerTest, Remove) {
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
   manager.progress_.pinned_bytes = 5000;
@@ -518,26 +528,26 @@
   manager.progress_.required_space = 20480;
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5000);
     EXPECT_EQ(progress.bytes_to_pin, 10000);
     EXPECT_EQ(progress.required_space, 20480);
   }
 
-  const DriveFsPinManager::StableId id1 = DriveFsPinManager::StableId(549);
-  const std::string path1 = "Path 1";
+  const Id id1 = Id(549);
+  const string path1 = "Path 1";
 
-  const DriveFsPinManager::StableId id2 = DriveFsPinManager::StableId(17);
-  const std::string path2 = "Path 2";
+  const Id id2 = Id(17);
+  const string path2 = "Path 2";
 
   // Put in place a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, DriveFsPinManager::Progress{.path = path1,
-                                         .transferred = 1200,
-                                         .total = 3000,
-                                         .in_progress = true});
+        id1, PinManager::File{.path = path1,
+                              .transferred = 1200,
+                              .total = 3000,
+                              .in_progress = true});
     ASSERT_TRUE(ok);
   }
 
@@ -550,16 +560,16 @@
   {
     const auto it = manager.files_to_track_.find(id1);
     ASSERT_NE(it, manager.files_to_track_.end());
-    const auto& [got_id, progress] = *it;
-    EXPECT_EQ(got_id, id1);
-    EXPECT_EQ(progress.path, path1);
-    EXPECT_EQ(progress.total, 3000);
-    EXPECT_EQ(progress.transferred, 1200);
-    EXPECT_TRUE(progress.in_progress);
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, 3000);
+    EXPECT_EQ(file.transferred, 1200);
+    EXPECT_TRUE(file.in_progress);
   }
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5000);
     EXPECT_EQ(progress.bytes_to_pin, 10000);
@@ -571,7 +581,7 @@
   EXPECT_THAT(manager.files_to_track_, IsEmpty());
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 6800);
     EXPECT_EQ(progress.bytes_to_pin, 10000);
@@ -581,10 +591,10 @@
   // Put in place a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, DriveFsPinManager::Progress{.path = path1,
-                                         .transferred = 1200,
-                                         .total = 3000,
-                                         .in_progress = true});
+        id1, PinManager::File{.path = path1,
+                              .transferred = 1200,
+                              .total = 3000,
+                              .in_progress = true});
     ASSERT_TRUE(ok);
   }
 
@@ -595,7 +605,7 @@
   EXPECT_THAT(manager.files_to_track_, IsEmpty());
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 5600);
     EXPECT_EQ(progress.bytes_to_pin, 7000);
@@ -605,10 +615,10 @@
   // Put in place a file to track.
   {
     const auto [it, ok] = manager.files_to_track_.try_emplace(
-        id1, DriveFsPinManager::Progress{.path = path1,
-                                         .transferred = 5000,
-                                         .total = 6000,
-                                         .in_progress = true});
+        id1, PinManager::File{.path = path1,
+                              .transferred = 5000,
+                              .total = 6000,
+                              .in_progress = true});
     ASSERT_TRUE(ok);
   }
 
@@ -619,7 +629,7 @@
   EXPECT_THAT(manager.files_to_track_, IsEmpty());
 
   {
-    const SetupProgress progress = manager.GetProgress();
+    const Progress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
     EXPECT_EQ(progress.pinned_bytes, 10600);
     EXPECT_EQ(progress.bytes_to_pin, 11000);
@@ -627,26 +637,209 @@
   }
 }
 
+// Tests DriveFsPinManagerTest::OnSyncingEvent().
+TEST_F(DriveFsPinManagerTest, OnSyncingEvent) {
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
+
+  DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_);
+  manager.progress_.bytes_to_pin = 30000;
+  manager.progress_.required_space = 32768;
+
+  {
+    const Progress progress = manager.GetProgress();
+    EXPECT_EQ(progress.failed_files, 0);
+    EXPECT_EQ(progress.pinned_files, 0);
+    EXPECT_EQ(progress.pinned_bytes, 0);
+    EXPECT_EQ(progress.bytes_to_pin, 30000);
+    EXPECT_EQ(progress.required_space, 32768);
+  }
+
+  const Id id1 = Id(549);
+  const string path1 = "Path 1";
+
+  const Id id2 = Id(17);
+  const string path2 = "Path 2";
+
+  // Put in place a couple of files to track.
+  {
+    const auto [it, ok] = manager.files_to_track_.try_emplace(
+        id1, PinManager::File{.path = path1, .total = 10000});
+    ASSERT_TRUE(ok);
+  }
+  {
+    const auto [it, ok] = manager.files_to_track_.try_emplace(
+        id2, PinManager::File{.path = path2, .total = 20000});
+    ASSERT_TRUE(ok);
+  }
+
+  EXPECT_THAT(manager.files_to_track_, SizeIs(2));
+
+  // An event with an unknown type is ignored.
+  {
+    ItemEvent event;
+    event.stable_id = static_cast<int64_t>(id2);
+    event.path = path2;
+    event.state = ItemEvent::State(-1);
+    event.bytes_to_transfer = -1;
+    event.bytes_transferred = -1;
+    EXPECT_FALSE(manager.OnSyncingEvent(event));
+  }
+
+  EXPECT_THAT(manager.files_to_track_, SizeIs(2));
+
+  {
+    const Progress progress = manager.GetProgress();
+    EXPECT_EQ(progress.failed_files, 0);
+    EXPECT_EQ(progress.pinned_files, 0);
+    EXPECT_EQ(progress.pinned_bytes, 0);
+    EXPECT_EQ(progress.bytes_to_pin, 30000);
+    EXPECT_EQ(progress.required_space, 32768);
+  }
+
+  // Mark file 1 as queued.
+  {
+    ItemEvent event;
+    event.stable_id = static_cast<int64_t>(id1);
+    event.path = path1;
+    event.state = ItemEvent::State::kQueued;
+    event.bytes_to_transfer = 0;
+    EXPECT_TRUE(manager.OnSyncingEvent(event));
+    EXPECT_FALSE(manager.OnSyncingEvent(event));
+  }
+
+  EXPECT_THAT(manager.files_to_track_, SizeIs(2));
+
+  {
+    const Progress progress = manager.GetProgress();
+    EXPECT_EQ(progress.failed_files, 0);
+    EXPECT_EQ(progress.pinned_files, 0);
+    EXPECT_EQ(progress.pinned_bytes, 0);
+    EXPECT_EQ(progress.bytes_to_pin, 30000);
+    EXPECT_EQ(progress.required_space, 32768);
+  }
+
+  {
+    const auto it = manager.files_to_track_.find(id1);
+    ASSERT_NE(it, manager.files_to_track_.end());
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, 10000);
+    EXPECT_EQ(file.transferred, 0);
+    EXPECT_TRUE(file.in_progress);
+  }
+
+  // Mark file 1 as in progress.
+  {
+    ItemEvent event;
+    event.stable_id = static_cast<int64_t>(id1);
+    event.path = path1;
+    event.state = ItemEvent::State::kInProgress;
+    event.bytes_to_transfer = 10000;
+    event.bytes_transferred = 5000;
+    EXPECT_TRUE(manager.OnSyncingEvent(event));
+    EXPECT_FALSE(manager.OnSyncingEvent(event));
+  }
+
+  EXPECT_THAT(manager.files_to_track_, SizeIs(2));
+
+  {
+    const Progress progress = manager.GetProgress();
+    EXPECT_EQ(progress.failed_files, 0);
+    EXPECT_EQ(progress.pinned_files, 0);
+    EXPECT_EQ(progress.pinned_bytes, 5000);
+    EXPECT_EQ(progress.bytes_to_pin, 30000);
+    EXPECT_EQ(progress.required_space, 32768);
+  }
+
+  {
+    const auto it = manager.files_to_track_.find(id1);
+    ASSERT_NE(it, manager.files_to_track_.end());
+    const auto& [id, file] = *it;
+    EXPECT_EQ(id, id1);
+    EXPECT_EQ(file.path, path1);
+    EXPECT_EQ(file.total, 10000);
+    EXPECT_EQ(file.transferred, 5000);
+    EXPECT_TRUE(file.in_progress);
+  }
+
+  // Mark file 1 as completed.
+  {
+    ItemEvent event;
+    event.stable_id = static_cast<int64_t>(id1);
+    event.path = path1;
+    event.state = ItemEvent::State::kCompleted;
+    event.bytes_to_transfer = -1;
+    event.bytes_transferred = -1;
+    EXPECT_TRUE(manager.OnSyncingEvent(event));
+    EXPECT_FALSE(manager.OnSyncingEvent(event));
+  }
+
+  EXPECT_THAT(manager.files_to_track_, SizeIs(1));
+
+  {
+    const Progress progress = manager.GetProgress();
+    EXPECT_EQ(progress.failed_files, 0);
+    EXPECT_EQ(progress.pinned_files, 1);
+    EXPECT_EQ(progress.pinned_bytes, 10000);
+    EXPECT_EQ(progress.bytes_to_pin, 30000);
+    EXPECT_EQ(progress.required_space, 32768);
+  }
+
+  {
+    const auto it = manager.files_to_track_.find(id1);
+    EXPECT_EQ(it, manager.files_to_track_.end());
+  }
+
+  // Mark file 2 as failed.
+  {
+    ItemEvent event;
+    event.stable_id = static_cast<int64_t>(id2);
+    event.path = path2;
+    event.state = ItemEvent::State::kFailed;
+    event.bytes_to_transfer = -1;
+    event.bytes_transferred = -1;
+    EXPECT_TRUE(manager.OnSyncingEvent(event));
+    EXPECT_FALSE(manager.OnSyncingEvent(event));
+  }
+
+  EXPECT_THAT(manager.files_to_track_, IsEmpty());
+
+  {
+    const Progress progress = manager.GetProgress();
+    EXPECT_EQ(progress.failed_files, 1);
+    EXPECT_EQ(progress.pinned_files, 1);
+    EXPECT_EQ(progress.pinned_bytes, 10000);
+    EXPECT_EQ(progress.bytes_to_pin, 10000);
+    EXPECT_EQ(progress.required_space, 12288);
+  }
+
+  {
+    const auto it = manager.files_to_track_.find(id2);
+    EXPECT_EQ(it, manager.files_to_track_.end());
+  }
+}
+
 TEST_F(DriveFsPinManagerTest, CannotGetFreeSpace) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
 
   base::RunLoop run_loop;
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(0);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_)).Times(0);
-  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotGetFreeSpace))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(0);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_)).Times(0);
+  EXPECT_CALL(mock_callback, Run(Stage::kCannotGetFreeSpace))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(-1));
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
 
-  const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kCannotGetFreeSpace);
+  const Progress progress = manager.GetProgress();
+  EXPECT_EQ(progress.stage, Stage::kCannotGetFreeSpace);
   EXPECT_EQ(progress.free_space, 0);
   EXPECT_EQ(progress.required_space, 0);
   EXPECT_EQ(progress.pinned_bytes, 0);
@@ -654,27 +847,27 @@
 }
 
 TEST_F(DriveFsPinManagerTest, CannotListFiles) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
 
   base::RunLoop run_loop;
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(1);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_FAILED)));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotListFiles))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(1);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_FAILED)));
+  EXPECT_CALL(mock_callback, Run(Stage::kCannotListFiles))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
 
-  const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kCannotListFiles);
+  const Progress progress = manager.GetProgress();
+  EXPECT_EQ(progress.stage, Stage::kCannotListFiles);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, 0);
   EXPECT_EQ(progress.pinned_bytes, 0);
@@ -682,26 +875,26 @@
 }
 
 TEST_F(DriveFsPinManagerTest, InvalidFileList) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
 
   base::RunLoop run_loop;
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(1);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
-      .WillOnce(Return(drive::FileError::FILE_ERROR_OK));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotListFiles))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(1);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
+      .WillOnce(Return(FileError::FILE_ERROR_OK));
+  EXPECT_CALL(mock_callback, Run(Stage::kCannotListFiles))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
 
-  const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kCannotListFiles);
+  const Progress progress = manager.GetProgress();
+  EXPECT_EQ(progress.stage, Stage::kCannotListFiles);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, 0);
   EXPECT_EQ(progress.pinned_bytes, 0);
@@ -709,34 +902,34 @@
 }
 
 TEST_F(DriveFsPinManagerTest, NotEnoughSpace) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
   base::RunLoop run_loop;
 
   // Mock Drive search to return 3 unpinned files that total just above 512 MB.
   // The available space of 1 GB is not enough if you take in account the 512 MB
   // margin.
-  const std::vector<DriveItem> items = {
+  const vector<DriveItem> items = {
       {.size = 300 << 20}, {.size = 212 << 20}, {.size = 1}};
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(1);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kNotEnoughSpace))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(1);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(mock_callback, Run(Stage::kNotEnoughSpace))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
 
-  const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kNotEnoughSpace);
+  const Progress progress = manager.GetProgress();
+  EXPECT_EQ(progress.stage, Stage::kNotEnoughSpace);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, (512 << 20) + (4 << 10));
   EXPECT_EQ(progress.pinned_bytes, 0);
@@ -744,35 +937,34 @@
 }
 
 TEST_F(DriveFsPinManagerTest, JustCheckRequiredSpace) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
   base::RunLoop run_loop;
 
   // Mock Drive search to return 2 unpinned files that total to 512 MB. The
   // available space of 1 GB is just enough if you take in account the 512 MB
   // margin.
-  const std::vector<DriveItem> items = {{.size = 300 << 20},
-                                        {.size = 212 << 20}};
+  const vector<DriveItem> items = {{.size = 300 << 20}, {.size = 212 << 20}};
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(1);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kSuccess))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(1);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(mock_callback, Run(Stage::kSuccess))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.ShouldPin(false);
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
 
-  const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kSuccess);
+  const Progress progress = manager.GetProgress();
+  EXPECT_EQ(progress.stage, Stage::kSuccess);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, 512 << 20);
   EXPECT_EQ(progress.pinned_bytes, 0);
@@ -781,35 +973,35 @@
 
 TEST_F(DriveFsPinManagerTest,
        DISABLED_FailingToPinOneItemShouldNotFailCompletely) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
 
   base::RunLoop run_loop;
 
-  const std::vector<DriveItem> items = {{.size = 128}, {.size = 128}};
+  const vector<DriveItem> items = {{.size = 128}, {.size = 128}};
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(2);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(2);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
       // Results returned whilst calculating free disk space.
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)))
       // Results returned when actually performing the pinning, don't return a
       // final empty list as this should be aborted due to one of the pinning
       // operations being mock failed.
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kSuccess))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(mock_callback, Run(Stage::kSuccess))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
-  EXPECT_CALL(mock_drivefs_, SetPinned(_, true, _))
+  EXPECT_CALL(drivefs_, SetPinned(_, true, _))
       // Mock the first file to successfully get pinned.
-      .WillOnce(RunOnceCallback<2>(drive::FILE_ERROR_OK))
+      .WillOnce(RunOnceCallback<2>(FileError::FILE_ERROR_OK))
       // Mock the second file to unsuccessfully get pinned.
-      .WillOnce(RunOnceCallback<2>(drive::FILE_ERROR_FAILED));
+      .WillOnce(RunOnceCallback<2>(FileError::FILE_ERROR_FAILED));
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
@@ -817,134 +1009,129 @@
 }
 
 TEST_F(DriveFsPinManagerTest, DISABLED_OnlyUnpinnedItemsShouldGetPinned) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
 
   base::RunLoop run_loop;
 
-  std::vector<DriveItem> items = {
-      {.size = 128, .path = base::FilePath("/a")},
-      {.size = 128, .path = base::FilePath("/b")},
-      {.size = 128, .path = base::FilePath("/c"), .pinned = true}};
+  vector<DriveItem> items = {
+      {.size = 128, .path = FilePath("/a")},
+      {.size = 128, .path = FilePath("/b")},
+      {.size = 128, .path = FilePath("/c"), .pinned = true}};
 
-  ON_CALL(mock_drivefs_, GetMetadata(_, _))
+  ON_CALL(drivefs_, GetMetadata(_, _))
       .WillByDefault(
-          [&items](
-              const base::FilePath& path,
-              base::OnceCallback<void(drive::FileError, mojom::FileMetadataPtr)>
-                  callback) {
+          [&items](const FilePath& path,
+                   OnceCallback<void(FileError, FileMetadataPtr)> callback) {
             for (const DriveItem& item : items) {
               if (item.path == path) {
-                std::move(callback).Run(drive::FILE_ERROR_OK,
+                std::move(callback).Run(FileError::FILE_ERROR_OK,
                                         MakeMetadata(item));
                 return;
               }
             }
-            std::move(callback).Run(drive::FILE_ERROR_NOT_FOUND, nullptr);
+            std::move(callback).Run(FileError::FILE_ERROR_NOT_FOUND, nullptr);
           });
 
-  EXPECT_CALL(mock_drivefs_, GetMetadata(_, _)).Times(0);
+  EXPECT_CALL(drivefs_, GetMetadata(_, _)).Times(0);
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(1);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(1);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
       // Results returned whilst calculating free disk space.
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
-  EXPECT_CALL(mock_drivefs_, SetPinnedByStableId(items[0].stable_id, true, _))
+  EXPECT_CALL(drivefs_, SetPinnedByStableId(items[0].stable_id, true, _))
       .WillOnce([&items](int64_t, bool,
-                         base::OnceCallback<void(drive::FileError)> callback) {
+                         OnceCallback<void(FileError)> callback) {
         items[0].pinned = true;
-        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-            FROM_HERE,
-            base::BindOnce(std::move(callback), drive::FILE_ERROR_OK));
+        SequencedTaskRunner::GetCurrentDefault()->PostTask(
+            FROM_HERE, BindOnce(std::move(callback), FileError::FILE_ERROR_OK));
       });
-  EXPECT_CALL(mock_drivefs_, SetPinnedByStableId(items[1].stable_id, true, _))
+  EXPECT_CALL(drivefs_, SetPinnedByStableId(items[1].stable_id, true, _))
       .WillOnce([&items](int64_t, bool,
-                         base::OnceCallback<void(drive::FileError)> callback) {
+                         OnceCallback<void(FileError)> callback) {
         items[1].pinned = true;
-        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-            FROM_HERE,
-            base::BindOnce(std::move(callback), drive::FILE_ERROR_OK));
+        SequencedTaskRunner::GetCurrentDefault()->PostTask(
+            FROM_HERE, BindOnce(std::move(callback), FileError::FILE_ERROR_OK));
       });
-  EXPECT_CALL(mock_callback, Run(SetupStage::kSuccess))
+  EXPECT_CALL(mock_callback, Run(Stage::kSuccess))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
 
   {
-    const mojom::SyncingStatusPtr status =
-        MakeSyncingStatus(items, mojom::ItemEvent::State::kQueued);
+    const SyncingStatusPtr status =
+        MakeSyncingStatus(items, ItemEvent::State::kQueued);
     manager.OnSyncingStatusUpdate(*status);
   }
 
   {
-    const mojom::SyncingStatusPtr status =
-        MakeSyncingStatus(items, mojom::ItemEvent::State::kInProgress);
+    const SyncingStatusPtr status =
+        MakeSyncingStatus(items, ItemEvent::State::kInProgress);
     manager.OnSyncingStatusUpdate(*status);
   }
 
   {
-    const mojom::SyncingStatusPtr status =
-        MakeSyncingStatus(items, mojom::ItemEvent::State::kCompleted);
+    const SyncingStatusPtr status =
+        MakeSyncingStatus(items, ItemEvent::State::kCompleted);
     manager.OnSyncingStatusUpdate(*status);
   }
 }
 
 TEST_F(DriveFsPinManagerTest,
        DISABLED_ZeroByteItemsAndHostedItemsShouldBePeriodicallyCleaned) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
 
   base::RunLoop run_loop;
 
-  base::FilePath gdoc_path("/a.gdoc");
-  base::FilePath b_path("/b");
-  const std::vector<DriveItem> items = {
+  FilePath gdoc_path("/a.gdoc");
+  FilePath b_path("/b");
+  const vector<DriveItem> items = {
       // The `a.gdoc` file will never receive an `OnSyncingStatusUpdate` and
       // thus needs to be removed via the periodic removal task.
       {.size = 0, .path = gdoc_path, .status_update = false},
       {.size = 128, .path = b_path}};
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(2);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(2);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
       // Results returned whilst calculating free disk space.
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)))
       // Results returned when actually performing the pinning, the final
       // response (i.e. PopulateNoSearchItems()) happens after the
       // `OnSyncingStatusUpdate` instead.
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
-  EXPECT_CALL(mock_drivefs_, SetPinned(_, true, _))
+  EXPECT_CALL(drivefs_, SetPinned(_, true, _))
       .Times(2)
-      .WillOnce(RunOnceCallback<2>(drive::FILE_ERROR_OK))
+      .WillOnce(RunOnceCallback<2>(FileError::FILE_ERROR_OK))
       // `RunOnceCallback` can't be chained together in a `DoAll` action
       // combinator, so use an inline lambda instead.
-      .WillOnce(
-          [&run_loop](const base::FilePath& path, bool pinned,
-                      base::OnceCallback<void(drive::FileError)> callback) {
-            std::move(callback).Run(drive::FILE_ERROR_OK);
-            run_loop.QuitClosure().Run();
-          });
+      .WillOnce([&run_loop](const FilePath& path, bool pinned,
+                            OnceCallback<void(FileError)> callback) {
+        std::move(callback).Run(FileError::FILE_ERROR_OK);
+        run_loop.QuitClosure().Run();
+      });
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
 
   // Create the syncing status update and emit the update to the manager.
-  const mojom::SyncingStatusPtr status = MakeSyncingStatus(items);
+  const SyncingStatusPtr status = MakeSyncingStatus(items);
   manager.OnSyncingStatusUpdate(*status);
 
   // Flipping all the events to `kCompleted` will not start the next search
@@ -953,21 +1140,21 @@
   // execute all tasks then automatically advance the clock until the periodic
   // removal task is executed, cleaning the "a.gdoc" file.
   base::RunLoop new_run_loop;
-  EXPECT_CALL(mock_drivefs_, GetMetadata(b_path, _))
+  EXPECT_CALL(drivefs_, GetMetadata(b_path, _))
       .WillOnce(RunOnceCallback<1>(
-          drive::FILE_ERROR_OK,
+          FileError::FILE_ERROR_OK,
           MakeMetadata(/*available_offline=*/true, /*size=*/128)));
-  EXPECT_CALL(mock_drivefs_, GetMetadata(gdoc_path, _))
+  EXPECT_CALL(drivefs_, GetMetadata(gdoc_path, _))
       // Mock the first file to be available offline with a 0 size.
       .WillOnce(RunOnceCallback<1>(
-          drive::FILE_ERROR_OK,
+          FileError::FILE_ERROR_OK,
           MakeMetadata(/*available_offline=*/true, /*size=*/0)));
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kSuccess))
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(mock_callback, Run(Stage::kSuccess))
       .WillOnce(RunClosure(new_run_loop.QuitClosure()));
-  SetState(status->item_events, mojom::ItemEvent::State::kCompleted);
+  SetState(status->item_events, ItemEvent::State::kCompleted);
   manager.OnSyncingStatusUpdate(*status);
   new_run_loop.Run();
 }
@@ -975,14 +1162,14 @@
 TEST_F(DriveFsPinManagerTest, OnDrop) {
   {
     MockObserver observer;
-    DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+    PinManager manager(temp_dir_.GetPath(), &drivefs_);
     manager.AddObserver(&observer);
     EXPECT_CALL(observer, OnDrop()).Times(1);
   }
   {
     MockObserver observer;
     EXPECT_CALL(observer, OnDrop()).Times(0);
-    DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+    PinManager manager(temp_dir_.GetPath(), &drivefs_);
     manager.AddObserver(&observer);
     manager.RemoveObserver(&observer);
   }
@@ -990,42 +1177,41 @@
 
 TEST_F(DriveFsPinManagerTest,
        DISABLED_SyncingStatusUpdateProgressIsReportedBackToObserver) {
-  base::MockOnceCallback<void(SetupStage)> mock_callback;
+  base::MockOnceCallback<void(Stage)> mock_callback;
 
   base::RunLoop run_loop;
 
-  base::FilePath file_path("/b");
-  const std::vector<DriveItem> items = {{.size = 128, .path = file_path}};
+  FilePath file_path("/b");
+  const vector<DriveItem> items = {{.size = 128, .path = file_path}};
 
-  EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(2);
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
+  EXPECT_CALL(drivefs_, OnStartSearchQuery(_)).Times(2);
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
       // Results returned whilst calculating free disk space.
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)))
       // Results returned when actually performing the pinning, the final
       // response (i.e. PopulateNoSearchItems()) happens after the
       // `OnSyncingStatusUpdate` instead.
-      .WillOnce(DoAll(PopulateSearchItems(items),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
+      .WillOnce(
+          DoAll(PopulateSearchItems(items), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
-  EXPECT_CALL(mock_drivefs_, SetPinned(_, true, _))
+  EXPECT_CALL(drivefs_, SetPinned(_, true, _))
       .Times(1)
       // `RunOnceCallback` can't be chained together in a `DoAll` action
       // combinator, so use an inline lambda instead.
-      .WillOnce(
-          [&run_loop](const base::FilePath& path, bool pinned,
-                      base::OnceCallback<void(drive::FileError)> callback) {
-            std::move(callback).Run(drive::FILE_ERROR_OK);
-            run_loop.QuitClosure().Run();
-          });
+      .WillOnce([&run_loop](const FilePath& path, bool pinned,
+                            OnceCallback<void(FileError)> callback) {
+        std::move(callback).Run(FileError::FILE_ERROR_OK);
+        run_loop.QuitClosure().Run();
+      });
 
   MockObserver observer;
   EXPECT_CALL(observer, OnProgress(_)).Times(AnyNumber());
 
-  DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+  PinManager manager(temp_dir_.GetPath(), &drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
   manager.AddObserver(&observer);
   manager.SetCompletionCallback(mock_callback.Get());
@@ -1033,18 +1219,17 @@
   run_loop.Run();
 
   // Create the syncing status update and emit the update to the manager.
-  const mojom::SyncingStatusPtr status = MakeSyncingStatus(items);
+  const SyncingStatusPtr status = MakeSyncingStatus(items);
   manager.OnSyncingStatusUpdate(*status);
 
   // Update the item in the syncing status to have transferred 10 bytes and
   // expect the progress to return that information.
   base::RunLoop setup_progress_run_loop;
-  SetState(status->item_events, mojom::ItemEvent::State::kInProgress);
+  SetState(status->item_events, ItemEvent::State::kInProgress);
   status->item_events.at(0)->bytes_transferred = 10;
-  EXPECT_CALL(
-      observer,
-      OnProgress(AllOf(Field(&SetupProgress::pinned_bytes, 10),
-                       Field(&SetupProgress::stage, SetupStage::kSyncing))))
+  EXPECT_CALL(observer,
+              OnProgress(AllOf(Field(&Progress::pinned_bytes, 10),
+                               Field(&Progress::stage, Stage::kSyncing))))
       .Times(1)
       .WillOnce(RunClosure(setup_progress_run_loop.QuitClosure()));
   manager.OnSyncingStatusUpdate(*status);
@@ -1054,21 +1239,20 @@
   // be the total size of the file. The reported progress should only add the
   // delta so we expect the pinned disk space to only equal the final file size.
   base::RunLoop new_run_loop;
-  EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
-      .WillOnce(DoAll(PopulateNoSearchItems(),
-                      Return(drive::FileError::FILE_ERROR_OK)));
-  EXPECT_CALL(mock_drivefs_, GetMetadata(_, _))
+  EXPECT_CALL(drivefs_, OnGetNextPage(_))
+      .WillOnce(
+          DoAll(PopulateNoSearchItems(), Return(FileError::FILE_ERROR_OK)));
+  EXPECT_CALL(drivefs_, GetMetadata(_, _))
       .WillOnce(RunOnceCallback<1>(
-          drive::FILE_ERROR_OK,
+          FileError::FILE_ERROR_OK,
           MakeMetadata(/*available_offline=*/true, /*size=*/128)));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kSuccess))
+  EXPECT_CALL(mock_callback, Run(Stage::kSuccess))
       .WillOnce(RunClosure(new_run_loop.QuitClosure()));
-  SetState(status->item_events, mojom::ItemEvent::State::kCompleted);
+  SetState(status->item_events, ItemEvent::State::kCompleted);
   status->item_events.at(0)->bytes_transferred = 128;
-  EXPECT_CALL(
-      observer,
-      OnProgress(AllOf(Field(&SetupProgress::pinned_bytes, 128),
-                       Field(&SetupProgress::stage, SetupStage::kSuccess))))
+  EXPECT_CALL(observer,
+              OnProgress(AllOf(Field(&Progress::pinned_bytes, 128),
+                               Field(&Progress::stage, Stage::kSuccess))))
       .Times(1)
       .WillOnce(RunClosure(setup_progress_run_loop.QuitClosure()));
   manager.OnSyncingStatusUpdate(*status);
diff --git a/chromeos/ash/components/network/onc/network_onc_utils.cc b/chromeos/ash/components/network/onc/network_onc_utils.cc
index e60970a7..b3da7154 100644
--- a/chromeos/ash/components/network/onc/network_onc_utils.cc
+++ b/chromeos/ash/components/network/onc/network_onc_utils.cc
@@ -507,15 +507,17 @@
   bool ethernet_not_found = false;
   int networks_created = 0;
   for (const auto& network : expanded_networks.GetList()) {
+    DCHECK(network.is_dict());
     // Remove irrelevant fields.
     onc::Normalizer normalizer(true /* remove recommended fields */);
-    base::Value normalized_network = normalizer.NormalizeObject(
-        &chromeos::onc::kNetworkConfigurationSignature, network);
+    base::Value::Dict normalized_network = normalizer.NormalizeObject(
+        &chromeos::onc::kNetworkConfigurationSignature, network.GetDict());
 
     // TODO(b/235297258): Use ONC and ManagedNetworkConfigurationHandler
     // instead.
     base::Value shill_dict = onc::TranslateONCObjectToShill(
-        &chromeos::onc::kNetworkConfigurationSignature, normalized_network);
+        &chromeos::onc::kNetworkConfigurationSignature,
+        base::Value(std::move(normalized_network)));
 
     std::unique_ptr<NetworkUIData> ui_data(
         NetworkUIData::CreateFromONC(::onc::ONC_SOURCE_USER_IMPORT));
diff --git a/chromeos/ash/components/network/onc/onc_normalizer.cc b/chromeos/ash/components/network/onc/onc_normalizer.cc
index c219b9e..4dee976 100644
--- a/chromeos/ash/components/network/onc/onc_normalizer.cc
+++ b/chromeos/ash/components/network/onc/onc_normalizer.cc
@@ -21,13 +21,12 @@
 
 Normalizer::~Normalizer() = default;
 
-base::Value Normalizer::NormalizeObject(
+base::Value::Dict Normalizer::NormalizeObject(
     const chromeos::onc::OncValueSignature* object_signature,
-    const base::Value& onc_object) {
+    const base::Value::Dict& onc_object) {
   CHECK(object_signature != nullptr);
   bool error = false;
-  base::Value result(
-      MapObject(*object_signature, onc_object.GetDict(), &error));
+  base::Value::Dict result = MapObject(*object_signature, onc_object, &error);
   DCHECK(!error);
   return result;
 }
diff --git a/chromeos/ash/components/network/onc/onc_normalizer.h b/chromeos/ash/components/network/onc/onc_normalizer.h
index 3419200d..ac75f6b 100644
--- a/chromeos/ash/components/network/onc/onc_normalizer.h
+++ b/chromeos/ash/components/network/onc/onc_normalizer.h
@@ -34,9 +34,9 @@
   // is set, but the field "HexSSID" is not, the contents of the "SSID" field is
   // converted to UTF-8 encoding, a hex representation of the byte sequence is
   // created and stored in the field "HexSSID".
-  base::Value NormalizeObject(
+  base::Value::Dict NormalizeObject(
       const chromeos::onc::OncValueSignature* object_signature,
-      const base::Value& onc_object);
+      const base::Value::Dict& onc_object);
 
  private:
   // Dispatch to the right normalization function according to |signature|.
diff --git a/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc b/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc
index ac4519d..27a34ec 100644
--- a/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc
+++ b/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc
@@ -17,15 +17,16 @@
 // if IPAddressConfigType is not 'Static'.
 TEST(ONCNormalizerTest, RemoveUnnecessaryAddressStaticIPConfigFields) {
   Normalizer normalizer(true);
-  base::Value data =
-      test_utils::ReadTestDictionaryValue("settings_with_normalization.json");
+  base::Value::Dict data =
+      test_utils::ReadTestDictionaryValue("settings_with_normalization.json")
+          .TakeDict();
 
-  const base::Value* original =
-      data.FindDictKey("unnecessary-address-staticipconfig");
-  const base::Value* expected_normalized =
-      data.FindDictKey("unnecessary-address-staticipconfig-normalized");
+  const base::Value::Dict* original =
+      data.FindDict("unnecessary-address-staticipconfig");
+  const base::Value::Dict* expected_normalized =
+      data.FindDict("unnecessary-address-staticipconfig-normalized");
 
-  base::Value actual_normalized = normalizer.NormalizeObject(
+  base::Value::Dict actual_normalized = normalizer.NormalizeObject(
       &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
@@ -35,15 +36,16 @@
 // {NameServers,IPAddress}ConfigType.
 TEST(ONCNormalizerTest, RetainExtraStaticIPConfigFields) {
   Normalizer normalizer(true);
-  base::Value data =
-      test_utils::ReadTestDictionaryValue("settings_with_normalization.json");
+  base::Value::Dict data =
+      test_utils::ReadTestDictionaryValue("settings_with_normalization.json")
+          .TakeDict();
 
-  const base::Value* original =
-      data.FindDictKey("unnecessary-address-staticipconfig");
-  const base::Value* expected_normalized =
-      data.FindDictKey("unnecessary-address-staticipconfig-normalized");
+  const base::Value::Dict* original =
+      data.FindDict("unnecessary-address-staticipconfig");
+  const base::Value::Dict* expected_normalized =
+      data.FindDict("unnecessary-address-staticipconfig-normalized");
 
-  base::Value actual_normalized = normalizer.NormalizeObject(
+  base::Value::Dict actual_normalized = normalizer.NormalizeObject(
       &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
@@ -52,15 +54,16 @@
 // removed.
 TEST(ONCNormalizerTest, RemoveStaticIPConfigFields) {
   Normalizer normalizer(true);
-  base::Value data =
-      test_utils::ReadTestDictionaryValue("settings_with_normalization.json");
+  base::Value::Dict data =
+      test_utils::ReadTestDictionaryValue("settings_with_normalization.json")
+          .TakeDict();
 
-  const base::Value* original =
-      data.FindDictKey("irrelevant-staticipconfig-fields");
-  const base::Value* expected_normalized =
-      data.FindDictKey("irrelevant-staticipconfig-fields-normalized");
+  const base::Value::Dict* original =
+      data.FindDict("irrelevant-staticipconfig-fields");
+  const base::Value::Dict* expected_normalized =
+      data.FindDict("irrelevant-staticipconfig-fields-normalized");
 
-  base::Value actual_normalized = normalizer.NormalizeObject(
+  base::Value::Dict actual_normalized = normalizer.NormalizeObject(
       &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
@@ -69,14 +72,15 @@
 // NameServersConfigType is 'DHCP'.
 TEST(ONCNormalizerTest, RemoveNameServers) {
   Normalizer normalizer(true);
-  base::Value data =
-      test_utils::ReadTestDictionaryValue("settings_with_normalization.json");
+  base::Value::Dict data =
+      test_utils::ReadTestDictionaryValue("settings_with_normalization.json")
+          .TakeDict();
 
-  const base::Value* original = data.FindDictKey("irrelevant-nameservers");
-  const base::Value* expected_normalized =
-      data.FindDictKey("irrelevant-nameservers-normalized");
+  const base::Value::Dict* original = data.FindDict("irrelevant-nameservers");
+  const base::Value::Dict* expected_normalized =
+      data.FindDict("irrelevant-nameservers-normalized");
 
-  base::Value actual_normalized = normalizer.NormalizeObject(
+  base::Value::Dict actual_normalized = normalizer.NormalizeObject(
       &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
@@ -85,28 +89,30 @@
 // is 'Static', but some required fields are missing.
 TEST(ONCNormalizerTest, RemoveIPFieldsForIncompleteConfig) {
   Normalizer normalizer(true);
-  base::Value data =
-      test_utils::ReadTestDictionaryValue("settings_with_normalization.json");
+  base::Value::Dict data =
+      test_utils::ReadTestDictionaryValue("settings_with_normalization.json")
+          .TakeDict();
 
-  const base::Value* original = data.FindDictKey("missing-ip-fields");
-  const base::Value* expected_normalized =
-      data.FindDictKey("missing-ip-fields-normalized");
+  const base::Value::Dict* original = data.FindDict("missing-ip-fields");
+  const base::Value::Dict* expected_normalized =
+      data.FindDict("missing-ip-fields-normalized");
 
-  base::Value actual_normalized = normalizer.NormalizeObject(
+  base::Value::Dict actual_normalized = normalizer.NormalizeObject(
       &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 // This test case is about validating valid ONC objects.
 TEST(ONCNormalizerTest, NormalizeNetworkConfigurationEthernetAndVPN) {
   Normalizer normalizer(true);
-  base::Value data =
-      test_utils::ReadTestDictionaryValue("settings_with_normalization.json");
+  base::Value::Dict data =
+      test_utils::ReadTestDictionaryValue("settings_with_normalization.json")
+          .TakeDict();
 
-  const base::Value* original = data.FindDictKey("ethernet-and-vpn");
-  const base::Value* expected_normalized =
-      data.FindDictKey("ethernet-and-vpn-normalized");
+  const base::Value::Dict* original = data.FindDict("ethernet-and-vpn");
+  const base::Value::Dict* expected_normalized =
+      data.FindDict("ethernet-and-vpn-normalized");
 
-  base::Value actual_normalized = normalizer.NormalizeObject(
+  base::Value::Dict actual_normalized = normalizer.NormalizeObject(
       &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
@@ -114,13 +120,15 @@
 // This test case is about validating valid ONC objects.
 TEST(ONCNormalizerTest, NormalizeNetworkConfigurationWifi) {
   Normalizer normalizer(true);
-  base::Value data =
-      test_utils::ReadTestDictionaryValue("settings_with_normalization.json");
+  base::Value::Dict data =
+      test_utils::ReadTestDictionaryValue("settings_with_normalization.json")
+          .TakeDict();
 
-  const base::Value* original = data.FindDictKey("wifi");
-  const base::Value* expected_normalized = data.FindDictKey("wifi-normalized");
+  const base::Value::Dict* original = data.FindDict("wifi");
+  const base::Value::Dict* expected_normalized =
+      data.FindDict("wifi-normalized");
 
-  base::Value actual_normalized = normalizer.NormalizeObject(
+  base::Value::Dict actual_normalized = normalizer.NormalizeObject(
       &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
diff --git a/chromeos/ash/components/network/policy_util.cc b/chromeos/ash/components/network/policy_util.cc
index 7ef0185..a1fa26b6 100644
--- a/chromeos/ash/components/network/policy_util.cc
+++ b/chromeos/ash/components/network/policy_util.cc
@@ -296,8 +296,8 @@
 
   // Remove irrelevant fields.
   onc::Normalizer normalizer(true /* remove recommended fields */);
-  effective = normalizer.NormalizeObject(
-      &chromeos::onc::kNetworkConfigurationSignature, effective);
+  effective = base::Value(normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, effective.GetDict()));
 
   base::Value shill_dictionary = onc::TranslateONCObjectToShill(
       &chromeos::onc::kNetworkConfigurationSignature, effective);
diff --git a/chromeos/components/onc/onc_test_utils.cc b/chromeos/components/onc/onc_test_utils.cc
index f51937d7..ced625a 100644
--- a/chromeos/components/onc/onc_test_utils.cc
+++ b/chromeos/components/onc/onc_test_utils.cc
@@ -99,6 +99,23 @@
                                        << *actual;
 }
 
+::testing::AssertionResult Equals(const base::Value::Dict* expected,
+                                  const base::Value::Dict* actual) {
+  CHECK(expected != nullptr);
+  if (actual == nullptr) {
+    return ::testing::AssertionFailure() << "Actual value pointer is nullptr";
+  }
+
+  if (*expected == *actual) {
+    return ::testing::AssertionSuccess() << "Values are equal";
+  }
+
+  return ::testing::AssertionFailure() << "Values are unequal.\n"
+                                       << "Expected value:\n"
+                                       << *expected << "Actual value:\n"
+                                       << *actual;
+}
+
 }  // namespace test_utils
 }  // namespace onc
 }  // namespace chromeos
diff --git a/chromeos/components/onc/onc_test_utils.h b/chromeos/components/onc/onc_test_utils.h
index 668691e8..d3a7067 100644
--- a/chromeos/components/onc/onc_test_utils.h
+++ b/chromeos/components/onc/onc_test_utils.h
@@ -31,6 +31,8 @@
 // EXPECT_TRUE(test_utils::Equals(expected, actual));
 ::testing::AssertionResult Equals(const base::Value* expected,
                                   const base::Value* actual);
+::testing::AssertionResult Equals(const base::Value::Dict* expected,
+                                  const base::Value::Dict* actual);
 
 }  // namespace test_utils
 }  // namespace onc
diff --git a/chromeos/components/onc/onc_validator.cc b/chromeos/components/onc/onc_validator.cc
index 7608f64f..74e59bd 100644
--- a/chromeos/components/onc/onc_validator.cc
+++ b/chromeos/components/onc/onc_validator.cc
@@ -33,29 +33,28 @@
 // According to the IEEE 802.11 standard the SSID is a series of 0 to 32 octets.
 const int kMaximumSSIDLengthInBytes = 32;
 
-void AddKeyToList(const char* key, base::Value* list) {
+void AddKeyToList(const char* key, base::Value::List* list) {
   base::Value key_value(key);
-  if (!base::Contains(list->GetList(), key_value))
+  if (!base::Contains(*list, key_value)) {
     list->Append(std::move(key_value));
+  }
 }
 
-std::string GetStringFromDict(const base::Value& dict, const char* key) {
-  const base::Value* value = dict.FindKeyOfType(key, base::Value::Type::STRING);
-  return value ? value->GetString() : std::string();
+std::string GetStringFromDict(const base::Value::Dict& dict, const char* key) {
+  const std::string* value = dict.FindString(key);
+  return value ? *value : std::string();
 }
 
-bool FieldIsRecommended(const base::Value& object,
+bool FieldIsRecommended(const base::Value::Dict& object,
                         const std::string& field_name) {
-  const base::Value* recommended =
-      object.FindKeyOfType(::onc::kRecommended, base::Value::Type::LIST);
-  return recommended &&
-         base::Contains(recommended->GetList(), base::Value(field_name));
+  const base::Value::List* recommended = object.FindList(::onc::kRecommended);
+  return recommended && base::Contains(*recommended, base::Value(field_name));
 }
 
-bool FieldIsSetToValueOrRecommended(const base::Value& object,
+bool FieldIsSetToValueOrRecommended(const base::Value::Dict& object,
                                     const std::string& field_name,
                                     const base::Value& expected_value) {
-  const base::Value* actual_value = object.GetDict().Find(field_name);
+  const base::Value* actual_value = object.Find(field_name);
   if (actual_value && expected_value == *actual_value)
     return true;
 
@@ -116,7 +115,7 @@
 base::Value::Dict Validator::MapObject(const OncValueSignature& signature,
                                        const base::Value::Dict& onc_object,
                                        bool* error) {
-  base::Value repaired(base::Value::Type::DICT);
+  base::Value::Dict repaired;
   bool valid = ValidateObjectDefault(signature, onc_object, &repaired);
 
   if (valid) {
@@ -171,7 +170,7 @@
   }
 
   if (valid)
-    return std::move(repaired).TakeDict();
+    return repaired;
 
   DCHECK(!validation_issues_.empty());
   *error = true;
@@ -243,11 +242,11 @@
 
 bool Validator::ValidateObjectDefault(const OncValueSignature& signature,
                                       const base::Value::Dict& onc_object,
-                                      base::Value* result) {
+                                      base::Value::Dict* result) {
   bool found_unknown_field = false;
   bool nested_error_occured = false;
   MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
-            &result->GetDict());
+            result);
 
   if (found_unknown_field && error_on_unknown_field_) {
     DVLOG(1) << "Unknown field names are errors: Aborting.";
@@ -262,11 +261,11 @@
 
 bool Validator::ValidateRecommendedField(
     const OncValueSignature& object_signature,
-    base::Value* result) {
+    base::Value::Dict* result) {
   CHECK(result);
 
   absl::optional<base::Value> recommended_value =
-      result->ExtractKey(::onc::kRecommended);
+      result->Extract(::onc::kRecommended);
   // This remove passes ownership to |recommended_value|.
   if (!recommended_value) {
     return true;
@@ -283,7 +282,7 @@
     return true;
   }
 
-  base::Value repaired_recommended(base::Value::Type::LIST);
+  base::Value::List repaired_recommended;
   for (const auto& entry : recommended_value->GetList()) {
     const std::string* field_name = entry.GetIfString();
     if (!field_name) {
@@ -320,12 +319,12 @@
     repaired_recommended.Append(*field_name);
   }
 
-  result->SetKey(::onc::kRecommended, std::move(repaired_recommended));
+  result->Set(::onc::kRecommended, std::move(repaired_recommended));
   return true;
 }
 
 bool Validator::ValidateClientCertFields(bool allow_cert_type_none,
-                                         base::Value* result) {
+                                         base::Value::Dict* result) {
   std::vector<const char*> valid_cert_types = {
       ::onc::client_cert::kRef, ::onc::client_cert::kPattern,
       ::onc::client_cert::kProvisioningProfileId,
@@ -372,9 +371,9 @@
 
 }  // namespace
 
-bool Validator::IsInDevicePolicy(base::Value* result,
+bool Validator::IsInDevicePolicy(base::Value::Dict* result,
                                  const std::string& field_name) {
-  if (result->GetDict().contains(field_name)) {
+  if (result->contains(field_name)) {
     if (onc_source_ != ::onc::ONC_SOURCE_DEVICE_POLICY) {
       std::ostringstream msg;
       msg << "Field '" << field_name << "' is only allowed in a device policy.";
@@ -400,10 +399,10 @@
 }
 
 bool Validator::FieldExistsAndHasNoValidValue(
-    const base::Value& object,
+    const base::Value::Dict& object,
     const std::string& field_name,
     const std::vector<const char*>& valid_values) {
-  const std::string* actual_value = object.FindStringKey(field_name);
+  const std::string* actual_value = object.FindString(field_name);
   if (!actual_value)
     return false;
 
@@ -413,11 +412,11 @@
   return !valid;
 }
 
-bool Validator::FieldExistsAndIsNotInRange(const base::Value& object,
+bool Validator::FieldExistsAndIsNotInRange(const base::Value::Dict& object,
                                            const std::string& field_name,
                                            int lower_bound,
                                            int upper_bound) {
-  absl::optional<int> actual_value = object.FindIntKey(field_name);
+  absl::optional<int> actual_value = object.FindInt(field_name);
   if (!actual_value || (lower_bound <= actual_value.value() &&
                         actual_value.value() <= upper_bound)) {
     return false;
@@ -433,9 +432,8 @@
   return true;
 }
 
-bool Validator::FieldExistsAndIsEmpty(const base::Value& object,
+bool Validator::FieldExistsAndIsEmpty(const base::Value::Dict& dict,
                                       const std::string& field_name) {
-  const base::Value::Dict& dict = object.GetDict();
   if (!dict.contains(field_name)) {
     return false;
   }
@@ -463,10 +461,9 @@
   return true;
 }
 
-bool Validator::FieldShouldExistOrBeRecommended(const base::Value& object,
+bool Validator::FieldShouldExistOrBeRecommended(const base::Value::Dict& object,
                                                 const std::string& field_name) {
-  if (object.GetDict().contains(field_name) ||
-      FieldIsRecommended(object, field_name)) {
+  if (object.contains(field_name) || FieldIsRecommended(object, field_name)) {
     return true;
   }
 
@@ -477,11 +474,10 @@
   return !error_on_missing_field_;
 }
 
-bool Validator::OnlyOneFieldSet(const base::Value& object,
+bool Validator::OnlyOneFieldSet(const base::Value::Dict& object,
                                 const std::string& field_name1,
                                 const std::string& field_name2) {
-  if (object.GetDict().contains(field_name1) &&
-      object.GetDict().contains(field_name2)) {
+  if (object.contains(field_name1) && object.contains(field_name2)) {
     std::ostringstream msg;
     msg << "At most one of '" << field_name1 << "' and '" << field_name2
         << "' can be set.";
@@ -492,14 +488,14 @@
 }
 
 bool Validator::ListFieldContainsValidValues(
-    const base::Value& object,
+    const base::Value::Dict& object,
     const std::string& field_name,
     const std::vector<const char*>& valid_values) {
-  const base::Value* list = object.FindListKey(field_name);
+  const base::Value::List* list = object.FindList(field_name);
   if (!list)
     return true;
   path_.push_back(field_name);
-  for (const auto& entry : list->GetList()) {
+  for (const auto& entry : *list) {
     const std::string* value = entry.GetIfString();
     if (!value) {
       NOTREACHED();  // The types of field values are already verified.
@@ -514,11 +510,11 @@
   return true;
 }
 
-bool Validator::ValidateSSIDAndHexSSID(base::Value* object) {
+bool Validator::ValidateSSIDAndHexSSID(base::Value::Dict* object) {
   const std::string kInvalidLength = "Invalid length";
 
   // Check SSID validity.
-  std::string* ssid_string = object->FindStringKey(::onc::wifi::kSSID);
+  std::string* ssid_string = object->FindString(::onc::wifi::kSSID);
   if (ssid_string && (ssid_string->size() <= 0 ||
                       ssid_string->size() > kMaximumSSIDLengthInBytes)) {
     path_.push_back(::onc::wifi::kSSID);
@@ -527,7 +523,7 @@
     // If the HexSSID field is present, ignore errors in SSID because these
     // might be caused by the usage of a non-UTF-8 encoding when the SSID
     // field was automatically added (see FillInHexSSIDField).
-    if (!object->GetDict().contains(::onc::wifi::kHexSSID)) {
+    if (!object->contains(::onc::wifi::kHexSSID)) {
       AddValidationIssue(true /* is_error */, msg.str());
       path_.pop_back();
       return false;
@@ -537,7 +533,7 @@
   }
 
   // Check HexSSID validity.
-  std::string* hex_ssid_string = object->FindStringKey(::onc::wifi::kHexSSID);
+  std::string* hex_ssid_string = object->FindString(::onc::wifi::kHexSSID);
   if (!hex_ssid_string)
     return true;
 
@@ -571,15 +567,15 @@
           << ::onc::wifi::kHexSSID << "' contain inconsistent values.";
       AddValidationIssue(false /* is_error */, msg.str());
       path_.pop_back();
-      object->RemoveKey(::onc::wifi::kSSID);
+      object->Remove(::onc::wifi::kSSID);
     }
   }
   return true;
 }
 
-bool Validator::RequireField(const base::Value& dict,
+bool Validator::RequireField(const base::Value::Dict& dict,
                              const std::string& field_name) {
-  if (dict.GetDict().contains(field_name)) {
+  if (dict.contains(field_name)) {
     return true;
   }
 
@@ -589,10 +585,10 @@
   return false;
 }
 
-bool Validator::CheckGuidIsUniqueAndAddToSet(const base::Value& dict,
+bool Validator::CheckGuidIsUniqueAndAddToSet(const base::Value::Dict& dict,
                                              const std::string& key_guid,
                                              std::set<std::string>* guids) {
-  const std::string* guid = dict.FindStringKey(key_guid);
+  const std::string* guid = dict.FindString(key_guid);
   if (!guid)
     return true;
 
@@ -609,9 +605,9 @@
 }
 
 bool Validator::IsGlobalNetworkConfigInUserImport(
-    const base::Value& onc_object) {
+    const base::Value::Dict& onc_object) {
   if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT &&
-      onc_object.GetDict().contains(
+      onc_object.contains(
           ::onc::toplevel_config::kGlobalNetworkConfiguration)) {
     std::ostringstream msg;
     msg << "Field '" << ::onc::toplevel_config::kGlobalNetworkConfiguration
@@ -622,7 +618,7 @@
   return false;
 }
 
-bool Validator::ValidateToplevelConfiguration(base::Value* result) {
+bool Validator::ValidateToplevelConfiguration(base::Value::Dict* result) {
   const std::vector<const char*> valid_types = {
       ::onc::toplevel_config::kUnencryptedConfiguration,
       ::onc::toplevel_config::kEncryptedConfiguration};
@@ -636,9 +632,9 @@
   return true;
 }
 
-bool Validator::ValidateNetworkConfiguration(base::Value* result) {
+bool Validator::ValidateNetworkConfiguration(base::Value::Dict* result) {
   const std::string* onc_type =
-      result->FindStringKey(::onc::network_config::kType);
+      result->FindString(::onc::network_config::kType);
   if (onc_type && *onc_type == ::onc::network_type::kWimaxDeprecated) {
     AddValidationIssue(/*is_error=*/false, "WiMax is deprecated");
     return true;
@@ -670,7 +666,7 @@
 
   bool all_required_exist = RequireField(*result, ::onc::network_config::kGUID);
 
-  bool remove = result->FindBoolKey(::onc::kRemove).value_or(false);
+  bool remove = result->FindBool(::onc::kRemove).value_or(false);
   if (!remove) {
     all_required_exist &= RequireField(*result, ::onc::network_config::kName) &&
                           RequireField(*result, ::onc::network_config::kType);
@@ -719,7 +715,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateEthernet(base::Value* result) {
+bool Validator::ValidateEthernet(base::Value::Dict* result) {
   const std::vector<const char*> valid_authentications = {
       ::onc::ethernet::kAuthenticationNone, ::onc::ethernet::k8021X};
   if (FieldExistsAndHasNoValidValue(*result, ::onc::ethernet::kAuthentication,
@@ -736,7 +732,8 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateIPConfig(base::Value* result, bool require_fields) {
+bool Validator::ValidateIPConfig(base::Value::Dict* result,
+                                 bool require_fields) {
   const std::vector<const char*> valid_types = {::onc::ipconfig::kIPv4,
                                                 ::onc::ipconfig::kIPv6};
   if (FieldExistsAndHasNoValidValue(*result, ::onc::ipconfig::kType,
@@ -770,7 +767,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::NetworkHasCorrectStaticIPConfig(base::Value* network) {
+bool Validator::NetworkHasCorrectStaticIPConfig(base::Value::Dict* network) {
   bool must_have_ip_config = FieldIsSetToValueOrRecommended(
       *network, ::onc::network_config::kIPAddressConfigType,
       base::Value(::onc::network_config::kIPConfigTypeStatic));
@@ -784,8 +781,8 @@
   if (!RequireField(*network, ::onc::network_config::kStaticIPConfig))
     return false;
 
-  base::Value* static_ip_config =
-      network->FindDictKey(::onc::network_config::kStaticIPConfig);
+  base::Value::Dict* static_ip_config =
+      network->FindDict(::onc::network_config::kStaticIPConfig);
   bool valid = true;
   // StaticIPConfig should have all fields required by the corresponding
   // IPAddressConfigType and NameServersConfigType values.
@@ -797,7 +794,7 @@
   return valid;
 }
 
-bool Validator::ValidateWiFi(base::Value* result) {
+bool Validator::ValidateWiFi(base::Value::Dict* result) {
   const std::vector<const char*> valid_securities = {
       ::onc::wifi::kSecurityNone, ::onc::wifi::kWEP_PSK,
       ::onc::wifi::kWEP_8021X, ::onc::wifi::kWPA_PSK, ::onc::wifi::kWPA_EAP};
@@ -811,10 +808,10 @@
   bool all_required_exist = RequireField(*result, ::onc::wifi::kSecurity);
 
   // One of {kSSID, kHexSSID} must be present.
-  if (!result->GetDict().contains(::onc::wifi::kSSID)) {
+  if (!result->contains(::onc::wifi::kSSID)) {
     all_required_exist &= RequireField(*result, ::onc::wifi::kHexSSID);
   }
-  if (!result->GetDict().contains(::onc::wifi::kHexSSID)) {
+  if (!result->contains(::onc::wifi::kHexSSID)) {
     all_required_exist &= RequireField(*result, ::onc::wifi::kSSID);
   }
 
@@ -828,7 +825,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateVPN(base::Value* result) {
+bool Validator::ValidateVPN(base::Value::Dict* result) {
   std::vector<const char*> valid_types = {
       ::onc::vpn::kIPsec,
       ::onc::vpn::kTypeL2TP_IPsec,
@@ -864,7 +861,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateIPsec(base::Value* result) {
+bool Validator::ValidateIPsec(base::Value::Dict* result) {
   const std::vector<const char*> valid_authentications = {
       ::onc::ipsec::kPSK, ::onc::ipsec::kCert, ::onc::ipsec::kEAP};
   if (FieldExistsAndHasNoValidValue(*result, ::onc::ipsec::kAuthenticationType,
@@ -892,10 +889,9 @@
 
   // For cert-based or EAP-based authentication, server CA must exist.
   // For PSK-based authentication, server CA must not exist.
-  const base::Value::Dict& dict = result->GetDict();
-  bool has_server_ca_cert = dict.contains(::onc::ipsec::kServerCARefs) ||
-                            dict.contains(::onc::ipsec::kServerCARef) ||
-                            dict.contains(::onc::ipsec::kServerCAPEMs);
+  bool has_server_ca_cert = result->contains(::onc::ipsec::kServerCARefs) ||
+                            result->contains(::onc::ipsec::kServerCARef) ||
+                            result->contains(::onc::ipsec::kServerCAPEMs);
   if ((auth == ::onc::ipsec::kCert || auth == ::onc::ipsec::kEAP) &&
       !has_server_ca_cert) {
     all_required_exist = false;
@@ -918,7 +914,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateOpenVPN(base::Value* result) {
+bool Validator::ValidateOpenVPN(base::Value::Dict* result) {
   const std::vector<const char*> valid_auth_retry_values = {
       ::onc::openvpn::kNone, ::onc::openvpn::kInteract,
       ::onc::openvpn::kNoInteract};
@@ -956,14 +952,14 @@
   // properties where appropriate.
   if ((onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY ||
        onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)) {
-    base::Value* recommended =
-        result->FindKeyOfType(::onc::kRecommended, base::Value::Type::LIST);
-    if (!recommended)
-      recommended = result->SetKey(::onc::kRecommended,
-                                   base::Value(base::Value::Type::LIST));
+    base::Value::List* recommended = result->FindList(::onc::kRecommended);
+    if (!recommended) {
+      recommended =
+          &result->Set(::onc::kRecommended, base::Value::List())->GetList();
+    }
 
     // If kUserAuthenticationType is unspecified, allow Password and OTP.
-    if (!result->FindStringKey(::onc::openvpn::kUserAuthenticationType)) {
+    if (!result->FindString(::onc::openvpn::kUserAuthenticationType)) {
       AddKeyToList(::onc::openvpn::kPassword, recommended);
       AddKeyToList(::onc::openvpn::kOTP, recommended);
     }
@@ -992,9 +988,8 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateWireGuard(base::Value* result) {
-  const base::Value::Dict& dict = result->GetDict();
-  const base::Value::List* peers = dict.FindList(::onc::wireguard::kPeers);
+bool Validator::ValidateWireGuard(base::Value::Dict* result) {
+  const base::Value::List* peers = result->FindList(::onc::wireguard::kPeers);
   std::ostringstream msg;
   if (!peers) {
     msg << "A " << ::onc::wireguard::kPeers
@@ -1016,21 +1011,21 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateThirdPartyVPN(base::Value* result) {
+bool Validator::ValidateThirdPartyVPN(base::Value::Dict* result) {
   const bool all_required_exist =
       RequireField(*result, ::onc::third_party_vpn::kExtensionID);
 
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateARCVPN(base::Value* result) {
+bool Validator::ValidateARCVPN(base::Value::Dict* result) {
   const bool all_required_exist =
       RequireField(*result, ::onc::arc_vpn::kTunnelChrome);
 
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateVerifyX509(base::Value* result) {
+bool Validator::ValidateVerifyX509(base::Value::Dict* result) {
   const std::vector<const char*> valid_types = {
       ::onc::verify_x509::types::kName, ::onc::verify_x509::types::kNamePrefix,
       ::onc::verify_x509::types::kSubject};
@@ -1044,12 +1039,11 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateCertificatePattern(base::Value* result) {
+bool Validator::ValidateCertificatePattern(base::Value::Dict* result) {
   bool all_required_exist = true;
-  const base::Value::Dict& dict = result->GetDict();
-  if (!dict.contains(::onc::client_cert::kSubject) &&
-      !dict.contains(::onc::client_cert::kIssuer) &&
-      !dict.contains(::onc::client_cert::kIssuerCARef)) {
+  if (!result->contains(::onc::client_cert::kSubject) &&
+      !result->contains(::onc::client_cert::kIssuer) &&
+      !result->contains(::onc::client_cert::kIssuerCARef)) {
     all_required_exist = false;
     std::ostringstream msg;
     msg << "None of the fields '" << ::onc::client_cert::kSubject << "', '"
@@ -1062,15 +1056,14 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateGlobalNetworkConfiguration(base::Value* result) {
+bool Validator::ValidateGlobalNetworkConfiguration(base::Value::Dict* result) {
   // Replace the deprecated kBlacklistedHexSSIDs with kBlockedHexSSIDs.
-  if (!result->GetDict().contains(
-          ::onc::global_network_config::kBlockedHexSSIDs)) {
+  if (!result->contains(::onc::global_network_config::kBlockedHexSSIDs)) {
     absl::optional<base::Value> blocked =
-        result->ExtractKey(::onc::global_network_config::kBlacklistedHexSSIDs);
+        result->Extract(::onc::global_network_config::kBlacklistedHexSSIDs);
     if (blocked) {
-      result->SetKey(::onc::global_network_config::kBlockedHexSSIDs,
-                     std::move(*blocked));
+      result->Set(::onc::global_network_config::kBlockedHexSSIDs,
+                  std::move(*blocked));
     }
   }
 
@@ -1108,7 +1101,7 @@
   return true;
 }
 
-bool Validator::ValidateProxySettings(base::Value* result) {
+bool Validator::ValidateProxySettings(base::Value::Dict* result) {
   const std::vector<const char*> valid_types = {
       ::onc::proxy::kDirect, ::onc::proxy::kManual, ::onc::proxy::kPAC,
       ::onc::proxy::kWPAD};
@@ -1125,14 +1118,14 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateProxyLocation(base::Value* result) {
+bool Validator::ValidateProxyLocation(base::Value::Dict* result) {
   bool all_required_exist = RequireField(*result, ::onc::proxy::kHost) &&
                             RequireField(*result, ::onc::proxy::kPort);
 
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateEAP(base::Value* result) {
+bool Validator::ValidateEAP(base::Value::Dict* result) {
   const std::vector<const char*> valid_inner_values = {
       ::onc::eap::kAutomatic, ::onc::eap::kGTC, ::onc::eap::kMD5,
       ::onc::eap::kMSCHAPv2, ::onc::eap::kPAP};
@@ -1169,7 +1162,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateSubjectAlternativeNameMatch(base::Value* result) {
+bool Validator::ValidateSubjectAlternativeNameMatch(base::Value::Dict* result) {
   const std::vector<const char*> valid_types = {
       ::onc::eap_subject_alternative_name_match::kEMAIL,
       ::onc::eap_subject_alternative_name_match::kDNS,
@@ -1188,7 +1181,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateCertificate(base::Value* result) {
+bool Validator::ValidateCertificate(base::Value::Dict* result) {
   const std::vector<const char*> valid_types = {::onc::certificate::kClient,
                                                 ::onc::certificate::kServer,
                                                 ::onc::certificate::kAuthority};
@@ -1206,7 +1199,7 @@
 
   bool all_required_exist = RequireField(*result, ::onc::certificate::kGUID);
 
-  bool remove = result->FindBoolKey(::onc::kRemove).value_or(false);
+  bool remove = result->FindBool(::onc::kRemove).value_or(false);
   if (remove) {
     path_.push_back(::onc::kRemove);
     std::ostringstream msg;
@@ -1227,7 +1220,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateScope(base::Value* result) {
+bool Validator::ValidateScope(base::Value::Dict* result) {
   const std::vector<const char*> valid_types = {::onc::scope::kDefault,
                                                 ::onc::scope::kExtension};
   if (FieldExistsAndHasNoValidValue(*result, ::onc::scope::kType,
@@ -1237,11 +1230,11 @@
   }
 
   bool all_required_exist = RequireField(*result, ::onc::scope::kType);
-  const std::string* type_string = result->FindStringKey(::onc::scope::kType);
+  const std::string* type_string = result->FindString(::onc::scope::kType);
   if (type_string && *type_string == ::onc::scope::kExtension) {
     all_required_exist &= RequireField(*result, ::onc::scope::kId);
     // Check Id validity for type 'Extension'.
-    const std::string* id_string = result->FindStringKey(::onc::scope::kId);
+    const std::string* id_string = result->FindString(::onc::scope::kId);
     if (id_string && !crx_file::id_util::IdIsValid(*id_string)) {
       std::ostringstream msg;
       msg << "Field '" << ::onc::scope::kId << "' is not a valid extension id.";
@@ -1253,7 +1246,7 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
-bool Validator::ValidateTether(base::Value* result) {
+bool Validator::ValidateTether(base::Value::Dict* result) {
   if (FieldExistsAndIsNotInRange(*result, ::onc::tether::kBatteryPercentage, 0,
                                  100) ||
       FieldExistsAndIsNotInRange(*result, ::onc::tether::kSignalStrength, 0,
diff --git a/chromeos/components/onc/onc_validator.h b/chromeos/components/onc/onc_validator.h
index 3de950b..53200ad 100644
--- a/chromeos/components/onc/onc_validator.h
+++ b/chromeos/components/onc/onc_validator.h
@@ -170,40 +170,41 @@
   // dictionary into which the repaired fields are written.
   bool ValidateObjectDefault(const OncValueSignature& object_signature,
                              const base::Value::Dict& onc_object,
-                             base::Value* result);
+                             base::Value::Dict* result);
 
   // Validates/repairs the kRecommended array in |result| according to
   // |object_signature| of the enclosing object.
   bool ValidateRecommendedField(const OncValueSignature& object_signature,
-                                base::Value* result);
+                                base::Value::Dict* result);
 
   // Validates the ClientCert* fields in a VPN or EAP object. Only if
   // |allow_cert_type_none| is true, the value "None" is allowed as
   // ClientCertType.
-  bool ValidateClientCertFields(bool allow_cert_type_none, base::Value* result);
+  bool ValidateClientCertFields(bool allow_cert_type_none,
+                                base::Value::Dict* result);
 
-  bool ValidateToplevelConfiguration(base::Value* result);
-  bool ValidateNetworkConfiguration(base::Value* result);
-  bool ValidateEthernet(base::Value* result);
-  bool ValidateIPConfig(base::Value* result, bool require_fields = true);
-  bool ValidateNameServersConfig(base::Value* result);
-  bool ValidateWiFi(base::Value* result);
-  bool ValidateVPN(base::Value* result);
-  bool ValidateIPsec(base::Value* result);
-  bool ValidateOpenVPN(base::Value* result);
-  bool ValidateWireGuard(base::Value* result);
-  bool ValidateThirdPartyVPN(base::Value* result);
-  bool ValidateARCVPN(base::Value* result);
-  bool ValidateVerifyX509(base::Value* result);
-  bool ValidateCertificatePattern(base::Value* result);
-  bool ValidateGlobalNetworkConfiguration(base::Value* result);
-  bool ValidateProxySettings(base::Value* result);
-  bool ValidateProxyLocation(base::Value* result);
-  bool ValidateEAP(base::Value* result);
-  bool ValidateSubjectAlternativeNameMatch(base::Value* result);
-  bool ValidateCertificate(base::Value* result);
-  bool ValidateScope(base::Value* result);
-  bool ValidateTether(base::Value* result);
+  bool ValidateToplevelConfiguration(base::Value::Dict* result);
+  bool ValidateNetworkConfiguration(base::Value::Dict* result);
+  bool ValidateEthernet(base::Value::Dict* result);
+  bool ValidateIPConfig(base::Value::Dict* result, bool require_fields = true);
+  bool ValidateNameServersConfig(base::Value::Dict* result);
+  bool ValidateWiFi(base::Value::Dict* result);
+  bool ValidateVPN(base::Value::Dict* result);
+  bool ValidateIPsec(base::Value::Dict* result);
+  bool ValidateOpenVPN(base::Value::Dict* result);
+  bool ValidateWireGuard(base::Value::Dict* result);
+  bool ValidateThirdPartyVPN(base::Value::Dict* result);
+  bool ValidateARCVPN(base::Value::Dict* result);
+  bool ValidateVerifyX509(base::Value::Dict* result);
+  bool ValidateCertificatePattern(base::Value::Dict* result);
+  bool ValidateGlobalNetworkConfiguration(base::Value::Dict* result);
+  bool ValidateProxySettings(base::Value::Dict* result);
+  bool ValidateProxyLocation(base::Value::Dict* result);
+  bool ValidateEAP(base::Value::Dict* result);
+  bool ValidateSubjectAlternativeNameMatch(base::Value::Dict* result);
+  bool ValidateCertificate(base::Value::Dict* result);
+  bool ValidateScope(base::Value::Dict* result);
+  bool ValidateTether(base::Value::Dict* result);
   void ValidateEthernetConfigs(base::Value::List* result);
   void OnlyKeepLast(base::Value::List* network_configurations_list,
                     const std::vector<std::string>& guids,
@@ -215,19 +216,20 @@
   bool IsValidValue(const std::string& field_value,
                     const std::vector<const char*>& valid_values);
 
-  bool IsInDevicePolicy(base::Value* result, const std::string& field_name);
+  bool IsInDevicePolicy(base::Value::Dict* result,
+                        const std::string& field_name);
 
   bool FieldExistsAndHasNoValidValue(
-      const base::Value& object,
+      const base::Value::Dict& object,
       const std::string& field_name,
       const std::vector<const char*>& valid_values);
 
-  bool FieldExistsAndIsNotInRange(const base::Value& object,
+  bool FieldExistsAndIsNotInRange(const base::Value::Dict& object,
                                   const std::string& field_name,
                                   int lower_bound,
                                   int upper_bound);
 
-  bool FieldExistsAndIsEmpty(const base::Value& object,
+  bool FieldExistsAndIsEmpty(const base::Value::Dict& object,
                              const std::string& field_name);
 
   // Validates 'StaticIPConfig' field of the given network configuration. This
@@ -235,36 +237,36 @@
   // because it needs other 'NetworkConfiguration' fields (e.g.
   // 'IPAddressConfigType' and 'NameServersConfigType') to check correctness of
   // the 'StaticIPConfig' field.
-  bool NetworkHasCorrectStaticIPConfig(base::Value* network);
+  bool NetworkHasCorrectStaticIPConfig(base::Value::Dict* network);
 
   // Validates that the given field either exists or is recommended.
-  bool FieldShouldExistOrBeRecommended(const base::Value& object,
+  bool FieldShouldExistOrBeRecommended(const base::Value::Dict& object,
                                        const std::string& field_name);
 
-  bool OnlyOneFieldSet(const base::Value& object,
+  bool OnlyOneFieldSet(const base::Value::Dict& object,
                        const std::string& field_name1,
                        const std::string& field_name2);
 
   bool ListFieldContainsValidValues(
-      const base::Value& object,
+      const base::Value::Dict& object,
       const std::string& field_name,
       const std::vector<const char*>& valid_values);
 
-  bool ValidateSSIDAndHexSSID(base::Value* object);
+  bool ValidateSSIDAndHexSSID(base::Value::Dict* object);
 
   // Returns true if |key| is a key of |dict|. Otherwise, returns false and,
   // depending on |error_on_missing_field_| raises an error or a warning.
-  bool RequireField(const base::Value& dict, const std::string& key);
+  bool RequireField(const base::Value::Dict& dict, const std::string& key);
 
   // Returns true if the GUID is unique or if the GUID is not a string
   // and false otherwise. The function also adds the GUID to a set in
   // order to identify duplicates.
-  bool CheckGuidIsUniqueAndAddToSet(const base::Value& dict,
+  bool CheckGuidIsUniqueAndAddToSet(const base::Value::Dict& dict,
                                     const std::string& kGUID,
                                     std::set<std::string>* guids);
 
   // Prohibit global network configuration in user ONC imports.
-  bool IsGlobalNetworkConfigInUserImport(const base::Value& onc_object);
+  bool IsGlobalNetworkConfigInUserImport(const base::Value::Dict& onc_object);
 
   void AddValidationIssue(bool is_error, const std::string& debug_info);
 
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index b423491..695c09e 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -478,11 +478,10 @@
     ui::OzonePlatform::InitParams ozone_params;
     ozone_params.single_process = true;
     ui::OzonePlatform::InitializeForGPU(ozone_params);
-    gl::GLDisplayEGL* display =
-        static_cast<gl::GLDisplayEGL*>(gl::init::InitializeGLOneOff(
-            /*gpu_preference=*/gl::GpuPreference::kDefault));
-    DCHECK(display);
-    gl_surface_ = gl::init::CreateOffscreenGLSurface(display, gfx::Size());
+    egl_display_ = static_cast<gl::GLDisplayEGL*>(gl::init::InitializeGLOneOff(
+        /*gpu_preference=*/gl::GpuPreference::kDefault));
+    DCHECK(egl_display_);
+    gl_surface_ = gl::init::CreateOffscreenGLSurface(egl_display_, gfx::Size());
     gl_context_ =
         gl::init::CreateGLContext(nullptr,  // share_group
                                   gl_surface_.get(), gl::GLContextAttribs());
@@ -490,10 +489,10 @@
     make_current_ = std::make_unique<ui::ScopedMakeCurrent>(gl_context_.get(),
                                                             gl_surface_.get());
 
-    if (display->ext->b_EGL_ARM_implicit_external_sync) {
+    if (egl_display_->ext->b_EGL_ARM_implicit_external_sync) {
       egl_sync_type_ = EGL_SYNC_FENCE_KHR;
     }
-    if (display->ext->b_EGL_ANDROID_native_fence_sync) {
+    if (egl_display_->ext->b_EGL_ANDROID_native_fence_sync) {
       egl_sync_type_ = EGL_SYNC_NATIVE_FENCE_ANDROID;
     }
 
@@ -737,7 +736,16 @@
 
 ClientBase::ClientBase() {}
 
-ClientBase::~ClientBase() {}
+ClientBase::~ClientBase() {
+  make_current_ = nullptr;
+  gl_context_ = nullptr;
+  gl_surface_ = nullptr;
+#if defined(USE_GBM)
+  if (egl_display_) {
+    gl::init::ShutdownGL(egl_display_, false);
+  }
+#endif
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // wl_touch_listener
diff --git a/components/exo/wayland/clients/client_base.h b/components/exo/wayland/clients/client_base.h
index 27308f84..fab7537d 100644
--- a/components/exo/wayland/clients/client_base.h
+++ b/components/exo/wayland/clients/client_base.h
@@ -211,6 +211,7 @@
 #if defined(USE_GBM)
   base::ScopedFD drm_fd_;
   std::unique_ptr<gbm_device> device_;
+  gl::GLDisplayEGL* egl_display_ = nullptr;
 #if defined(USE_VULKAN)
   std::unique_ptr<gpu::VulkanImplementation> vk_implementation_;
   std::unique_ptr<ScopedVkInstance> vk_instance_;
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index 35ffec8..a4ce724e 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -42,6 +42,10 @@
              "LensImageFormatOptimizations",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kEnableContextMenuInLensSidePanel,
+             "EnableContextMenuInLensSidePanel",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 const base::FeatureParam<bool> kEnableUKMLoggingForRegionSearch{
     &kLensStandalone, "region-search-enable-ukm-logging", true};
 
@@ -172,5 +176,9 @@
   return kEncodingQualityRegionSearch.Get();
 }
 
+bool GetEnableContextMenuInLensSidePanel() {
+  return base::FeatureList::IsEnabled(kEnableContextMenuInLensSidePanel);
+}
+
 }  // namespace features
 }  // namespace lens
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 4ecb770..cb0810f 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -48,6 +48,10 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 BASE_DECLARE_FEATURE(kLensImageFormatOptimizations);
 
+// Enables the context menu in the Lens side panel.
+COMPONENT_EXPORT(LENS_FEATURES)
+BASE_DECLARE_FEATURE(EnableContextMenuInLensSidePanel);
+
 // Enables UKM logging for the Lens Region Search feature.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern const base::FeatureParam<bool> kEnableUKMLoggingForRegionSearch;
@@ -178,6 +182,10 @@
 // Get the encoding quality for region search queries.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern int GetRegionSearchEncodingQuality();
+
+// Returns whether to enable the context menu in the Lens side panel.
+COMPONENT_EXPORT(LENS_FEATURES)
+extern bool GetEnableContextMenuInLensSidePanel();
 }  // namespace features
 }  // namespace lens
 
diff --git a/components/media_message_center/media_controls_progress_view.cc b/components/media_message_center/media_controls_progress_view.cc
index db6d97d..a66264f 100644
--- a/components/media_message_center/media_controls_progress_view.cc
+++ b/components/media_message_center/media_controls_progress_view.cc
@@ -103,7 +103,11 @@
 
   const base::TimeDelta current_position = media_position.GetPosition();
   const base::TimeDelta duration = media_position.duration();
-  SetBarProgress(is_live_ ? 1.0 : current_position / duration);
+  // Use 1.0 for live playback, correctly, or as a fallback for those cases in
+  // which the result is unfriendly.
+  SetBarProgress((is_live_ || duration.is_zero() || current_position.is_inf())
+                     ? 1.0
+                     : current_position / duration);
 
   // For durations greater than 24 hours, prefer base::DURATION_WIDTH_NARROW for
   // better readability (e.g., 27h 23m 10s rather than 27:23:10).
diff --git a/components/paint_preview/player/android/player_compositor_delegate_android.cc b/components/paint_preview/player/android/player_compositor_delegate_android.cc
index 09ac166eb..b77113f 100644
--- a/components/paint_preview/player/android/player_compositor_delegate_android.cc
+++ b/components/paint_preview/player/android/player_compositor_delegate_android.cc
@@ -282,9 +282,6 @@
     frame_guid =
         base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
             env, j_frame_guid);
-    if (frame_guid->is_empty()) {
-      frame_guid = absl::nullopt;
-    }
   }
 
   // Callback can skip UI thread.
@@ -347,14 +344,14 @@
     const JavaParamRef<jobject>& j_frame_guid,
     jint j_x,
     jint j_y) {
-  auto frame_guid =
+  absl::optional<base::UnguessableToken> frame_guid =
       base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
           env, j_frame_guid);
-  if (frame_guid.is_empty()) {
+  if (!frame_guid.has_value()) {
     return base::android::ConvertUTF8ToJavaString(env, "");
   }
   auto res = PlayerCompositorDelegate::OnClick(
-      std::move(frame_guid),
+      frame_guid.value(),
       gfx::Rect(static_cast<int>(j_x), static_cast<int>(j_y), 1U, 1U));
   if (res.empty())
     return base::android::ConvertUTF8ToJavaString(env, "");
diff --git a/components/policy/core/common/cloud/realtime_reporting_job_configuration_unittest.cc b/components/policy/core/common/cloud/realtime_reporting_job_configuration_unittest.cc
index d34465b6..be14499 100644
--- a/components/policy/core/common/cloud/realtime_reporting_job_configuration_unittest.cc
+++ b/components/policy/core/common/cloud/realtime_reporting_job_configuration_unittest.cc
@@ -7,6 +7,7 @@
 #include <set>
 #include <vector>
 
+#include "base/check_deref.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/test/task_environment.h"
@@ -35,8 +36,6 @@
 
 namespace policy {
 
-std::vector<std::string> ids = {"id1", "id2", "id3"};
-
 constexpr char kAppPackage[] = "appPackage";
 constexpr char kEventType[] = "eventType";
 constexpr char kAppInstallEvent[] = "androidAppInstallEvent";
@@ -79,8 +78,8 @@
     base::Value::Dict context;
     context.SetByDottedPath("browser.userAgent", "dummyAgent");
     base::Value::List events;
-    for (size_t i = 0; i < ids.size(); ++i) {
-      base::Value::Dict event = CreateEvent(ids[i], i);
+    for (size_t i = 0; i < kIds.size(); ++i) {
+      base::Value::Dict event = CreateEvent(kIds[i], i);
       events.Append(std::move(event));
     }
 
@@ -90,7 +89,9 @@
   }
 
  protected:
-  static base::Value::Dict CreateEvent(std::string& event_id, int type) {
+  const std::vector<std::string> kIds = {"id1", "id2", "id3"};
+
+  static base::Value::Dict CreateEvent(const std::string& event_id, int type) {
     base::Value::Dict event;
     event.Set(kAppPackage, kPackage);
     event.Set(kEventType, type);
@@ -209,18 +210,22 @@
 
   base::Value* events =
       payload->FindListKey(RealtimeReportingJobConfiguration::kEventListKey);
-  EXPECT_EQ(ids.size(), events->GetList().size());
+  EXPECT_EQ(kIds.size(), events->GetList().size());
   int i = -1;
-  for (const auto& event : events->GetList()) {
-    auto* id = event.FindStringKey(kEventId);
-    EXPECT_EQ(ids[++i], *id);
-    auto type = event.FindKey(kAppInstallEvent)->FindIntKey(kEventType);
+  for (const base::Value& event_val : events->GetList()) {
+    const base::Value::Dict& event = event_val.GetDict();
+    const std::string& id = CHECK_DEREF(event.FindString(kEventId));
+    EXPECT_EQ(kIds[++i], id);
+    const absl::optional<int> type =
+        event.FindDict(kAppInstallEvent)->FindInt(kEventType);
+    ASSERT_TRUE(type.has_value());
     EXPECT_EQ(i, *type);
   }
 }
 
 TEST_F(RealtimeReportingJobConfigurationTest, OnURLLoadComplete_Success) {
-  base::Value::Dict response = CreateResponse({ids[0], ids[1], ids[2]}, {}, {});
+  base::Value::Dict response =
+      CreateResponse({kIds[0], kIds[1], kIds[2]}, {}, {});
   EXPECT_CALL(callback_observer_,
               OnURLLoadComplete(&job_, DM_STATUS_SUCCESS,
                                 DeviceManagementService::kSuccess,
@@ -289,7 +294,7 @@
 
 TEST_F(RealtimeReportingJobConfigurationTest, ShouldRetry_Success) {
   auto response_string =
-      CreateResponseString(CreateResponse({ids[0], ids[1], ids[2]}, {}, {}));
+      CreateResponseString(CreateResponse({kIds[0], kIds[1], kIds[2]}, {}, {}));
   auto should_retry = configuration_->ShouldRetry(
       DeviceManagementService::kSuccess, response_string);
   EXPECT_EQ(DeviceManagementService::Job::NO_RETRY, should_retry);
@@ -298,7 +303,7 @@
 TEST_F(RealtimeReportingJobConfigurationTest, ShouldRetry_PartialFalure) {
   // Batch failures are retried
   auto response_string =
-      CreateResponseString(CreateResponse({ids[0], ids[1]}, {ids[2]}, {}));
+      CreateResponseString(CreateResponse({kIds[0], kIds[1]}, {kIds[2]}, {}));
   auto should_retry = configuration_->ShouldRetry(
       DeviceManagementService::kSuccess, response_string);
   EXPECT_EQ(DeviceManagementService::Job::RETRY_WITH_DELAY, should_retry);
@@ -307,7 +312,7 @@
 TEST_F(RealtimeReportingJobConfigurationTest, ShouldRetry_PermanentFailure) {
   // Permanent failures are not retried.
   auto response_string =
-      CreateResponseString(CreateResponse({ids[0], ids[1]}, {}, {ids[2]}));
+      CreateResponseString(CreateResponse({kIds[0], kIds[1]}, {}, {kIds[2]}));
   auto should_retry = configuration_->ShouldRetry(
       DeviceManagementService::kSuccess, response_string);
   EXPECT_EQ(DeviceManagementService::Job::NO_RETRY, should_retry);
@@ -325,7 +330,7 @@
   // Only those events whose ids are in failed_uploads should be in the payload
   // after the OnBeforeRetry call.
   auto response_string =
-      CreateResponseString(CreateResponse({ids[0]}, {ids[1]}, {ids[2]}));
+      CreateResponseString(CreateResponse({kIds[0]}, {kIds[1]}, {kIds[2]}));
   configuration_->OnBeforeRetry(DeviceManagementService::kSuccess,
                                 response_string);
   absl::optional<base::Value> payload =
@@ -334,7 +339,7 @@
       payload->FindListKey(RealtimeReportingJobConfiguration::kEventListKey);
   EXPECT_EQ(1u, events->GetList().size());
   auto& event = events->GetList()[0];
-  EXPECT_EQ(ids[1], *event.FindStringKey(kEventId));
+  EXPECT_EQ(kIds[1], *event.FindStringKey(kEventId));
 }
 
 }  // namespace policy
diff --git a/components/reporting/proto/synced/record.proto b/components/reporting/proto/synced/record.proto
index b9c9bf6..e616f04 100644
--- a/components/reporting/proto/synced/record.proto
+++ b/components/reporting/proto/synced/record.proto
@@ -86,14 +86,23 @@
   // to do with that is a decision that the caller needs to make).
   optional int64 sequencing_id = 1;
 
-  // Generation ID (required). Unique per device and priority. Generated
-  // randomly anew when previous record digest is not found at startup (e.g.
-  // after powerwash).
+  // Generation ID (required). Generated randomly anew for each user + device +
+  // priority combination when previous record digest is not found at startup
+  // (e.g. after powerwash). A new `generation_id` indicates the server should
+  // expect a `sequencing_id` of 0. Not unique -- the key space of user + device
+  // + priority combinations is too large for 64 bits.
   optional int64 generation_id = 2;
 
   // Priority (required)
   // Generation IDs are per Priority.
   optional Priority priority = 3;
+
+  // Generation GUID (required for unmanaged devices). Unique per combination of
+  // user + device + priority. Behaves the same way as `generation_id` but is
+  // large enough to serve as a GUID across all user + device + priority
+  // combinations. Used as a key on the server to retrieve
+  // `SequenceInformation`.
+  optional string generation_guid = 4;
 }
 
 // Envelope for the |WrappedRecord| and associated metadata as it is stored on
diff --git a/components/services/app_service/public/cpp/intent_filter.h b/components/services/app_service/public/cpp/intent_filter.h
index 97ff76e..9c83ccf 100644
--- a/components/services/app_service/public/cpp/intent_filter.h
+++ b/components/services/app_service/public/cpp/intent_filter.h
@@ -81,7 +81,8 @@
   // The ConditionValue is a file extension (e.g. "png") or a wildcard ("*")
   // which is matched against file names in the Intent. Common double extension
   // file types are supported: for example, a file named "file.tar.gz" matches
-  // both "gz" and "tar.gz" ConditionValues.
+  // both "gz" and "tar.gz" ConditionValues. File extension matching is
+  // case-insensitive.
   kFileExtension = 5,
   // The ConditionValue matches any files which are directories.
   kIsDirectory = 6,
diff --git a/components/services/app_service/public/cpp/intent_util_unittest.cc b/components/services/app_service/public/cpp/intent_util_unittest.cc
index f68df4f..687b4e8 100644
--- a/components/services/app_service/public/cpp/intent_util_unittest.cc
+++ b/components/services/app_service/public/cpp/intent_util_unittest.cc
@@ -566,6 +566,31 @@
   EXPECT_TRUE(intent->MatchFilter(file_filter_dot));
 }
 
+TEST_F(IntentUtilTest, FileExtensionMatchCaseInsensitive) {
+  auto lowercase_filter =
+      apps_util::MakeFileFilterForView("text/csv", "csv", "label");
+  auto uppercase_filter =
+      apps_util::MakeFileFilterForView("text/csv", "CSV", "label");
+
+  auto lowercase_intent = std::make_unique<apps::Intent>(
+      apps_util::kIntentActionView,
+      CreateIntentFiles(test_url("abc.csv"), absl::nullopt, false));
+  EXPECT_TRUE(lowercase_intent->MatchFilter(lowercase_filter));
+  EXPECT_TRUE(lowercase_intent->MatchFilter(uppercase_filter));
+
+  auto uppercase_intent = std::make_unique<apps::Intent>(
+      apps_util::kIntentActionView,
+      CreateIntentFiles(test_url("abc.CSV"), absl::nullopt, false));
+  EXPECT_TRUE(uppercase_intent->MatchFilter(lowercase_filter));
+  EXPECT_TRUE(uppercase_intent->MatchFilter(uppercase_filter));
+
+  auto mixcase_intent = std::make_unique<apps::Intent>(
+      apps_util::kIntentActionView,
+      CreateIntentFiles(test_url("abc.CsV"), absl::nullopt, false));
+  EXPECT_TRUE(mixcase_intent->MatchFilter(lowercase_filter));
+  EXPECT_TRUE(mixcase_intent->MatchFilter(uppercase_filter));
+}
+
 TEST_F(IntentUtilTest, FileURLMatch) {
   std::string mp3_url_pattern = R"(filesystem:chrome-extension://.*/.*\.mp3)";
 
diff --git a/components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom b/components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom
index fc94fe3..e4ecd63 100644
--- a/components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom
+++ b/components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom
@@ -4,7 +4,7 @@
 
 module storage.mojom;
 
-enum DisallowClientActivationReason {
+enum DisallowInactiveClientReason {
   kClientEventIsTriggered = 0,
   kTransactionIsAcquiringLocks = 1,
   kTransactionIsBlockingOthers = 2,
@@ -30,23 +30,35 @@
   // 2. If the client is in some inactive state (e.g. BFCache), it will be
   // disallowed from being activated again in the future.
   // See `RenderFrameHost::IsInactiveAndDisallowActivation()`.
-  // `keep_active` is used to force a client to remain active. This has no
-  // effect if the client is no longer active by the time the IPC message
-  // is handled.
-  RequireClientToBeActiveAndKeepActive(
-      DisallowClientActivationReason reason,
-      pending_receiver<IndexedDBClientKeepActive> keep_active
+  // `keep_active` is used to keep an active client away from entering
+  // the inactive state if while it's valid and connected.
+  // This has no effect if the client is no longer active by the time the IPC
+  // message is handled.
+  DisallowInactiveClient(
+      DisallowInactiveClientReason reason,
+      pending_receiver<IndexedDBClientKeepActive>? keep_active
   ) => (bool was_active);
-  // Similar to `RequireClientToBeActiveAndKeepActive`, but do not force
-  // the client to remain active. This method should be used if the caller
-  // only needs to disallow the client activation from an inactive state,
-  // as it won't be affected if the active client becomes inactive.
-  RequireClientToBeActive(DisallowClientActivationReason reason)
-    => (bool was_active);
+
+  // Summary of allowed state transitions under different scenarios.
+  // There are three possible states for the IndexedDB client: active,
+  // inactive and destroyed.
+
+  // In the default case, the following transactions are allowed:
+  // - active -> inactive
+  // - active -> destroyed
+  // - inactive -> active
+  // - inactive -> destroyed
+
+  // After `DisallowInactiveClient` has been called, the following transitions
+  // are allowed:
+  // - active -> destroyed
+  // - inactive -> destroyed
+  // Additionally, if `keep_active` is not set or goes out of scope, the
+  // following transition will be allowed as well:
+  // - active -> inactive
 };
 
-// Keeping an instance of this interface alive pins the associated client
-// and forces it to remain active (e.g. not able to enter some state like
-// BFCache). Closing the other end (i.e. the remote) ends the keep active
-// scope associated with the instance.
+// Preventing an instance of this interface from entering some inactive state
+// like BFCache. Closing the other end (i.e. the remote) ends the scope
+// associated with the instance.
 interface IndexedDBClientKeepActive {};
diff --git a/components/unexportable_keys/unexportable_key_task_manager_unittest.cc b/components/unexportable_keys/unexportable_key_task_manager_unittest.cc
index 66814fbb..c991ba3 100644
--- a/components/unexportable_keys/unexportable_key_task_manager_unittest.cc
+++ b/components/unexportable_keys/unexportable_key_task_manager_unittest.cc
@@ -92,7 +92,7 @@
 TEST_F(UnexportableKeyTaskManagerTest, FromWrappedKeyAsync_Failure) {
   base::test::TestFuture<scoped_refptr<RefCountedUnexportableSigningKey>>
       future;
-  std::vector<const uint8_t> empty_wrapped_key;
+  std::vector<uint8_t> empty_wrapped_key;
   task_manager().FromWrappedSigningKeySlowlyAsync(
       empty_wrapped_key, BackgroundTaskPriority::kBestEffort,
       future.GetCallback());
@@ -113,7 +113,7 @@
 
   // Second, sign some data with the key.
   base::test::TestFuture<absl::optional<std::vector<uint8_t>>> sign_future;
-  std::vector<const uint8_t> data = {4, 8, 15, 16, 23, 42};
+  std::vector<uint8_t> data = {4, 8, 15, 16, 23, 42};
   task_manager().SignSlowlyAsync(key, data, BackgroundTaskPriority::kBestEffort,
                                  sign_future.GetCallback());
   EXPECT_FALSE(sign_future.IsReady());
@@ -132,7 +132,7 @@
 
 TEST_F(UnexportableKeyTaskManagerTest, SignAsync_NullKey) {
   base::test::TestFuture<absl::optional<std::vector<uint8_t>>> sign_future;
-  std::vector<const uint8_t> data = {4, 8, 15, 16, 23, 42};
+  std::vector<uint8_t> data = {4, 8, 15, 16, 23, 42};
   task_manager().SignSlowlyAsync(nullptr, data,
                                  BackgroundTaskPriority::kBestEffort,
                                  sign_future.GetCallback());
diff --git a/content/browser/android/gpu_process_callback.cc b/content/browser/android/gpu_process_callback.cc
index bead2702..65349429 100644
--- a/content/browser/android/gpu_process_callback.cc
+++ b/content/browser/android/gpu_process_callback.cc
@@ -20,7 +20,7 @@
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& token,
     const base::android::JavaParamRef<jobject>& surface) {
-  base::UnguessableToken requestToken =
+  absl::optional<base::UnguessableToken> requestToken =
       base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(env,
                                                                        token);
   if (!requestToken) {
@@ -33,7 +33,8 @@
   base::android::ScopedJavaGlobalRef<jobject> jsurface;
   jsurface.Reset(env, surface);
   ScopedSurfaceRequestManager::GetInstance()->FulfillScopedSurfaceRequest(
-      requestToken, gl::ScopedJavaSurface(jsurface, /*auto_release=*/true));
+      requestToken.value(),
+      gl::ScopedJavaSurface(jsurface, /*auto_release=*/true));
 }
 
 base::android::ScopedJavaLocalRef<jobject>
diff --git a/content/browser/indexed_db/database_impl.cc b/content/browser/indexed_db/database_impl.cc
index c9b5f0d..e762789 100644
--- a/content/browser/indexed_db/database_impl.cc
+++ b/content/browser/indexed_db/database_impl.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_math.h"
@@ -752,9 +753,10 @@
         // The transaction is created but not started yet, which means it may be
         // blocked by others and waiting for the lock to be acquired. We should
         // disallow the activation for the client.
-        connection_->RequireClientToBeActive(
-            storage::mojom::DisallowClientActivationReason::
-                kTransactionIsAcquiringLocks);
+        connection_->DisallowInactiveClient(
+            storage::mojom::DisallowInactiveClientReason::
+                kTransactionIsAcquiringLocks,
+            base::NullCallback());
         return;
       }
       case IndexedDBTransaction::State::STARTED: {
@@ -763,9 +765,10 @@
           // The transaction is holding the locks while others are waiting for
           // the acquisition. We should disallow the activation for this client
           // so the lock is immediately available.
-          connection_->RequireClientToBeActive(
-              storage::mojom::DisallowClientActivationReason::
-                  kTransactionIsBlockingOthers);
+          connection_->DisallowInactiveClient(
+              storage::mojom::DisallowInactiveClientReason::
+                  kTransactionIsBlockingOthers,
+              base::NullCallback());
           return;
         }
         break;
diff --git a/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.cc b/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.cc
index 7d6343d..6746f9e 100644
--- a/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.cc
+++ b/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.cc
@@ -17,14 +17,14 @@
 IndexedDBClientStateCheckerWrapper::~IndexedDBClientStateCheckerWrapper() =
     default;
 
-void IndexedDBClientStateCheckerWrapper::RequireClientToBeActiveAndKeepActive(
-    storage::mojom::DisallowClientActivationReason reason,
+void IndexedDBClientStateCheckerWrapper::DisallowInactiveClient(
+    storage::mojom::DisallowInactiveClientReason reason,
     mojo::PendingReceiver<storage::mojom::IndexedDBClientKeepActive>
         keep_active,
-    storage::mojom::IndexedDBClientStateChecker::RequireClientToBeActiveCallback
+    storage::mojom::IndexedDBClientStateChecker::DisallowInactiveClientCallback
         callback) {
   if (client_state_checker_remote_.is_bound()) {
-    client_state_checker_remote_->RequireClientToBeActiveAndKeepActive(
+    client_state_checker_remote_->DisallowInactiveClient(
         reason, std::move(keep_active), std::move(callback));
   } else {
     // If the remote is no longer connected, we expect the client will terminate
@@ -33,18 +33,4 @@
   }
 }
 
-void IndexedDBClientStateCheckerWrapper::RequireClientToBeActive(
-    storage::mojom::DisallowClientActivationReason reason,
-    storage::mojom::IndexedDBClientStateChecker::RequireClientToBeActiveCallback
-        callback) {
-  if (client_state_checker_remote_.is_bound()) {
-    client_state_checker_remote_->RequireClientToBeActive(reason,
-                                                          std::move(callback));
-  } else {
-    // If the remote is no longer connected, we expect the client will terminate
-    // the connection soon, so marking `was_active` true here.
-    std::move(callback).Run(/*was_active=*/true);
-  }
-}
-
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.h b/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.h
index 3ab085bf..646c28c9 100644
--- a/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.h
+++ b/content/browser/indexed_db/indexed_db_client_state_checker_wrapper.h
@@ -30,16 +30,12 @@
   IndexedDBClientStateCheckerWrapper& operator=(
       const IndexedDBClientStateCheckerWrapper&) = delete;
 
-  void RequireClientToBeActiveAndKeepActive(
-      storage::mojom::DisallowClientActivationReason reason,
+  void DisallowInactiveClient(
+      storage::mojom::DisallowInactiveClientReason reason,
       mojo::PendingReceiver<storage::mojom::IndexedDBClientKeepActive>
           keep_active,
       storage::mojom::IndexedDBClientStateChecker::
-          RequireClientToBeActiveCallback callback);
-  void RequireClientToBeActive(
-      storage::mojom::DisallowClientActivationReason reason,
-      storage::mojom::IndexedDBClientStateChecker::
-          RequireClientToBeActiveCallback callback);
+          DisallowInactiveClientCallback callback);
 
  protected:
   virtual ~IndexedDBClientStateCheckerWrapper();
diff --git a/content/browser/indexed_db/indexed_db_connection.cc b/content/browser/indexed_db/indexed_db_connection.cc
index 6b87be7..6bb4ffc 100644
--- a/content/browser/indexed_db/indexed_db_connection.cc
+++ b/content/browser/indexed_db/indexed_db_connection.cc
@@ -17,6 +17,7 @@
 #include "content/browser/indexed_db/indexed_db_database_error.h"
 #include "content/browser/indexed_db/indexed_db_factory.h"
 #include "content/browser/indexed_db/indexed_db_transaction.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
 
@@ -188,19 +189,22 @@
   transactions_.erase(id);
 }
 
-void IndexedDBConnection::RequireClientToBeActiveAndKeepActive(
-    storage::mojom::DisallowClientActivationReason reason,
+void IndexedDBConnection::DisallowInactiveClient(
+    storage::mojom::DisallowInactiveClientReason reason,
     base::OnceCallback<void(bool)> callback) {
-  mojo::Remote<storage::mojom::IndexedDBClientKeepActive>
-      client_keep_active_remote;
-  client_state_checker_->RequireClientToBeActiveAndKeepActive(
-      reason, client_keep_active_remote.BindNewPipeAndPassReceiver(),
-      std::move(callback));
-  client_keep_active_remotes_.Add(std::move(client_keep_active_remote));
+  if (reason ==
+      storage::mojom::DisallowInactiveClientReason::kClientEventIsTriggered) {
+    // It's only necessary to keep the client active under this scenario.
+    mojo::Remote<storage::mojom::IndexedDBClientKeepActive>
+        client_keep_active_remote;
+    client_state_checker_->DisallowInactiveClient(
+        reason, client_keep_active_remote.BindNewPipeAndPassReceiver(),
+        std::move(callback));
+    client_keep_active_remotes_.Add(std::move(client_keep_active_remote));
+  } else {
+    client_state_checker_->DisallowInactiveClient(reason, mojo::NullReceiver(),
+                                                  std::move(callback));
+  }
 }
 
-void IndexedDBConnection::RequireClientToBeActive(
-    storage::mojom::DisallowClientActivationReason reason) {
-  client_state_checker_->RequireClientToBeActive(reason, base::NullCallback());
-}
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_connection.h b/content/browser/indexed_db/indexed_db_connection.h
index f4c2187..d671fa9 100644
--- a/content/browser/indexed_db/indexed_db_connection.h
+++ b/content/browser/indexed_db/indexed_db_connection.h
@@ -90,16 +90,10 @@
   // if so. This is called when the client is not supposed to be inactive,
   // otherwise it may affect the IndexedDB service (e.g. blocking others from
   // acquiring the locks).
-  void RequireClientToBeActiveAndKeepActive(
-      storage::mojom::DisallowClientActivationReason reason,
+  void DisallowInactiveClient(
+      storage::mojom::DisallowInactiveClientReason reason,
       base::OnceCallback<void(bool)> callback);
 
-  // Disallow the client from activation, this method is used when the caller
-  // does not care about if the client was active or not and do not force the
-  // client to remain active.
-  void RequireClientToBeActive(
-      storage::mojom::DisallowClientActivationReason reason);
-
   const base::flat_map<int64_t, std::unique_ptr<IndexedDBTransaction>>&
   transactions() const {
     return transactions_;
diff --git a/content/browser/indexed_db/indexed_db_context_unittest.cc b/content/browser/indexed_db/indexed_db_context_unittest.cc
index 53d7bc503..da5cca3 100644
--- a/content/browser/indexed_db/indexed_db_context_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_context_unittest.cc
@@ -44,16 +44,12 @@
     ~MockIndexedDBClientStateChecker() override = default;
 
     // storage::mojom::IndexedDBClientStateChecker overrides
-    void RequireClientToBeActiveAndKeepActive(
-        storage::mojom::DisallowClientActivationReason reason,
+    void DisallowInactiveClient(
+        storage::mojom::DisallowInactiveClientReason reason,
         mojo::PendingReceiver<storage::mojom::IndexedDBClientKeepActive>
             keep_active,
         storage::mojom::IndexedDBClientStateChecker::
-            RequireClientToBeActiveCallback callback) override {}
-    void RequireClientToBeActive(
-        storage::mojom::DisallowClientActivationReason reason,
-        storage::mojom::IndexedDBClientStateChecker::
-            RequireClientToBeActiveCallback callback) override {}
+            DisallowInactiveClientCallback callback) override {}
   };
 
   IndexedDBContextTest()
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 11969416..e670b70 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -13,6 +13,7 @@
 #include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
@@ -224,9 +225,10 @@
       }
     }
     if (should_require_connection_to_be_active) {
-      connection->RequireClientToBeActive(
-          storage::mojom::DisallowClientActivationReason::
-              kTransactionIsBlockingOthers);
+      connection->DisallowInactiveClient(
+          storage::mojom::DisallowInactiveClientReason::
+              kTransactionIsBlockingOthers,
+          base::NullCallback());
     }
   }
 }
@@ -1818,9 +1820,8 @@
     // method is executed asynchronously.
     if (base::FeatureList::IsEnabled(
             blink::features::kAllowPageWithIDBConnectionInBFCache)) {
-      connection->RequireClientToBeActiveAndKeepActive(
-          storage::mojom::DisallowClientActivationReason::
-              kClientEventIsTriggered,
+      connection->DisallowInactiveClient(
+          storage::mojom::DisallowInactiveClientReason::kClientEventIsTriggered,
           base::BindOnce(
               [](base::WeakPtr<IndexedDBConnection> connection,
                  int64_t old_version, int64_t new_version,
diff --git a/content/browser/indexed_db/indexed_db_transaction_unittest.cc b/content/browser/indexed_db/indexed_db_transaction_unittest.cc
index a16834b..49ae2c2 100644
--- a/content/browser/indexed_db/indexed_db_transaction_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_transaction_unittest.cc
@@ -654,8 +654,8 @@
 
   // Register a transaction with ReadWrite mode to object store 1.
   // The transaction should be started and it's not blocking any others.
-  ASSERT_EQ(transaction->state(), IndexedDBTransaction::STARTED);
-  ASSERT_FALSE(db_->IsTransactionBlockingOthers(transaction));
+  EXPECT_EQ(transaction->state(), IndexedDBTransaction::STARTED);
+  EXPECT_FALSE(db_->IsTransactionBlockingOthers(transaction));
 
   const int64_t id2 = 1;
   IndexedDBTransaction* transaction2 = connection->CreateTransaction(
@@ -666,8 +666,8 @@
   // Register another transaction with ReadWrite mode to the same object store.
   // The transaction should be blocked in `CREATED` state and the previous
   // transaction is now blocking others.
-  ASSERT_EQ(transaction2->state(), IndexedDBTransaction::CREATED);
-  ASSERT_TRUE(db_->IsTransactionBlockingOthers(transaction));
+  EXPECT_EQ(transaction2->state(), IndexedDBTransaction::CREATED);
+  EXPECT_TRUE(db_->IsTransactionBlockingOthers(transaction));
 
   RunPostedTasks();
 
@@ -676,9 +676,9 @@
 
   // Abort the blocked transaction, and the previous transaction should not be
   // blocking others anymore.
-  ASSERT_EQ(transaction2->state(), IndexedDBTransaction::FINISHED);
+  EXPECT_EQ(transaction2->state(), IndexedDBTransaction::FINISHED);
   RunPostedTasks();
-  ASSERT_FALSE(db_->IsTransactionBlockingOthers(transaction));
+  EXPECT_FALSE(db_->IsTransactionBlockingOthers(transaction));
 }
 
 }  // namespace indexed_db_transaction_unittest
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h
index fab4097..4100c00 100644
--- a/content/browser/preloading/prerender/prerender_host.h
+++ b/content/browser/preloading/prerender/prerender_host.h
@@ -103,8 +103,8 @@
   };
 
   // Returns the PrerenderHost that the given `frame_tree_node` is in, if it is
-  // being prerendered. Note that this function returns false if the prerender
-  // has been canceled.
+  // being prerendered. Note that this function returns a nullptr if the
+  // prerender has been canceled.
   // TODO(https://crbug.com/1355279): Always return a non-null ptr if the
   // frame_tree_node is in a prerendering tree.
   static PrerenderHost* GetPrerenderHostFromFrameTreeNode(
diff --git a/content/browser/renderer_host/indexed_db_client_state_checker_factory.cc b/content/browser/renderer_host/indexed_db_client_state_checker_factory.cc
index f3714c1b..b83315b 100644
--- a/content/browser/renderer_host/indexed_db_client_state_checker_factory.cc
+++ b/content/browser/renderer_host/indexed_db_client_state_checker_factory.cc
@@ -19,7 +19,7 @@
 namespace {
 
 using IndexedDBDisallowActivationReason =
-    storage::mojom::DisallowClientActivationReason;
+    storage::mojom::DisallowInactiveClientReason;
 
 DisallowActivationReasonId ConvertToDisallowActivationReasonId(
     IndexedDBDisallowActivationReason reason) {
@@ -50,16 +50,11 @@
   // storage::mojom::IndexedDBClientStateChecker overrides:
   // Non-document clients are always active, since the inactive state such as
   // back/forward cache is not applicable to them.
-  void RequireClientToBeActiveAndKeepActive(
-      storage::mojom::DisallowClientActivationReason reason,
+  void DisallowInactiveClient(
+      storage::mojom::DisallowInactiveClientReason reason,
       mojo::PendingReceiver<storage::mojom::IndexedDBClientKeepActive>
           keep_active,
-      RequireClientToBeActiveCallback callback) override {
-    std::move(callback).Run(/*was_active=*/true);
-  }
-  void RequireClientToBeActive(
-      storage::mojom::DisallowClientActivationReason reason,
-      RequireClientToBeActiveCallback callback) override {
+      DisallowInactiveClientCallback callback) override {
     std::move(callback).Run(/*was_active=*/true);
   }
 };
@@ -82,7 +77,7 @@
   }
 
   bool CheckIfClientWasActive(
-      storage::mojom::DisallowClientActivationReason reason) {
+      storage::mojom::DisallowInactiveClientReason reason) {
     bool was_active = false;
 
     if (render_frame_host().GetLifecycleState() ==
@@ -103,16 +98,17 @@
   }
 
   // storage::mojom::IndexedDBClientStateChecker overrides:
-  void RequireClientToBeActiveAndKeepActive(
-      storage::mojom::DisallowClientActivationReason reason,
+  void DisallowInactiveClient(
+      storage::mojom::DisallowInactiveClientReason reason,
       mojo::PendingReceiver<storage::mojom::IndexedDBClientKeepActive>
           keep_active,
-      RequireClientToBeActiveCallback callback) override {
-    // This is the only reason that we need to keep the client active.
-    CHECK_EQ(reason, storage::mojom::DisallowClientActivationReason::
-                         kClientEventIsTriggered);
+      DisallowInactiveClientCallback callback) override {
     bool was_active = CheckIfClientWasActive(reason);
-    if (was_active) {
+    if (was_active && keep_active.is_valid()) {
+      // This is the only reason that we need to prevent the client from
+      // inactive state.
+      CHECK_EQ(reason, storage::mojom::DisallowInactiveClientReason::
+                           kClientEventIsTriggered);
       // If the document is active, we need to register a non sticky feature to
       // prevent putting it into BFCache until the IndexedDB connection is
       // successfully closed and the context is automatically destroyed.
@@ -131,13 +127,6 @@
     std::move(callback).Run(was_active);
   }
 
-  void RequireClientToBeActive(
-      storage::mojom::DisallowClientActivationReason reason,
-      RequireClientToBeActiveCallback callback) override {
-    bool was_active = CheckIfClientWasActive(reason);
-    std::move(callback).Run(was_active);
-  }
-
  private:
   // Keep the association between the receiver and the feature handle it
   // registered.
diff --git a/content/browser/renderer_host/indexed_db_client_state_checker_factory_unittest.cc b/content/browser/renderer_host/indexed_db_client_state_checker_factory_unittest.cc
index 4d63fba..da563b1d8 100644
--- a/content/browser/renderer_host/indexed_db_client_state_checker_factory_unittest.cc
+++ b/content/browser/renderer_host/indexed_db_client_state_checker_factory_unittest.cc
@@ -38,16 +38,16 @@
 
   ~IndexedDBClientStateCheckerFactoryTest() override = default;
 
-  // A helper function used for testing the `RequireClientToBeActive` method
+  // A helper function used for testing the `DisallowInactiveClient` method
   // with callback.
-  void TestRequireClientToBeActive(
+  void TestDisallowInactiveClient(
       storage::mojom::IndexedDBClientStateChecker* checker,
-      storage::mojom::DisallowClientActivationReason reason,
+      storage::mojom::DisallowInactiveClientReason reason,
       bool expected_was_active) {
     mojo::Remote<storage::mojom::IndexedDBClientKeepActive> test_remote_;
     base::RunLoop run_loop;
     base::OnceClosure quit_closure = run_loop.QuitClosure();
-    checker->RequireClientToBeActiveAndKeepActive(
+    checker->DisallowInactiveClient(
         reason, test_remote_.BindNewPipeAndPassReceiver(),
         base::BindOnce(
             [](base::OnceClosure closure, bool expected_was_active,
@@ -64,7 +64,7 @@
 };
 
 TEST_F(IndexedDBClientStateCheckerFactoryTest,
-       RequireClientToBeActive_DocumentBFCache) {
+       DisallowInactiveClient_DocumentBFCache) {
   RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(main_rfh());
   ASSERT_TRUE(rfh);
   storage::mojom::IndexedDBClientStateChecker* checker =
@@ -75,9 +75,9 @@
   EXPECT_EQ(rfh->GetLifecycleState(), RenderFrameHost::LifecycleState::kActive);
   // For the active document, the client state checker should claim that it's
   // active.
-  TestRequireClientToBeActive(
+  TestDisallowInactiveClient(
       checker,
-      storage::mojom::DisallowClientActivationReason::kClientEventIsTriggered,
+      storage::mojom::DisallowInactiveClientReason::kClientEventIsTriggered,
       /*expected_was_active=*/true);
   // There is no side effect to the active document.
   EXPECT_EQ(rfh->GetLifecycleState(),
@@ -87,16 +87,16 @@
   rfh->SetLifecycleState(
       RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache);
   // Now the client state check should report that the document is not active.
-  TestRequireClientToBeActive(
+  TestDisallowInactiveClient(
       checker,
-      storage::mojom::DisallowClientActivationReason::kClientEventIsTriggered,
+      storage::mojom::DisallowInactiveClientReason::kClientEventIsTriggered,
       /*expected_was_active=*/false);
   // The page will be evicted from back/forward cache as the side effect.
   EXPECT_TRUE(rfh->is_evicted_from_back_forward_cache());
 }
 
 TEST_F(IndexedDBClientStateCheckerFactoryTest,
-       RequireClientToBeActive_DocumentPrerendering) {
+       DisallowInactiveClient_DocumentPrerendering) {
   // Set up a `RenderFrameHost` that's in `kPrerendering`.
   test::ScopedPrerenderWebContentsDelegate web_contents_delegate(
       *web_contents());
@@ -112,9 +112,9 @@
           GetOrCreateIndexedDBClientStateCheckerForTesting(rfh->GetGlobalId());
   // For prerendering case, the client state checker should claim it as
   // active, since IndexedDB is supported in prerendering page.
-  TestRequireClientToBeActive(
+  TestDisallowInactiveClient(
       checker,
-      storage::mojom::DisallowClientActivationReason::kClientEventIsTriggered,
+      storage::mojom::DisallowInactiveClientReason::kClientEventIsTriggered,
       /*expected_was_active=*/true);
   EXPECT_EQ(rfh->GetLifecycleState(),
             RenderFrameHost::LifecycleState::kPrerendering);
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 176ad17b1..61b47ad 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1483,10 +1483,12 @@
             origin, net::SchemefulSite(origin), base::OptionalToPtr(nonce),
             blink::mojom::AncestorChainBit::kSameSite);
   } else {
+    net::SchemefulSite top_level_site(top_level_origin);
     navigation_request->commit_params_->storage_key =
         blink::StorageKey::CreateWithOptionalNonce(
-            origin, net::SchemefulSite(top_level_origin), nullptr,
-            render_frame_host->ComputeSiteForCookies().IsNull()
+            origin, top_level_site, nullptr,
+            (render_frame_host->ComputeSiteForCookies().IsNull() &&
+             !top_level_site.opaque())
                 ? blink::mojom::AncestorChainBit::kCrossSite
                 : blink::mojom::AncestorChainBit::kSameSite);
   }
@@ -1941,6 +1943,23 @@
           metrics->GetWebExposedNotRestoredReasons();
     }
   }
+
+  // Record `SameDocumentCrossOriginInitiator` metric. It happens in the
+  // NavigationRequest constructor, to catch every kind of same-document
+  // navigation: the one initiated from the navigating frame's process, and the
+  // others.
+  if (common_params_->navigation_type ==
+          blink::mojom::NavigationType::SAME_DOCUMENT &&
+      GetInitiatorOrigin() &&
+      !GetInitiatorOrigin()->IsSameOriginWith(
+          GetTentativeOriginAtRequestTime())) {
+    // This is reported to navigating frame's current document, because this is
+    // the document that behave differently if this navigation was turned into a
+    // cross-document one.
+    GetContentClient()->browser()->LogWebFeatureForCurrentPage(
+        frame_tree_node_->current_frame_host(),
+        blink::mojom::WebFeature::kSameDocumentCrossOriginInitiator);
+  }
 }
 
 NavigationRequest::~NavigationRequest() {
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index f14b25c..21f335f30 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4057,22 +4057,25 @@
   if (ignore_top_level_extension) {
     ancestor_chain.pop_back();
   }
+  net::SchemefulSite top_level_site(origin(ancestor_chain.back()));
 
-  // Compute the AncestorChainBit. It represents whether every ancestors are all
-  // same-site or not.
+  // Compute the AncestorChainBit. It represents whether every ancestors are
+  // all same-site or not. If `top_level_site` is opaque the bit must be
+  // kSameSite as this is the default value (which won't be serialized).
   auto site_for_cookies = net::SiteForCookies::FromOrigin(new_rfh_origin);
   blink::mojom::AncestorChainBit ancestor_chain_bit =
       blink::mojom::AncestorChainBit::kSameSite;
-  for (auto* ancestor : ancestor_chain) {
-    if (!site_for_cookies.IsFirstParty(origin(ancestor).GetURL())) {
-      ancestor_chain_bit = blink::mojom::AncestorChainBit::kCrossSite;
-      break;
+  if (!top_level_site.opaque()) {
+    for (auto* ancestor : ancestor_chain) {
+      if (!site_for_cookies.IsFirstParty(origin(ancestor).GetURL())) {
+        ancestor_chain_bit = blink::mojom::AncestorChainBit::kCrossSite;
+        break;
+      }
     }
   }
 
   return blink::StorageKey::CreateWithOptionalNonce(
-      new_rfh_origin, net::SchemefulSite(origin(ancestor_chain.back())),
-      nullptr, ancestor_chain_bit);
+      new_rfh_origin, top_level_site, nullptr, ancestor_chain_bit);
 }
 
 void RenderFrameHostImpl::SetOriginDependentStateOfNewFrame(
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index dd600e5..c13bafd94 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -4164,7 +4164,7 @@
   // Note that this is a no-op for pending commit RenderFrameHosts (which start
   // with owner pointing to the FrameTreeNode owning them) and prerendering
   // activations (where RenderFrameHost's owner has been updated in
-  // PrerenderPageHolder::Activate), but is necessary for RFHs restored from
+  // PrerenderHost::Activate), but is necessary for RFHs restored from
   // back/forward cache.
   if (render_frame_host_)
     render_frame_host_->SetRenderFrameHostOwner(frame_tree_node_);
diff --git a/content/browser/service_worker/service_worker_registry.cc b/content/browser/service_worker/service_worker_registry.cc
index a7f2be1e..97dd50b 100644
--- a/content/browser/service_worker/service_worker_registry.cc
+++ b/content/browser/service_worker/service_worker_registry.cc
@@ -275,15 +275,12 @@
     CreateInvokerAndStartRemoteCall(
         &storage::mojom::ServiceWorkerStorageControl::
             FindRegistrationForClientUrl,
-        base::BindOnce(
-            &ServiceWorkerRegistry::DidFindRegistrationForClientUrl,
-            weak_factory_.GetWeakPtr(), client_url, key, trace_event_id,
-            base::BindOnce(
-                [](blink::ServiceWorkerStatusCode status,
-                   scoped_refptr<ServiceWorkerRegistration> registration) {
-                  NOTREACHED()
-                      << "This is a dummy function that should not be called.";
-                })),
+        base::BindOnce(&ServiceWorkerRegistry::DidFindRegistrationForClientUrl,
+                       weak_factory_.GetWeakPtr(), client_url, key,
+                       trace_event_id,
+                       // Pass a fake callback here as the proper callback will
+                       // be invoked via find_registration_callbacks_
+                       /*FindRegistrationCallback=*/base::DoNothing()),
         client_url, key);
   } else {
     TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index b83e26a..aa5d3bf 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -386,6 +386,9 @@
 crbug.com/1382332 [ fuchsia ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ]
 crbug.com/1382332 [ linux nvidia-0x2184 passthrough debug angle-vulkan ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ]
 
+# Pixel_MediaRecorderFromVideoElement flakes on Linux FYI Release (Intel UHD 630)
+crbug.com/1382332 [ linux release renderer-skia-vulkan intel-0x9bc5 ] Pixel_MediaRecorderFromVideoElement [ RetryOnFailure ]
+
 # WebGL tests are seeing occasional hangs on Linux FYI Release (AMD RX 5500 XT).
 crbug.com/1396451 [ linux desktop amd-0x7340 ] Pixel_WebGLSadCanvas [ RetryOnFailure ]
 
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 6294e69..891628b0 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -609,6 +609,8 @@
 crbug.com/1276186 [ android android-pixel-2 ] conformance2/glsl3/array-equality.html [ Failure ]
 crbug.com/angleproject/7421 [ android android-pixel-2 angle-disabled no-passthrough ] conformance2/renderbuffers/invalidate-framebuffer.html [ Failure ]
 
+crbug.com/1403824 [ android android-pixel-2 no-passthrough ] deqp/functional/gles3/vertexarrays/multiple_attributes.stride.html [ RetryOnFailure ]
+
 ## Pixel 4 ##
 
 # Failing test when experiment DrDc is enabled via fieldtrial_testing_config.json.
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index ceec74a..bc9a2310 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -125,14 +125,15 @@
         * The value of `installerdata` needs to be URL encoded.
         * The data will be decoded and written to a file same as in
           [installdataindex](#installdataindex).
-    *   --offlinedir={absolute dir} or {GUID} relative to the "Offline" dir
+    *   --offlinedir={GUID}
         *   Performs offline install, which means no update check or file
             download is performed against the server during installation.
             All data is read from the files in the offline directory instead.
-        *   Files in offline directory:
+        *   The following are the files in the offline directory, which is at
+            `{CURRENT_PROCESS_DIR}\Offline\{GUID}`:
             * Manifest file, named `OfflineManifest.gup` or *`<app-id>`*`.gup`.
               The file contains the update check response in XML format.
-            * App installer.
+            * {AppId}\AppInstaller.exe/msi.
             * See the "Offline installs" section below for more information.
         *   The switch can be combined with `--handoff` above.
         *   --enterprise
@@ -386,6 +387,18 @@
   format.
 * app installer.
 
+Offline install command line format:
+* The offline directory is specified on the command line as a relative path in
+the format "/offlinedir {GUID}".
+* The actual offline directory is at `{CURRENT_PROCESS_DIR}\Offline\{GUID}`.
+* The offline manifest is at
+`{CURRENT_PROCESS_DIR}\Offline\{GUID}\OfflineManifest.gup`.
+* The installer is at
+`{CURRENT_PROCESS_DIR}\Offline\{GUID}\{app_id}\installer.exe`.
+  * `installer.exe` may not correspond exactly to the value of the manifest's
+  `run` attribute, so the code picks the first file it finds in the
+  directory if that is the case.
+
 For online app installs, the update server checks the compatibility between the
 application and the host OS that the install is attempted on.
 
@@ -400,17 +413,6 @@
 return "x86_64" as the architecture for amd64. The updater accounts for this by
 treating "x64" the same as "x86_64".
 
-The offline dir can be specified as a relative path when it is in the format
-"/offlinedir {GUID}". In this case:
-* the actual offline directory is `{CURRENT_PROCESS_DIR}\Offline\{GUID}`,
-* the offline manifest is
-  `{CURRENT_PROCESS_DIR}\Offline\{GUID}\OfflineManifest.gup`, and
-* the installer is at
-  `{CURRENT_PROCESS_DIR}\Offline\{GUID}\{app_id}\installer.exe`.
-  * `installer.exe` may not correspond exactly to the value of the manifest's
-    `run` attribute, so the code picks the first file it finds in the directory
-    if that is the case.
-
 For more information, see the
 [protocol document](protocol_3_1.md#update-checks-body-update-check-response-objects-update-check-response-3).
 
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 3edd828..5512601 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-742296256ce51f98c91ef0a46f436ff708a13e4b
\ No newline at end of file
+ac99e8b865b36c27ac447091c470c9dc8de30d21
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index d77f1ae..9dd2992 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-0159f540c2768d798e18566af7ee6eaabfb4a97d
\ No newline at end of file
+2868695d3e37f5c8937f965db22789a389760b86
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 1824524d..d4c3546 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-2d3a49b4aa5f54c1de28a9a5acc44003e42206ff
\ No newline at end of file
+1922152d833b12b4270cb66b4ffab63b60c272bd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index c159bb2..b71014e 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-400d142c7c5e5bc9b6cf8bc9157474c65196ed47
\ No newline at end of file
+fa1f11109d99f3a637fffd60dc3da8033243115e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 56e1282..c88711c 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3e11efa0d34a38c1b7c375c198bdb642e3a239c9
\ No newline at end of file
+6697b7ba3641596932ee2df04fe4b3c7e1a0236b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index a2dd6f9..01010da 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-6b3576fbf7fecf2e3bf8e9087eb63ed9d887c3ad
\ No newline at end of file
+d7a4ee3fd47e9d08400784b3ab045e781c46461c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index e93e4781..926f2f6 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-927b2074d317d4a2833d8b06ac7f32d2dfabf06f
\ No newline at end of file
+b51e791087b959359b201f0906b09df38edb8cde
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index d21418a..868a7c0 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-ddeea1c61e29f9ad03ed621b35ab9a0b5f701aa9
\ No newline at end of file
+cdabcbaa79697a25141dc586947566a33f71ba0d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 80313e3..316b963 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-51e6811cdcf7c7bd39ae3535a95c75938fd85774
\ No newline at end of file
+f1098c119828fda4f6c208c97e4a62848dffba08
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index cb9df612..159ac76 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-ddb9c1004132e04184cde71363b8166bf887b567
\ No newline at end of file
+00cf2834b5dfcbe21dfd0d895bb2b0a4ee77a28e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 171ccb3..e4dcaf0f 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-35912984219cd041f4993b38727667ad0efd528f
\ No newline at end of file
+e241b546be349cd2a9a68bd077f460b8df044b11
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 119d1e2..006e8ec3 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-dd031f5e06e17c922339c91164b011354a94f161
\ No newline at end of file
+df067bf0d2ba0145c67342944af17adf896c64c9
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index cd93acf9..c9e7a75 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -281,9 +281,7 @@
     if (!base::DeleteFile(disable_file_path)) {
       LOG(WARNING) << "Could not delete " << kForceDisableEffectsPath;
     }
-    base::File file(ash::features::IsVCBackgroundBlurEnabled() ||
-                            ash::features::IsVCBackgroundReplaceEnabled() ||
-                            ash::features::IsVCPortraitRelightingEnabled()
+    base::File file(ash::features::IsVideoConferenceEnabled()
                         ? enable_file_path
                         : disable_file_path,
                     base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
diff --git a/media/gpu/chromeos/gl_image_processor_backend.cc b/media/gpu/chromeos/gl_image_processor_backend.cc
index a67b0b8..faabc48 100644
--- a/media/gpu/chromeos/gl_image_processor_backend.cc
+++ b/media/gpu/chromeos/gl_image_processor_backend.cc
@@ -119,6 +119,10 @@
           base::ThreadPool::CreateSingleThreadTaskRunner(
               {base::TaskPriority::USER_VISIBLE})) {}
 
+std::string GLImageProcessorBackend::type() const {
+  return "GLImageProcessor";
+}
+
 bool GLImageProcessorBackend::IsSupported(const PortConfig& input_config,
                                           const PortConfig& output_config,
                                           VideoRotation relative_rotation) {
diff --git a/media/gpu/chromeos/gl_image_processor_backend.h b/media/gpu/chromeos/gl_image_processor_backend.h
index 29f4f6c..97218fa 100644
--- a/media/gpu/chromeos/gl_image_processor_backend.h
+++ b/media/gpu/chromeos/gl_image_processor_backend.h
@@ -45,6 +45,7 @@
   static bool IsSupported(const PortConfig& input_config,
                           const PortConfig& output_config,
                           VideoRotation relative_rotation);
+  std::string type() const override;
 
  private:
   // Callback for initialization.
diff --git a/media/gpu/chromeos/image_processor.h b/media/gpu/chromeos/image_processor.h
index 2295927..149e2313 100644
--- a/media/gpu/chromeos/image_processor.h
+++ b/media/gpu/chromeos/image_processor.h
@@ -79,6 +79,7 @@
 
   OutputMode output_mode() const { return backend_->output_mode(); }
 
+  std::string backend_type() const { return backend_->type(); }
   // Called by client to process |frame|. The resulting processed frame will be
   // stored in a ImageProcessor-owned output buffer and notified via |cb|. The
   // processor will drop all its references to |frame| after it finishes
diff --git a/media/gpu/chromeos/image_processor_backend.h b/media/gpu/chromeos/image_processor_backend.h
index b4e0102e..9acf6bb 100644
--- a/media/gpu/chromeos/image_processor_backend.h
+++ b/media/gpu/chromeos/image_processor_backend.h
@@ -120,6 +120,8 @@
     return backend_task_runner_;
   }
 
+  virtual std::string type() const = 0;
+
  protected:
   friend struct std::default_delete<ImageProcessorBackend>;
 
diff --git a/media/gpu/chromeos/image_processor_with_pool.h b/media/gpu/chromeos/image_processor_with_pool.h
index 1054729..e2039650 100644
--- a/media/gpu/chromeos/image_processor_with_pool.h
+++ b/media/gpu/chromeos/image_processor_with_pool.h
@@ -56,6 +56,8 @@
     return image_processor_ && image_processor_->SupportsIncoherentBufs();
   }
 
+  std::string backend_type() const { return image_processor_->backend_type(); }
+
  private:
   friend class VideoDecoderPipelineTest;
 
diff --git a/media/gpu/chromeos/libyuv_image_processor_backend.cc b/media/gpu/chromeos/libyuv_image_processor_backend.cc
index 9459ee1..45885d8 100644
--- a/media/gpu/chromeos/libyuv_image_processor_backend.cc
+++ b/media/gpu/chromeos/libyuv_image_processor_backend.cc
@@ -346,6 +346,10 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(backend_sequence_checker_);
 }
 
+std::string LibYUVImageProcessorBackend::type() const {
+  return "LibYUVImageProcessor";
+}
+
 void LibYUVImageProcessorBackend::Process(
     scoped_refptr<VideoFrame> input_frame,
     scoped_refptr<VideoFrame> output_frame,
diff --git a/media/gpu/chromeos/libyuv_image_processor_backend.h b/media/gpu/chromeos/libyuv_image_processor_backend.h
index 3e3c251..ef4dd008 100644
--- a/media/gpu/chromeos/libyuv_image_processor_backend.h
+++ b/media/gpu/chromeos/libyuv_image_processor_backend.h
@@ -62,6 +62,8 @@
 
   bool supports_incoherent_buffers() const override;
 
+  std::string type() const override;
+
  private:
   LibYUVImageProcessorBackend(
       std::unique_ptr<VideoFrameMapper> input_frame_mapper,
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
index 0e87d44..738840f 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -964,7 +964,7 @@
   }
 
   image_processor_ = std::move(status_or_image_processor).value();
-
+  VLOGF(2) << "ImageProcessor is created: " << image_processor_->backend_type();
   if (decoder_)
     decoder_->SetDmaIncoherentV4L2(image_processor_->SupportsIncoherentBufs());
 
diff --git a/media/gpu/v4l2/v4l2_image_processor_backend.cc b/media/gpu/v4l2/v4l2_image_processor_backend.cc
index f3049f4..3f2140c 100644
--- a/media/gpu/v4l2/v4l2_image_processor_backend.cc
+++ b/media/gpu/v4l2/v4l2_image_processor_backend.cc
@@ -146,6 +146,10 @@
   poll_weak_this_ = poll_weak_this_factory_.GetWeakPtr();
 }
 
+std::string V4L2ImageProcessorBackend::type() const {
+  return "V4L2ImageProcessor";
+}
+
 void V4L2ImageProcessorBackend::Destroy() {
   DVLOGF(3);
   DCHECK_CALLED_ON_VALID_SEQUENCE(backend_sequence_checker_);
diff --git a/media/gpu/v4l2/v4l2_image_processor_backend.h b/media/gpu/v4l2/v4l2_image_processor_backend.h
index 282f90e..b8b95504 100644
--- a/media/gpu/v4l2/v4l2_image_processor_backend.h
+++ b/media/gpu/v4l2/v4l2_image_processor_backend.h
@@ -87,6 +87,8 @@
                               gfx::Size* output_size,
                               size_t* num_planes);
 
+  std::string type() const override;
+
  private:
   friend struct std::default_delete<V4L2ImageProcessorBackend>;
 
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
index c2f0c64..056d59ca 100644
--- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -1900,9 +1900,9 @@
   encoder_task_runner_ = encoder_thread_.task_runner();
 
   encoder_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&V4L2JpegEncodeAccelerator::InitializeTask, weak_ptr_,
-                     client, BindToCurrentLoop(std::move(init_cb))));
+      FROM_HERE, base::BindOnce(&V4L2JpegEncodeAccelerator::InitializeTask,
+                                base::Unretained(this), client,
+                                BindToCurrentLoop(std::move(init_cb))));
 }
 
 size_t V4L2JpegEncodeAccelerator::GetMaxCodedBufferSize(
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index a8c51951..1486e9e 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -594,8 +594,9 @@
     return false;
   }
 
-  DCHECK_EQ(gl_image_size_, image_processor_->output_config().size);
+  VLOGF(2) << "ImageProcessor is created: " << image_processor_->backend_type();
 
+  DCHECK_EQ(gl_image_size_, image_processor_->output_config().size);
   return true;
 }
 bool V4L2SliceVideoDecodeAccelerator::CreateInputBuffers() {
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index e47ed8f..a71e272 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -2379,6 +2379,7 @@
     return false;
   }
 
+  VLOGF(2) << "ImageProcessor is created: " << image_processor_->backend_type();
   return true;
 }
 
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index d452ba4..1989c66 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -277,6 +277,8 @@
     return false;
   }
 
+  driver_name_ = device_->GetDriverName();
+
   encoder_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&V4L2VideoEncodeAccelerator::InitializeTask,
                                 weak_this_, config));
@@ -468,6 +470,7 @@
     VLOGF(1) << "Failed initializing image processor";
     return false;
   }
+  VLOGF(2) << "ImageProcessor is created: " << image_processor_->backend_type();
   num_frames_in_image_processor_ = 0;
 
   // The output of image processor is the input of encoder. Output coded
@@ -1411,10 +1414,14 @@
         return false;
       }
 
-      // Keep |gmb_handle| alive as long as |frame| is alive so that fds passed
-      // to the driver are valid during encoding.
-      frame->AddDestructionObserver(base::BindOnce(
-          [](gfx::GpuMemoryBufferHandle) {}, std::move(gmb_handle)));
+      // TODO(b/266443239): Remove this workaround once RK3399 boards reaches
+      // EOL. v4lplugin holds v4l2_buffer in QBUF without duplicating the passed
+      // fds and resumes the QBUF request later after VIDIOC_QBUF returns. It is
+      // required to keep the passed fds valid until DQBUF is complete.
+      if (driver_name_ == "hantro-vpu") {
+        frame->AddDestructionObserver(base::BindOnce(
+            [](gfx::GpuMemoryBufferHandle) {}, std::move(gmb_handle)));
+      }
       break;
     }
     default:
@@ -1423,6 +1430,8 @@
       return false;
   }
 
+  // Keep |frame| in |input_record| so that a client doesn't use |frame| until
+  // a driver finishes using it, that is, VIDIOC_DQBUF is called.
   InputRecord& input_record = input_buffer_map_[buffer_id];
   input_record.frame = frame;
   input_record.ip_output_buffer_index = frame_info.ip_output_buffer_index;
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.h b/media/gpu/v4l2/v4l2_video_encode_accelerator.h
index e3dfdf39..1e9235a0 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.h
@@ -268,6 +268,8 @@
   static base::AtomicRefCount num_instances_;
   const bool can_use_encoder_;
 
+  std::string driver_name_;
+
   // Our original calling task runner for the child thread and its checker.
   const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
   SEQUENCE_CHECKER(child_sequence_checker_);
diff --git a/media/gpu/vaapi/vaapi_image_processor_backend.cc b/media/gpu/vaapi/vaapi_image_processor_backend.cc
index d3cd8052..cdc8f04 100644
--- a/media/gpu/vaapi/vaapi_image_processor_backend.cc
+++ b/media/gpu/vaapi/vaapi_image_processor_backend.cc
@@ -152,6 +152,10 @@
   }
 }
 
+std::string VaapiImageProcessorBackend::type() const {
+  return "VaapiImageProcessor";
+}
+
 const VASurface* VaapiImageProcessorBackend::GetSurfaceForVideoFrame(
     scoped_refptr<VideoFrame> frame,
     bool use_protected) {
diff --git a/media/gpu/vaapi/vaapi_image_processor_backend.h b/media/gpu/vaapi/vaapi_image_processor_backend.h
index 7ac87f6..fe4c94a 100644
--- a/media/gpu/vaapi/vaapi_image_processor_backend.h
+++ b/media/gpu/vaapi/vaapi_image_processor_backend.h
@@ -45,6 +45,8 @@
                FrameReadyCB cb) override;
   void Reset() override;
 
+  std::string type() const override;
+
  private:
   VaapiImageProcessorBackend(const PortConfig& input_config,
                              const PortConfig& output_config,
diff --git a/media/mojo/mojom/speech_recognition.mojom b/media/mojo/mojom/speech_recognition.mojom
index b720c6a..452cf30 100644
--- a/media/mojo/mojom/speech_recognition.mojom
+++ b/media/mojo/mojom/speech_recognition.mojom
@@ -6,6 +6,7 @@
 
 import "media/mojo/mojom/audio_data.mojom";
 import "mojo/public/mojom/base/time.mojom";
+import "mojo/public/mojom/base/unguessable_token.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
 // Corresponds to the LangIdEvent.ConfidenceInterval defined in
@@ -186,6 +187,16 @@
   OnFullscreenToggled@1();
 };
 
+// Static metadata about a remote speech surface. Used by the speech service
+// client in Ash.
+[Stable]
+struct SpeechRecognitionSurfaceMetadata {
+  // A unique identifier for the "session" (i.e. tab) of the surface. Is used to
+  // hide the caption bubble for all streams in a tab if the bubble is closed
+  // once.
+  mojo_base.mojom.UnguessableToken session_id;
+};
+
 // This interface between the speech recognition client and the browser.
 // The remote lives in the renderer process and the receiver lives in the
 // browser process. Not necessary for browser-side features (e.g. CrOS system
@@ -195,6 +206,16 @@
   // Bind the speech recognition availability observer.
   BindSpeechRecognitionBrowserObserver@0(
     pending_remote<SpeechRecognitionBrowserObserver> observer);
+
+  // Requests that a remote speech recognition client be instantiated and bound
+  // in the Ash browser process. The instantiated client should use the surface
+  // and surface client bindings to perform tasks (such as refocusing) that
+  // require coordination with the current lacros tab.
+  [MinVersion=1] BindRecognizerToRemoteClient@1(
+    pending_receiver<SpeechRecognitionRecognizerClient> client,
+    pending_receiver<SpeechRecognitionSurfaceClient> surface_client,
+    pending_remote<SpeechRecognitionSurface> surface,
+    SpeechRecognitionSurfaceMetadata metadata);
 };
 
 // Corresponds to ExtendedSodaConfigMsg.RecognitionMode in
diff --git a/mojo/core/core.cc b/mojo/core/core.cc
index 4e6f0ab4..4408982 100644
--- a/mojo/core/core.cc
+++ b/mojo/core/core.cc
@@ -1051,9 +1051,9 @@
   if (!handles_ok)
     return MOJO_RESULT_INVALID_ARGUMENT;
 
-  base::UnguessableToken token =
+  absl::optional<base::UnguessableToken> token =
       mojo::internal::PlatformHandleInternal::UnmarshalUnguessableToken(guid);
-  if (token.is_empty()) {
+  if (!token.has_value()) {
     return MOJO_RESULT_INVALID_ARGUMENT;
   }
 
@@ -1076,7 +1076,7 @@
       base::subtle::PlatformSharedMemoryRegion::Take(
           CreateSharedMemoryRegionHandleFromPlatformHandles(
               std::move(handles[0]), std::move(handles[1])),
-          mode, size, std::move(token));
+          mode, size, token.value());
   if (!region.IsValid())
     return MOJO_RESULT_UNKNOWN;
 
diff --git a/mojo/public/cpp/platform/platform_handle_internal.h b/mojo/public/cpp/platform/platform_handle_internal.h
index 9b727c97..89dc0c8d 100644
--- a/mojo/public/cpp/platform/platform_handle_internal.h
+++ b/mojo/public/cpp/platform/platform_handle_internal.h
@@ -22,9 +22,9 @@
     return {.high = token.GetHighForSerialization(),
             .low = token.GetLowForSerialization()};
   }
-  static base::UnguessableToken UnmarshalUnguessableToken(
+  static absl::optional<base::UnguessableToken> UnmarshalUnguessableToken(
       const MojoSharedBufferGuid* guid) {
-    return base::UnguessableToken::Deserialize(guid->high, guid->low);
+    return base::UnguessableToken::Deserialize2(guid->high, guid->low);
   }
 };
 
diff --git a/mojo/public/cpp/system/platform_handle.cc b/mojo/public/cpp/system/platform_handle.cc
index a7e0e0e..5c9e8e09 100644
--- a/mojo/public/cpp/system/platform_handle.cc
+++ b/mojo/public/cpp/system/platform_handle.cc
@@ -173,14 +173,14 @@
       return base::subtle::PlatformSharedMemoryRegion();
   }
 
-  base::UnguessableToken guid =
+  absl::optional<base::UnguessableToken> guid =
       internal::PlatformHandleInternal::UnmarshalUnguessableToken(&mojo_guid);
-  if (guid.is_empty()) {
+  if (!guid.has_value()) {
     return base::subtle::PlatformSharedMemoryRegion();
   }
 
   return base::subtle::PlatformSharedMemoryRegion::Take(
-      std::move(region_handle), mode, size, std::move(guid));
+      std::move(region_handle), mode, size, guid.value());
 }
 
 ScopedHandle WrapPlatformHandle(PlatformHandle handle) {
diff --git a/net/base/schemeful_site.h b/net/base/schemeful_site.h
index a4449fc..f834901 100644
--- a/net/base/schemeful_site.h
+++ b/net/base/schemeful_site.h
@@ -17,6 +17,7 @@
 
 namespace blink {
 class BlinkSchemefulSite;
+class StorageKey;
 }  // namespace blink
 
 namespace IPC {
@@ -165,7 +166,11 @@
   // Needed because cookies do not account for scheme.
   friend class CookieMonster;
 
+  // Needed for access to nonce for serialization.
+  friend class blink::StorageKey;
+
   FRIEND_TEST_ALL_PREFIXES(SchemefulSiteTest, OpaqueSerialization);
+  FRIEND_TEST_ALL_PREFIXES(SchemefulSiteTest, InternalValue);
 
   struct ObtainASiteResult {
     url::Origin origin;
@@ -201,6 +206,11 @@
     return site_as_origin_.host();
   }
 
+  // This should not be used casually, it's an opaque Origin or an scheme+eTLD+1
+  // packed into an Origin. If you extract this value SchemefulSite is not
+  // responsible for any unexpected friction you might encounter.
+  const url::Origin& internal_value() const { return site_as_origin_; }
+
   // Origin which stores the result of running the steps documented at
   // https://html.spec.whatwg.org/multipage/origin.html#obtain-a-site.
   // This is not an arbitrary origin. It must either be an opaque origin, or a
diff --git a/net/base/schemeful_site_unittest.cc b/net/base/schemeful_site_unittest.cc
index 06086d4e..b536c07 100644
--- a/net/base/schemeful_site_unittest.cc
+++ b/net/base/schemeful_site_unittest.cc
@@ -397,4 +397,13 @@
   }
 }
 
+TEST(SchemefulSiteTest, InternalValue) {
+  url::Origin origin = url::Origin::Create(GURL("https://example.com"));
+  SchemefulSite site(origin);
+  EXPECT_EQ(site.internal_value(), origin);
+  url::Origin opaque_origin;
+  SchemefulSite opaque_site(opaque_origin);
+  EXPECT_EQ(opaque_site.internal_value(), opaque_origin);
+}
+
 }  // namespace net
diff --git a/third_party/abseil-cpp/BUILD.gn b/third_party/abseil-cpp/BUILD.gn
index f17ae8f2..b9bfc84c 100644
--- a/third_party/abseil-cpp/BUILD.gn
+++ b/third_party/abseil-cpp/BUILD.gn
@@ -198,6 +198,7 @@
         "absl/crc:crc_cord_state_test",
         "absl/crc:crc_memcpy_test",
         "absl/crc:non_temporal_memcpy_test",
+        "absl/debugging:stacktrace_test",
         "absl/functional:any_invocable_test",
         "absl/hash:hash_test",
         "absl/hash:low_level_hash_test",
diff --git a/third_party/abseil-cpp/CMake/AbseilDll.cmake b/third_party/abseil-cpp/CMake/AbseilDll.cmake
index 73848bda..1e4120c 100644
--- a/third_party/abseil-cpp/CMake/AbseilDll.cmake
+++ b/third_party/abseil-cpp/CMake/AbseilDll.cmake
@@ -144,6 +144,47 @@
   "hash/internal/spy_hash_state.h"
   "hash/internal/low_level_hash.h"
   "hash/internal/low_level_hash.cc"
+  "log/absl_check.h"
+  "log/absl_log.h"
+  "log/check.h"
+  "log/die_if_null.cc"
+  "log/die_if_null.h"
+  "log/globals.cc"
+  "log/globals.h"
+  "log/internal/append_truncated.h"
+  "log/internal/check_impl.h"
+  "log/internal/check_op.cc"
+  "log/internal/check_op.h"
+  "log/internal/conditions.cc"
+  "log/internal/conditions.h"
+  "log/internal/config.h"
+  "log/internal/globals.cc"
+  "log/internal/globals.h"
+  "log/internal/log_format.cc"
+  "log/internal/log_format.h"
+  "log/internal/log_impl.h"
+  "log/internal/log_message.cc"
+  "log/internal/log_message.h"
+  "log/internal/log_sink_set.cc"
+  "log/internal/log_sink_set.h"
+  "log/internal/nullguard.cc"
+  "log/internal/nullguard.h"
+  "log/internal/nullstream.h"
+  "log/internal/proto.h"
+  "log/internal/proto.cc"
+  "log/internal/strip.h"
+  "log/internal/structured.h"
+  "log/internal/voidify.h"
+  "log/initialize.cc"
+  "log/initialize.h"
+  "log/log.h"
+  "log/log_entry.cc"
+  "log/log_entry.h"
+  "log/log_sink.cc"
+  "log/log_sink.h"
+  "log/log_sink_registry.h"
+  "log/log_streamer.h"
+  "log/structured.h"
   "memory/memory.h"
   "meta/type_traits.h"
   "numeric/bits.h"
@@ -170,7 +211,6 @@
   "random/internal/fast_uniform_bits.h"
   "random/internal/generate_real.h"
   "random/internal/iostream_state_saver.h"
-  "random/internal/mock_helpers.h"
   "random/internal/nonsecure_base.h"
   "random/internal/pcg_engine.h"
   "random/internal/platform.h"
@@ -380,6 +420,8 @@
 )
 
 set(ABSL_INTERNAL_DLL_TARGETS
+  "absl_check"
+  "absl_log"
   "algorithm"
   "algorithm_container"
   "any"
@@ -394,6 +436,7 @@
   "bind_front"
   "bits"
   "btree"
+  "check"
   "city"
   "civil_time"
   "compare"
@@ -411,6 +454,7 @@
   "debugging"
   "debugging_internal"
   "demangle_internal"
+  "die_if_null"
   "dynamic_annotations"
   "endian"
   "examine_stack"
@@ -433,7 +477,31 @@
   "kernel_timeout_internal"
   "layout"
   "leak_check"
+  "log_internal_check_impl"
+  "log_internal_check_op"
+  "log_internal_conditions"
+  "log_internal_config"
+  "log_internal_format"
+  "log_internal_globals"
+  "log_internal_log_impl"
+  "log_internal_proto"
+  "log_internal_message"
+  "log_internal_log_sink_set"
+  "log_internal_nullguard"
+  "log_internal_nullstream"
+  "log_internal_strip"
+  "log_internal_voidify"
+  "log_internal_append_truncated"
+  "log_globals"
+  "log_initialize"
+  "log"
+  "log_entry"
+  "log_sink"
+  "log_sink_registry"
+  "log_streamer"
+  "log_internal_structured"
   "log_severity"
+  "log_structured"
   "malloc_internal"
   "memory"
   "meta"
@@ -501,6 +569,27 @@
   "variant"
 )
 
+set(ABSL_INTERNAL_TEST_DLL_FILES
+  "hash/hash_testing.h"
+  "log/scoped_mock_log.cc"
+  "log/scoped_mock_log.h"
+  "random/internal/mock_helpers.h"
+  "random/internal/mock_overload_set.h"
+  "random/mocking_bit_gen.h"
+  "random/mock_distributions.h"
+  "strings/cordz_test_helpers.h"
+  "strings/cord_test_helpers.h"
+)
+
+set(ABSL_INTERNAL_TEST_DLL_TARGETS
+  "cord_test_helpers"
+  "cordz_test_helpers"
+  "hash_testing"
+  "random_mocking_bit_gen"
+  "random_internal_mock_overload_set"
+  "scoped_mock_log"
+)
+
 function(_absl_target_compile_features_if_available TARGET TYPE FEATURE)
   if(FEATURE IN_LIST CMAKE_CXX_COMPILE_FEATURES)
     target_compile_features(${TARGET} ${TYPE} ${FEATURE})
@@ -552,6 +641,28 @@
   endif()
 endfunction()
 
+function(absl_internal_test_dll_contains)
+  cmake_parse_arguments(ABSL_INTERNAL_TEST_DLL
+    ""
+    "OUTPUT;TARGET"
+    ""
+    ${ARGN}
+  )
+
+  STRING(REGEX REPLACE "^absl::" "" _target ${ABSL_INTERNAL_TEST_DLL_TARGET})
+
+  list(FIND
+    ABSL_INTERNA_TEST_DLL_TARGETS
+    "${_target}"
+    _index)
+
+  if (${_index} GREATER -1)
+    set(${ABSL_INTERNAL_TEST_DLL_OUTPUT} 1 PARENT_SCOPE)
+  else()
+    set(${ABSL_INTERNAL_TEST_DLL_OUTPUT} 0 PARENT_SCOPE)
+  endif()
+endfunction()
+
 function(absl_internal_dll_targets)
   cmake_parse_arguments(ABSL_INTERNAL_DLL
   ""
@@ -562,9 +673,12 @@
 
   set(_deps "")
   foreach(dep IN LISTS ABSL_INTERNAL_DLL_DEPS)
-    absl_internal_dll_contains(TARGET ${dep} OUTPUT _contains)
-    if (_contains)
+    absl_internal_dll_contains(TARGET ${dep} OUTPUT _dll_contains)
+    absl_internal_test_dll_contains(TARGET ${dep} OUTPUT _test_dll_contains)
+    if (_dll_contains)
       list(APPEND _deps abseil_dll)
+    elseif (_test_dll_contains)
+      list(APPEND _deps abseil_test_dll)
     else()
       list(APPEND _deps ${dep})
     endif()
@@ -576,26 +690,50 @@
 endfunction()
 
 function(absl_make_dll)
+  cmake_parse_arguments(ABSL_INTERNAL_MAKE_DLL
+  ""
+  "TEST"
+  ""
+  ${ARGN}
+  )
+
+  if (ABSL_INTERNAL_MAKE_DLL_TEST)
+    set(_dll "abseil_test_dll")
+    set(_dll_files ${ABSL_INTERNAL_TEST_DLL_FILES})
+    set(_dll_libs "abseil_dll" "GTest::gtest" "GTest::gmock")
+    set(_dll_compile_definiations "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+    set(_dll_includes ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})
+  else()
+    set(_dll "abseil_dll")
+    set(_dll_files ${ABSL_INTERNAL_DLL_FILES})
+    set(_dll_libs "")
+    set(_dll_compile_definiations "")
+    set(_dll_includes "")
+  endif()
+
   add_library(
-    abseil_dll
+    ${_dll}
     SHARED
-      "${ABSL_INTERNAL_DLL_FILES}"
+      ${_dll_files}
   )
   target_link_libraries(
-    abseil_dll
+    ${_dll}
     PRIVATE
+      ${_dll_libs}
       ${ABSL_DEFAULT_LINKOPTS}
   )
-  set_property(TARGET abseil_dll PROPERTY LINKER_LANGUAGE "CXX")
+  set_property(TARGET ${_dll} PROPERTY LINKER_LANGUAGE "CXX")
   target_include_directories(
-    abseil_dll
+    ${_dll}
     PUBLIC
       "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
       $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    PRIVATE
+      ${_dll_includes}
   )
 
   target_compile_options(
-    abseil_dll
+    ${_dll}
     PRIVATE
       ${ABSL_DEFAULT_COPTS}
   )
@@ -612,23 +750,25 @@
   endforeach()
   string(REPLACE ";" " " PC_LINKOPTS "${ABSL_CC_LIB_LINKOPTS}")
 
-  FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/abseil_dll.pc" CONTENT "\
+  FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/${_dll}.pc" CONTENT "\
 prefix=${CMAKE_INSTALL_PREFIX}\n\
 exec_prefix=\${prefix}\n\
 libdir=${CMAKE_INSTALL_FULL_LIBDIR}\n\
 includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}\n\
 \n\
-Name: abseil_dll\n\
+Name: ${_dll}\n\
 Description: Abseil DLL library\n\
 URL: https://abseil.io/\n\
 Version: ${absl_VERSION}\n\
 Libs: -L\${libdir} ${PC_LINKOPTS} $<$<NOT:$<BOOL:${ABSL_CC_LIB_IS_INTERFACE}>>:-labseil_dll>\n\
 Cflags: -I\${includedir}${PC_CFLAGS}\n")
-  INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/abseil_dll.pc"
+  INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/${_dll}.pc"
     DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
 
   target_compile_definitions(
-    abseil_dll
+    ${_dll}
+    PUBLIC
+      GTEST_LINKED_AS_SHARED_LIBRARY=1
     PRIVATE
       ABSL_BUILD_DLL
       NOMINMAX
@@ -655,7 +795,7 @@
     set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
   endif()
 
-  install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets
+  install(TARGETS ${_dll} EXPORT ${PROJECT_NAME}Targets
         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
         LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
         ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
index e3569e9..cfe55825 100644
--- a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
+++ b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
@@ -132,10 +132,12 @@
   if (${ABSL_BUILD_DLL})
     if(ABSL_ENABLE_INSTALL)
       absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
+      absl_internal_test_dll_contains(TARGET ${_NAME} OUTPUT _in_test_dll)
     else()
       absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll)
+      absl_internal_test_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_test_dll)
     endif()
-    if (${_in_dll})
+    if (${_in_dll} OR ${_in_test_dll})
       # This target should be replaced by the DLL
       set(_build_type "dll")
       set(ABSL_CC_LIB_IS_INTERFACE 1)
@@ -157,6 +159,9 @@
       else()
         set(PC_VERSION "head")
       endif()
+      if(NOT _build_type STREQUAL "dll")
+        set(LNK_LIB "${LNK_LIB} -labsl_${_NAME}")
+      endif()
       foreach(dep ${ABSL_CC_LIB_DEPS})
         if(${dep} MATCHES "^absl::(.*)")
           # for DLL builds many libs are not created, but add
@@ -179,7 +184,6 @@
               set(PC_DEPS "${PC_DEPS},")
             endif()
             set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}")
-            set(LNK_LIB "${LNK_LIB} -labsl_${_NAME}")
           endif()
         endif()
       endforeach()
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index 361a838..9d37f80 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: a86f1cec941ee7842a2ce1bce1cc4aa83eeb8d8d
+Revision: b0a2b10bb125a90b35727be67b972f4e5b89283b
 Security Critical: yes
 
 Description:
diff --git a/third_party/abseil-cpp/absl/CMakeLists.txt b/third_party/abseil-cpp/absl/CMakeLists.txt
index 19a91c6..3a7c12fe 100644
--- a/third_party/abseil-cpp/absl/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/CMakeLists.txt
@@ -38,4 +38,7 @@
 
 if (${ABSL_BUILD_DLL})
   absl_make_dll()
+  if (${ABSL_BUILD_TEST_HELPERS})
+    absl_make_dll(TEST ON)
+  endif()
 endif()
diff --git a/third_party/abseil-cpp/absl/algorithm/container.h b/third_party/abseil-cpp/absl/algorithm/container.h
index 1f57dab..c7782d4f 100644
--- a/third_party/abseil-cpp/absl/algorithm/container.h
+++ b/third_party/abseil-cpp/absl/algorithm/container.h
@@ -77,9 +77,8 @@
     decltype(std::make_pair(ContainerIter<C1>(), ContainerIter<C2>()));
 
 template <typename C>
-using ContainerDifferenceType =
-    decltype(std::distance(std::declval<ContainerIter<C>>(),
-                           std::declval<ContainerIter<C>>()));
+using ContainerDifferenceType = decltype(std::distance(
+    std::declval<ContainerIter<C>>(), std::declval<ContainerIter<C>>()));
 
 template <typename C>
 using ContainerPointerType =
@@ -97,10 +96,14 @@
 // These are meant for internal use only.
 
 template <typename C>
-ContainerIter<C> c_begin(C& c) { return begin(c); }
+ContainerIter<C> c_begin(C& c) {
+  return begin(c);
+}
 
 template <typename C>
-ContainerIter<C> c_end(C& c) { return end(c); }
+ContainerIter<C> c_end(C& c) {
+  return end(c);
+}
 
 template <typename T>
 struct IsUnorderedContainer : std::false_type {};
@@ -343,8 +346,8 @@
 // return the first element where two ordered containers differ. Applies `==` to
 // the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
 template <typename C1, typename C2>
-container_algorithm_internal::ContainerIterPairType<C1, C2>
-c_mismatch(C1& c1, C2& c2) {
+container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(C1& c1,
+                                                                       C2& c2) {
   auto first1 = container_algorithm_internal::c_begin(c1);
   auto last1 = container_algorithm_internal::c_end(c1);
   auto first2 = container_algorithm_internal::c_begin(c2);
@@ -365,8 +368,8 @@
 // the function's test condition. Applies `pred`to the first N elements of `c1`
 // and `c2`, where N = min(size(c1), size(c2)).
 template <typename C1, typename C2, typename BinaryPredicate>
-container_algorithm_internal::ContainerIterPairType<C1, C2>
-c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
+container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(
+    C1& c1, C2& c2, BinaryPredicate pred) {
   auto first1 = container_algorithm_internal::c_begin(c1);
   auto last1 = container_algorithm_internal::c_end(c1);
   auto first2 = container_algorithm_internal::c_begin(c2);
@@ -655,11 +658,10 @@
 // some condition, and return the results within an iterator.
 template <typename C, typename OutputIterator, typename Pred, typename T>
 OutputIterator c_replace_copy_if(const C& c, OutputIterator result, Pred&& pred,
-                                 T&& new_value) {
+                                 const T& new_value) {
   return std::replace_copy_if(container_algorithm_internal::c_begin(c),
                               container_algorithm_internal::c_end(c), result,
-                              std::forward<Pred>(pred),
-                              std::forward<T>(new_value));
+                              std::forward<Pred>(pred), new_value);
 }
 
 // c_fill()
@@ -667,9 +669,9 @@
 // Container-based version of the <algorithm> `std::fill()` function to fill a
 // container with some value.
 template <typename C, typename T>
-void c_fill(C& c, T&& value) {
+void c_fill(C& c, const T& value) {
   std::fill(container_algorithm_internal::c_begin(c),
-            container_algorithm_internal::c_end(c), std::forward<T>(value));
+            container_algorithm_internal::c_end(c), value);
 }
 
 // c_fill_n()
@@ -677,9 +679,8 @@
 // Container-based version of the <algorithm> `std::fill_n()` function to fill
 // the first N elements in a container with some value.
 template <typename C, typename Size, typename T>
-void c_fill_n(C& c, Size n, T&& value) {
-  std::fill_n(container_algorithm_internal::c_begin(c), n,
-              std::forward<T>(value));
+void c_fill_n(C& c, Size n, const T& value) {
+  std::fill_n(container_algorithm_internal::c_begin(c), n, value);
 }
 
 // c_generate()
@@ -716,10 +717,11 @@
 // copy a container's elements while removing any elements matching the given
 // `value`.
 template <typename C, typename OutputIterator, typename T>
-OutputIterator c_remove_copy(const C& c, OutputIterator result, T&& value) {
+OutputIterator c_remove_copy(const C& c, OutputIterator result,
+                             const T& value) {
   return std::remove_copy(container_algorithm_internal::c_begin(c),
                           container_algorithm_internal::c_end(c), result,
-                          std::forward<T>(value));
+                          value);
 }
 
 // c_remove_copy_if()
@@ -1064,20 +1066,19 @@
 // which does not compare less than `value`.
 template <typename Sequence, typename T>
 container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
-    Sequence& sequence, T&& value) {
+    Sequence& sequence, const T& value) {
   return std::lower_bound(container_algorithm_internal::c_begin(sequence),
-                          container_algorithm_internal::c_end(sequence),
-                          std::forward<T>(value));
+                          container_algorithm_internal::c_end(sequence), value);
 }
 
 // Overload of c_lower_bound() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
 container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
-    Sequence& sequence, T&& value, LessThan&& comp) {
+    Sequence& sequence, const T& value, LessThan&& comp) {
   return std::lower_bound(container_algorithm_internal::c_begin(sequence),
-                          container_algorithm_internal::c_end(sequence),
-                          std::forward<T>(value), std::forward<LessThan>(comp));
+                          container_algorithm_internal::c_end(sequence), value,
+                          std::forward<LessThan>(comp));
 }
 
 // c_upper_bound()
@@ -1087,20 +1088,19 @@
 // which is greater than `value`.
 template <typename Sequence, typename T>
 container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
-    Sequence& sequence, T&& value) {
+    Sequence& sequence, const T& value) {
   return std::upper_bound(container_algorithm_internal::c_begin(sequence),
-                          container_algorithm_internal::c_end(sequence),
-                          std::forward<T>(value));
+                          container_algorithm_internal::c_end(sequence), value);
 }
 
 // Overload of c_upper_bound() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
 container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
-    Sequence& sequence, T&& value, LessThan&& comp) {
+    Sequence& sequence, const T& value, LessThan&& comp) {
   return std::upper_bound(container_algorithm_internal::c_begin(sequence),
-                          container_algorithm_internal::c_end(sequence),
-                          std::forward<T>(value), std::forward<LessThan>(comp));
+                          container_algorithm_internal::c_end(sequence), value,
+                          std::forward<LessThan>(comp));
 }
 
 // c_equal_range()
@@ -1110,20 +1110,19 @@
 // sorted container which compare equal to `value`.
 template <typename Sequence, typename T>
 container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
-c_equal_range(Sequence& sequence, T&& value) {
+c_equal_range(Sequence& sequence, const T& value) {
   return std::equal_range(container_algorithm_internal::c_begin(sequence),
-                          container_algorithm_internal::c_end(sequence),
-                          std::forward<T>(value));
+                          container_algorithm_internal::c_end(sequence), value);
 }
 
 // Overload of c_equal_range() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
 container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
-c_equal_range(Sequence& sequence, T&& value, LessThan&& comp) {
+c_equal_range(Sequence& sequence, const T& value, LessThan&& comp) {
   return std::equal_range(container_algorithm_internal::c_begin(sequence),
-                          container_algorithm_internal::c_end(sequence),
-                          std::forward<T>(value), std::forward<LessThan>(comp));
+                          container_algorithm_internal::c_end(sequence), value,
+                          std::forward<LessThan>(comp));
 }
 
 // c_binary_search()
@@ -1132,20 +1131,19 @@
 // to test if any element in the sorted container contains a value equivalent to
 // 'value'.
 template <typename Sequence, typename T>
-bool c_binary_search(Sequence&& sequence, T&& value) {
+bool c_binary_search(Sequence&& sequence, const T& value) {
   return std::binary_search(container_algorithm_internal::c_begin(sequence),
                             container_algorithm_internal::c_end(sequence),
-                            std::forward<T>(value));
+                            value);
 }
 
 // Overload of c_binary_search() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-bool c_binary_search(Sequence&& sequence, T&& value, LessThan&& comp) {
+bool c_binary_search(Sequence&& sequence, const T& value, LessThan&& comp) {
   return std::binary_search(container_algorithm_internal::c_begin(sequence),
                             container_algorithm_internal::c_end(sequence),
-                            std::forward<T>(value),
-                            std::forward<LessThan>(comp));
+                            value, std::forward<LessThan>(comp));
 }
 
 //------------------------------------------------------------------------------
@@ -1560,8 +1558,8 @@
 // smallest and largest values, respectively, using `operator<` to make the
 // comparisons.
 template <typename C>
-container_algorithm_internal::ContainerIterPairType<C, C>
-c_minmax_element(C& c) {
+container_algorithm_internal::ContainerIterPairType<C, C> c_minmax_element(
+    C& c) {
   return std::minmax_element(container_algorithm_internal::c_begin(c),
                              container_algorithm_internal::c_end(c));
 }
@@ -1569,8 +1567,8 @@
 // Overload of c_minmax_element() for performing `comp` comparisons other than
 // `operator<`.
 template <typename C, typename LessThan>
-container_algorithm_internal::ContainerIterPairType<C, C>
-c_minmax_element(C& c, LessThan&& comp) {
+container_algorithm_internal::ContainerIterPairType<C, C> c_minmax_element(
+    C& c, LessThan&& comp) {
   return std::minmax_element(container_algorithm_internal::c_begin(c),
                              container_algorithm_internal::c_end(c),
                              std::forward<LessThan>(comp));
@@ -1588,7 +1586,8 @@
 // that capital letters ("A-Z") have ASCII values less than lowercase letters
 // ("a-z").
 template <typename Sequence1, typename Sequence2>
-bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) {
+bool c_lexicographical_compare(const Sequence1& sequence1,
+                               const Sequence2& sequence2) {
   return std::lexicographical_compare(
       container_algorithm_internal::c_begin(sequence1),
       container_algorithm_internal::c_end(sequence1),
@@ -1599,8 +1598,8 @@
 // Overload of c_lexicographical_compare() for performing a lexicographical
 // comparison using a `comp` operator instead of `operator<`.
 template <typename Sequence1, typename Sequence2, typename LessThan>
-bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2,
-                               LessThan&& comp) {
+bool c_lexicographical_compare(const Sequence1& sequence1,
+                               const Sequence2& sequence2, LessThan&& comp) {
   return std::lexicographical_compare(
       container_algorithm_internal::c_begin(sequence1),
       container_algorithm_internal::c_end(sequence1),
@@ -1659,11 +1658,11 @@
 // to compute successive values of `value`, as if incremented with `++value`
 // after each element is written. and write them to the container.
 template <typename Sequence, typename T>
-void c_iota(Sequence& sequence, T&& value) {
+void c_iota(Sequence& sequence, const T& value) {
   std::iota(container_algorithm_internal::c_begin(sequence),
-            container_algorithm_internal::c_end(sequence),
-            std::forward<T>(value));
+            container_algorithm_internal::c_end(sequence), value);
 }
+
 // c_accumulate()
 //
 // Container-based version of the <numeric> `std::accumulate()` function
diff --git a/third_party/abseil-cpp/absl/base/config.h b/third_party/abseil-cpp/absl/base/config.h
index 1058ce7..5cbc985 100644
--- a/third_party/abseil-cpp/absl/base/config.h
+++ b/third_party/abseil-cpp/absl/base/config.h
@@ -928,4 +928,15 @@
 #define ABSL_INTERNAL_HAVE_ARM_NEON 1
 #endif
 
+// ABSL_HAVE_CONSTANT_EVALUATED is used for compile-time detection of
+// constant evaluation support through `absl::is_constant_evaluated`.
+#ifdef ABSL_HAVE_CONSTANT_EVALUATED
+#error ABSL_HAVE_CONSTANT_EVALUATED cannot be directly set
+#endif
+#ifdef __cpp_lib_is_constant_evaluated
+#define ABSL_HAVE_CONSTANT_EVALUATED 1
+#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
+#define ABSL_HAVE_CONSTANT_EVALUATED 1
+#endif
+
 #endif  // ABSL_BASE_CONFIG_H_
diff --git a/third_party/abseil-cpp/absl/base/policy_checks.h b/third_party/abseil-cpp/absl/base/policy_checks.h
index 2626fb6..b8cd4c9 100644
--- a/third_party/abseil-cpp/absl/base/policy_checks.h
+++ b/third_party/abseil-cpp/absl/base/policy_checks.h
@@ -50,11 +50,11 @@
 #error "This package requires Visual Studio 2017 (MSVC++ 15.0) or higher."
 #endif
 
-// We support gcc 5 and later.
+// We support GCC 7 and later.
 // This minimum will go up.
 #if defined(__GNUC__) && !defined(__clang__)
-#if __GNUC__ < 5
-#error "This package requires gcc 5 or higher."
+#if __GNUC__ < 7
+#error "This package requires GCC 7 or higher."
 #endif
 #endif
 
diff --git a/third_party/abseil-cpp/absl/container/CMakeLists.txt b/third_party/abseil-cpp/absl/container/CMakeLists.txt
index 7736df6..416e3e3 100644
--- a/third_party/abseil-cpp/absl/container/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/container/CMakeLists.txt
@@ -707,13 +707,13 @@
     absl::endian
     absl::hash_policy_traits
     absl::hashtable_debug_hooks
+    absl::hashtablez_sampler
     absl::memory
     absl::meta
     absl::optional
     absl::prefetch
     absl::raw_logging_internal
     absl::utility
-    absl::hashtablez_sampler
   PUBLIC
 )
 
@@ -725,18 +725,18 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::base
+    absl::config
     absl::container_memory
+    absl::core_headers
     absl::flat_hash_map
     absl::flat_hash_set
     absl::hash_function_defaults
     absl::hash_policy_testing
     absl::hashtable_debug
-    absl::raw_hash_set
-    absl::base
-    absl::config
     absl::log
-    absl::core_headers
     absl::prefetch
+    absl::raw_hash_set
     absl::raw_logging_internal
     absl::strings
     GTest::gmock_main
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc
index 15deddc..f77f2a7 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc
@@ -16,6 +16,7 @@
 #include <cmath>
 #include <numeric>
 #include <random>
+#include <tuple>
 #include <utility>
 #include <vector>
 
@@ -512,6 +513,12 @@
   return table->find(key) != table->end();
 }
 
+// This is useful because the find isn't inlined but the iterator comparison is.
+bool CodegenAbslRawHashSetStringFindNeEnd(
+    absl::container_internal::StringTable* table, const std::string& key) {
+  return table->find(key) != table->end();
+}
+
 auto CodegenAbslRawHashSetInt64Insert(absl::container_internal::IntTable* table,
                                       int64_t key)
     -> decltype(table->insert(key)) {
@@ -531,6 +538,7 @@
 int odr =
     (::benchmark::DoNotOptimize(std::make_tuple(
          &CodegenAbslRawHashSetInt64Find, &CodegenAbslRawHashSetInt64FindNeEnd,
+         &CodegenAbslRawHashSetStringFindNeEnd,
          &CodegenAbslRawHashSetInt64Insert, &CodegenAbslRawHashSetInt64Contains,
          &CodegenAbslRawHashSetInt64Iterate)),
      1);
diff --git a/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake b/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake
index 04e7b44..430916f 100644
--- a/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake
+++ b/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake
@@ -72,6 +72,7 @@
     "-DNOMINMAX"
     "-Wno-deprecated-declarations"
     "-Wno-missing-declarations"
+    "-Wno-self-move"
     "-Wno-sign-compare"
     "-Wno-unused-function"
     "-Wno-unused-parameter"
diff --git a/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl b/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl
index 84f4bff..011d8a98 100644
--- a/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl
+++ b/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl
@@ -73,6 +73,7 @@
     "-DNOMINMAX",
     "-Wno-deprecated-declarations",
     "-Wno-missing-declarations",
+    "-Wno-self-move",
     "-Wno-sign-compare",
     "-Wno-unused-function",
     "-Wno-unused-parameter",
diff --git a/third_party/abseil-cpp/absl/copts/copts.py b/third_party/abseil-cpp/absl/copts/copts.py
index 06eeb67b..e6e1194 100644
--- a/third_party/abseil-cpp/absl/copts/copts.py
+++ b/third_party/abseil-cpp/absl/copts/copts.py
@@ -33,6 +33,7 @@
 ABSL_GCC_TEST_ADDITIONAL_FLAGS = [
     "-Wno-deprecated-declarations",
     "-Wno-missing-declarations",
+    "-Wno-self-move",
     "-Wno-sign-compare",
     "-Wno-unused-function",
     "-Wno-unused-parameter",
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/third_party/abseil-cpp/absl/debugging/BUILD.bazel
index a40285c..edbb369 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.bazel
@@ -53,6 +53,18 @@
     ],
 )
 
+cc_test(
+    name = "stacktrace_test",
+    srcs = ["stacktrace_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":stacktrace",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
 cc_library(
     name = "symbolize",
     srcs = [
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.gn b/third_party/abseil-cpp/absl/debugging/BUILD.gn
index 7585fa79..1d0ba6e5 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.gn
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.gn
@@ -28,6 +28,14 @@
   ]
 }
 
+absl_test("stacktrace_test") {
+  sources = ["stacktrace_test.cc"]
+  deps = [
+    ":stacktrace",
+    "//third_party/abseil-cpp/absl/base:core_headers",
+  ]
+}
+
 absl_source_set("symbolize") {
   sources = [
     "symbolize.cc",
diff --git a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
index e823f15b..8f29cc0 100644
--- a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
@@ -45,6 +45,19 @@
   PUBLIC
 )
 
+absl_cc_test(
+  NAME
+    stacktrace_test
+  SRCS
+    "stacktrace_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::stacktrace
+    absl::core_headers
+    GTest::gmock_main
+)
+
 absl_cc_library(
   NAME
     symbolize
diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc
index 2f8bf42..7b26464e 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc
+++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -112,6 +112,10 @@
 
 // Assume stack frames larger than 100,000 bytes are bogus.
 static const int kMaxFrameBytes = 100000;
+// Stack end to use when we don't know the actual stack end
+// (effectively just the end of address space).
+constexpr uintptr_t kUnknownStackEnd =
+    std::numeric_limits<size_t>::max() - sizeof(void *);
 
 // Returns the stack frame pointer from signal context, 0 if unknown.
 // vuc is a ucontext_t *.  We use void* to avoid the use
@@ -258,8 +262,26 @@
     // With the stack growing downwards, older stack frame must be
     // at a greater address that the current one.
     if (new_fp_u <= old_fp_u) return nullptr;
-    if (new_fp_u - old_fp_u > kMaxFrameBytes) return nullptr;
 
+    // If we get a very large frame size, it may be an indication that we
+    // guessed frame pointers incorrectly and now risk a paging fault
+    // dereferencing a wrong frame pointer. Or maybe not because large frames
+    // are possible as well. The main stack is assumed to be readable,
+    // so we assume the large frame is legit if we know the real stack bounds
+    // and are within the stack.
+    if (new_fp_u - old_fp_u > kMaxFrameBytes) {
+      if (stack_high < kUnknownStackEnd &&
+          static_cast<size_t>(getpagesize()) < stack_low) {
+        // Stack bounds are known.
+        if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) {
+          // new_fp_u is not within the known stack.
+          return nullptr;
+        }
+      } else {
+        // Stack bounds are unknown, prefer truncated stack to possible crash.
+        return nullptr;
+      }
+    }
     if (stack_low < old_fp_u && old_fp_u <= stack_high) {
       // Old BP was in the expected stack region...
       if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) {
@@ -312,7 +334,7 @@
 
   // Assume that the first page is not stack.
   size_t stack_low = static_cast<size_t>(getpagesize());
-  size_t stack_high = std::numeric_limits<size_t>::max() - sizeof(void *);
+  size_t stack_high = kUnknownStackEnd;
 
   while (fp && n < max_depth) {
     if (*(fp + 1) == reinterpret_cast<void *>(0)) {
diff --git a/third_party/abseil-cpp/absl/debugging/stacktrace_test.cc b/third_party/abseil-cpp/absl/debugging/stacktrace_test.cc
new file mode 100644
index 0000000..78ce7ad0
--- /dev/null
+++ b/third_party/abseil-cpp/absl/debugging/stacktrace_test.cc
@@ -0,0 +1,47 @@
+// Copyright 2023 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/debugging/stacktrace.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+
+namespace {
+
+// This test is currently only known to pass on linux/x86_64.
+#if defined(__linux__) && defined(__x86_64__)
+ABSL_ATTRIBUTE_NOINLINE void Unwind(void* p) {
+  ABSL_ATTRIBUTE_UNUSED static void* volatile sink = p;
+  constexpr int kSize = 16;
+  void* stack[kSize];
+  int frames[kSize];
+  absl::GetStackTrace(stack, kSize, 0);
+  absl::GetStackFrames(stack, frames, kSize, 0);
+}
+
+ABSL_ATTRIBUTE_NOINLINE void HugeFrame() {
+  char buffer[1 << 20];
+  Unwind(buffer);
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+
+TEST(StackTrace, HugeFrame) {
+  // Ensure that the unwinder is not confused by very large stack frames.
+  HugeFrame();
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+#endif
+
+}  // namespace
diff --git a/third_party/abseil-cpp/absl/log/internal/log_message.cc b/third_party/abseil-cpp/absl/log/internal/log_message.cc
index a808061..bdb10f2 100644
--- a/third_party/abseil-cpp/absl/log/internal/log_message.cc
+++ b/third_party/abseil-cpp/absl/log/internal/log_message.cc
@@ -163,7 +163,8 @@
                                            absl::Time timestamp)
     : extra_sinks_only(false),
       manipulated(nullptr),
-      encoded_remaining(encoded_buf) {
+      // This `absl::MakeSpan` silences spurious -Wuninitialized from GCC:
+      encoded_remaining(absl::MakeSpan(encoded_buf)) {
   // Legacy defaults for LOG's ostream:
   manipulated.setf(std::ios_base::showbase | std::ios_base::boolalpha);
   entry.full_filename_ = file;
diff --git a/third_party/abseil-cpp/absl/log/internal/nullguard.cc b/third_party/abseil-cpp/absl/log/internal/nullguard.cc
index 7b785c55..4f2f9d4 100644
--- a/third_party/abseil-cpp/absl/log/internal/nullguard.cc
+++ b/third_party/abseil-cpp/absl/log/internal/nullguard.cc
@@ -23,11 +23,11 @@
 ABSL_NAMESPACE_BEGIN
 namespace log_internal {
 
-ABSL_CONST_INIT const std::array<char, 7> kCharNull{
+ABSL_DLL ABSL_CONST_INIT const std::array<char, 7> kCharNull{
     {'(', 'n', 'u', 'l', 'l', ')', '\0'}};
-ABSL_CONST_INIT const std::array<signed char, 7> kSignedCharNull{
+ABSL_DLL ABSL_CONST_INIT const std::array<signed char, 7> kSignedCharNull{
     {'(', 'n', 'u', 'l', 'l', ')', '\0'}};
-ABSL_CONST_INIT const std::array<unsigned char, 7> kUnsignedCharNull{
+ABSL_DLL ABSL_CONST_INIT const std::array<unsigned char, 7> kUnsignedCharNull{
     {'(', 'n', 'u', 'l', 'l', ')', '\0'}};
 
 }  // namespace log_internal
diff --git a/third_party/abseil-cpp/absl/log/internal/nullguard.h b/third_party/abseil-cpp/absl/log/internal/nullguard.h
index a0ed4ad..926f61b 100644
--- a/third_party/abseil-cpp/absl/log/internal/nullguard.h
+++ b/third_party/abseil-cpp/absl/log/internal/nullguard.h
@@ -34,9 +34,11 @@
 ABSL_NAMESPACE_BEGIN
 namespace log_internal {
 
-ABSL_CONST_INIT extern const std::array<char, 7> kCharNull;
-ABSL_CONST_INIT extern const std::array<signed char, 7> kSignedCharNull;
-ABSL_CONST_INIT extern const std::array<unsigned char, 7> kUnsignedCharNull;
+ABSL_DLL ABSL_CONST_INIT extern const std::array<char, 7> kCharNull;
+ABSL_DLL ABSL_CONST_INIT extern const std::array<signed char, 7>
+    kSignedCharNull;
+ABSL_DLL ABSL_CONST_INIT extern const std::array<unsigned char, 7>
+    kUnsignedCharNull;
 
 template <typename T>
 struct NullGuard final {
diff --git a/third_party/abseil-cpp/absl/memory/memory.h b/third_party/abseil-cpp/absl/memory/memory.h
index e5ff0e6..3508135 100644
--- a/third_party/abseil-cpp/absl/memory/memory.h
+++ b/third_party/abseil-cpp/absl/memory/memory.h
@@ -158,6 +158,26 @@
   return std::weak_ptr<T>(ptr);
 }
 
+// -----------------------------------------------------------------------------
+// Class Template: pointer_traits
+// -----------------------------------------------------------------------------
+//
+// Historical note: Abseil once provided an implementation of
+// `std::pointer_traits` for platforms that had not yet provided it. Those
+// platforms are no longer supported. New code should simply use
+// `std::pointer_traits`.
+using std::pointer_traits;
+
+// -----------------------------------------------------------------------------
+// Class Template: allocator_traits
+// -----------------------------------------------------------------------------
+//
+// Historical note: Abseil once provided an implementation of
+// `std::allocator_traits` for platforms that had not yet provided it. Those
+// platforms are no longer supported. New code should simply use
+// `std::allocator_traits`.
+using std::allocator_traits;
+
 namespace memory_internal {
 
 // ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D.
@@ -175,357 +195,6 @@
 template <template <typename> class Extract, typename Obj, typename Default>
 using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type;
 
-// Extractors for the features of allocators.
-template <typename T>
-using GetPointer = typename T::pointer;
-
-template <typename T>
-using GetConstPointer = typename T::const_pointer;
-
-template <typename T>
-using GetVoidPointer = typename T::void_pointer;
-
-template <typename T>
-using GetConstVoidPointer = typename T::const_void_pointer;
-
-template <typename T>
-using GetDifferenceType = typename T::difference_type;
-
-template <typename T>
-using GetSizeType = typename T::size_type;
-
-template <typename T>
-using GetPropagateOnContainerCopyAssignment =
-    typename T::propagate_on_container_copy_assignment;
-
-template <typename T>
-using GetPropagateOnContainerMoveAssignment =
-    typename T::propagate_on_container_move_assignment;
-
-template <typename T>
-using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap;
-
-template <typename T>
-using GetIsAlwaysEqual = typename T::is_always_equal;
-
-template <typename T>
-struct GetFirstArg;
-
-template <template <typename...> class Class, typename T, typename... Args>
-struct GetFirstArg<Class<T, Args...>> {
-  using type = T;
-};
-
-template <typename Ptr, typename = void>
-struct ElementType {
-  using type = typename GetFirstArg<Ptr>::type;
-};
-
-template <typename T>
-struct ElementType<T, void_t<typename T::element_type>> {
-  using type = typename T::element_type;
-};
-
-template <typename T, typename U>
-struct RebindFirstArg;
-
-template <template <typename...> class Class, typename T, typename... Args,
-          typename U>
-struct RebindFirstArg<Class<T, Args...>, U> {
-  using type = Class<U, Args...>;
-};
-
-template <typename T, typename U, typename = void>
-struct RebindPtr {
-  using type = typename RebindFirstArg<T, U>::type;
-};
-
-template <typename T, typename U>
-struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> {
-  using type = typename T::template rebind<U>;
-};
-
-template <typename T, typename U>
-constexpr bool HasRebindAlloc(...) {
-  return false;
-}
-
-template <typename T, typename U>
-constexpr bool HasRebindAlloc(typename T::template rebind<U>::other*) {
-  return true;
-}
-
-template <typename T, typename U, bool = HasRebindAlloc<T, U>(nullptr)>
-struct RebindAlloc {
-  using type = typename RebindFirstArg<T, U>::type;
-};
-
-template <typename T, typename U>
-struct RebindAlloc<T, U, true> {
-  using type = typename T::template rebind<U>::other;
-};
-
-}  // namespace memory_internal
-
-// -----------------------------------------------------------------------------
-// Class Template: pointer_traits
-// -----------------------------------------------------------------------------
-//
-// An implementation of C++11's std::pointer_traits.
-//
-// Provided for portability on toolchains that have a working C++11 compiler,
-// but the standard library is lacking in C++11 support. For example, some
-// version of the Android NDK.
-//
-
-template <typename Ptr>
-struct pointer_traits {
-  using pointer = Ptr;
-
-  // element_type:
-  // Ptr::element_type if present. Otherwise T if Ptr is a template
-  // instantiation Template<T, Args...>
-  using element_type = typename memory_internal::ElementType<Ptr>::type;
-
-  // difference_type:
-  // Ptr::difference_type if present, otherwise std::ptrdiff_t
-  using difference_type =
-      memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr,
-                                  std::ptrdiff_t>;
-
-  // rebind:
-  // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a
-  // template instantiation Template<T, Args...>
-  template <typename U>
-  using rebind = typename memory_internal::RebindPtr<Ptr, U>::type;
-
-  // pointer_to:
-  // Calls Ptr::pointer_to(r)
-  static pointer pointer_to(element_type& r) {  // NOLINT(runtime/references)
-    return Ptr::pointer_to(r);
-  }
-};
-
-// Specialization for T*.
-template <typename T>
-struct pointer_traits<T*> {
-  using pointer = T*;
-  using element_type = T;
-  using difference_type = std::ptrdiff_t;
-
-  template <typename U>
-  using rebind = U*;
-
-  // pointer_to:
-  // Calls std::addressof(r)
-  static pointer pointer_to(
-      element_type& r) noexcept {  // NOLINT(runtime/references)
-    return std::addressof(r);
-  }
-};
-
-// -----------------------------------------------------------------------------
-// Class Template: allocator_traits
-// -----------------------------------------------------------------------------
-//
-// A C++11 compatible implementation of C++17's std::allocator_traits.
-//
-#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
-using std::allocator_traits;
-#else  // __cplusplus >= 201703L
-template <typename Alloc>
-struct allocator_traits {
-  using allocator_type = Alloc;
-
-  // value_type:
-  // Alloc::value_type
-  using value_type = typename Alloc::value_type;
-
-  // pointer:
-  // Alloc::pointer if present, otherwise value_type*
-  using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer,
-                                              Alloc, value_type*>;
-
-  // const_pointer:
-  // Alloc::const_pointer if present, otherwise
-  // absl::pointer_traits<pointer>::rebind<const value_type>
-  using const_pointer =
-      memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc,
-                                  typename absl::pointer_traits<pointer>::
-                                      template rebind<const value_type>>;
-
-  // void_pointer:
-  // Alloc::void_pointer if present, otherwise
-  // absl::pointer_traits<pointer>::rebind<void>
-  using void_pointer = memory_internal::ExtractOrT<
-      memory_internal::GetVoidPointer, Alloc,
-      typename absl::pointer_traits<pointer>::template rebind<void>>;
-
-  // const_void_pointer:
-  // Alloc::const_void_pointer if present, otherwise
-  // absl::pointer_traits<pointer>::rebind<const void>
-  using const_void_pointer = memory_internal::ExtractOrT<
-      memory_internal::GetConstVoidPointer, Alloc,
-      typename absl::pointer_traits<pointer>::template rebind<const void>>;
-
-  // difference_type:
-  // Alloc::difference_type if present, otherwise
-  // absl::pointer_traits<pointer>::difference_type
-  using difference_type = memory_internal::ExtractOrT<
-      memory_internal::GetDifferenceType, Alloc,
-      typename absl::pointer_traits<pointer>::difference_type>;
-
-  // size_type:
-  // Alloc::size_type if present, otherwise
-  // std::make_unsigned<difference_type>::type
-  using size_type = memory_internal::ExtractOrT<
-      memory_internal::GetSizeType, Alloc,
-      typename std::make_unsigned<difference_type>::type>;
-
-  // propagate_on_container_copy_assignment:
-  // Alloc::propagate_on_container_copy_assignment if present, otherwise
-  // std::false_type
-  using propagate_on_container_copy_assignment = memory_internal::ExtractOrT<
-      memory_internal::GetPropagateOnContainerCopyAssignment, Alloc,
-      std::false_type>;
-
-  // propagate_on_container_move_assignment:
-  // Alloc::propagate_on_container_move_assignment if present, otherwise
-  // std::false_type
-  using propagate_on_container_move_assignment = memory_internal::ExtractOrT<
-      memory_internal::GetPropagateOnContainerMoveAssignment, Alloc,
-      std::false_type>;
-
-  // propagate_on_container_swap:
-  // Alloc::propagate_on_container_swap if present, otherwise std::false_type
-  using propagate_on_container_swap =
-      memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap,
-                                  Alloc, std::false_type>;
-
-  // is_always_equal:
-  // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
-  using is_always_equal =
-      memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc,
-                                  typename std::is_empty<Alloc>::type>;
-
-  // rebind_alloc:
-  // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc
-  // is Alloc<U, Args>
-  template <typename T>
-  using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type;
-
-  // rebind_traits:
-  // absl::allocator_traits<rebind_alloc<T>>
-  template <typename T>
-  using rebind_traits = absl::allocator_traits<rebind_alloc<T>>;
-
-  // allocate(Alloc& a, size_type n):
-  // Calls a.allocate(n)
-  static pointer allocate(Alloc& a,  // NOLINT(runtime/references)
-                          size_type n) {
-    return a.allocate(n);
-  }
-
-  // allocate(Alloc& a, size_type n, const_void_pointer hint):
-  // Calls a.allocate(n, hint) if possible.
-  // If not possible, calls a.allocate(n)
-  static pointer allocate(Alloc& a, size_type n,  // NOLINT(runtime/references)
-                          const_void_pointer hint) {
-    return allocate_impl(0, a, n, hint);
-  }
-
-  // deallocate(Alloc& a, pointer p, size_type n):
-  // Calls a.deallocate(p, n)
-  static void deallocate(Alloc& a, pointer p,  // NOLINT(runtime/references)
-                         size_type n) {
-    a.deallocate(p, n);
-  }
-
-  // construct(Alloc& a, T* p, Args&&... args):
-  // Calls a.construct(p, std::forward<Args>(args)...) if possible.
-  // If not possible, calls
-  //   ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
-  template <typename T, typename... Args>
-  static void construct(Alloc& a, T* p,  // NOLINT(runtime/references)
-                        Args&&... args) {
-    construct_impl(0, a, p, std::forward<Args>(args)...);
-  }
-
-  // destroy(Alloc& a, T* p):
-  // Calls a.destroy(p) if possible. If not possible, calls p->~T().
-  template <typename T>
-  static void destroy(Alloc& a, T* p) {  // NOLINT(runtime/references)
-    destroy_impl(0, a, p);
-  }
-
-  // max_size(const Alloc& a):
-  // Returns a.max_size() if possible. If not possible, returns
-  //   std::numeric_limits<size_type>::max() / sizeof(value_type)
-  static size_type max_size(const Alloc& a) { return max_size_impl(0, a); }
-
-  // select_on_container_copy_construction(const Alloc& a):
-  // Returns a.select_on_container_copy_construction() if possible.
-  // If not possible, returns a.
-  static Alloc select_on_container_copy_construction(const Alloc& a) {
-    return select_on_container_copy_construction_impl(0, a);
-  }
-
- private:
-  template <typename A>
-  static auto allocate_impl(int, A& a,  // NOLINT(runtime/references)
-                            size_type n, const_void_pointer hint)
-      -> decltype(a.allocate(n, hint)) {
-    return a.allocate(n, hint);
-  }
-  static pointer allocate_impl(char, Alloc& a,  // NOLINT(runtime/references)
-                               size_type n, const_void_pointer) {
-    return a.allocate(n);
-  }
-
-  template <typename A, typename... Args>
-  static auto construct_impl(int, A& a,  // NOLINT(runtime/references)
-                             Args&&... args)
-      -> decltype(a.construct(std::forward<Args>(args)...)) {
-    a.construct(std::forward<Args>(args)...);
-  }
-
-  template <typename T, typename... Args>
-  static void construct_impl(char, Alloc&, T* p, Args&&... args) {
-    ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
-  }
-
-  template <typename A, typename T>
-  static auto destroy_impl(int, A& a,  // NOLINT(runtime/references)
-                           T* p) -> decltype(a.destroy(p)) {
-    a.destroy(p);
-  }
-  template <typename T>
-  static void destroy_impl(char, Alloc&, T* p) {
-    p->~T();
-  }
-
-  template <typename A>
-  static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) {
-    return a.max_size();
-  }
-  static size_type max_size_impl(char, const Alloc&) {
-    return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
-  }
-
-  template <typename A>
-  static auto select_on_container_copy_construction_impl(int, const A& a)
-      -> decltype(a.select_on_container_copy_construction()) {
-    return a.select_on_container_copy_construction();
-  }
-  static Alloc select_on_container_copy_construction_impl(char,
-                                                          const Alloc& a) {
-    return a;
-  }
-};
-#endif  // __cplusplus >= 201703L
-
-namespace memory_internal {
-
 // This template alias transforms Alloc::is_nothrow into a metafunction with
 // Alloc as a parameter so it can be used with ExtractOrT<>.
 template <typename Alloc>
diff --git a/third_party/abseil-cpp/absl/memory/memory_test.cc b/third_party/abseil-cpp/absl/memory/memory_test.cc
index 6f01cdff..fafd3a41 100644
--- a/third_party/abseil-cpp/absl/memory/memory_test.cc
+++ b/third_party/abseil-cpp/absl/memory/memory_test.cc
@@ -190,338 +190,6 @@
 }
 */
 
-template <typename T>
-struct SmartPointer {
-  using difference_type = char;
-};
-
-struct PointerWith {
-  using element_type = int32_t;
-  using difference_type = int16_t;
-  template <typename U>
-  using rebind = SmartPointer<U>;
-
-  static PointerWith pointer_to(
-      element_type& r) {  // NOLINT(runtime/references)
-    return PointerWith{&r};
-  }
-
-  element_type* ptr;
-};
-
-template <typename... Args>
-struct PointerWithout {};
-
-TEST(PointerTraits, Types) {
-  using TraitsWith = absl::pointer_traits<PointerWith>;
-  EXPECT_TRUE((std::is_same<TraitsWith::pointer, PointerWith>::value));
-  EXPECT_TRUE((std::is_same<TraitsWith::element_type, int32_t>::value));
-  EXPECT_TRUE((std::is_same<TraitsWith::difference_type, int16_t>::value));
-  EXPECT_TRUE((
-      std::is_same<TraitsWith::rebind<int64_t>, SmartPointer<int64_t>>::value));
-
-  using TraitsWithout = absl::pointer_traits<PointerWithout<double, int>>;
-  EXPECT_TRUE((std::is_same<TraitsWithout::pointer,
-                            PointerWithout<double, int>>::value));
-  EXPECT_TRUE((std::is_same<TraitsWithout::element_type, double>::value));
-  EXPECT_TRUE(
-      (std::is_same<TraitsWithout ::difference_type, std::ptrdiff_t>::value));
-  EXPECT_TRUE((std::is_same<TraitsWithout::rebind<int64_t>,
-                            PointerWithout<int64_t, int>>::value));
-
-  using TraitsRawPtr = absl::pointer_traits<char*>;
-  EXPECT_TRUE((std::is_same<TraitsRawPtr::pointer, char*>::value));
-  EXPECT_TRUE((std::is_same<TraitsRawPtr::element_type, char>::value));
-  EXPECT_TRUE(
-      (std::is_same<TraitsRawPtr::difference_type, std::ptrdiff_t>::value));
-  EXPECT_TRUE((std::is_same<TraitsRawPtr::rebind<int64_t>, int64_t*>::value));
-}
-
-TEST(PointerTraits, Functions) {
-  int i;
-  EXPECT_EQ(&i, absl::pointer_traits<PointerWith>::pointer_to(i).ptr);
-  EXPECT_EQ(&i, absl::pointer_traits<int*>::pointer_to(i));
-}
-
-TEST(AllocatorTraits, Typedefs) {
-  struct A {
-    struct value_type {};
-  };
-  EXPECT_TRUE((
-      std::is_same<A,
-                   typename absl::allocator_traits<A>::allocator_type>::value));
-  EXPECT_TRUE(
-      (std::is_same<A::value_type,
-                    typename absl::allocator_traits<A>::value_type>::value));
-
-  struct X {};
-  struct HasPointer {
-    using value_type = X;
-    using pointer = SmartPointer<X>;
-  };
-  EXPECT_TRUE((std::is_same<SmartPointer<X>, typename absl::allocator_traits<
-                                                 HasPointer>::pointer>::value));
-  EXPECT_TRUE(
-      (std::is_same<A::value_type*,
-                    typename absl::allocator_traits<A>::pointer>::value));
-
-  EXPECT_TRUE(
-      (std::is_same<
-          SmartPointer<const X>,
-          typename absl::allocator_traits<HasPointer>::const_pointer>::value));
-  EXPECT_TRUE(
-      (std::is_same<const A::value_type*,
-                    typename absl::allocator_traits<A>::const_pointer>::value));
-
-  struct HasVoidPointer {
-    using value_type = X;
-    struct void_pointer {};
-  };
-
-  EXPECT_TRUE((std::is_same<HasVoidPointer::void_pointer,
-                            typename absl::allocator_traits<
-                                HasVoidPointer>::void_pointer>::value));
-  EXPECT_TRUE(
-      (std::is_same<SmartPointer<void>, typename absl::allocator_traits<
-                                            HasPointer>::void_pointer>::value));
-
-  struct HasConstVoidPointer {
-    using value_type = X;
-    struct const_void_pointer {};
-  };
-
-  EXPECT_TRUE(
-      (std::is_same<HasConstVoidPointer::const_void_pointer,
-                    typename absl::allocator_traits<
-                        HasConstVoidPointer>::const_void_pointer>::value));
-  EXPECT_TRUE((std::is_same<SmartPointer<const void>,
-                            typename absl::allocator_traits<
-                                HasPointer>::const_void_pointer>::value));
-
-  struct HasDifferenceType {
-    using value_type = X;
-    using difference_type = int;
-  };
-  EXPECT_TRUE(
-      (std::is_same<int, typename absl::allocator_traits<
-                             HasDifferenceType>::difference_type>::value));
-  EXPECT_TRUE((std::is_same<char, typename absl::allocator_traits<
-                                      HasPointer>::difference_type>::value));
-
-  struct HasSizeType {
-    using value_type = X;
-    using size_type = unsigned int;
-  };
-  EXPECT_TRUE((std::is_same<unsigned int, typename absl::allocator_traits<
-                                              HasSizeType>::size_type>::value));
-  EXPECT_TRUE((std::is_same<unsigned char, typename absl::allocator_traits<
-                                               HasPointer>::size_type>::value));
-
-  struct HasPropagateOnCopy {
-    using value_type = X;
-    struct propagate_on_container_copy_assignment {};
-  };
-
-  EXPECT_TRUE(
-      (std::is_same<HasPropagateOnCopy::propagate_on_container_copy_assignment,
-                    typename absl::allocator_traits<HasPropagateOnCopy>::
-                        propagate_on_container_copy_assignment>::value));
-  EXPECT_TRUE(
-      (std::is_same<std::false_type,
-                    typename absl::allocator_traits<
-                        A>::propagate_on_container_copy_assignment>::value));
-
-  struct HasPropagateOnMove {
-    using value_type = X;
-    struct propagate_on_container_move_assignment {};
-  };
-
-  EXPECT_TRUE(
-      (std::is_same<HasPropagateOnMove::propagate_on_container_move_assignment,
-                    typename absl::allocator_traits<HasPropagateOnMove>::
-                        propagate_on_container_move_assignment>::value));
-  EXPECT_TRUE(
-      (std::is_same<std::false_type,
-                    typename absl::allocator_traits<
-                        A>::propagate_on_container_move_assignment>::value));
-
-  struct HasPropagateOnSwap {
-    using value_type = X;
-    struct propagate_on_container_swap {};
-  };
-
-  EXPECT_TRUE(
-      (std::is_same<HasPropagateOnSwap::propagate_on_container_swap,
-                    typename absl::allocator_traits<HasPropagateOnSwap>::
-                        propagate_on_container_swap>::value));
-  EXPECT_TRUE(
-      (std::is_same<std::false_type, typename absl::allocator_traits<A>::
-                                         propagate_on_container_swap>::value));
-
-  struct HasIsAlwaysEqual {
-    using value_type = X;
-    struct is_always_equal {};
-  };
-
-  EXPECT_TRUE((std::is_same<HasIsAlwaysEqual::is_always_equal,
-                            typename absl::allocator_traits<
-                                HasIsAlwaysEqual>::is_always_equal>::value));
-  EXPECT_TRUE((std::is_same<std::true_type, typename absl::allocator_traits<
-                                                A>::is_always_equal>::value));
-  struct NonEmpty {
-    using value_type = X;
-    int i;
-  };
-  EXPECT_TRUE(
-      (std::is_same<std::false_type,
-                    absl::allocator_traits<NonEmpty>::is_always_equal>::value));
-}
-
-template <typename T>
-struct AllocWithPrivateInheritance : private std::allocator<T> {
-  using value_type = T;
-};
-
-TEST(AllocatorTraits, RebindWithPrivateInheritance) {
-  // Regression test for some versions of gcc that do not like the sfinae we
-  // used in combination with private inheritance.
-  EXPECT_TRUE(
-      (std::is_same<AllocWithPrivateInheritance<int>,
-                    absl::allocator_traits<AllocWithPrivateInheritance<char>>::
-                        rebind_alloc<int>>::value));
-}
-
-template <typename T>
-struct Rebound {};
-
-struct AllocWithRebind {
-  using value_type = int;
-  template <typename T>
-  struct rebind {
-    using other = Rebound<T>;
-  };
-};
-
-template <typename T, typename U>
-struct AllocWithoutRebind {
-  using value_type = int;
-};
-
-TEST(AllocatorTraits, Rebind) {
-  EXPECT_TRUE(
-      (std::is_same<Rebound<int>,
-                    typename absl::allocator_traits<
-                        AllocWithRebind>::template rebind_alloc<int>>::value));
-  EXPECT_TRUE(
-      (std::is_same<absl::allocator_traits<Rebound<int>>,
-                    typename absl::allocator_traits<
-                        AllocWithRebind>::template rebind_traits<int>>::value));
-
-  EXPECT_TRUE(
-      (std::is_same<AllocWithoutRebind<double, char>,
-                    typename absl::allocator_traits<AllocWithoutRebind<
-                        int, char>>::template rebind_alloc<double>>::value));
-  EXPECT_TRUE(
-      (std::is_same<absl::allocator_traits<AllocWithoutRebind<double, char>>,
-                    typename absl::allocator_traits<AllocWithoutRebind<
-                        int, char>>::template rebind_traits<double>>::value));
-}
-
-struct TestValue {
-  TestValue() {}
-  explicit TestValue(int* trace) : trace(trace) { ++*trace; }
-  ~TestValue() {
-    if (trace) --*trace;
-  }
-  int* trace = nullptr;
-};
-
-struct MinimalMockAllocator {
-  MinimalMockAllocator() : value(0) {}
-  explicit MinimalMockAllocator(int value) : value(value) {}
-  MinimalMockAllocator(const MinimalMockAllocator& other)
-      : value(other.value) {}
-  using value_type = TestValue;
-  MOCK_METHOD(value_type*, allocate, (size_t));
-  MOCK_METHOD(void, deallocate, (value_type*, size_t));
-
-  int value;
-};
-
-TEST(AllocatorTraits, FunctionsMinimal) {
-  int trace = 0;
-  int hint;
-  alignas(TestValue) char buffer[sizeof(TestValue)];
-  auto* x = reinterpret_cast<TestValue*>(buffer);
-  MinimalMockAllocator mock;
-  using Traits = absl::allocator_traits<MinimalMockAllocator>;
-  EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(x));
-  EXPECT_CALL(mock, deallocate(x, 7));
-
-  EXPECT_EQ(x, Traits::allocate(mock, 7));
-  static_cast<void>(Traits::allocate(mock, 7, static_cast<const void*>(&hint)));
-  EXPECT_EQ(x, Traits::allocate(mock, 7, static_cast<const void*>(&hint)));
-  Traits::deallocate(mock, x, 7);
-
-  EXPECT_EQ(0, trace);
-  Traits::construct(mock, x, &trace);
-  EXPECT_EQ(1, trace);
-  Traits::destroy(mock, x);
-  EXPECT_EQ(0, trace);
-
-  EXPECT_EQ(std::numeric_limits<size_t>::max() / sizeof(TestValue),
-            Traits::max_size(mock));
-
-  EXPECT_EQ(0, mock.value);
-  EXPECT_EQ(0, Traits::select_on_container_copy_construction(mock).value);
-}
-
-struct FullMockAllocator {
-  FullMockAllocator() : value(0) {}
-  explicit FullMockAllocator(int value) : value(value) {}
-  FullMockAllocator(const FullMockAllocator& other) : value(other.value) {}
-  using value_type = TestValue;
-  MOCK_METHOD(value_type*, allocate, (size_t));
-  MOCK_METHOD(value_type*, allocate, (size_t, const void*));
-  MOCK_METHOD(void, construct, (value_type*, int*));
-  MOCK_METHOD(void, destroy, (value_type*));
-  MOCK_METHOD(size_t, max_size, (),
-              (const));
-  MOCK_METHOD(FullMockAllocator, select_on_container_copy_construction, (),
-              (const));
-
-  int value;
-};
-
-TEST(AllocatorTraits, FunctionsFull) {
-  int trace = 0;
-  int hint;
-  TestValue x(&trace), y;
-  FullMockAllocator mock;
-  using Traits = absl::allocator_traits<FullMockAllocator>;
-  EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x));
-  EXPECT_CALL(mock, allocate(13, &hint)).WillRepeatedly(Return(&y));
-  EXPECT_CALL(mock, construct(&x, &trace));
-  EXPECT_CALL(mock, destroy(&x));
-  EXPECT_CALL(mock, max_size()).WillRepeatedly(Return(17u));
-  EXPECT_CALL(mock, select_on_container_copy_construction())
-      .WillRepeatedly(Return(FullMockAllocator(23)));
-
-  EXPECT_EQ(&x, Traits::allocate(mock, 7));
-  EXPECT_EQ(&y, Traits::allocate(mock, 13, static_cast<const void*>(&hint)));
-
-  EXPECT_EQ(1, trace);
-  Traits::construct(mock, &x, &trace);
-  EXPECT_EQ(1, trace);
-  Traits::destroy(mock, &x);
-  EXPECT_EQ(1, trace);
-
-  EXPECT_EQ(17u, Traits::max_size(mock));
-
-  EXPECT_EQ(0, mock.value);
-  EXPECT_EQ(23, Traits::select_on_container_copy_construction(mock).value);
-}
-
 TEST(AllocatorNoThrowTest, DefaultAllocator) {
 #if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
   EXPECT_TRUE(absl::default_allocator_is_nothrow::value);
diff --git a/third_party/abseil-cpp/absl/meta/BUILD.bazel b/third_party/abseil-cpp/absl/meta/BUILD.bazel
index 4478ccf..125446f 100644
--- a/third_party/abseil-cpp/absl/meta/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/meta/BUILD.bazel
@@ -42,7 +42,9 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":type_traits",
+        "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/time",
         "@com_google_googletest//:gtest_main",
     ],
 )
diff --git a/third_party/abseil-cpp/absl/meta/BUILD.gn b/third_party/abseil-cpp/absl/meta/BUILD.gn
index 2d67121..5f0034a 100644
--- a/third_party/abseil-cpp/absl/meta/BUILD.gn
+++ b/third_party/abseil-cpp/absl/meta/BUILD.gn
@@ -13,6 +13,8 @@
   sources = [ "type_traits_test.cc" ]
   deps = [
     ":type_traits",
+    "//third_party/abseil-cpp/absl/base:config",
     "//third_party/abseil-cpp/absl/base:core_headers",
+    "//third_party/abseil-cpp/absl/time",
   ]
 }
diff --git a/third_party/abseil-cpp/absl/meta/CMakeLists.txt b/third_party/abseil-cpp/absl/meta/CMakeLists.txt
index f16f17b..bb767d1 100644
--- a/third_party/abseil-cpp/absl/meta/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/meta/CMakeLists.txt
@@ -34,6 +34,8 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::config
+    absl::time
     absl::core_headers
     absl::type_traits
     GTest::gmock_main
diff --git a/third_party/abseil-cpp/absl/meta/type_traits.h b/third_party/abseil-cpp/absl/meta/type_traits.h
index dd9de42..b1656c3 100644
--- a/third_party/abseil-cpp/absl/meta/type_traits.h
+++ b/third_party/abseil-cpp/absl/meta/type_traits.h
@@ -844,6 +844,45 @@
 struct is_trivially_relocatable : std::integral_constant<bool, false> {};
 #endif
 
+// absl::is_constant_evaluated()
+//
+// Detects whether the function call occurs within a constant-evaluated context.
+// Returns true if the evaluation of the call occurs within the evaluation of an
+// expression or conversion that is manifestly constant-evaluated; otherwise
+// returns false.
+//
+// This function is implemented in terms of `std::is_constant_evaluated` for
+// c++20 and up. For older c++ versions, the function is implemented in terms
+// of `__builtin_is_constant_evaluated` if available, otherwise the function
+// will fail to compile.
+//
+// Applications can inspect `ABSL_HAVE_CONSTANT_EVALUATED` at compile time
+// to check if this function is supported.
+//
+// Example:
+//
+// constexpr MyClass::MyClass(int param) {
+// #ifdef ABSL_HAVE_CONSTANT_EVALUATED
+//   if (!absl::is_constant_evaluated()) {
+//     ABSL_LOG(INFO) << "MyClass(" << param << ")";
+//   }
+// #endif  // ABSL_HAVE_CONSTANT_EVALUATED
+// }
+//
+// Upstream documentation:
+//
+// http://en.cppreference.com/w/cpp/types/is_constant_evaluated
+// http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#:~:text=__builtin_is_constant_evaluated
+//
+#if defined(ABSL_HAVE_CONSTANT_EVALUATED)
+constexpr bool is_constant_evaluated() noexcept {
+#ifdef __cpp_lib_is_constant_evaluated
+  return std::is_constant_evaluated();
+#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
+  return __builtin_is_constant_evaluated();
+#endif
+}
+#endif  // ABSL_HAVE_CONSTANT_EVALUATED
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/third_party/abseil-cpp/absl/meta/type_traits_test.cc b/third_party/abseil-cpp/absl/meta/type_traits_test.cc
index d08d9ad..b2a7a67 100644
--- a/third_party/abseil-cpp/absl/meta/type_traits_test.cc
+++ b/third_party/abseil-cpp/absl/meta/type_traits_test.cc
@@ -22,6 +22,9 @@
 
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
 
 namespace {
 
@@ -1413,4 +1416,33 @@
   EXPECT_TRUE(absl::is_trivially_relocatable<TrivialAbi>::value);
 }
 
+#ifdef ABSL_HAVE_CONSTANT_EVALUATED
+
+constexpr int64_t NegateIfConstantEvaluated(int64_t i) {
+  if (absl::is_constant_evaluated()) {
+    return -i;
+  } else {
+    return i;
+  }
+}
+
+#endif  // ABSL_HAVE_CONSTANT_EVALUATED
+
+TEST(TrivallyRelocatable, is_constant_evaluated) {
+#ifdef ABSL_HAVE_CONSTANT_EVALUATED
+  constexpr int64_t constant = NegateIfConstantEvaluated(42);
+  EXPECT_EQ(constant, -42);
+
+  int64_t now = absl::ToUnixSeconds(absl::Now());
+  int64_t not_constant = NegateIfConstantEvaluated(now);
+  EXPECT_EQ(not_constant, now);
+
+  static int64_t const_init = NegateIfConstantEvaluated(42);
+  EXPECT_EQ(const_init, -42);
+#else
+  GTEST_SKIP() << "absl::is_constant_evaluated is not defined";
+#endif  // ABSL_HAVE_CONSTANT_EVALUATED
+}
+
+
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/strings/escaping.h b/third_party/abseil-cpp/absl/strings/escaping.h
index f47cf73..7c082fe 100644
--- a/third_party/abseil-cpp/absl/strings/escaping.h
+++ b/third_party/abseil-cpp/absl/strings/escaping.h
@@ -138,9 +138,8 @@
 // Converts a `src` string encoded in Base64 (RFC 4648 section 4) to its binary
 // equivalent, writing it to a `dest` buffer, returning `true` on success. If
 // `src` contains invalid characters, `dest` is cleared and returns `false`.
-// Padding is optional, and note that `Base64Escape()` does not produce it. If
-// padding is included, it must be correct. In the padding, '=' and '.' are
-// treated identically.
+// If padding is included (note that `Base64Escape()` does produce it), it must
+// be correct. In the padding, '=' and '.' are treated identically.
 bool Base64Unescape(absl::string_view src, std::string* dest);
 
 // WebSafeBase64Unescape()
@@ -148,8 +147,8 @@
 // Converts a `src` string encoded in "web safe" Base64 (RFC 4648 section 5) to
 // its binary equivalent, writing it to a `dest` buffer. If `src` contains
 // invalid characters, `dest` is cleared and returns `false`. If padding is
-// included, it must be correct. In the padding, '=' and '.' are treated
-// identically.
+// included (note that `WebSafeBase64Escape()` does not produce it), it must be
+// correct. In the padding, '=' and '.' are treated identically.
 bool WebSafeBase64Unescape(absl::string_view src, std::string* dest);
 
 // HexStringToBytes()
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_functions.h b/third_party/abseil-cpp/absl/strings/internal/cordz_functions.h
index 93f46ec..ed108bf 100644
--- a/third_party/abseil-cpp/absl/strings/internal/cordz_functions.h
+++ b/third_party/abseil-cpp/absl/strings/internal/cordz_functions.h
@@ -32,18 +32,10 @@
 // Sets the sample rate with the average interval between samples.
 void set_cordz_mean_interval(int32_t mean_interval);
 
-// Enable cordz unless any of the following applies:
-// - no thread local support
-// - MSVC build
-// - Android build
-// - Apple build
-// - DLL build
-// Hashtablez is turned off completely in opensource builds.
-// MSVC's static atomics are dynamically initialized in debug mode, which breaks
-// sampling.
-#if defined(ABSL_HAVE_THREAD_LOCAL) && !defined(_MSC_VER)  && \
-    !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL) && \
-    !defined(__ANDROID__) && !defined(__APPLE__)
+// Cordz is only enabled on Linux with thread_local support.
+#if defined(ABSL_INTERNAL_CORDZ_ENABLED)
+#error ABSL_INTERNAL_CORDZ_ENABLED cannot be set directly
+#elif defined(__linux__) && defined(ABSL_HAVE_THREAD_LOCAL)
 #define ABSL_INTERNAL_CORDZ_ENABLED 1
 #endif
 
diff --git a/third_party/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance.h b/third_party/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance.h
index 1a96842..7a4bd64 100644
--- a/third_party/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance.h
+++ b/third_party/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance.h
@@ -15,8 +15,7 @@
 #ifndef ABSL_STRINGS_INTERNAL_DAMERAU_LEVENSHTEIN_DISTANCE_H_
 #define ABSL_STRINGS_INTERNAL_DAMERAU_LEVENSHTEIN_DISTANCE_H_
 
-#include <numeric>
-#include <vector>
+#include <cstdint>
 
 #include "absl/strings/string_view.h"
 
diff --git a/third_party/abseil-cpp/absl/strings/str_cat.cc b/third_party/abseil-cpp/absl/strings/str_cat.cc
index e5cb6d8..114a2ff 100644
--- a/third_party/abseil-cpp/absl/strings/str_cat.cc
+++ b/third_party/abseil-cpp/absl/strings/str_cat.cc
@@ -144,12 +144,12 @@
 std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
   std::string result;
   size_t total_size = 0;
-  for (const absl::string_view& piece : pieces) total_size += piece.size();
+  for (absl::string_view piece : pieces) total_size += piece.size();
   strings_internal::STLStringResizeUninitialized(&result, total_size);
 
   char* const begin = &result[0];
   char* out = begin;
-  for (const absl::string_view& piece : pieces) {
+  for (absl::string_view piece : pieces) {
     const size_t this_size = piece.size();
     if (this_size != 0) {
       memcpy(out, piece.data(), this_size);
@@ -173,7 +173,7 @@
                   std::initializer_list<absl::string_view> pieces) {
   size_t old_size = dest->size();
   size_t total_size = old_size;
-  for (const absl::string_view& piece : pieces) {
+  for (absl::string_view piece : pieces) {
     ASSERT_NO_OVERLAP(*dest, piece);
     total_size += piece.size();
   }
@@ -181,7 +181,7 @@
 
   char* const begin = &(*dest)[0];
   char* out = begin + old_size;
-  for (const absl::string_view& piece : pieces) {
+  for (absl::string_view piece : pieces) {
     const size_t this_size = piece.size();
     if (this_size != 0) {
       memcpy(out, piece.data(), this_size);
diff --git a/third_party/abseil-cpp/absl/strings/str_cat.h b/third_party/abseil-cpp/absl/strings/str_cat.h
index 5ee26db0..730b4d8c 100644
--- a/third_party/abseil-cpp/absl/strings/str_cat.h
+++ b/third_party/abseil-cpp/absl/strings/str_cat.h
@@ -242,8 +242,10 @@
 // -----------------------------------------------------------------------------
 //
 // The `AlphaNum` class acts as the main parameter type for `StrCat()` and
-// `StrAppend()`, providing efficient conversion of numeric, boolean, and
-// hexadecimal values (through the `Hex` type) into strings.
+// `StrAppend()`, providing efficient conversion of numeric, boolean, decimal,
+// and hexadecimal values (through the `Dec` and `Hex` types) into strings.
+// `AlphaNum` should only be used as a function parameter. Do not instantiate
+//  `AlphaNum` directly as a stack variable.
 
 class AlphaNum {
  public:
diff --git a/third_party/abseil-cpp/absl/strings/str_split_test.cc b/third_party/abseil-cpp/absl/strings/str_split_test.cc
index 1b4427b..04a64a4 100644
--- a/third_party/abseil-cpp/absl/strings/str_split_test.cc
+++ b/third_party/abseil-cpp/absl/strings/str_split_test.cc
@@ -369,7 +369,7 @@
 TEST(Splitter, RangeIterators) {
   auto splitter = absl::StrSplit("a,b,c", ',');
   std::vector<absl::string_view> output;
-  for (const absl::string_view& p : splitter) {
+  for (absl::string_view p : splitter) {
     output.push_back(p);
   }
   EXPECT_THAT(output, ElementsAre("a", "b", "c"));
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.cc b/third_party/abseil-cpp/absl/synchronization/mutex.cc
index 23919de4..064ccb7 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.cc
@@ -2823,7 +2823,7 @@
   // kTrue logic.
   if (a == nullptr || a->eval_ == nullptr) {
     return b == nullptr || b->eval_ == nullptr;
-  }else  if (b == nullptr || b->eval_ == nullptr) {
+  } else if (b == nullptr || b->eval_ == nullptr) {
     return false;
   }
   // Check equality of the representative fields.
diff --git a/third_party/abseil-cpp/ci/linux_docker_containers.sh b/third_party/abseil-cpp/ci/linux_docker_containers.sh
index f55e153..1dd8b74 100644
--- a/third_party/abseil-cpp/ci/linux_docker_containers.sh
+++ b/third_party/abseil-cpp/ci/linux_docker_containers.sh
@@ -18,4 +18,4 @@
 readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026"
 readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217"
 readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217"
-readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20220621"
+readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20230120"
diff --git a/third_party/blink/common/storage_key/storage_key.cc b/third_party/blink/common/storage_key/storage_key.cc
index 9ea99056..fc3eaf30 100644
--- a/third_party/blink/common/storage_key/storage_key.cc
+++ b/third_party/blink/common/storage_key/storage_key.cc
@@ -41,23 +41,30 @@
 absl::optional<StorageKey> StorageKey::Deserialize(base::StringPiece in) {
   using EncodedAttribute = StorageKey::EncodedAttribute;
   // As per the Serialize() call, we have to expect the
-  // following structure: <StorageKey 'key'.origin> + "/" + [ "^0" + <StorageKey
+  // following structure: <StorageKey `key`.origin> + "/" + [ "^0" + <StorageKey
   // `key`.top_level_site> + "^3" + <StorageKey `key`.ancestor_chain_bit> ]
   // The brackets indicate an optional component.
   // - or -
-  // <StorageKey 'key'.origin> + "/" + "^1" + <StorageKey 'nonce'.High64Bits> +
-  // "^2" + <StorageKey 'nonce'.Low64Bits>
+  // <StorageKey `key`.origin> + "/" + "^1" + <StorageKey
+  // `key`.nonce.High64Bits> + "^2" + <StorageKey `key`.nonce.Low64Bits>
+  // - or -
+  // <StorageKey `key`.origin> + "/" + [ ^4" + <StorageKey
+  // `key`.top_level_site.nonce.High64Bits> + "^5" + <StorageKey
+  // `key`.top_level_site.nonce.Low64Bits>  + "^6" + <StorageKey
+  // `key`.top_level_site.precursor> ]
 
   // Let's check for a delimiting caret. The presence of a caret means this key
   // is partitioned.
 
-  // More than two encoded attributes (delimited by carets) indicates a
+  // More than three encoded attributes (delimited by carets) indicates a
   // malformed input.
-  if (base::ranges::count(in, '^') > 2)
+  if (base::ranges::count(in, '^') > 3) {
     return absl::nullopt;
+  }
 
-  size_t pos_first_caret = in.find_first_of('^');
-  size_t pos_last_caret = in.find_last_of('^');
+  const size_t pos_first_caret = in.find_first_of('^');
+  const size_t pos_second_caret = in.find_first_of('^', pos_first_caret + 1);
+  const size_t pos_third_caret = in.find_first_of('^', pos_second_caret + 1);
 
   url::Origin key_origin;
   net::SchemefulSite key_top_level_site;
@@ -93,36 +100,41 @@
 
   switch (first_attribute.value()) {
     case EncodedAttribute::kTopLevelSite: {
-      // A top-level site is serialized.
+      // A top-level site is serialized and has only two encoded attributes.
+      if (pos_third_caret != std::string::npos) {
+        return absl::nullopt;
+      }
 
       // The origin is the portion up to, but not including, the caret
       // separator.
       key_origin = url::Origin::Create(GURL(in.substr(0, pos_first_caret)));
 
       // The top_level_site is the portion between the two separators.
-      int length_of_site = pos_last_caret - (pos_first_caret + 2);
+      int length_of_site = pos_second_caret - (pos_first_caret + 2);
       key_top_level_site = net::SchemefulSite(
           GURL(in.substr(pos_first_caret + 2, length_of_site)));
 
       // There is no nonce.
 
-      // Make sure we found the last separator, it's valid, that it's the
+      // Make sure we found the second separator, it's valid, that it's the
       // correct attribute.
-      if (pos_last_caret == std::string::npos ||
-          !ValidSeparatorWithData(in, pos_last_caret))
+      if (pos_second_caret == std::string::npos ||
+          !ValidSeparatorWithData(in, pos_second_caret)) {
         return absl::nullopt;
+      }
 
       absl::optional<EncodedAttribute> last_attribute =
-          DeserializeAttributeSeparator(in.substr(pos_last_caret, 2));
+          DeserializeAttributeSeparator(in.substr(pos_second_caret, 2));
       if (!last_attribute.has_value() ||
           last_attribute.value() != EncodedAttribute::kAncestorChainBit)
         return absl::nullopt;
 
-      // The ancestor_chain_bit is the portion beyond the last separator.
+      // The ancestor_chain_bit is the portion beyond the second separator.
       int raw_bit;
-      if (!base::StringToInt(in.substr(pos_last_caret + 2, std::string::npos),
-                             &raw_bit))
+      if (!base::StringToInt(in.substr(pos_second_caret + 2, std::string::npos),
+                             &raw_bit)) {
         return absl::nullopt;
+      }
 
       // If the integer conversion results in a value outside the enumerated
       // indices of [0,1]
@@ -145,10 +157,10 @@
                         ancestor_chain_bit);
     }
     case EncodedAttribute::kNonceHigh: {
-      // A nonce is serialized.
-      // There should be three caret separators, let's grab the second
-      // (the separator between high and low nonce).
-      size_t pos_second_caret = in.find_first_of('^', pos_first_caret + 2);
+      // A nonce is serialized and has only two encoded attributes.
+      if (pos_third_caret != std::string::npos) {
+        return absl::nullopt;
+      }
 
       // Make sure we found the next separator, it's valid, that it's the
       // correct attribute.
@@ -173,12 +185,10 @@
       // The first high 64 bits of the nonce are next, between the two
       // separators.
       int length_of_high = pos_second_caret - (pos_first_caret + 2);
-      int length_of_low = pos_last_caret - (pos_second_caret + 2);
-      std::string high_digits = static_cast<std::string>(
-          in.substr(pos_first_caret + 2, length_of_high));
+      base::StringPiece high_digits =
+          in.substr(pos_first_caret + 2, length_of_high);
       // The low 64 bits are last, after the second separator.
-      std::string low_digits = static_cast<std::string>(
-          in.substr(pos_second_caret + 2, length_of_low));
+      base::StringPiece low_digits = in.substr(pos_second_caret + 2);
 
       uint64_t nonce_high = 0;
       uint64_t nonce_low = 0;
@@ -201,6 +211,84 @@
                         &nonce.value(),
                         blink::mojom::AncestorChainBit::kSameSite);
     }
+    case EncodedAttribute::kTopLevelSiteOpaqueNonceHigh: {
+      // An opaque `top_level_site` is serialized.
+
+      // Make sure we found the next separator, it's valid, that it's the
+      // correct attribute.
+      if (pos_second_caret == std::string::npos ||
+          !ValidSeparatorWithData(in, pos_second_caret)) {
+        return absl::nullopt;
+      }
+
+      absl::optional<EncodedAttribute> second_attribute =
+          DeserializeAttributeSeparator(in.substr(pos_second_caret, 2));
+      if (!second_attribute.has_value() ||
+          second_attribute.value() !=
+              EncodedAttribute::kTopLevelSiteOpaqueNonceLow) {
+        return absl::nullopt;
+      }
+
+      // The origin is the portion up to, but not including, the first
+      // separator.
+      key_origin = url::Origin::Create(GURL(in.substr(0, pos_first_caret)));
+
+      // The first high 64 bits of the sites's nonce are next, between the first
+      // separators.
+      int length_of_high = pos_second_caret - (pos_first_caret + 2);
+      base::StringPiece high_digits =
+          in.substr(pos_first_caret + 2, length_of_high);
+      // The low 64 bits are next, after the second separator.
+      int length_of_low = pos_third_caret - (pos_second_caret + 2);
+      base::StringPiece low_digits =
+          in.substr(pos_second_caret + 2, length_of_low);
+
+      uint64_t nonce_high = 0;
+      uint64_t nonce_low = 0;
+
+      if (!base::StringToUint64(high_digits, &nonce_high)) {
+        return absl::nullopt;
+      }
+
+      if (!base::StringToUint64(low_digits, &nonce_low)) {
+        return absl::nullopt;
+      }
+
+      const absl::optional<base::UnguessableToken> site_nonce =
+          base::UnguessableToken::Deserialize2(nonce_high, nonce_low);
+
+      // Make sure we found the final separator, it's valid, that it's the
+      // correct attribute.
+      if (pos_third_caret == std::string::npos ||
+          (in.size() - pos_third_caret) < 2) {
+        return absl::nullopt;
+      }
+
+      absl::optional<EncodedAttribute> third_attribute =
+          DeserializeAttributeSeparator(in.substr(pos_third_caret, 2));
+      if (!third_attribute.has_value() ||
+          third_attribute.value() !=
+              EncodedAttribute::kTopLevelSiteOpaquePrecursor) {
+        return absl::nullopt;
+      }
+
+      // The precursor is the rest of the input.
+      const GURL url_precursor(in.substr(pos_third_caret + 2));
+      const url::SchemeHostPort tuple_precursor(url_precursor);
+
+      if (key_origin.opaque() || !site_nonce ||
+          (!url_precursor.is_empty() && !tuple_precursor.IsValid())) {
+        return absl::nullopt;
+      }
+
+      // This constructor makes a copy of the site's nonce, so getting the raw
+      // pointer is safe.
+      return StorageKey(
+          key_origin,
+          net::SchemefulSite(url::Origin(url::Origin::Nonce(site_nonce.value()),
+                                         tuple_precursor)),
+          nullptr, blink::mojom::AncestorChainBit::kSameSite);
+    }
     default: {
       // Malformed input case. We saw a separator that we don't understand
       // or one in the wrong order.
@@ -225,10 +313,11 @@
 StorageKey StorageKey::CreateForTesting(
     const url::Origin& origin,
     const net::SchemefulSite& top_level_site) {
-  return StorageKey(origin, top_level_site, nullptr,
-                    top_level_site == net::SchemefulSite(origin)
-                        ? blink::mojom::AncestorChainBit::kSameSite
-                        : blink::mojom::AncestorChainBit::kCrossSite);
+  return StorageKey(
+      origin, top_level_site, nullptr,
+      (top_level_site == net::SchemefulSite(origin) || top_level_site.opaque())
+          ? blink::mojom::AncestorChainBit::kSameSite
+          : blink::mojom::AncestorChainBit::kCrossSite);
 }
 
 // static
@@ -290,6 +379,7 @@
                               ? ancestor_chain_bit
                               : blink::mojom::AncestorChainBit::kSameSite),
       ancestor_chain_bit_if_third_party_enabled_(ancestor_chain_bit) {
+#if DCHECK_IS_ON()
   // If we're setting a `nonce`, the `top_level_site` must be the same as
   // the `origin` and the `ancestor_chain_bit` must be kSameSite. We don't
   // serialize those pieces of information so have to check to prevent
@@ -299,18 +389,25 @@
     DCHECK_EQ(top_level_site, net::SchemefulSite(origin));
     DCHECK_EQ(ancestor_chain_bit, blink::mojom::AncestorChainBit::kSameSite);
   }
+  // If we're setting an opaque `top_level_site`, the `ancestor_chain_bit` must
+  // be kSameSite. We don't serialize that information so have to check to
+  // prevent mistaken reliance on what is supposed to be an invariant.
+  if (top_level_site.opaque()) {
+    DCHECK_EQ(ancestor_chain_bit, blink::mojom::AncestorChainBit::kSameSite);
+  }
+#endif
 }
 
 std::string StorageKey::Serialize() const {
   using EncodedAttribute = StorageKey::EncodedAttribute;
   DCHECK(!origin_.opaque());
-  DCHECK(!top_level_site_.opaque());
 
-  // If the storage key has a nonce then we need to serialize the key to fit the
-  // following scheme:
+  // If the storage key has a nonce, implying the top_level_site is the same as
+  // origin and ancestor_chain_bit is kSameSite, then we need to serialize the
+  // key to fit the following scheme:
   //
-  // <StorageKey 'key'.origin> + "/" + "^1" + <StorageKey 'nonce'.High64Bits> +
-  // "^2" + <StorageKey 'nonce'.Low64Bits>
+  // <StorageKey `key`.origin> + "/" + "^1" + <StorageKey
+  // `key`.nonce.High64Bits> + "^2" + <StorageKey `key`.nonce.Low64Bits>
   //
   // Note that we intentionally do not include the AncestorChainBit in
   // serialization with nonce formats as that information is not applicable
@@ -326,9 +423,17 @@
   // Else if storage partitioning is enabled we need to serialize the key to fit
   // the following scheme:
   //
-  // <StorageKey 'key'.origin> + "/" + [ "^0" + <StorageKey
+  // <StorageKey `key`.origin> + "/" + [ "^0" + <StorageKey
   // `key`.top_level_site> + "^3" + <StorageKey `key`.ancestor_chain_bit> ]
   //
+  // Or if the top_level_site is opaque, ancestor_chain_bit must be kSameSite,
+  // so the following scheme is used:
+  //
+  // <StorageKey `key`.origin> + "/" + [ ^4" + <StorageKey
+  // `key`.top_level_site.nonce.High64Bits> + "^5" + <StorageKey
+  // `key`.top_level_site.nonce.Low64Bits>  + "^6" + <StorageKey
+  // `key`.top_level_site.precursor> ]
+  //
   // The top_level_site is optional (indicated by the square brackets) if it's
   // the same site as the origin and kSameSite in order to enable backwards
   // compatibility for 1p contexts. Meaning that in the case of a 1p context the
@@ -337,12 +442,34 @@
   if (IsThirdPartyStoragePartitioningEnabled() &&
       (top_level_site_ != net::SchemefulSite(origin_) ||
        ancestor_chain_bit_ == blink::mojom::AncestorChainBit::kCrossSite)) {
-    return base::StrCat(
-        {origin_.GetURL().spec(),
-         SerializeAttributeSeparator(EncodedAttribute::kTopLevelSite),
-         top_level_site_.Serialize(),
-         SerializeAttributeSeparator(EncodedAttribute::kAncestorChainBit),
-         base::NumberToString(static_cast<int>(ancestor_chain_bit_))});
+    if (top_level_site_.opaque()) {
+      return base::StrCat({
+          origin_.GetURL().spec(),
+          SerializeAttributeSeparator(
+              EncodedAttribute::kTopLevelSiteOpaqueNonceHigh),
+          base::NumberToString(top_level_site_.internal_value()
+                                   .GetNonceForSerialization()
+                                   ->GetHighForSerialization()),
+          SerializeAttributeSeparator(
+              EncodedAttribute::kTopLevelSiteOpaqueNonceLow),
+          base::NumberToString(top_level_site_.internal_value()
+                                   .GetNonceForSerialization()
+                                   ->GetLowForSerialization()),
+          SerializeAttributeSeparator(
+              EncodedAttribute::kTopLevelSiteOpaquePrecursor),
+          top_level_site_.internal_value()
+              .GetTupleOrPrecursorTupleIfOpaque()
+              .Serialize(),
+      });
+    } else {
+      return base::StrCat({
+          origin_.GetURL().spec(),
+          SerializeAttributeSeparator(EncodedAttribute::kTopLevelSite),
+          top_level_site_.Serialize(),
+          SerializeAttributeSeparator(EncodedAttribute::kAncestorChainBit),
+          base::NumberToString(static_cast<int>(ancestor_chain_bit_)),
+      });
+    }
   }
 
   return origin_.GetURL().spec();
@@ -460,10 +587,13 @@
     absl::optional<EncodedAttribute> attribute = DeserializeAttributeSeparator(
         reg_key_string.substr(pos_first_caret, 2));
     // Do skip if partitioning is disabled and we detect a top-level site
-    // serialization scheme:
+    // serialization scheme (opaque or otherwise):
     if (attribute.has_value() &&
-        attribute == StorageKey::EncodedAttribute::kTopLevelSite)
+        (attribute == StorageKey::EncodedAttribute::kTopLevelSite ||
+         attribute ==
+             StorageKey::EncodedAttribute::kTopLevelSiteOpaqueNonceHigh)) {
       return true;
+    }
   }
   // If otherwise first-party, nonce, or corrupted, don't skip.
   return false;
diff --git a/third_party/blink/common/storage_key/storage_key_mojom_traits_unittest.cc b/third_party/blink/common/storage_key/storage_key_mojom_traits_unittest.cc
index 486da98a..f230106 100644
--- a/third_party/blink/common/storage_key/storage_key_mojom_traits_unittest.cc
+++ b/third_party/blink/common/storage_key/storage_key_mojom_traits_unittest.cc
@@ -58,7 +58,15 @@
             url::Origin::Create(GURL("http://sub2.example.com")),
             net::SchemefulSite(
                 url::Origin::Create(GURL("https://example.com"))),
-            nullptr, blink::mojom::AncestorChainBit::kCrossSite)};
+            nullptr, blink::mojom::AncestorChainBit::kCrossSite),
+        StorageKey::CreateWithOptionalNonce(
+            url::Origin(), net::SchemefulSite(), nullptr,
+            blink::mojom::AncestorChainBit::kSameSite),
+        StorageKey::CreateWithOptionalNonce(
+            url::Origin::Create(GURL("http://example.com")),
+            net::SchemefulSite(), nullptr,
+            blink::mojom::AncestorChainBit::kSameSite),
+    };
 
     for (auto& original : test_keys) {
       StorageKey copied;
diff --git a/third_party/blink/common/storage_key/storage_key_unittest.cc b/third_party/blink/common/storage_key/storage_key_unittest.cc
index 2a8308d..bdc26428 100644
--- a/third_party/blink/common/storage_key/storage_key_unittest.cc
+++ b/third_party/blink/common/storage_key/storage_key_unittest.cc
@@ -32,8 +32,19 @@
 
 }  // namespace
 
+class StorageKeyTest : public ::testing::Test {
+ protected:
+  const net::SchemefulSite GetOpaqueSite(uint64_t high,
+                                         uint64_t low,
+                                         base::StringPiece url_string) {
+    return net::SchemefulSite(url::Origin(
+        url::Origin::Nonce(base::UnguessableToken::CreateForTesting(high, low)),
+        url::SchemeHostPort(GURL(url_string))));
+  }
+};
+
 // Test when a constructed StorageKey object should be considered valid/opaque.
-TEST(StorageKeyTest, ConstructionValidity) {
+TEST_F(StorageKeyTest, ConstructionValidity) {
   StorageKey empty = StorageKey();
   EXPECT_TRUE(IsOpaque(empty));
   // These cases will have the same origin for both `origin` and
@@ -53,7 +64,7 @@
 
 // Test that StorageKeys are/aren't equivalent as expected when storage
 // partitioning is disabled.
-TEST(StorageKeyTest, EquivalenceUnpartitioned) {
+TEST_F(StorageKeyTest, EquivalenceUnpartitioned) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -112,7 +123,7 @@
 
 // Test that StorageKeys are/aren't equivalent as expected when storage
 // partitioning is enabled.
-TEST(StorageKeyTest, EquivalencePartitioned) {
+TEST_F(StorageKeyTest, EquivalencePartitioned) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -154,7 +165,7 @@
 
 // Test that StorageKeys Serialize to the expected value with partitioning
 // enabled and disabled.
-TEST(StorageKeyTest, SerializeFirstParty) {
+TEST_F(StorageKeyTest, SerializeFirstParty) {
   for (const bool toggle : {false, true}) {
     base::test::ScopedFeatureList scope_feature_list;
     scope_feature_list.InitWithFeatureState(
@@ -183,7 +194,7 @@
   }
 }
 
-TEST(StorageKeyTest, SerializeFirstPartyForLocalStorage) {
+TEST_F(StorageKeyTest, SerializeFirstPartyForLocalStorage) {
   for (const bool toggle : {false, true}) {
     base::test::ScopedFeatureList scope_feature_list;
     scope_feature_list.InitWithFeatureState(
@@ -215,7 +226,7 @@
 // Tests that the top-level site is correctly serialized for service workers
 // when kThirdPartyStoragePartitioning is enabled. This is expected to be the
 // same for localStorage.
-TEST(StorageKeyTest, SerializePartitioned) {
+TEST_F(StorageKeyTest, SerializePartitioned) {
   base::test::ScopedFeatureList scope_feature_list;
   scope_feature_list.InitAndEnableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -250,7 +261,7 @@
   }
 }
 
-TEST(StorageKeyTest, SerializeNonce) {
+TEST_F(StorageKeyTest, SerializeNonce) {
   struct {
     const std::pair<const char*, const base::UnguessableToken> origin_and_nonce;
     const char* expected_serialization;
@@ -280,7 +291,7 @@
 }
 
 // Test that deserialized StorageKeys are valid/opaque as expected.
-TEST(StorageKeyTest, Deserialize) {
+TEST_F(StorageKeyTest, Deserialize) {
   const struct {
     std::string serialized_string;
     bool expected_has_value;
@@ -338,7 +349,7 @@
 }
 
 // Test that string -> StorageKey test function performs as expected.
-TEST(StorageKeyTest, CreateFromStringForTesting) {
+TEST_F(StorageKeyTest, CreateFromStringForTesting) {
   std::string example = "https://example.com/";
   std::string wrong = "I'm not a valid URL.";
 
@@ -354,7 +365,7 @@
 
 // Test that a StorageKey, constructed by deserializing another serialized
 // StorageKey, is equivalent to the original.
-TEST(StorageKeyTest, SerializeDeserialize) {
+TEST_F(StorageKeyTest, SerializeDeserialize) {
   const char* kTestCases[] = {"https://example.com", "https://sub.test.example",
                               "file://", "file://example.fileshare.com"};
 
@@ -386,7 +397,7 @@
 
 // Same as SerializeDeserialize but for partitioned StorageKeys when
 // kThirdPartyStoragePartitioning is enabled.
-TEST(StorageKeyTest, SerializeDeserializePartitioned) {
+TEST_F(StorageKeyTest, SerializeDeserializePartitioned) {
   base::test::ScopedFeatureList scope_feature_list;
   scope_feature_list.InitAndEnableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -442,7 +453,7 @@
   }
 }
 
-TEST(StorageKeyTest, SerializeDeserializeNonce) {
+TEST_F(StorageKeyTest, SerializeDeserializeNonce) {
   struct {
     const char* origin;
     const base::UnguessableToken nonce;
@@ -479,7 +490,133 @@
   }
 }
 
-TEST(StorageKeyTest, IsThirdPartyStoragePartitioningEnabled) {
+TEST_F(StorageKeyTest, SerializeDeserializeOpaqueTopLevelSite) {
+  for (const bool toggle : {false, true}) {
+    base::test::ScopedFeatureList scope_feature_list;
+    scope_feature_list.InitWithFeatureState(
+        net::features::kThirdPartyStoragePartitioning, toggle);
+    struct {
+      const url::Origin origin;
+      const net::SchemefulSite& top_level_site;
+      const char* expected_serialization_without_partitioning;
+      const char* expected_serialization_with_partitioning;
+    } kTestCases[] = {
+        {
+            url::Origin::Create(GURL("https://example.com/")),
+            GetOpaqueSite(12345ULL, 67890ULL, ""),
+            "https://example.com/",
+            "https://example.com/^412345^567890^6",
+        },
+        {
+            url::Origin::Create(GURL("https://sub.example.com/")),
+            GetOpaqueSite(22222ULL, 99999ULL, ""),
+            "https://sub.example.com/",
+            "https://sub.example.com/^422222^599999^6",
+        },
+        {
+            url::Origin::Create(GURL("https://example.com/")),
+            GetOpaqueSite(9876ULL, 54321ULL, "https://notexample.com/"),
+            "https://example.com/",
+            "https://example.com/^49876^554321^6https://notexample.com",
+        },
+        {
+            url::Origin::Create(GURL("https://sub.example.com/")),
+            GetOpaqueSite(3735928559ULL, 110521ULL,
+                          "https://sub.notexample.com/"),
+            "https://sub.example.com/",
+            "https://sub.example.com/^43735928559^5110521^6https://"
+            "sub.notexample.com",
+        },
+    };
+
+    for (const auto& test : kTestCases) {
+      if (toggle) {
+        SCOPED_TRACE(test.expected_serialization_with_partitioning);
+      } else {
+        SCOPED_TRACE(test.expected_serialization_without_partitioning);
+      }
+      EXPECT_TRUE(test.top_level_site.opaque());
+      StorageKey key = StorageKey::CreateWithOptionalNonce(
+          test.origin, test.top_level_site, nullptr,
+          blink::mojom::AncestorChainBit::kSameSite);
+      if (toggle) {
+        EXPECT_EQ(test.expected_serialization_with_partitioning,
+                  key.Serialize());
+        EXPECT_EQ(key, StorageKey::Deserialize(
+                           test.expected_serialization_with_partitioning));
+      } else {
+        EXPECT_EQ(test.expected_serialization_without_partitioning,
+                  key.Serialize());
+        EXPECT_EQ(key, StorageKey::Deserialize(
+                           test.expected_serialization_without_partitioning));
+      }
+    }
+  }
+}
+
+TEST_F(StorageKeyTest, DeserializeBadNonces) {
+  for (const bool toggle : {false, true}) {
+    base::test::ScopedFeatureList scope_feature_list;
+    scope_feature_list.InitWithFeatureState(
+        net::features::kThirdPartyStoragePartitioning, toggle);
+    struct {
+      const char* serialization;
+      absl::optional<blink::StorageKey> expected_key;
+    } kTestCases[] = {
+        {
+            "https://example.com/^40^50^6",
+            absl::nullopt,
+        },
+        {
+            "https://example.com/^41^50^6",
+            blink::StorageKey::CreateForTesting(
+                url::Origin::Create(GURL("https://example.com/")),
+                GetOpaqueSite(1ULL, 0ULL, "")),
+        },
+        {
+            "https://example.com/^40^51^6",
+            blink::StorageKey::CreateForTesting(
+                url::Origin::Create(GURL("https://example.com/")),
+                GetOpaqueSite(0ULL, 1ULL, "")),
+        },
+        {
+            "https://example.com/^41^51^6",
+            blink::StorageKey::CreateForTesting(
+                url::Origin::Create(GURL("https://example.com/")),
+                GetOpaqueSite(1ULL, 1ULL, "")),
+        },
+        {
+            "https://example.com/^10^20",
+            absl::nullopt,
+        },
+        {
+            "https://example.com/^11^20",
+            blink::StorageKey::CreateWithNonceForTesting(
+                url::Origin::Create(GURL("https://example.com/")),
+                base::UnguessableToken::CreateForTesting(1ULL, 0ULL)),
+        },
+        {
+            "https://example.com/^10^21",
+            blink::StorageKey::CreateWithNonceForTesting(
+                url::Origin::Create(GURL("https://example.com/")),
+                base::UnguessableToken::CreateForTesting(0ULL, 1ULL)),
+        },
+        {
+            "https://example.com/^11^21",
+            blink::StorageKey::CreateWithNonceForTesting(
+                url::Origin::Create(GURL("https://example.com/")),
+                base::UnguessableToken::CreateForTesting(1ULL, 1ULL)),
+        },
+    };
+
+    for (const auto& test : kTestCases) {
+      SCOPED_TRACE(test.serialization);
+      EXPECT_EQ(test.expected_key, StorageKey::Deserialize(test.serialization));
+    }
+  }
+}
+
+TEST_F(StorageKeyTest, IsThirdPartyStoragePartitioningEnabled) {
   for (const bool toggle : {false, true}) {
     base::test::ScopedFeatureList scope_feature_list;
     scope_feature_list.InitWithFeatureState(
@@ -490,7 +627,7 @@
 
 // Test that StorageKey's top_level_site getter returns origin's site when
 // storage partitioning is disabled.
-TEST(StorageKeyTest, TopLevelSiteGetterWithPartitioningDisabled) {
+TEST_F(StorageKeyTest, TopLevelSiteGetterWithPartitioningDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -508,7 +645,7 @@
 
 // Test that StorageKey's top_level_site getter returns the top level site when
 // storage partitioning is enabled.
-TEST(StorageKeyTest, TopLevelSiteGetterWithPartitioningEnabled) {
+TEST_F(StorageKeyTest, TopLevelSiteGetterWithPartitioningEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -527,7 +664,7 @@
 
 // Test that the AncestorChainBit enum class is not reordered and returns
 // kSameSite when partitioning is not enabled.
-TEST(StorageKeyTest, AncestorChainBitGetterWithPartitioningDisabled) {
+TEST_F(StorageKeyTest, AncestorChainBitGetterWithPartitioningDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -551,7 +688,7 @@
 
 // Test that the AncestorChainBit enum class is not reordered and returns the
 // correct value when storage partitioning is enabled.
-TEST(StorageKeyTest, AncestorChainBitGetterWithPartitioningEnabled) {
+TEST_F(StorageKeyTest, AncestorChainBitGetterWithPartitioningEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -573,7 +710,7 @@
             key_cross_site->ancestor_chain_bit());
 }
 
-TEST(StorageKeyTest, IsThirdPartyContext) {
+TEST_F(StorageKeyTest, IsThirdPartyContext) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -622,7 +759,7 @@
   EXPECT_EQ(true, cross_key.IsThirdPartyContext());
 }
 
-TEST(StorageKeyTest, ToNetSiteForCookies) {
+TEST_F(StorageKeyTest, ToNetSiteForCookies) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       net::features::kThirdPartyStoragePartitioning);
@@ -680,7 +817,7 @@
   }
 }
 
-TEST(StorageKeyTest, CopyWithForceEnabledThirdPartyStoragePartitioning) {
+TEST_F(StorageKeyTest, CopyWithForceEnabledThirdPartyStoragePartitioning) {
   const url::Origin kOrigin = url::Origin::Create(GURL("https://foo.com"));
   const url::Origin kOtherOrigin = url::Origin::Create(GURL("https://bar.com"));
 
@@ -709,7 +846,7 @@
   }
 }
 
-TEST(StorageKeyTest, ToCookiePartitionKey) {
+TEST_F(StorageKeyTest, ToCookiePartitionKey) {
   struct TestCase {
     const StorageKey storage_key;
     const absl::optional<net::CookiePartitionKey> expected;
@@ -791,7 +928,7 @@
   }
 }
 
-TEST(StorageKeyTest, NonceRequiresMatchingOriginSiteAndSameSite) {
+TEST_F(StorageKeyTest, NonceRequiresMatchingOriginSiteAndSameSite) {
   const url::Origin origin = url::Origin::Create(GURL("https://foo.com"));
   const net::SchemefulSite site(origin);
   const net::SchemefulSite opaque_site;
@@ -804,7 +941,7 @@
         net::features::kThirdPartyStoragePartitioning, toggle);
 
     // A nonce key with a matching origin/site that's SameSite works.
-    (void)StorageKey::CreateWithOptionalNonce(
+    std::ignore = StorageKey::CreateWithOptionalNonce(
         origin, site, &nonce, mojom::AncestorChainBit::kSameSite);
 
     // A nonce key with a non-matching origin/site that's SameSite fails.
@@ -825,4 +962,78 @@
   }
 }
 
+TEST_F(StorageKeyTest, OpaqueTopLevelSiteRequiresSameSite) {
+  const url::Origin origin = url::Origin::Create(GURL("https://foo.com"));
+  const net::SchemefulSite site(origin);
+  const net::SchemefulSite opaque_site;
+
+  for (const bool toggle : {false, true}) {
+    base::test::ScopedFeatureList scope_feature_list;
+    scope_feature_list.InitWithFeatureState(
+        net::features::kThirdPartyStoragePartitioning, toggle);
+
+    // A non-opaque site with SameSite and CrossSite works.
+    std::ignore = StorageKey::CreateWithOptionalNonce(
+        origin, site, nullptr, mojom::AncestorChainBit::kSameSite);
+    std::ignore = StorageKey::CreateWithOptionalNonce(
+        origin, site, nullptr, mojom::AncestorChainBit::kCrossSite);
+
+    // An opaque site with SameSite works.
+    std::ignore = StorageKey::CreateWithOptionalNonce(
+        origin, opaque_site, nullptr, mojom::AncestorChainBit::kSameSite);
+
+    // An opaque site with CrossSite fails.
+    EXPECT_DCHECK_DEATH(StorageKey::CreateWithOptionalNonce(
+        origin, opaque_site, nullptr, mojom::AncestorChainBit::kCrossSite));
+  }
+}
+
+TEST_F(StorageKeyTest, ShouldSkipKeyDueToPartitioning) {
+  const struct {
+    std::string serialized_key;
+    bool expected_skip;
+  } kTestCases[] = {
+      // First party keys should not be skipped.
+      {
+          "https://example.com/",
+          false,
+      },
+      // Nonce keys should not be skipped.
+      {
+          "https://example.com/^19876^25432",
+          false,
+      },
+      // Third-party keys should be skipped.
+      {
+          "https://example.com/^0https://test.example^31",
+          true,
+      },
+      // Third-party keys with opaque sites should be skipped.
+      {
+          "https://example.com/^412345^567890^6",
+          true,
+      },
+      // Corrupted keys should be not skipped.
+      {
+          "https://example.com/^7",
+          false,
+      },
+  };
+
+  for (const bool toggle : {false, true}) {
+    base::test::ScopedFeatureList scope_feature_list;
+    scope_feature_list.InitWithFeatureState(
+        net::features::kThirdPartyStoragePartitioning, toggle);
+    for (const auto& test_case : kTestCases) {
+      if (toggle) {
+        EXPECT_FALSE(StorageKey::ShouldSkipKeyDueToPartitioning(
+            test_case.serialized_key));
+      } else {
+        EXPECT_EQ(StorageKey::ShouldSkipKeyDueToPartitioning(
+                      test_case.serialized_key),
+                  test_case.expected_skip);
+      }
+    }
+  }
+}
 }  // namespace blink
diff --git a/third_party/blink/public/common/storage_key/storage_key.h b/third_party/blink/public/common/storage_key/storage_key.h
index 8670f19..81e7721 100644
--- a/third_party/blink/public/common/storage_key/storage_key.h
+++ b/third_party/blink/public/common/storage_key/storage_key.h
@@ -49,6 +49,10 @@
 // Keys with a nonce disregard the top level site and ancestor chain bit. For
 // consistency we set them to the origin's site and `kSameSite` respectively.
 //
+// Storage keys might have an opaque top level site (for example, if an
+// iframe is embedded in a data url). These storage keys always have a
+// `kSameSite` ancestor chain bit as it provides no additional distinctiveness.
+//
 // For more details on the overall design, see
 // https://docs.google.com/document/d/1xd6MXcUhfnZqIe5dt2CTyCn6gEZ7nOezAEWS0W9hwbQ/edit.
 class BLINK_COMMON_EXPORT StorageKey {
@@ -76,7 +80,8 @@
 
   // Callers may specify an optional `nonce` by passing nullptr.
   // If the `nonce` isn't null, `top_level_site` must be the same as `origin`
-  // and `ancestor_chain_bit` must be kSameSite.
+  // and `ancestor_chain_bit` must be kSameSite. If `top_level_site` is opaque,
+  // `ancestor_chain_bit` must be `kSameSite`.
   static StorageKey CreateWithOptionalNonce(
       const url::Origin& origin,
       const net::SchemefulSite& top_level_site,
@@ -143,12 +148,12 @@
   static bool IsThirdPartyStoragePartitioningEnabled();
 
   // Serializes the `StorageKey` into a string.
-  // Do not call if `this` is opaque.
+  // Do not call if `origin_` is opaque.
   std::string Serialize() const;
 
   // Serializes into a string in the format used for localStorage (without
   // trailing slashes). Prefer Serialize() for uses other than localStorage. Do
-  // not call if `this` is opaque.
+  // not call if `origin_` is opaque.
   std::string SerializeForLocalStorage() const;
 
   // `IsThirdPartyContext` returns true if the StorageKey is for a context that
@@ -239,7 +244,10 @@
     kNonceHigh = 1,
     kNonceLow = 2,
     kAncestorChainBit = 3,
-    kMaxValue = kAncestorChainBit,
+    kTopLevelSiteOpaqueNonceHigh = 4,
+    kTopLevelSiteOpaqueNonceLow = 5,
+    kTopLevelSiteOpaquePrecursor = 6,
+    kMaxValue = kTopLevelSiteOpaquePrecursor,
   };
 
   StorageKey(const url::Origin& origin,
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index adbaa01..6023f84 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -3790,6 +3790,7 @@
   kWindowManagementPermissionPolicyParsed = 4449,
   kWindowPlacementPermissionPolicyParsed = 4450,
   kContentDispositionInSvgUse = 4451,
+  kSameDocumentCrossOriginInitiator = 4452,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index d87d2e1..c33133f 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2432,7 +2432,7 @@
     // TODO(tkent): We should avoid updating style.  We'd like to check only
     // DOM-level focusability here.
     GetDocument().UpdateStyleAndLayoutTreeForNode(this);
-    if (!SupportsFocus()) {
+    if (!SupportsFocus() && !GetFocusableArea()) {
       blur();
     }
   }
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 60887e9c..12f0fc4b 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -7674,6 +7674,54 @@
   return OffsetPoint(parent).top;
 }
 
+LayoutSize LayoutBox::Size() const {
+  NOT_DESTROYED();
+  if (!RuntimeEnabledFeatures::LayoutNGNoCopyBackEnabled()) {
+    return frame_size_;
+  }
+  const auto& results = GetLayoutResults();
+  if (results.size() == 0) {
+    return LayoutSize();
+  }
+  const auto& first_fragment = results[0]->PhysicalFragment();
+  if (results.size() == 1u) {
+    return first_fragment.Size().ToLayoutSize();
+  }
+  WritingModeConverter converter(first_fragment.Style().GetWritingDirection());
+  const NGBlockBreakToken* previous_break_token = nullptr;
+  LogicalSize size;
+  for (const auto& result : results) {
+    const auto& physical_fragment =
+        To<NGPhysicalBoxFragment>(result->PhysicalFragment());
+    LogicalSize fragment_logical_size =
+        converter.ToLogical(physical_fragment.Size());
+    if (physical_fragment.IsFirstForNode()) {
+      // Inline-size will only be set at the first fragment. Subsequent
+      // fragments may have different inline-size (either because fragmentainer
+      // inline-size is variable, or e.g. because available inline-size is
+      // affected by floats). The legacy engine doesn't handle variable
+      // inline-size (since it doesn't really understand fragmentation).  This
+      // means that things like offsetWidth won't work correctly (since that's
+      // still being handled by the legacy engine), but at least layout,
+      // painting and hit-testing will be correct.
+      size = fragment_logical_size;
+    } else {
+      DCHECK(previous_break_token);
+      size.block_size = fragment_logical_size.block_size +
+                        previous_break_token->ConsumedBlockSizeForLegacy();
+    }
+    previous_break_token = physical_fragment.BreakToken();
+    // Continue in order to update logical height, unless this fragment is
+    // past the block-end of the generating node (happens with overflow) or
+    // is a repeated one.
+    if (!previous_break_token || previous_break_token->IsRepeated() ||
+        previous_break_token->IsAtBlockEnd()) {
+      break;
+    }
+  }
+  return converter.ToPhysical(size).ToLayoutSize();
+}
+
 LayoutBox* LayoutBox::LocationContainer() const {
   NOT_DESTROYED();
   // Location of a non-root SVG object derived from LayoutBox should not be
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 7163258..158f869 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -407,10 +407,7 @@
     auto location = Location();
     return LayoutSize(location.X(), location.Y());
   }
-  virtual LayoutSize Size() const {
-    NOT_DESTROYED();
-    return frame_size_;
-  }
+  virtual LayoutSize Size() const;
 
   void SetLocation(const LayoutPoint& location) {
     NOT_DESTROYED();
@@ -2155,6 +2152,9 @@
   bool HasAnchorScrollTranslation() const;
   PhysicalOffset AnchorScrollTranslationOffset() const;
 
+  // This should be called when the border-box size of this box is changed.
+  void SizeChanged();
+
  protected:
   ~LayoutBox() override;
 
@@ -2347,7 +2347,6 @@
       delete;  // This will catch anyone doing an unnecessary check.
 
   void LocationChanged();
-  void SizeChanged();
 
   void UpdateBackgroundAttachmentFixedStatusAfterStyleChange();
 
@@ -2415,8 +2414,12 @@
   // includes any logical top/left along with this box's margins. It doesn't
   // include transforms, relative position offsets etc.
   LayoutPoint frame_location_;
+
+ protected:
+  // TODO(crbug.com/1353190): Remove frame_size_.
   LayoutSize frame_size_;
 
+ private:
   // Previous value of frame_size_, updated after paint invalidation.
   LayoutSize previous_size_;
 
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index fc8b2c8..3e4d4e8 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -106,7 +106,7 @@
 
 AffineTransform LayoutEmbeddedContent::EmbeddedContentTransform() const {
   auto frozen_size = FrozenFrameSize();
-  if (!frozen_size) {
+  if (!frozen_size || frozen_size->IsEmpty()) {
     const PhysicalOffset content_box_offset = PhysicalContentBoxOffset();
     return AffineTransform().Translate(content_box_offset.left,
                                        content_box_offset.top);
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content_test.cc b/third_party/blink/renderer/core/layout/layout_embedded_content_test.cc
index c1b1253..5e0275d 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content_test.cc
@@ -76,4 +76,25 @@
             PhysicalRect(32, 2, 240, 150));
 }
 
+TEST_F(LayoutEmbeddedContentTest, FreozenSizeEmpty) {
+  Document& document = GetDocument();
+  auto* element = MakeGarbageCollected<HTMLFreezableIFrameElement>(document);
+  element->setAttribute(html_names::kSrcAttr, "http://example.com/");
+  element->SetInlineStyleProperty(CSSPropertyID::kObjectFit,
+                                  CSSValueID::kContain);
+  document.body()->AppendChild(element);
+  UpdateAllLifecyclePhasesForTest();
+  auto* layout_object = element->GetLayoutFreezableIFrame();
+  ASSERT_TRUE(layout_object);
+  EXPECT_EQ(layout_object->ReplacedContentRect(), PhysicalRect(2, 2, 300, 150));
+
+  layout_object->FreezeSizeForTesting(PhysicalSize(0, 10));
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_EQ(layout_object->ReplacedContentRect(), PhysicalRect(2, 2, 300, 150));
+
+  layout_object->FreezeSizeForTesting(PhysicalSize(10, 0));
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_EQ(layout_object->ReplacedContentRect(), PhysicalRect(2, 2, 300, 150));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
index 23ce55490..01fa3afb 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -1633,4 +1633,10 @@
   last_set_worked_on_ = state.ColumnSet();
 }
 
+LayoutSize LayoutMultiColumnFlowThread::Size() const {
+  NOT_DESTROYED();
+  // TODO(crbug.com/1353190): Do not refer to frame_size_.
+  return frame_size_;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
index 49e9788f..40d9b74 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
@@ -336,6 +336,8 @@
   // "public" for |MakeGarbageCollected<T>|.
   explicit LayoutMultiColumnFlowThread(bool needs_paint_layer);
 
+  LayoutSize Size() const override;
+
  private:
   void UpdateLayout() override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
index c398942..0130b10 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -622,6 +622,12 @@
   DetachFromFlowThread();
 }
 
+LayoutSize LayoutMultiColumnSet::Size() const {
+  NOT_DESTROYED();
+  // TODO(crbug.com/1353190): Do not refer to frame_size_.
+  return frame_size_;
+}
+
 void LayoutMultiColumnSet::AttachToFlowThread() {
   NOT_DESTROYED();
   if (DocumentBeingDestroyed())
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.h b/third_party/blink/renderer/core/layout/layout_multi_column_set.h
index b00ebeb..b76dce8 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set.h
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.h
@@ -284,6 +284,7 @@
 
   void InsertedIntoTree() final;
   void WillBeRemovedFromTree() final;
+  LayoutSize Size() const override;
 
   bool IsSelfCollapsingBlock() const override {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 965a56a..cc9bb2f 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -2538,13 +2538,28 @@
       item_result->can_break_after = last->can_break_after;
       return;
     }
-    if (was_auto_wrap || last->can_break_after) {
-      item_result->can_break_after =
-          last->can_break_after ||
-          IsBreakableSpace(Text()[item_result->EndOffset()]);
+    if (last->can_break_after) {
+      // A break opportunity before a close tag always propagates to after the
+      // close tag.
+      item_result->can_break_after = true;
       last->can_break_after = false;
       return;
     }
+    if (was_auto_wrap) {
+      // We can break before a breakable space if we either:
+      //   a) allow breaking before a white space, or
+      //   b) the break point is preceded by another breakable space.
+      // TODO(abotella): What if the following breakable space is after an
+      // open tag which has a different white-space value?
+      bool preceded_by_breakable_space =
+          item_result->EndOffset() > 0 &&
+          IsBreakableSpace(Text()[item_result->EndOffset() - 1]);
+      item_result->can_break_after =
+          IsBreakableSpace(Text()[item_result->EndOffset()]) &&
+          (!current_style_->BreakOnlyAfterWhiteSpace() ||
+           preceded_by_breakable_space);
+      return;
+    }
     if (auto_wrap_ && !IsBreakableSpace(Text()[item_result->EndOffset() - 1]))
       ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_);
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index db45895ee..0441f7c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -934,6 +934,7 @@
   bool clear_trailing_results =
       break_token || box_->PhysicalFragmentCount() > 1;
 
+  const LayoutSize old_box_size = box_->Size();
   StoreResultInLayoutBox(layout_result, break_token, clear_trailing_results);
 
   if (block_flow) {
@@ -970,6 +971,11 @@
   }
 
   CopyFragmentDataToLayoutBox(constraint_space, *layout_result, break_token);
+  if (RuntimeEnabledFeatures::LayoutNGNoCopyBackEnabled() &&
+      !layout_result->PhysicalFragment().BreakToken() &&
+      box_->Size() != old_box_size) {
+    box_->SizeChanged();
+  }
 }
 
 void NGBlockNode::StoreResultInLayoutBox(const NGLayoutResult* result,
@@ -1303,30 +1309,29 @@
     const NGBlockBreakToken* previous_break_token) const {
   const auto& physical_fragment =
       To<NGPhysicalBoxFragment>(layout_result.PhysicalFragment());
-
-  NGBoxFragment fragment(constraint_space.GetWritingDirection(),
-                         physical_fragment);
-  LogicalSize fragment_logical_size = fragment.Size();
-  NGBoxStrut borders = fragment.Borders();
-  NGBoxStrut scrollbars = ComputeScrollbars(constraint_space, *this);
-  NGBoxStrut padding = fragment.Padding();
-  NGBoxStrut border_scrollbar_padding = borders + scrollbars + padding;
   bool is_last_fragment = !physical_fragment.BreakToken();
 
-  // For each fragment we process, we'll accumulate the block-size. We reset it
-  // at the first fragment, and accumulate at each method call for fragments
-  // belonging to the same layout object. Inline-size will only be set at the
-  // first fragment. Subsequent fragments may have different inline-size (either
-  // because fragmentainer inline-size is variable, or e.g. because available
-  // inline-size is affected by floats). The legacy engine doesn't handle
-  // variable inline-size (since it doesn't really understand fragmentation).
-  // This means that things like offsetWidth won't work correctly (since that's
-  // still being handled by the legacy engine), but at least layout, painting
-  // and hit-testing will be correct.
-  if (LIKELY(physical_fragment.IsFirstForNode())) {
-    box_->SetSize(LayoutSize(physical_fragment.Size().width,
-                             physical_fragment.Size().height));
-    if (!RuntimeEnabledFeatures::LayoutNGNoCopyBackEnabled()) {
+  if (!RuntimeEnabledFeatures::LayoutNGNoCopyBackEnabled()) {
+    NGBoxFragment fragment(constraint_space.GetWritingDirection(),
+                           physical_fragment);
+    NGBoxStrut borders = fragment.Borders();
+    NGBoxStrut scrollbars = ComputeScrollbars(constraint_space, *this);
+    NGBoxStrut padding = fragment.Padding();
+    NGBoxStrut border_scrollbar_padding = borders + scrollbars + padding;
+
+    // For each fragment we process, we'll accumulate the block-size. We reset
+    // it at the first fragment, and accumulate at each method call for
+    // fragments belonging to the same layout object. Inline-size will only be
+    // set at the first fragment. Subsequent fragments may have different
+    // inline-size (either because fragmentainer inline-size is variable, or
+    // e.g. because available inline-size is affected by floats). The legacy
+    // engine doesn't handle variable inline-size (since it doesn't really
+    // understand fragmentation). This means that things like offsetWidth won't
+    // work correctly (since that's still being handled by the legacy engine),
+    // but at least layout, painting and hit-testing will be correct.
+    if (LIKELY(physical_fragment.IsFirstForNode())) {
+      box_->SetSize(LayoutSize(physical_fragment.Size().width,
+                               physical_fragment.Size().height));
       // If this is a fragment from a node that didn't break into multiple
       // fragments, write back the intrinsic size. We skip this if the node has
       // fragmented, since intrinsic block-size is rather meaningless in that
@@ -1341,16 +1346,16 @@
             layout_result.IntrinsicBlockSize() -
             border_scrollbar_padding.BlockSum());
       }
-    }
-  } else {
-    // Update logical height, unless this fragment is past the block-end of the
-    // generating node (happens with overflow).
-    if (previous_break_token && !previous_break_token->IsAtBlockEnd()) {
-      box_->SetLogicalHeight(
-          fragment_logical_size.block_size +
-          previous_break_token->ConsumedBlockSizeForLegacy());
     } else {
-      DCHECK_EQ(fragment_logical_size.block_size, LayoutUnit());
+      // Update logical height, unless this fragment is past the block-end of
+      // the generating node (happens with overflow).
+      if (previous_break_token && !previous_break_token->IsAtBlockEnd()) {
+        box_->SetLogicalHeight(
+            fragment.Size().block_size +
+            previous_break_token->ConsumedBlockSizeForLegacy());
+      } else {
+        DCHECK_EQ(fragment.Size().block_size, LayoutUnit());
+      }
     }
   }
 
@@ -1617,6 +1622,8 @@
       LayoutPoint point =
           ToLayoutPoint(child_fragment, child.offset, physical_fragment,
                         previous_container_break_token);
+      // TODO(crbug.com/1353190): SetLocation*() and SetLogicalWidth() should
+      // be removed.
       flow_thread->SetLocationAndUpdateOverflowControlsIfNeeded(point);
       flow_thread->SetLogicalWidth(logical_size.inline_size);
       has_processed_first_column_in_flow_thread = true;
@@ -1648,6 +1655,8 @@
           ToLayoutPoint(child_fragment, physical_offset, physical_fragment,
                         previous_container_break_token);
 
+      // TODO(crbug.com/1353190): SetLocation() and SetLogicalWidth() should
+      // be removed.
       pending_column_set->SetLocation(point);
       pending_column_set->SetLogicalWidth(column_row_inline_size);
       pending_column_set->ResetColumnHeight();
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
index 1326b6a..8422b6a 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
@@ -129,4 +129,10 @@
   }
 }
 
+// TODO(crbug.com/1371882): Table columns should have physical fragments,
+// and this function should refer to the fragment sizes.
+LayoutSize LayoutNGTableColumn::Size() const {
+  return frame_size_;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h
index 77c3eab..9d58fc3 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h
@@ -39,6 +39,8 @@
   // Clears needs-layout for child columns too.
   void ClearNeedsLayoutForChildren() const;
 
+  LayoutSize Size() const override;
+
   // LayoutObject methods start.
 
   const char* GetName() const override {
diff --git a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
index 13a777ae..cc72b160 100644
--- a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
+++ b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/geometry/dom_rect.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/layout/deferred_shaping_controller.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/page/print_context.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -1110,6 +1111,13 @@
 };
 
 TEST_F(MAYBE_ScrollAnchorFindInPageTest, FindInPageResultPrioritized) {
+  // getBoundingClientRect() clears physical fragments of deferred boxes to
+  // return precise geometry. So the sizes of some boxes are 0x0 during
+  // ScrollAnchor handling.
+  // The behavior doesn't cause issues in production because deferred boxes
+  // are usually re-shaped before user interaction.
+  DeferredShapingController::From(GetDocument())->DisallowDeferredShaping();
+
   ResizeAndFocus();
   SetHtmlInnerHTML(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 7469497..7ca1821 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -1886,33 +1886,6 @@
   return AppliedTextDecorationsInternal()->data;
 }
 
-bool ComputedStyle::IsAppliedTextDecorationsSame(
-    const ComputedStyle& other) const {
-  if (HasSimpleUnderlineInternal() != other.HasSimpleUnderlineInternal()) {
-    return false;
-  }
-  if (AppliedTextDecorationsInternal().get() ==
-      other.AppliedTextDecorationsInternal().get()) {
-    return true;
-  }
-
-  // Rare but sometimes two instances of |AppliedTextDecorations()| may have the
-  // same items. Check if all items are the same.
-  // e.g., tables/mozilla/bugs/bug126742.html
-  const Vector<AppliedTextDecoration>& decorations = AppliedTextDecorations();
-  const Vector<AppliedTextDecoration>& other_decorations =
-      other.AppliedTextDecorations();
-  if (decorations.size() != other_decorations.size()) {
-    return false;
-  }
-  for (wtf_size_t index = 0; index < decorations.size(); ++index) {
-    if (decorations[index] != other_decorations[index]) {
-      return false;
-    }
-  }
-  return true;
-}
-
 static bool HasInitialVariables(const StyleInitialData* initial_data) {
   return initial_data && initial_data->HasInitialVariables();
 }
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index ae2f962..7442a72 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -1817,7 +1817,6 @@
   CORE_EXPORT const Vector<AppliedTextDecoration>& AppliedTextDecorations()
       const;
   CORE_EXPORT TextDecorationLine TextDecorationsInEffect() const;
-  bool IsAppliedTextDecorationsSame(const ComputedStyle& other) const;
 
   // Overflow utility functions.
 
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.idl b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.idl
index 33eb400..3c7131c 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.idl
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_sync_access_handle.idl
@@ -2,13 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(fivedots): Replace link with explainer, once it lands.
-// https://docs.google.com/document/d/1g7ZCqZ5NdiU7oqyCpsc2iZ7rRAY1ZXO-9VoG4LfP7fM
-
-// TODO(crbug.com/1338340): Update `any` return type to a specific type once
-// we migrate all methods to be sync. Currently, `any` is used to hold either
-// Promise or value during migration.
-
+// https://fs.spec.whatwg.org/#api-filesystemsyncaccesshandle
 [
   Exposed=DedicatedWorker,
   RuntimeEnabled=FileSystemAccessAccessHandle,
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
index 16a6ae9..ff29668 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/platform/wtf/conditional_destructor.h"
 #include "third_party/blink/renderer/platform/wtf/hash_table.h"
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
+#include "third_party/blink/renderer/platform/wtf/key_value_pair.h"
 #include "third_party/blink/renderer/platform/wtf/sanitizers.h"
 #include "v8/include/cppgc/custom-space.h"
 #include "v8/include/cppgc/explicit-management.h"
diff --git a/third_party/blink/renderer/platform/network/blink_schemeful_site.h b/third_party/blink/renderer/platform/network/blink_schemeful_site.h
index 67707d19..d92b7e78 100644
--- a/third_party/blink/renderer/platform/network/blink_schemeful_site.h
+++ b/third_party/blink/renderer/platform/network/blink_schemeful_site.h
@@ -73,6 +73,8 @@
     return !operator==(rhs);
   }
 
+  bool IsOpaque() const { return site_as_origin_->IsOpaque(); }
+
  private:
   friend struct WTF::HashTraits<BlinkSchemefulSite>;
 
diff --git a/third_party/blink/renderer/platform/network/blink_schemeful_site_test.cc b/third_party/blink/renderer/platform/network/blink_schemeful_site_test.cc
index 0455c17..4c4691d3 100644
--- a/third_party/blink/renderer/platform/network/blink_schemeful_site_test.cc
+++ b/third_party/blink/renderer/platform/network/blink_schemeful_site_test.cc
@@ -136,4 +136,12 @@
   EXPECT_FALSE(blink_schemeful_site_map_.Contains(opaque_site_1));
 }
 
+TEST(BlinkSchemefulSiteTest, IsOpaque) {
+  BlinkSchemefulSite site(
+      SecurityOrigin::CreateFromString("https://example.com"));
+  EXPECT_FALSE(site.IsOpaque());
+  BlinkSchemefulSite opaque_site;
+  EXPECT_TRUE(opaque_site.IsOpaque());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/storage/blink_storage_key.cc b/third_party/blink/renderer/platform/storage/blink_storage_key.cc
index cfec393..610fb61 100644
--- a/third_party/blink/renderer/platform/storage/blink_storage_key.cc
+++ b/third_party/blink/renderer/platform/storage/blink_storage_key.cc
@@ -46,6 +46,7 @@
                               ? ancestor_chain_bit
                               : mojom::blink::AncestorChainBit::kSameSite),
       ancestor_chain_bit_if_third_party_enabled_(ancestor_chain_bit) {
+#if DCHECK_IS_ON()
   DCHECK(origin_);
   // If we're setting a `nonce`, the `top_level_site` must be the same as
   // the `origin` and the `ancestor_chain_bit` must be kSameSite. We don't
@@ -56,6 +57,13 @@
     DCHECK(top_level_site == BlinkSchemefulSite(origin));
     DCHECK_EQ(ancestor_chain_bit, mojom::blink::AncestorChainBit::kSameSite);
   }
+  // If we're setting an opaque `top_level_site`, the `ancestor_chain_bit` must
+  // be kSameSite. We don't serialize that information so have to check to
+  // prevent mistaken reliance on what is supposed to be an invariant.
+  if (top_level_site.IsOpaque()) {
+    DCHECK_EQ(ancestor_chain_bit, mojom::blink::AncestorChainBit::kSameSite);
+  }
+#endif
 }
 
 // static
@@ -79,7 +87,8 @@
     scoped_refptr<const SecurityOrigin> origin,
     const BlinkSchemefulSite& top_level_site) {
   return BlinkStorageKey(origin, top_level_site, nullptr,
-                         BlinkSchemefulSite(origin) == top_level_site
+                         (BlinkSchemefulSite(origin) == top_level_site ||
+                          top_level_site.IsOpaque())
                              ? mojom::blink::AncestorChainBit::kSameSite
                              : mojom::blink::AncestorChainBit::kCrossSite);
 }
diff --git a/third_party/blink/renderer/platform/storage/blink_storage_key_mojom_traits_test.cc b/third_party/blink/renderer/platform/storage/blink_storage_key_mojom_traits_test.cc
index 46b52da..903d362 100644
--- a/third_party/blink/renderer/platform/storage/blink_storage_key_mojom_traits_test.cc
+++ b/third_party/blink/renderer/platform/storage/blink_storage_key_mojom_traits_test.cc
@@ -50,6 +50,10 @@
       BlinkStorageKey::CreateWithNonce(origin2, nonce),
       BlinkStorageKey(origin2, site2, nullptr,
                       mojom::blink::AncestorChainBit::kCrossSite),
+      BlinkStorageKey(origin1, BlinkSchemefulSite(), nullptr,
+                      mojom::blink::AncestorChainBit::kSameSite),
+      BlinkStorageKey(origin2, BlinkSchemefulSite(), nullptr,
+                      mojom::blink::AncestorChainBit::kSameSite),
   };
 
   for (BlinkStorageKey& key : keys) {
@@ -103,6 +107,12 @@
       StorageKey::CreateWithOptionalNonce(
           url_origin2, net_site2, nullptr,
           mojom::blink::AncestorChainBit::kCrossSite),
+      StorageKey::CreateWithOptionalNonce(
+          url_origin1, net_site1, nullptr,
+          mojom::blink::AncestorChainBit::kSameSite),
+      StorageKey::CreateWithOptionalNonce(
+          url_origin2, net_site1, nullptr,
+          mojom::blink::AncestorChainBit::kSameSite),
   };
   Vector<BlinkStorageKey> blink_storage_keys = {
       BlinkStorageKey(origin1),
@@ -117,6 +127,10 @@
       BlinkStorageKey::CreateWithNonce(origin2, nonce),
       BlinkStorageKey(origin2, blink_site2, nullptr,
                       mojom::blink::AncestorChainBit::kCrossSite),
+      BlinkStorageKey(origin1, blink_site1, nullptr,
+                      mojom::blink::AncestorChainBit::kSameSite),
+      BlinkStorageKey(origin2, blink_site1, nullptr,
+                      mojom::blink::AncestorChainBit::kSameSite),
   };
 
   for (size_t i = 0; i < storage_keys.size(); ++i) {
@@ -175,6 +189,12 @@
         StorageKey::CreateWithOptionalNonce(
             url_origin2, net_site2, nullptr,
             mojom::blink::AncestorChainBit::kCrossSite),
+        StorageKey::CreateWithOptionalNonce(
+            url_origin1, net_site1, nullptr,
+            mojom::blink::AncestorChainBit::kSameSite),
+        StorageKey::CreateWithOptionalNonce(
+            url_origin2, net_site1, nullptr,
+            mojom::blink::AncestorChainBit::kSameSite),
     };
 
     Vector<BlinkStorageKey> blink_storage_keys = {
@@ -190,6 +210,10 @@
         BlinkStorageKey::CreateWithNonce(origin2, nonce),
         BlinkStorageKey(origin2, blink_site2, nullptr,
                         mojom::blink::AncestorChainBit::kCrossSite),
+        BlinkStorageKey(origin1, blink_site1, nullptr,
+                        mojom::blink::AncestorChainBit::kSameSite),
+        BlinkStorageKey(origin2, blink_site1, nullptr,
+                        mojom::blink::AncestorChainBit::kSameSite),
     };
 
     for (size_t i = 0; i < storage_keys.size(); ++i) {
diff --git a/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc b/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc
index e3b8281..b9d82f9 100644
--- a/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc
+++ b/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc
@@ -111,7 +111,11 @@
         BlinkStorageKey::CreateWithNonce(origin1, nonce),
         BlinkStorageKey::CreateWithNonce(origin2, nonce),
         BlinkStorageKey(origin1, BlinkSchemefulSite(origin2), nullptr,
-                        mojom::blink::AncestorChainBit::kCrossSite),
+                        mojom::blink::AncestorChainBit::kSameSite),
+        BlinkStorageKey(origin1, BlinkSchemefulSite(), nullptr,
+                        mojom::blink::AncestorChainBit::kSameSite),
+        BlinkStorageKey(origin2, BlinkSchemefulSite(), nullptr,
+                        mojom::blink::AncestorChainBit::kSameSite),
     };
 
     for (BlinkStorageKey& key : keys) {
@@ -145,7 +149,14 @@
         StorageKey::CreateWithNonceForTesting(url_origin2, nonce),
         StorageKey::CreateWithOptionalNonce(
             url_origin1, net::SchemefulSite(url_origin2), nullptr,
-            blink::mojom::AncestorChainBit::kCrossSite)};
+            blink::mojom::AncestorChainBit::kCrossSite),
+        StorageKey::CreateWithOptionalNonce(
+            url_origin1, net::SchemefulSite(), nullptr,
+            blink::mojom::AncestorChainBit::kSameSite),
+        StorageKey::CreateWithOptionalNonce(
+            url_origin2, net::SchemefulSite(), nullptr,
+            blink::mojom::AncestorChainBit::kSameSite),
+    };
 
     for (const auto& key : storage_keys) {
       EXPECT_EQ(key, StorageKey(BlinkStorageKey(key)));
@@ -256,8 +267,8 @@
         net::features::kThirdPartyStoragePartitioning, toggle);
 
     // A nonce key with a matching origin/site that's SameSite works.
-    (void)BlinkStorageKey(origin, site, &nonce,
-                          mojom::blink::AncestorChainBit::kSameSite);
+    std::ignore = BlinkStorageKey(origin, site, &nonce,
+                                  mojom::blink::AncestorChainBit::kSameSite);
 
     // A nonce key with a non-matching origin/site that's SameSite fails.
     EXPECT_DCHECK_DEATH(
@@ -280,4 +291,32 @@
   }
 }
 
+TEST(StorageKeyTest, OpaqueTopLevelSiteRequiresSameSite) {
+  scoped_refptr<const SecurityOrigin> origin =
+      SecurityOrigin::CreateFromString("https://foo.com");
+  const BlinkSchemefulSite site(origin);
+  const BlinkSchemefulSite opaque_site;
+
+  for (const bool toggle : {false, true}) {
+    base::test::ScopedFeatureList scope_feature_list;
+    scope_feature_list.InitWithFeatureState(
+        net::features::kThirdPartyStoragePartitioning, toggle);
+
+    // A non-opaque site with SameSite and CrossSite works.
+    std::ignore = BlinkStorageKey(origin, site, nullptr,
+                                  mojom::blink::AncestorChainBit::kSameSite);
+    std::ignore = BlinkStorageKey(origin, site, nullptr,
+                                  mojom::blink::AncestorChainBit::kCrossSite);
+
+    // An opaque site with SameSite works.
+    std::ignore = BlinkStorageKey(origin, opaque_site, nullptr,
+                                  mojom::blink::AncestorChainBit::kSameSite);
+
+    // An opaque site with CrossSite fails.
+    EXPECT_DCHECK_DEATH(
+        BlinkStorageKey(origin, opaque_site, nullptr,
+                        mojom::blink::AncestorChainBit::kCrossSite));
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn
index b4329d5..5fae71c6 100644
--- a/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -77,13 +77,13 @@
     "get_ptr.h",
     "hash_counted_set.h",
     "hash_functions.h",
-    "hash_iterators.h",
     "hash_map.h",
     "hash_set.h",
     "hash_table.cc",
     "hash_table.h",
     "hash_table_deleted_value_type.h",
     "hash_traits.h",
+    "key_value_pair.h",
     "leak_annotations.h",
     "linked_hash_set.h",
     "math_extras.h",
diff --git a/third_party/blink/renderer/platform/wtf/hash_map.h b/third_party/blink/renderer/platform/wtf/hash_map.h
index 124e8552..80b136f8 100644
--- a/third_party/blink/renderer/platform/wtf/hash_map.h
+++ b/third_party/blink/renderer/platform/wtf/hash_map.h
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/platform/wtf/atomic_operations.h"
 #include "third_party/blink/renderer/platform/wtf/construct_traits.h"
 #include "third_party/blink/renderer/platform/wtf/hash_table.h"
+#include "third_party/blink/renderer/platform/wtf/key_value_pair.h"
 
 namespace WTF {
 
@@ -67,8 +68,9 @@
 
 // Note: empty or deleted key values are not allowed, using them may lead to
 // undefined behavior. For pointer keys this means that null pointers are not
-// allowed; for integer keys 0 or -1 can't be used as a key. This restriction
-// can be lifted if you supply custom key traits.
+// allowed; for integer keys 0 or -1 can't be used as a key. You can change
+// the restriction with a custom key hash traits. See hash_traits.h for how to
+// define hash traits.
 template <typename KeyArg,
           typename MappedArg,
           typename KeyTraitsArg = HashTraits<KeyArg>,
@@ -294,14 +296,20 @@
   ~HashMapValuesProxy() = delete;
 };
 
-template <typename KeyTraits, typename MappedTraits>
-struct HashMapValueTraits : KeyValuePairHashTraits<KeyTraits, MappedTraits> {
-  STATIC_ONLY(HashMapValueTraits);
-  static bool IsEmptyValue(
-      const typename KeyValuePairHashTraits<KeyTraits, MappedTraits>::TraitType&
-          value) {
+template <typename KeyTraits, typename ValueTraits>
+struct HashMapValueTraits : KeyValuePairHashTraits<KeyTraits, ValueTraits> {
+  using P = typename KeyValuePairHashTraits<KeyTraits, ValueTraits>::TraitType;
+  static bool IsEmptyValue(const P& value) {
     return IsHashTraitsEmptyValue<KeyTraits>(value.key);
   }
+  // HashTable should never use the following functions/flags of this traits
+  // type. They make sense in the KeyTraits only.
+  static bool Equal(const P&, const P&) = delete;
+  static void ConstructDeletedValue(P&) = delete;
+  static bool IsDeletedValue(const P&) = delete;
+
+ private:
+  static const bool kSafeToCompareToEmptyOrDeleted;
 };
 
 template <typename KeyTraits, typename ValueTraits>
diff --git a/third_party/blink/renderer/platform/wtf/hash_set.h b/third_party/blink/renderer/platform/wtf/hash_set.h
index cd541ef..ad6a0bd 100644
--- a/third_party/blink/renderer/platform/wtf/hash_set.h
+++ b/third_party/blink/renderer/platform/wtf/hash_set.h
@@ -37,6 +37,7 @@
 // undefined behavior. For pointer keys this means that null pointers are not
 // allowed; for integer keys 0 or -1 can't be used as a key. This restriction
 // can be lifted if you supply custom key traits.
+// See hash_traits.h for how to define hash traits.
 template <typename ValueArg,
           typename TraitsArg = HashTraits<ValueArg>,
           typename Allocator = PartitionAllocator>
@@ -199,10 +200,7 @@
     insert(element);
 }
 
-template <typename Value,
-
-          typename Traits,
-          typename Allocator>
+template <typename Value, typename Traits, typename Allocator>
 auto HashSet<Value, Traits, Allocator>::operator=(
     std::initializer_list<ValueType> elements) -> HashSet& {
   *this = HashSet(std::move(elements));
@@ -255,19 +253,13 @@
   return impl_.find(value);
 }
 
-template <typename Value,
-
-          typename Traits,
-          typename Allocator>
+template <typename Value, typename Traits, typename Allocator>
 inline bool HashSet<Value, Traits, Allocator>::Contains(
     ValuePeekInType value) const {
   return impl_.Contains(value);
 }
 
-template <typename Value,
-
-          typename Traits,
-          typename Allocator>
+template <typename Value, typename Traits, typename Allocator>
 template <typename HashTranslator, typename T>
 typename HashSet<Value, Traits, Allocator>::
     iterator inline HashSet<Value, Traits, Allocator>::Find(
@@ -275,10 +267,7 @@
   return impl_.template Find<HashSetTranslatorAdapter<HashTranslator>>(value);
 }
 
-template <typename Value,
-
-          typename Traits,
-          typename Allocator>
+template <typename Value, typename Traits, typename Allocator>
 template <typename HashTranslator, typename T>
 inline bool HashSet<Value, Traits, Allocator>::Contains(const T& value) const {
   return impl_.template Contains<HashSetTranslatorAdapter<HashTranslator>>(
@@ -292,10 +281,7 @@
   return impl_.insert(std::forward<IncomingValueType>(value));
 }
 
-template <typename Value,
-
-          typename Traits,
-          typename Allocator>
+template <typename Value, typename Traits, typename Allocator>
 template <typename HashTranslator, typename T>
 inline typename HashSet<Value, Traits, Allocator>::AddResult
 HashSet<Value, Traits, Allocator>::AddWithTranslator(T&& value) {
diff --git a/third_party/blink/renderer/platform/wtf/hash_table.h b/third_party/blink/renderer/platform/wtf/hash_table.h
index 447302a2..c6b36c11 100644
--- a/third_party/blink/renderer/platform/wtf/hash_table.h
+++ b/third_party/blink/renderer/platform/wtf/hash_table.h
@@ -1183,16 +1183,11 @@
 template <typename Traits,
           typename Allocator,
           typename Value,
-          typename Enable = void>
-struct HashTableBucketInitializer;
-
-template <typename Traits, typename Allocator, typename Value>
-struct HashTableBucketInitializer<
-    Traits,
-    Allocator,
-    Value,
-    std::enable_if_t<!Traits::kEmptyValueIsZero>> {
+          bool = Traits::kEmptyValueIsZero>
+struct HashTableBucketInitializer {
   STATIC_ONLY(HashTableBucketInitializer);
+  static_assert(!Traits::kEmptyValueIsZero);
+
   static void Initialize(Value& bucket) {
     ConstructTraits<Value, Traits, Allocator>::ConstructAndNotifyElement(
         &bucket, Traits::EmptyValue());
@@ -1226,10 +1221,7 @@
 // Specialization when the hash traits for a type have kEmptyValueIsZero = true
 // which indicate that all zero bytes represent an empty object.
 template <typename Traits, typename Allocator, typename Value>
-struct HashTableBucketInitializer<Traits,
-                                  Allocator,
-                                  Value,
-                                  std::enable_if_t<Traits::kEmptyValueIsZero>> {
+struct HashTableBucketInitializer<Traits, Allocator, Value, true> {
   STATIC_ONLY(HashTableBucketInitializer);
   static void Initialize(Value& bucket) {
     // The memset to 0 looks like a slow operation but is optimized by the
@@ -1521,7 +1513,6 @@
 template <typename Key,
           typename Value,
           typename Extractor,
-
           typename Traits,
           typename KeyTraits,
           typename Allocator>
@@ -1622,14 +1613,8 @@
           typename Traits,
           typename KeyTraits,
           typename Allocator>
-void HashTable<Key,
-               Value,
-               Extractor,
-
-               Traits,
-               KeyTraits,
-               Allocator>::DeleteAllBucketsAndDeallocate(ValueType* table,
-                                                         unsigned size) {
+void HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::
+    DeleteAllBucketsAndDeallocate(ValueType* table, unsigned size) {
   // We delete a bucket in the following cases:
   // - It is not trivially destructible.
   // - The table is weak (thus garbage collected) and we are currently marking.
@@ -1842,13 +1827,7 @@
           typename Traits,
           typename KeyTraits,
           typename Allocator>
-void HashTable<Key,
-               Value,
-               Extractor,
-
-               Traits,
-               KeyTraits,
-               Allocator>::clear() {
+void HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::clear() {
   RegisterModification();
   if (!table_)
     return;
@@ -1925,13 +1904,8 @@
           typename Traits,
           typename KeyTraits,
           typename Allocator>
-void HashTable<Key,
-               Value,
-               Extractor,
-
-               Traits,
-               KeyTraits,
-               Allocator>::swap(HashTable& other) {
+void HashTable<Key, Value, Extractor, Traits, KeyTraits, Allocator>::swap(
+    HashTable& other) {
   DCHECK(!AccessForbidden());
   // Following 3 lines swap table_ and other.table_ using atomic stores. These
   // are needed for Oilpan concurrent marking which might trace the hash table
@@ -2264,6 +2238,4 @@
 
 }  // namespace WTF
 
-#include "third_party/blink/renderer/platform/wtf/hash_iterators.h"
-
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_HASH_TABLE_H_
diff --git a/third_party/blink/renderer/platform/wtf/hash_traits.h b/third_party/blink/renderer/platform/wtf/hash_traits.h
index 98c68a19..cdc1242d 100644
--- a/third_party/blink/renderer/platform/wtf/hash_traits.h
+++ b/third_party/blink/renderer/platform/wtf/hash_traits.h
@@ -38,6 +38,38 @@
 
 namespace WTF {
 
+// A hash traits type is required for a type when the type is used as the key
+// or value of a HashTable-based classes. See documentation in
+// GenericHashTraitsBase for the HashTraits API.
+//
+// A hash traits type can be defined as
+// - a specialization of the HashTraits template, which will be automatically
+//   used, or
+// - a standalone hash traits type, which should be passed as the *Traits
+//   template parameters of HashTable-based classes.
+// The former is preferred if the hash traits defines the default hash behavior
+// of the type. The latter is suitable when a type has multiple hash behaviors,
+// e.g. CaseFoldingHashTraits defines an alternative hash behavior of strings.
+//
+// This file contains definitions of hash traits for integral types,
+// floating-point types, enums, raw and smart pointers, std::pair, etc.
+// These types can be used as hash key or value directly.
+//
+// This file also contains hash traits types that can be used as the base class
+// of hash traits of other types.
+//
+// A simple hash traits type for a key type can be like:
+//   template <>
+//   HashTraits<KeyType> : GenericHashTraits<KeyType> {
+//     static unsigned GetHash(const KeyType& key) { ...; }
+//     static KeyType EmptyValue() { ...; }
+//     static KeyType DeletedValue() { ...; }
+//   };
+//
+// A hash traits type for a value type can be even simpler. See documentation
+// in GenericHashTraitsBase for which functions/flags are for key types only
+// (i.e. not needed for a value type).
+//
 template <typename T>
 struct HashTraits;
 
@@ -69,9 +101,11 @@
   static const T& Peek(const T& value) { return value; }
 
   // Computes the hash code.
+  // This is for key types only.
   static unsigned GetHash(const T&) = delete;
 
   // Whether two values are equal. By default, operator== is used.
+  // This is for key types only.
   static bool Equal(const T& a, const T& b) { return a == b; }
 
   // When this is true, the hash table can optimize lookup operations by
@@ -83,6 +117,7 @@
   // is an empty or a deleted value. When T is a pointer type, Equal(a, b) can
   // dereference a and b safely without checking if a or b is nullptr or an
   // invalid pointer that represents the deleted value.
+  // This is for key types only.
   static constexpr bool kSafeToCompareToEmptyOrDeleted = true;
 
   // Defines the empty value which is used to fill unused slots in the hash
@@ -113,17 +148,24 @@
   // and ConstructDeletedValue() when the deleted value can be represented with
   // a value that can be safely and trivially compared/assigned to another
   // value.
+  // This is for key types only.
+  // NOTE: The destructor of the returned value *may not* be called, so the
+  // value should not own any dynamically allocated resources.
   static T DeletedValue() = delete;
 
   // Checks if a given value is a deleted value. If this is defined, the hash
   // table will call this function (through IsHashTraitsDeletedValue()) to check
   // if a slot is deleted. Otherwise `v == DeletedValue()` will be used.
+  // This is for key typess only.
   static bool IsDeletedValue(const T& v) = delete;
 
   // Constructs a deleted value in-place in the given memory space.
   // This must be defined if IsDeletedValue() is defined, and will be called
   // through ConstructHashTraitsDeletedValue(). Otherwise
   // `slot = DeletedValue()` will be used.
+  // This is for key types only.
+  // NOTE: The destructor of the constructed value *will not* be called, so the
+  // value should not own any dynamically allocated resources.
   static void ConstructDeletedValue(T& slot) = delete;
 
   // The starting table size. Can be overridden when we know beforehand that a
@@ -543,7 +585,7 @@
     return T(FirstTraits::EmptyValue(), SecondTraits::EmptyValue());
   }
 
-  static bool IsEmptyValue(const TraitType& value) {
+  static bool IsEmptyValue(const T& value) {
     return IsHashTraitsEmptyValue<FirstTraits>(value.*first_field) &&
            IsHashTraitsEmptyValue<SecondTraits>(value.*second_field);
   }
@@ -592,43 +634,6 @@
 struct HashTraits<std::pair<First, Second>>
     : public PairHashTraits<HashTraits<First>, HashTraits<Second>> {};
 
-template <typename KeyTypeArg, typename ValueTypeArg>
-struct KeyValuePair {
-  typedef KeyTypeArg KeyType;
-  typedef ValueTypeArg ValueType;
-
-  template <typename IncomingKeyType, typename IncomingValueType>
-  KeyValuePair(IncomingKeyType&& key, IncomingValueType&& value)
-      : key(std::forward<IncomingKeyType>(key)),
-        value(std::forward<IncomingValueType>(value)) {}
-
-  template <typename OtherKeyType, typename OtherValueType>
-  KeyValuePair(KeyValuePair<OtherKeyType, OtherValueType>&& other)
-      : key(std::move(other.key)), value(std::move(other.value)) {}
-
-  KeyTypeArg key;
-  ValueTypeArg value;
-};
-
-template <typename K, typename V>
-struct IsWeak<KeyValuePair<K, V>>
-    : std::integral_constant<bool, IsWeak<K>::value || IsWeak<V>::value> {};
-
-template <typename KeyTraitsArg,
-          typename ValueTraitsArg,
-          typename P = KeyValuePair<typename KeyTraitsArg::TraitType,
-                                    typename ValueTraitsArg::TraitType>>
-struct KeyValuePairHashTraits
-    : TwoFieldsHashTraits<P, &P::key, &P::value, KeyTraitsArg, ValueTraitsArg> {
-  using TraitType = P;
-  using KeyTraits = KeyTraitsArg;
-  using ValueTraits = ValueTraitsArg;
-};
-
-template <typename Key, typename Value>
-struct HashTraits<KeyValuePair<Key, Value>>
-    : public KeyValuePairHashTraits<HashTraits<Key>, HashTraits<Value>> {};
-
 // Shortcut of HashTraits<T>::GetHash(), which can deduct T automatically.
 template <typename T>
 unsigned GetHash(const T& key) {
diff --git a/third_party/blink/renderer/platform/wtf/hash_iterators.h b/third_party/blink/renderer/platform/wtf/key_value_pair.h
similarity index 88%
rename from third_party/blink/renderer/platform/wtf/hash_iterators.h
rename to third_party/blink/renderer/platform/wtf/key_value_pair.h
index b050fd9..84a50a92 100644
--- a/third_party/blink/renderer/platform/wtf/hash_iterators.h
+++ b/third_party/blink/renderer/platform/wtf/key_value_pair.h
@@ -23,13 +23,52 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_HASH_ITERATORS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_HASH_ITERATORS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_KEY_VALUE_PAIR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_KEY_VALUE_PAIR_H_
+
+#include <utility>
 
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace WTF {
 
+template <typename KeyTypeArg, typename ValueTypeArg>
+struct KeyValuePair {
+  using KeyType = KeyTypeArg;
+  using ValueType = ValueTypeArg;
+
+  template <typename IncomingKeyType, typename IncomingValueType>
+  KeyValuePair(IncomingKeyType&& key, IncomingValueType&& value)
+      : key(std::forward<IncomingKeyType>(key)),
+        value(std::forward<IncomingValueType>(value)) {}
+
+  template <typename OtherKeyType, typename OtherValueType>
+  KeyValuePair(KeyValuePair<OtherKeyType, OtherValueType>&& other)
+      : key(std::move(other.key)), value(std::move(other.value)) {}
+
+  KeyTypeArg key;
+  ValueTypeArg value;
+};
+
+template <typename K, typename V>
+struct IsWeak<KeyValuePair<K, V>>
+    : std::integral_constant<bool, IsWeak<K>::value || IsWeak<V>::value> {};
+
+template <typename KeyTraitsArg,
+          typename ValueTraitsArg,
+          typename P = KeyValuePair<typename KeyTraitsArg::TraitType,
+                                    typename ValueTraitsArg::TraitType>>
+struct KeyValuePairHashTraits
+    : TwoFieldsHashTraits<P, &P::key, &P::value, KeyTraitsArg, ValueTraitsArg> {
+  using TraitType = P;
+  using KeyTraits = KeyTraitsArg;
+  using ValueTraits = ValueTraitsArg;
+};
+
+template <typename Key, typename Value>
+struct HashTraits<KeyValuePair<Key, Value>>
+    : public KeyValuePairHashTraits<HashTraits<Key>, HashTraits<Value>> {};
+
 template <typename HashTableType, typename KeyType, typename MappedType>
 struct HashTableConstKeysIterator;
 template <typename HashTableType, typename KeyType, typename MappedType>
@@ -399,4 +438,4 @@
 
 }  // namespace WTF
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_HASH_ITERATORS_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_KEY_VALUE_PAIR_H_
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 78f893af..36ef29c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2988,7 +2988,8 @@
 crbug.com/webrtc/10567 external/wpt/webrtc/simulcast/setParameters-encodings.https.html [ Failure Pass ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/626703 [ Mac11 ] external/wpt/url/IdnaTestV2.window.html [ Timeout Failure ]
+crbug.com/626703 [ Win11 ] external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html [ Failure Timeout ]
+crbug.com/626703 [ Mac11 ] external/wpt/url/IdnaTestV2.window.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/css/css-box/margin-trim/block-container-non-adjoining-item.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-box/margin-trim/flex-block-end-trimmed-only.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-box/margin-trim/flex-block-start-trimmed-only.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 76bbf643..31f96966 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -2624,6 +2624,13 @@
         {}
        ]
       ],
+      "spanner-inside-inline-in-overflowed-container.html": [
+       "d53d295271ce9e3a05d4a45402a860663db0beb2",
+       [
+        null,
+        {}
+       ]
+      ],
       "specified-height-with-just-spanner-and-oof.html": [
        "3c4d51b0f433f4cbdb9e76f4301162924b6918f1",
        [
@@ -3096,6 +3103,13 @@
         {}
        ]
       ],
+      "block-aspect-ratio-051-crash.html": [
+       "763d1cf51fd8810154eeae56c023cd8926a517f8",
+       [
+        null,
+        {}
+       ]
+      ],
       "large-aspect-ratio-crash.html": [
        "a1e69cdd7c80bfa22f0f911c0b38ee27d5345496",
        [
@@ -91243,6 +91257,58 @@
         {}
        ]
       ],
+      "oof-in-cell-with-alignment-001.html": [
+       "7933012cb6aeccaf8d8a8cf1d35c8ee0d490a04f",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "oof-in-cell-with-alignment-002.html": [
+       "1b9629c9ed9255aeab5649b17759fe46d6b16d46",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "oof-in-cell-with-alignment-003.html": [
+       "8d026e42fcdeae71efc5c51b108fd61f93d3a318",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "oof-in-cell-with-alignment-004.html": [
+       "5805415de7d307ebe4fc90b0a1233c4a243f0d92",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "overflow-scroll-row.html": [
        "8ed379e5dd29681704c63e46b2702b1536f789b8",
        [
@@ -131175,6 +131241,19 @@
           {}
          ]
         ],
+        "masonry-item-placement-008.html": [
+         "c68a9787b8330afd85bb01a7a48b9067df903ba9",
+         [
+          null,
+          [
+           [
+            "/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-008-ref.html",
+            "=="
+           ]
+          ],
+          {}
+         ]
+        ],
         "masonry-rows-item-placement-auto-flow-next-001.html": [
          "c425490d2d8f464e9fae0a1777c4c8366cb283af",
          [
@@ -149980,6 +150059,32 @@
        {}
       ]
      ],
+     "multicol-span-all-018.html": [
+      "7dbfe3a495923adcf1e6b73837a2ffa1414f2874",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "multicol-span-all-019.html": [
+      "e1a0de3854b17a4a02fc7d57d24d46b48cb5b15c",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "multicol-span-all-block-sibling-003.xht": [
       "abaa45f0a85023f3f07a9db483629b74d2b09d71",
       [
@@ -166735,6 +166840,58 @@
         {}
        ]
       ],
+      "block-aspect-ratio-052.html": [
+       "3d36835cd95c41525b15af7cc103a1f15d99ad21",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "block-aspect-ratio-053.html": [
+       "ce1411e027e00fd92cd990bef9b42883948627cb",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "block-aspect-ratio-054.html": [
+       "c80f91f5cb9d4011b479be4e879eafc2d71be15d",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "block-aspect-ratio-055.html": [
+       "19af2a39ab35076ca6a55c72aa49f78200931f60",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "block-aspect-ratio-with-margin-collapsing-001.html": [
        "78a0418fe285da58030cdd863460add0533e6af5",
        [
@@ -176563,7 +176720,7 @@
        ]
       ],
       "line-break-normal-015a.xht": [
-       "db3ee2a586fb90433f85b626cf05c2da5eb143cb",
+       "d2e0fe34995f43ffc1e4da10209efb9a71912ceb",
        [
         null,
         [
@@ -176758,7 +176915,7 @@
        ]
       ],
       "line-break-strict-015a.xht": [
-       "9114120bc86e2b629a555539fd97682c8bfe6d6e",
+       "ad31e4fc54d80cd815e09889ae11a6bc633d80a8",
        [
         null,
         [
@@ -182878,6 +183035,19 @@
         {}
        ]
       ],
+      "break-spaces-011.html": [
+       "8c40a31a35688512742727639c11091ac8163dd8",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "break-spaces-051.html": [
        "2626511808335491910d3c14d752bb08494fcbc2",
        [
@@ -221534,6 +221704,19 @@
        {}
       ]
      ],
+     "rtl-with-scrollbar.html": [
+      "d235a3f6990f12db8fcaabc0353b98662c47918f",
+      [
+       null,
+       [
+        [
+         "/css/css-view-transitions/rtl-with-scrollbar-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "scroller-child-abspos.html": [
       "952a2679aabdbbc56df43ff5256f0297f317ad0d",
       [
@@ -262883,16 +263066,6 @@
    }
   },
   "support": {
-   ".cache": {
-    "gitignore2.json": [
-     "6f2df68aa63828ae35b1cfa0d06aa1de2ba5b3a4",
-     []
-    ],
-    "mtime.json": [
-     "7cdaf2d4e83802cd8c9d94d3e95cc9622c64698e",
-     []
-    ]
-   },
    ".gitignore": [
     "d93e645d547894b50149d3726de2654957b6e06f",
     []
@@ -263158,18 +263331,6 @@
      "545f0bec6d9822e7862fc4010fb8d52d3dc4b768",
      []
     ],
-    "back-forward-cache-open-connection.window.js.ini": [
-     "e9ec6bf98544bbbf3bf03b0aca3ccbfdef063eb6",
-     []
-    ],
-    "back-forward-cache-open-transaction.window-expected.txt": [
-     "4c5a32a551ae31f506dbdaeda997e17217db4165",
-     []
-    ],
-    "back-forward-cache-open-transaction.window.js.ini": [
-     "6f0150ab787c0be71138e2a4d72992f5adb5e187",
-     []
-    ],
     "database-names-by-origin.html.ini": [
      "21e89fe0a7caf86946c6fe5d345b6fb4b68defa9",
      []
@@ -278889,6 +279050,46 @@
       "dc7f77f2b3441ebee25f3e40a9480b668ee79ea4",
       []
      ],
+     "anchor-scroll-basics.tentative.html.ini": [
+      "b11398997c0d844481a3a872f1eb06bb4e6fe0cf",
+      []
+     ],
+     "anchor-scroll-nested.tentative.html.ini": [
+      "0e9d17885a766709ef56f976532bf44a6bb50d24",
+      []
+     ],
+     "anchor-scroll-update-001.tentative.html.ini": [
+      "0a16da344f6311c60b7bbe3d246ea0836c2aa5b8",
+      []
+     ],
+     "anchor-scroll-update-002.tentative.html.ini": [
+      "08b46c027fbb4950767495b012c0900167f56401",
+      []
+     ],
+     "anchor-scroll-update-003.tentative.html.ini": [
+      "4c98b567952ce7e9a71e516e3f8f8ed7ca439639",
+      []
+     ],
+     "anchor-scroll-update-004.tentative.html.ini": [
+      "64801cfb7837b8cf5956097f3921e99b9a3b6326",
+      []
+     ],
+     "anchor-scroll-update-005.tentative.html.ini": [
+      "bc7e891e0155face76900eedf352874697e9dcb6",
+      []
+     ],
+     "anchor-scroll-update-006.tentative.html.ini": [
+      "d0ce399276e220f1310ab6896ec3664161d413cf",
+      []
+     ],
+     "anchor-scroll-vlr.tentative.html.ini": [
+      "c3f96ea242af7a20bc5ec588f8faea1b161384ad",
+      []
+     ],
+     "anchor-scroll-vrl.tentative.html.ini": [
+      "4f3fe39eed570ad07ac3bbd3dace1d25d862999e",
+      []
+     ],
      "reference": {
       "anchor-scroll-fixedpos-ref.html": [
        "e73354df72dac33f7a94eaef445e80ec61e3976a",
@@ -285238,10 +285439,6 @@
        "298ed182cec84b130ce3edf739dc9bd3303b3906",
        []
       ],
-      "at-container-serialization-expected.txt": [
-       "5d60cc54acfd860a14759d93c9c5724452a182fb",
-       []
-      ],
       "at-container-serialization.html.ini": [
        "45e977bf814d2ab876172b3e16403876a01d451a",
        []
@@ -285290,10 +285487,6 @@
        "e760d717b2fc4cf6775c0ba0d86daaf6783f5c50",
        []
       ],
-      "idlharness-expected.txt": [
-       "91e80aec9b76951b4c70256f2b0d7932806ee7cc",
-       []
-      ],
       "idlharness.html.ini": [
        "c2b2fb5c1aef328c7fccf5d969e17630c7853b20",
        []
@@ -290962,7 +291155,7 @@
       []
      ],
      "cjk-kerning.html.ini": [
-      "cf10f40714d0b64c83f8037bd93071a2b6b95c94",
+      "5f57054ae95563dfd924ace4a18776bd51a65c77",
       []
      ],
      "crash-large-grapheme-cluster.html.ini": [
@@ -300762,6 +300955,10 @@
          "50236046fb0610dcac5723f212ab69a9155847b1",
          []
         ],
+        "masonry-item-placement-008-ref.html": [
+         "e14ca3173abdda981bf7ba7e3a7d5c4760a72190",
+         []
+        ],
         "masonry-rows-item-placement-auto-flow-next-001-ref.html": [
          "cbb3e825a4b76d28dc6e93b53eeeea1b5e40a118",
          []
@@ -316714,7 +316911,7 @@
         []
        ],
        "line-break-normal-015a-ref.xht": [
-        "941e18242d9868a45dbde986a189feecaed8b05c",
+        "23cf1487b1b3c11d67787b5d4dfc422f61495254",
         []
        ],
        "line-break-normal-015b-ref.xht": [
@@ -316770,7 +316967,7 @@
         []
        ],
        "line-break-strict-015a-ref.xht": [
-        "f8a1222a3334edb8117e9141359958c9b8f51748",
+        "252818c22a0c0cce5d2844a283d447a32f4b5420",
         []
        ],
        "line-break-strict-015b-ref.xht": [
@@ -318947,7 +319144,7 @@
        []
       ],
       "text-transform-capitalize-007.html.ini": [
-       "a29c6839a53a872c397c39993b88ef3cc8ef182a",
+       "86896271d145aabe41d03d4e8f8e896490c5b1f8",
        []
       ],
       "text-transform-capitalize-010.html.ini": [
@@ -318963,7 +319160,7 @@
        []
       ],
       "text-transform-capitalize-018.html.ini": [
-       "87e51404e16bbebfa59694f95dfaa34426e0f4b4",
+       "5e9565445a693b0bac1d54974434291a0d9604d7",
        []
       ],
       "text-transform-capitalize-026.html.ini": [
@@ -325048,6 +325245,10 @@
        "2a170629651d9defa1951ceceeab784ca50ea285",
        []
       ],
+      "kind-of-widget-fallback-input-submit-border-inline-start-color-001.html.ini": [
+       "ba656066415036934497094e7fa4efae3845dd9c",
+       []
+      ],
       "kind-of-widget-fallback-input-submit-border-inline-start-style-001.html.ini": [
        "57acbdd3666e3a4965d10651a009475c0449b77c",
        []
@@ -325240,6 +325441,14 @@
        "f3bbc312a7def4d12ce50b151b0578d9fd76a0af",
        []
       ],
+      "kind-of-widget-fallback-textarea-border-block-end-style-001.html.ini": [
+       "10d4e093393272fd1fa437f1a4147d9af353598f",
+       []
+      ],
+      "kind-of-widget-fallback-textarea-border-bottom-width-001.html.ini": [
+       "ddeb070c64563f1c0545dbbfc26a2f318730b492",
+       []
+      ],
       "kind-of-widget-fallback-textarea-border-image-outset-001.html.ini": [
        "c7113a77e18e06f4043614fb70e43ea3b7c34f93",
        []
@@ -326072,7 +326281,7 @@
       []
      ],
      "outline-025.html.ini": [
-      "c5515ab0e129b5c55bd8b4e73f4750c363cae17d",
+      "cc571ab0463da9cf32819f1e820b5ef4b9ce9ab4",
       []
      ],
      "outline-026.html.ini": [
@@ -328370,7 +328579,7 @@
       []
      ],
      "3d-transform-incoming.html.ini": [
-      "b2c8041faebaa1101764cd0ea775cc455cbf8d62",
+      "9a9a97581bc23c151b4b4ff217603b62e9e5dd74",
       []
      ],
      "3d-transform-outgoing-ref.html": [
@@ -328378,7 +328587,7 @@
       []
      ],
      "3d-transform-outgoing.html.ini": [
-      "c3360cdd650247990dedf496b5df445c9d191aba",
+      "e44ce420ef7532f1254358fb68f8a6fb429f574b",
       []
      ],
      "break-inside-avoid-child-ref.html": [
@@ -328402,7 +328611,7 @@
       []
      ],
      "content-smaller-than-box-size.html.ini": [
-      "dd6b575d76f0e1dfb4cb56a327ea17f726b99d7a",
+      "9ff4ca3ec0b3134c2dec8269f7d7230c94894d3f",
       []
      ],
      "content-visibility-auto-shared-element-ref.html": [
@@ -328410,7 +328619,7 @@
       []
      ],
      "content-visibility-auto-shared-element.html.ini": [
-      "17013c52becacd1993791d04cb56ab88f84c647a",
+      "cf1ea938991eae99ee4109439f934d5e0f4ee063",
       []
      ],
      "content-with-clip-max-texture-size-ref.html": [
@@ -328418,7 +328627,7 @@
       []
      ],
      "content-with-clip-max-texture-size.html.ini": [
-      "9adefd74cdd6b0dfc74d5b6bd340137511be6705",
+      "243c1b5ef4502506132f9ea05d027bb40cf3aa8d",
       []
      ],
      "content-with-clip-ref.html": [
@@ -328430,11 +328639,11 @@
       []
      ],
      "content-with-clip-root.html.ini": [
-      "19599dc96caccb35a5402e834be40e13637dc483",
+      "39d4ab411c0abfa3c65526be1290db84aab20d35",
       []
      ],
      "content-with-clip.html.ini": [
-      "046323dcb0f122aa55883dfbee42ee17564edd14",
+      "dc69b5b7ae54ba9f16616a6e5d23948784b19ab7",
       []
      ],
      "content-with-inline-child-ref.html": [
@@ -328442,7 +328651,7 @@
       []
      ],
      "content-with-inline-child.html.ini": [
-      "3c9eeb041ddc1786cad0c6dbbc11fd3474d2b9df",
+      "64518753354810d659f570d879557213b865162d",
       []
      ],
      "content-with-overflow-ref.html": [
@@ -328454,7 +328663,7 @@
       []
      ],
      "content-with-transform-new-image.html.ini": [
-      "8ba8457eec10b8417d9952953a7b4d017df67701",
+      "632ee128645004501f32dd2908753138cd6ec6cf",
       []
      ],
      "content-with-transform-old-image.html.ini": [
@@ -328474,11 +328683,11 @@
       []
      ],
      "css-tags-paint-order-with-entry.html.ini": [
-      "2baa468e77628b48ce04aacd51e12e1250d82a70",
+      "6177a0562637e4a3a044ea5722cc59bf019bc476",
       []
      ],
      "css-tags-paint-order.html.ini": [
-      "0e7c2730e21a7fc9cc9d1e2ce6a6c47da53253aa",
+      "8bfa895e0d2b4a4c0643bcba165a7173dfda6053",
       []
      ],
      "css-tags-shared-element-ref.html": [
@@ -328486,7 +328695,7 @@
       []
      ],
      "css-tags-shared-element.html.ini": [
-      "3c6300dd48026db6b2196a301f3b4150e077cfd3",
+      "ce28c4eeb2f70021e6b44c4b4f5995c51ae65a37",
       []
      ],
      "dialog-in-rtl-iframe-ref.html": [
@@ -328494,15 +328703,15 @@
       []
      ],
      "dialog-in-rtl-iframe.html.ini": [
-      "1620904396e6ae54e4eb03c35b3b69a4d8cdf6dd",
+      "cf33837c684b1e3bcd1d9c9b6cdfc444cd7f635f",
       []
      ],
      "dialog-in-top-layer-during-transition-new.html.ini": [
-      "17cf0b949be7e0f1db0cd42d636e6a262ec7d65f",
+      "ce48fcbc7b57465de12639e57f10166e77d8f7bb",
       []
      ],
      "dialog-in-top-layer-during-transition-old.html.ini": [
-      "3a4d114bbe30f86e28df3580d50f79c0745ccb6c",
+      "333ffd9c263db89e56c000e185c9c9ca65ccfeb0",
       []
      ],
      "dialog-in-top-layer-during-transition-ref.html": [
@@ -328514,7 +328723,7 @@
       []
      ],
      "duplicate-tag-rejects-start.html.ini": [
-      "718c4bf9b7473da6b22d6b275b99e4ba85533395",
+      "f734d71bb711b98be396424bd50493ae607f1cdf",
       []
      ],
      "element-with-overflow-ref.html": [
@@ -328522,11 +328731,11 @@
       []
      ],
      "element-with-overflow.html.ini": [
-      "ad317c23ecd80b89a7363babf7f379c9a9878f8f",
+      "e399542a7084ac41e3249f0e6ce6f975a607200f",
       []
      ],
      "event-pseudo-name.html.ini": [
-      "132fa88bf335503a653fef3b1ab1cd4af4461574",
+      "9f532e58ceaab151e8557f2f18bfcfc458a84f48",
       []
      ],
      "far-away-capture-ref.html": [
@@ -328534,11 +328743,11 @@
       []
      ],
      "far-away-capture.html.ini": [
-      "01ebbf177c3e6489f6434170e63a68e097f58978",
+      "d30709276cd7375b8a016ce1461e1d1fb7b145ea",
       []
      ],
      "hit-test-unpainted-element-from-point.html.ini": [
-      "07da5c68f09db6fccf96a5dc1aa794ca8219f807",
+      "83a48913e2486a26dc63d8417d15600317a385bc",
       []
      ],
      "hit-test-unpainted-element-ref.html": [
@@ -328546,7 +328755,7 @@
       []
      ],
      "hit-test-unpainted-element.html.ini": [
-      "816eb7f0a792850f1e9b12670e92e5b10169ac23",
+      "36ba25cad983b904818cd2c0fb7c91708d6f0c52",
       []
      ],
      "hit-test-unrelated-element-ref.html": [
@@ -328554,7 +328763,7 @@
       []
      ],
      "hit-test-unrelated-element.html.ini": [
-      "dca27ccae7c39cbea267fbaacb93a550b94add3d",
+      "1061e7d5226ee7ffc295856ca5e6b5dcbc565670",
       []
      ],
      "iframe-transition-ref.html": [
@@ -328586,11 +328795,11 @@
       []
      ],
      "japanese-tag.html.ini": [
-      "3b8aad5ac4e1b856c0cf44e06cf22200240c6290",
+      "e8d77cf2b973f850397d5e88c3e2b9b4eceb2eb6",
       []
      ],
      "mix-blend-mode-only-on-transition.html.ini": [
-      "c2b2bb8bf30386445a33e58cb2d28bdf6493ee1f",
+      "76ff933d4bf224b0b30e2288eae00085c9577086",
       []
      ],
      "new-and-old-sizes-match-ref.html": [
@@ -328598,7 +328807,7 @@
       []
      ],
      "new-and-old-sizes-match.html.ini": [
-      "601e19b5b6f425e6873a272e5227ff893ffa7e00",
+      "6b1a312637ee3c77b98c3cdc5cadf4d742960914",
       []
      ],
      "new-content-captures-clip-path-ref.html": [
@@ -328606,7 +328815,7 @@
       []
      ],
      "new-content-captures-clip-path.html.ini": [
-      "857d28d59b2465475483cfefc9430b5640fd63c9",
+      "5e70c3f4d3c24862545109ef2476e135bdfab920",
       []
      ],
      "new-content-captures-different-size-ref.html": [
@@ -328622,7 +328831,7 @@
       []
      ],
      "new-content-captures-opacity.html.ini": [
-      "bb2bfdd1762ce7a2b4b0782637bf6df588ef8e95",
+      "d7050b65f96330547518a1c4d9f4550b7cf14912",
       []
      ],
      "new-content-captures-root-ref.html": [
@@ -328630,7 +328839,7 @@
       []
      ],
      "new-content-captures-root.html.ini": [
-      "c7f61f9fcf34056dfd5d974de38ccee978e61700",
+      "81041064ae9dd711b5a5d17f0bb09ecb552a941e",
       []
      ],
      "new-content-container-writing-modes-ref.html": [
@@ -328638,7 +328847,7 @@
       []
      ],
      "new-content-container-writing-modes.html.ini": [
-      "c3e6f5457c4455baed463bbd6a624862854ea596",
+      "1fd8d8a3b48099d8e4844649b6942f917b47add1",
       []
      ],
      "new-content-element-writing-modes-ref.html": [
@@ -328646,7 +328855,7 @@
       []
      ],
      "new-content-element-writing-modes.html.ini": [
-      "83d5122a968b3c18026d23ea902bc7cca39a7f4f",
+      "9ab0bda0248a35a14bec97726283f022e0473b5e",
       []
      ],
      "new-content-has-scrollbars-ref.html": [
@@ -328658,7 +328867,7 @@
       []
      ],
      "new-content-intrinsic-aspect-ratio.html.ini": [
-      "fa18c60023d714471cc7816cca3c1a820af84951",
+      "dd8121062b36f51c0fa600189adf4b6f97f99a35",
       []
      ],
      "new-content-is-empty-div-ref.html": [
@@ -328666,15 +328875,15 @@
       []
      ],
      "new-content-is-empty-div.html.ini": [
-      "39b37c5ae3ff81bb6d1ee14df6cc0781e14fe173",
+      "d2002da6ff79473b48025456b05eb1d5782c6fd0",
       []
      ],
      "new-content-object-fit-fill.html.ini": [
-      "222e6b5c8916391f27fea05354584c3867d46ef2",
+      "aafa8271b8ce984fd97ba8dd6ab5fce29c0f3d64",
       []
      ],
      "new-content-object-fit-none.html.ini": [
-      "f16f679da4e15e31b8a727e23ec83d38d06bbc69",
+      "9513d2b6d137af381fa4bacfa687a083602f4714",
       []
      ],
      "new-content-object-view-box-clip-path-ref.html": [
@@ -328686,11 +328895,11 @@
       []
      ],
      "new-content-object-view-box-clip-path-reference.html.ini": [
-      "ae0ce744792eec299fe577f1e5f5c7065e6dacff",
+      "85a247eaa98969cc55a31555e106795b98f85590",
       []
      ],
      "new-content-object-view-box-clip-path.html.ini": [
-      "5592e6539db6b79af7d7afed71555a321d2ea448",
+      "574b248cefb4a1e9ccb433f304690ff0a617791d",
       []
      ],
      "new-content-object-view-box-overflow-clipped-ref.html": [
@@ -328698,7 +328907,7 @@
       []
      ],
      "new-content-object-view-box-overflow-clipped.html.ini": [
-      "ab8549382b281a3787906d0cf07ec7a18535d01e",
+      "4aa3c3ed9228ea0154ecd07c55c1836c538a9b4b",
       []
      ],
      "new-content-object-view-box-overflow-ref.html": [
@@ -328706,7 +328915,7 @@
       []
      ],
      "new-content-object-view-box-overflow.html.ini": [
-      "123812233d4d73a1efd8a7891e75477438d3c5ce",
+      "8007b36cfc8e6c5445ea086f4f79707261de36a4",
       []
      ],
      "new-content-scaling-ref.html": [
@@ -328714,15 +328923,15 @@
       []
      ],
      "new-content-scaling.html.ini": [
-      "5793134f24228d9b772f03d63bd4322adcb301d5",
+      "5829a441cc1ce805ffcbfc040eaeaceb2f8ccdca",
       []
      ],
      "new-content-with-overflow-zoomed.html.ini": [
-      "268e9974922bde5f73f1cd1b235b5d001be9dc68",
+      "e911e365a1d6fc539b2f64c5a481cbda9c50a91c",
       []
      ],
      "new-content-with-overflow.html.ini": [
-      "e5e6fae26026c7db4f2b21db2f247abfc6e1d5ab",
+      "1da0e28519b1e2ad8e1f4d66fb093e5248474754",
       []
      ],
      "new-element-on-start-ref.html": [
@@ -328730,7 +328939,7 @@
       []
      ],
      "new-element-on-start.html.ini": [
-      "852b47a736499052572ce864cea287a679588792",
+      "1f994c0122086f05873b7d7f40d596014fa858e2",
       []
      ],
      "new-root-vertical-writing-mode-ref.html": [
@@ -328738,15 +328947,15 @@
       []
      ],
      "new-root-vertical-writing-mode.html.ini": [
-      "2f7cbaf31ae7339a3514d8f55bbc1e11cee6006d",
+      "0f259cb76bdf8b332c734d6b5ad3c6d2c64cb5f5",
       []
      ],
      "no-containment-on-new-element-mid-transition.html.ini": [
-      "ca7dd2e55f554a7e5d175dcc6c9a2d210f067f0f",
+      "3501cc7a93eece1083d52412199717eaf67d50e3",
       []
      ],
      "no-containment-on-new-element.html.ini": [
-      "68916853bf5b00670d4989ae606ddfe20bdb4b7e",
+      "a188f1c5b384c5428a5c84157bb682c6541ace85",
       []
      ],
      "no-containment-on-old-element.html.ini": [
@@ -328754,7 +328963,7 @@
       []
      ],
      "no-crash-set-exception.html.ini": [
-      "df3c99e2b337886563280071be2ee1f5910288d8",
+      "d7484cdd99d021018bcdd4fc1549e0b1cf13e201",
       []
      ],
      "no-css-animation-while-render-blocked.html.ini": [
@@ -328770,7 +328979,7 @@
       []
      ],
      "no-root-capture.html.ini": [
-      "17790fab03f9038f59c357e7095f52e7b3eadacd",
+      "8a6a28cafe93907b816012e846a41af893f0111c",
       []
      ],
      "nothing-captured-ref.html": [
@@ -328778,11 +328987,11 @@
       []
      ],
      "nothing-captured.html.ini": [
-      "32b14d18fcbf7754845e180e5203a58927c49857",
+      "1210b39415352bc4e0ee88742fe1249c7201c2f8",
       []
      ],
      "object-view-box-new-image.html.ini": [
-      "a944f19c681b9f430585497635bbbc6db0e29ba6",
+      "3faa887468713f2120f82ffb9517b638df78aab7",
       []
      ],
      "object-view-box-old-image.html.ini": [
@@ -328798,7 +329007,7 @@
       []
      ],
      "old-content-captures-clip-path.html.ini": [
-      "660a6e5a4e5785bf859044663bc1a7d8e29ff691",
+      "67fc6d8cbb1b067eee03844932424475ae95b41a",
       []
      ],
      "old-content-captures-different-size-ref.html": [
@@ -328814,7 +329023,7 @@
       []
      ],
      "old-content-captures-opacity.html.ini": [
-      "8c707afe7044263618981aef492425c3198cf150",
+      "8295d746ca21a8a8f401d7907ddac73b3bef0e67",
       []
      ],
      "old-content-captures-root-ref.html": [
@@ -328822,7 +329031,7 @@
       []
      ],
      "old-content-captures-root.html.ini": [
-      "1ad03fc8d3bbb320d11bfccf757bca2415f3294d",
+      "5c179f0e34fcbad379344661a3fa46252a497fdc",
       []
      ],
      "old-content-container-writing-modes-ref.html": [
@@ -328830,7 +329039,7 @@
       []
      ],
      "old-content-container-writing-modes.html.ini": [
-      "62b0617ee8b476b350c2d310bd69e4962a01b0b1",
+      "5155113a869d0d98e870d154265a1291ae30a23b",
       []
      ],
      "old-content-element-writing-modes-ref.html": [
@@ -328838,7 +329047,7 @@
       []
      ],
      "old-content-element-writing-modes.html.ini": [
-      "27febda88cedbea80fca52a5b6d0b775824ae8b9",
+      "e77d2464e45489b738257b2cc2099518702555d8",
       []
      ],
      "old-content-has-scrollbars-ref.html": [
@@ -328850,7 +329059,7 @@
       []
      ],
      "old-content-intrinsic-aspect-ratio.html.ini": [
-      "59af5df2881c1b544f36cdeec529ac094a2b6d9a",
+      "943ad7c2bfcb338438f528857cd5740fcf1220ad",
       []
      ],
      "old-content-is-empty-div-ref.html": [
@@ -328858,15 +329067,15 @@
       []
      ],
      "old-content-is-empty-div.html.ini": [
-      "5739224dab6d1028fa52e199195e1cc9e999ed49",
+      "cf25b03828b7121cb910be1d0aef5938d3796427",
       []
      ],
      "old-content-object-fit-fill.html.ini": [
-      "9b409d736cdbc4928c4b1628db034ce6ab620743",
+      "d0d58886fd7582aa7c180cf0c89febe7354699fb",
       []
      ],
      "old-content-object-fit-none.html.ini": [
-      "69a6229882fd79e20db089a3275d087fedc0401d",
+      "b561acf3a0253b241947b93a27cf01325f75285a",
       []
      ],
      "old-content-object-view-box-clip-path-ref.html": [
@@ -328878,11 +329087,11 @@
       []
      ],
      "old-content-object-view-box-clip-path-reference.html.ini": [
-      "5d2953f23d23d71855e0c503769655508955c108",
+      "a1662c49893e832f7f0af88c5803d0b531fc8a99",
       []
      ],
      "old-content-object-view-box-clip-path.html.ini": [
-      "f9e6bff64d2a7acc646aa4e728a2d698a70ecbb3",
+      "2d2073bfad8c0c6ece3f6167d2c31e006e959fcb",
       []
      ],
      "old-content-object-view-box-overflow-ref.html": [
@@ -328890,15 +329099,15 @@
       []
      ],
      "old-content-object-view-box-overflow.html.ini": [
-      "0f369bb03e2c2cbb6f087bd517d0c5bf7689feea",
+      "547f9dae87abd8e61e512ad8bdfc1324201bbfde",
       []
      ],
      "old-content-with-overflow-zoomed.html.ini": [
-      "fd9d6e2b9e56976f8456c1c45fcf8dc7ee526412",
+      "9786f85019a397debf8d9fbdd8938020df61228c",
       []
      ],
      "old-content-with-overflow.html.ini": [
-      "7381b140cae7b78dbb7c9c31dc35d337cb702120",
+      "f3c51a4e61726eff1f8a368a416e17e853c8dda7",
       []
      ],
      "old-root-vertical-writing-mode-ref.html": [
@@ -328906,7 +329115,7 @@
       []
      ],
      "old-root-vertical-writing-mode.html.ini": [
-      "4500fd227965e9afb6e2dfcf196044167db7c294",
+      "92d2dd38005ef9f32fba6adda65db117a93bed54",
       []
      ],
      "only-child-group.html.ini": [
@@ -328940,19 +329149,19 @@
       ]
      },
      "paused-animation-at-end.html.ini": [
-      "eba4b15b237f6ee6b1061e3a451e7a51e96e1626",
+      "ecfe8d2631f5dfe7f5ca506cb619fde97ac71c49",
       []
      ],
      "pseudo-computed-style-stays-in-sync-with-new-element.html.ini": [
-      "d28519d677e7408251d3c1b56876ca2e12b22661",
+      "4c1391a2d721b9c5a3e7aeca604ab1c74fe0e1ff",
       []
      ],
      "pseudo-get-computed-style.html.ini": [
-      "a2886dced835ebf5c98bbacb3e1fb03311826631",
+      "8b54ee4550e887d2456a6492081495c97eca18f6",
       []
      ],
      "ready_resolves_after_dom_before_raf.html.ini": [
-      "8069d342705326fbe126346027df8baff8b079fb",
+      "4b7c244a869b13fde999f85bdd44d19fdf5f7884",
       []
      ],
      "root-captured-as-different-tag-ref.html": [
@@ -328960,7 +329169,7 @@
       []
      ],
      "root-captured-as-different-tag.html.ini": [
-      "45c9965a043db5215ba33599e2dddcd9a7036b70",
+      "da70aa92c865bb515a5d375ee7e4cc03db91d3de",
       []
      ],
      "root-scrollbar-with-fixed-background-ref.html": [
@@ -328968,7 +329177,7 @@
       []
      ],
      "root-scrollbar-with-fixed-background.html.ini": [
-      "c5477ecf463ff7374e6940233c353baeca3218b3",
+      "25af7d4de2f800a9a601baad92c04110dcd9ac8b",
       []
      ],
      "root-style-change-during-animation-ref.html": [
@@ -328976,7 +329185,7 @@
       []
      ],
      "root-style-change-during-animation.html.ini": [
-      "4e8a35d76ce8bd545bfd5f764a593335965ee281",
+      "ff0a6d81749b4c3219b7b27de6034deb9f81c3bf",
       []
      ],
      "root-to-shared-animation-end-ref.html": [
@@ -328984,7 +329193,7 @@
       []
      ],
      "root-to-shared-animation-end.html.ini": [
-      "6d4d024b6c14f92a945680776813324864306c85",
+      "4cba721896a73ab45a7a77d806be619ed6e77c6e",
       []
      ],
      "root-to-shared-animation-incoming-ref.html": [
@@ -328992,7 +329201,7 @@
       []
      ],
      "root-to-shared-animation-incoming.html.ini": [
-      "65ef17cbdbfb02042304761e759f147b5114ac33",
+      "6f70e52930593128ae6ddbee4ee4e9061a9ab425",
       []
      ],
      "root-to-shared-animation-start-ref.html": [
@@ -329000,7 +329209,15 @@
       []
      ],
      "root-to-shared-animation-start.html.ini": [
-      "79aee8a098997542f8492d15d63e028b65562e52",
+      "312347064b525a7b1a06c7ac0eb52519c958e5d2",
+      []
+     ],
+     "rtl-with-scrollbar-ref.html": [
+      "c429136a2d21ec95f42ec75ef29ead03a5509166",
+      []
+     ],
+     "rtl-with-scrollbar.html.ini": [
+      "76ca4c534aceda7ec1e4d718fdf9f7254426c707",
       []
      ],
      "scroller-child-abspos-ref.html": [
@@ -329048,11 +329265,11 @@
       []
      ],
      "set-universal-specificity.html.ini": [
-      "29a87934234965bb0a5f582160b3e0dde6620b1b",
+      "c1b05cf4470687abd31418c899895d2cb0a50c1f",
       []
      ],
      "style-inheritance.html.ini": [
-      "2d0556260a8a081fe57073e562ba44e5ac02d509",
+      "e917dbc57fd46f62a707c93a68b44b29b78824c1",
       []
      ],
      "support": {
@@ -329070,15 +329287,15 @@
       []
      ],
      "transition-skipped-after-animation-started.html.ini": [
-      "1fd386372fc1d21868f8b7a1de2e4a5f59c01132",
+      "417aa725c34912e28c42513e2422fb898adf880a",
       []
      ],
      "transition-skipped-from-invalid-callback.html.ini": [
-      "19b8e4e0d791142e840d9411ef9b415d19a19784",
+      "b7aae07ef719848af81794103845e7331443fffa",
       []
      ],
      "unset-and-initial-view-transition-name.html.ini": [
-      "47d69a5cb06400fbd6b8b16ca31136b2f5e84df5",
+      "19274926655672b94bdfebffc1b2bfefd187ddbb",
       []
      ],
      "view-transition-name-is-backdrop-filter-root-ref.html": [
@@ -329102,7 +329319,7 @@
       []
      ],
      "view-transition-name-on-removed-element.html.ini": [
-      "1e5f7f99779191c620cbce5cf709819834cdb7cf",
+      "1778eb8b3220515f801fab6562b325fe10905881",
       []
      ],
      "web-animations-api-ref.html": [
@@ -329110,7 +329327,11 @@
       []
      ],
      "web-animations-api.html.ini": [
-      "48b3c25ccd085bffe5d98c25ce7dc01eec85a417",
+      "39906bcffc985898323bc17db6564a846e62594e",
+      []
+     ],
+     "window-resize-aborts-transition.html.ini": [
+      "1a98a8d9e64adcdaf47db0a36c6b39366411db07",
       []
      ]
     },
@@ -332623,10 +332844,6 @@
      ]
     },
     "cssom": {
-     "CSSContainerRule.tentative-expected.txt": [
-      "d7df92df5a0401ab06819deab209dc79287c6d43",
-      []
-     ],
      "CSSContainerRule.tentative.html.ini": [
       "c78d40283649792e74f8c4e8ff5c96a4abeec48a",
       []
@@ -349206,6 +349423,10 @@
          "79a20f30fc0f486014c8b93edef7483605101504",
          []
         ],
+        "removed-iframe.sub.https.html.ini": [
+         "6ec7e9803f41fefca851f14b9bc1909873749344",
+         []
+        ],
         "resources": {
          "data-to-javascript-test.mjs": [
           "3a88253ee3053465472ef7d6ecba74b92fab79ce",
@@ -374992,7 +375213,7 @@
       []
      ],
      "performance-navigation-timing-same-origin-bfcache.tentative.window.js.ini": [
-      "2faeab35f7932b2191cc0d963c0bc95d8cdfd868",
+      "a7414b2e31aaebcdf7373b5217c283682827ab56",
       []
      ],
      "performance-navigation-timing-same-origin-replace.tentative.window.js.ini": [
@@ -393365,7 +393586,7 @@
      []
     ],
     "RTCPeerConnection-helper.js": [
-     "ac435279bd24fe5e54383cae2121f7b0a324df22",
+     "eefe10579b4e17964375a81068debb0310938586",
      []
     ],
     "RTCPeerConnection-mandatory-getStats.https-expected.txt": [
@@ -393432,6 +393653,14 @@
      "b1c11eb4f4e274e74273b28340704c517662bda9",
      []
     ],
+    "RTCPeerConnection-setLocalDescription-rollback-expected.txt": [
+     "42df901ae6af477f16aae84e889013a16d307ba0",
+     []
+    ],
+    "RTCPeerConnection-setLocalDescription-rollback.html.ini": [
+     "df9c1ed2432f80e5586fbc778c777278f678e2c1",
+     []
+    ],
     "RTCPeerConnection-setRemoteDescription-expected.txt": [
      "a83779eae57ab90789993146191fe87cbfebfc7b",
      []
@@ -393444,6 +393673,14 @@
      "64f04e41f281eb470da41d2e2a51ab629e8596dc",
      []
     ],
+    "RTCPeerConnection-setRemoteDescription-rollback-expected.txt": [
+     "847a311d84800b2332ae187505eae97fac62030b",
+     []
+    ],
+    "RTCPeerConnection-setRemoteDescription-rollback.html.ini": [
+     "5892394149670a93e443b41bf307f57ec5e14d31",
+     []
+    ],
     "RTCPeerConnection-setRemoteDescription-simulcast.https-expected.txt": [
      "b2e50f46927d484792eaebdc607c3945074b4f1d",
      []
@@ -393520,6 +393757,14 @@
      "4149d820c97d349f23f2d771fd1465c5f6ca1f46",
      []
     ],
+    "RTCRtpSender-setParameters-expected.txt": [
+     "732026443caca0263c69821bd02431a3000d2524",
+     []
+    ],
+    "RTCRtpSender-setParameters.html.ini": [
+     "6a234e6c36b494488ced358163da781f1876e40a",
+     []
+    ],
     "RTCRtpTransceiver-setCodecPreferences.html.ini": [
      "4b7e0389bb17b766591c96afd001347d5dcb63c0",
      []
@@ -393634,7 +393879,7 @@
       []
      ],
      "simulcast-answer-expected.txt": [
-      "e58b0c1087175ea0eeb2b1fe133031d9d054d28b",
+      "1c3638b9471e1d7f2a9b071cda85e5aa65f171fd",
       []
      ],
      "simulcast-answer.html.ini": [
@@ -424595,6 +424840,24 @@
       }
      ]
     ],
+    "compute_pressure_update_toJSON.tentative.https.window.js": [
+     "7f3acf3e07fb0f537b057ac3d9181559dafd1c2f",
+     [
+      "compute-pressure/compute_pressure_update_toJSON.tentative.https.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/resources/test-only-api.js"
+        ],
+        [
+         "script",
+         "resources/pressure-helpers.js"
+        ]
+       ]
+      }
+     ]
+    ],
     "idlharness.https.window.js": [
      "1cdfb59be031ce1fccda43609c61b00a401c245a",
      [
@@ -435249,6 +435512,27 @@
        {}
       ]
      ],
+     "anchor-transition-001.html": [
+      "b5849510e838b47fd5ddcf30489842e755225d5b",
+      [
+       null,
+       {}
+      ]
+     ],
+     "anchor-transition-002.html": [
+      "b6a1ff4511ac9ddfb20a531086137741b137b36b",
+      [
+       null,
+       {}
+      ]
+     ],
+     "anchor-transition-003.html": [
+      "e7441275141176078e14fc16aadf134bf9b65a37",
+      [
+       null,
+       {}
+      ]
+     ],
      "at-fallback-position-allowed-declarations.html": [
       "873fa13140047c0943dde64faa8ab7dc54b28203",
       [
@@ -435926,49 +436210,49 @@
        ]
       ],
       "animation-range-end-computed.html": [
-       "ff30fbfc3fb9cca723b2615ad908f149ee3375b8",
+       "157487ebca0cc5345d3fd656a599cb82c75d42c3",
        [
         null,
         {}
        ]
       ],
       "animation-range-end-invalid.html": [
-       "c1f2800feeeed6222758bb262edd2cd425b34fb5",
+       "f446a8d9bcc10216d92f7cd2194e858e3d40eb93",
        [
         null,
         {}
        ]
       ],
       "animation-range-end-valid.html": [
-       "b2aee359adc5eaf9a5c684a1109218950b79f70c",
+       "c3c0bcce5521bccc159e7ecdbe99fda550de68d9",
        [
         null,
         {}
        ]
       ],
       "animation-range-shorthand.html": [
-       "dcccc2fc4dbae73342c4a5f357398a05132748a4",
+       "1301f04a7f25117609f01d7ec7420e56fd6b0310",
        [
         null,
         {}
        ]
       ],
       "animation-range-start-computed.html": [
-       "e2d9498f41c9bc0ed8e967a52263a5bf87b99898",
+       "5fb4cb120117852d86407150b881ebf949215cdb",
        [
         null,
         {}
        ]
       ],
       "animation-range-start-invalid.html": [
-       "b2eaecc293a492694ba9e8aa644c2d3f7708a650",
+       "65496a306548572dbfb47c0e22dadb174c03575a",
        [
         null,
         {}
        ]
       ],
       "animation-range-start-valid.html": [
-       "1aea7e15729e071c5e12794209a78b4ebe39ea4d",
+       "0ccc5be84604a3ea1e708b201b16a30adff54823",
        [
         null,
         {}
@@ -438353,7 +438637,7 @@
        ]
       ],
       "at-container-style-serialization.html": [
-       "a498c4a7e6c209967d3281a3123f15156f767f6e",
+       "9544463859106e2a4a3ca34cd80364139de29160",
        [
         null,
         {}
@@ -463010,6 +463294,15 @@
        null,
        {}
       ]
+     ],
+     "window-resize-aborts-transition.html": [
+      "e2424cad8c7b2839aea19ddebc4c4a2e5bcc2d7c",
+      [
+       null,
+       {
+        "testdriver": true
+       }
+      ]
      ]
     },
     "css-will-change": {
@@ -565873,7 +566166,7 @@
      ]
     ],
     "MediaStreamTrack-iframe-audio-transfer.https.html": [
-     "963f42c4cbbb89a24bd30112daf75dc54613b3cc",
+     "3f132e10db85bf54136bf0066b79c1275a99a65d",
      [
       null,
       {
@@ -565882,7 +566175,7 @@
      ]
     ],
     "MediaStreamTrack-iframe-transfer.https.html": [
-     "745f314e6fbdda505e3d276cca922d281ff1df7c",
+     "2215954669e533e2b3e43f3f079dddae76cdb658",
      [
       null,
       {
@@ -592840,7 +593133,7 @@
       ]
      ],
      "view-timeline-range-animation.html": [
-      "32febb2f2b6666cf5530b6fe6f20527c494ba667",
+      "dc3785078a60f45c053f5336ea708ec5a2ba5d19",
       [
        null,
        {}
@@ -598643,6 +598936,13 @@
        }
       ]
      ],
+     "delegatesFocus-tabindex-change.html": [
+      "f159c22164bb62064b62bc089faf5bd05cba555f",
+      [
+       null,
+       {}
+      ]
+     ],
      "focus-autofocus.html": [
       "75a50b84c6df5525b5da0df86192637b70247820",
       [
@@ -629998,7 +630298,7 @@
      ]
     ],
     "RTCPeerConnection-relay-canvas.https.html": [
-     "6e9cd068220d6f0ec2a8a77e215a40702f91ee75",
+     "7c3c92bc8de40f608417663844329ed19f61cea0",
      [
       null,
       {
@@ -630072,7 +630372,7 @@
      ]
     ],
     "RTCPeerConnection-setLocalDescription-rollback.html": [
-     "06bbcf9b10b58e7ee755e3183c7174ceb32f2c24",
+     "787edc92e7a393c0ed6f0a210209d83c96c8fd9b",
      [
       null,
       {}
@@ -630121,7 +630421,7 @@
      ]
     ],
     "RTCPeerConnection-setRemoteDescription-rollback.html": [
-     "94ed79cdb2f0420690d547bb4a5c2b76671cd8a6",
+     "0e6213d70832fecc25aae7954f6cf5190b4f0a48",
      [
       null,
       {}
@@ -630294,7 +630594,7 @@
      ]
     ],
     "RTCRtpSender-setParameters.html": [
-     "0d09495ac1de327c89d7edd2b95b77d1deb0f22b",
+     "94c572343de711c0535332cf89131fd2e117c8c8",
      [
       null,
       {}
@@ -630403,7 +630703,7 @@
      ]
     ],
     "RollbackEvents.https.html": [
-     "0207a076c88be713abd564f6ea2826dbf3b99d61",
+     "25c83842c9e751eff491863d5f1d7c3d639f9940",
      [
       null,
       {}
@@ -630478,7 +630778,7 @@
      ]
     },
     "no-media-call.html": [
-     "590571c01299f2e2a5ec8269ff7b8d8e1aaa7eeb",
+     "dba0b1d2df95fc26c1e49fb6a0b967f2fd0d15a8",
      [
       null,
       {}
@@ -630500,10 +630800,12 @@
       ]
      ],
      "bundle.https.html": [
-      "cff801d3e08119c57e5bc89f8593b5f50dea50c3",
+      "569f1fdadfc8036d13040684f6a5cafb8c64d671",
       [
        null,
-       {}
+       {
+        "timeout": "long"
+       }
       ]
      ],
      "candidate-exchange.https.html": [
@@ -630592,7 +630894,7 @@
       ]
      ],
      "msid-generate.html": [
-      "0fcf28ee6b8a8a8f580388ac8017d807437a28b0",
+      "29226c704e2b5335843354f874907735df014d09",
       [
        null,
        {}
@@ -630624,7 +630926,7 @@
       ]
      ],
      "rtp-extension-support.html": [
-      "bf6954ed138db48ed513c80d67bb514aec71d86d",
+      "045701c171f58ac54c7b9790fdb4c98c81cfc8b5",
       [
        null,
        {}
@@ -630661,7 +630963,7 @@
       ]
      ],
      "simulcast-answer.html": [
-      "06a6e796d369cfcdd27020efd0e13ed9baf7f545",
+      "5e19bc08ff5d7fa4860e8e53e4a0611e00d3c6c1",
       [
        null,
        {}
@@ -630787,7 +631089,7 @@
       ]
      ],
      "setParameters-active.https.html": [
-      "36f096add385d86bab2aaab16c58f98a2c48c2c4",
+      "dbe162c610ece70a60a2abab59ad778edbec932f",
       [
        null,
        {
@@ -630797,7 +631099,7 @@
       ]
      ],
      "setParameters-encodings.https.html": [
-      "fb33529db6ff47354055f23de2699588e7630836",
+      "ac04ca55fb1f34ee51641bb05048de0bff0d57ea",
       [
        null,
        {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-basics.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-basics.tentative.html.ini
new file mode 100644
index 0000000..b113989
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-basics.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-basics.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-nested.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-nested.tentative.html.ini
new file mode 100644
index 0000000..0e9d178
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-nested.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-nested.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-001.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-001.tentative.html.ini
new file mode 100644
index 0000000..0a16da34
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-001.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-update-001.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-002.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-002.tentative.html.ini
new file mode 100644
index 0000000..08b46c02
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-002.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-update-002.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-003.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-003.tentative.html.ini
new file mode 100644
index 0000000..4c98b56
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-003.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-update-003.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-004.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-004.tentative.html.ini
new file mode 100644
index 0000000..64801cfb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-004.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-update-004.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-005.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-005.tentative.html.ini
new file mode 100644
index 0000000..bc7e891e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-005.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-update-005.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-006.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-006.tentative.html.ini
new file mode 100644
index 0000000..d0ce3992
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-update-006.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-update-006.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-vlr.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-vlr.tentative.html.ini
new file mode 100644
index 0000000..c3f96ea2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-vlr.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-vlr.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-vrl.tentative.html.ini b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-vrl.tentative.html.ini
new file mode 100644
index 0000000..4f3fe39e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-vrl.tentative.html.ini
@@ -0,0 +1,2 @@
+[anchor-scroll-vrl.tentative.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/cjk-kerning.html.ini b/third_party/blink/web_tests/external/wpt/css/css-fonts/cjk-kerning.html.ini
index cf10f407..5f57054 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-fonts/cjk-kerning.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/cjk-kerning.html.ini
@@ -6,11 +6,11 @@
 
   [expected match: .default .cjk vs .kernOFF .cjk]
     expected:
-      if (processor == "x86_64") and (flag_specific == "") and (product == "content_shell"): FAIL
+      if (os == "linux") and (flag_specific == "") and (product == "content_shell"): FAIL
 
   [expected mismatch: .kernOFF .cjk vs .kernON .cjk]
     expected:
-      if (processor == "x86_64") and (flag_specific == "") and (product == "content_shell"): PASS
+      if (os == "linux") and (flag_specific == "") and (product == "content_shell"): PASS
       FAIL
 
   [expected mismatch: .paltOFFkernON .cjk vs .paltONkernON .cjk]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-008-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-008-ref.html
new file mode 100644
index 0000000..e14ca31
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-008-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Grid Test: Masonry item placement w/ Images</title>
+  <link rel="author" title="Brandon Stewart" href="mailto:brandonstewart@apple.com">
+  <link rel="help" href="https://drafts.csswg.org/css-grid-2">
+</head>
+
+<body>
+<style>
+grid {
+  display: inline-grid;
+  grid-template-columns: 400px;
+}
+
+img {
+  width: 100%;
+  height: auto;
+  background-color: cyan;
+}
+</style>
+
+<grid>
+    <img width="400" height="400" />
+</grid>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-008.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-008.html
new file mode 100644
index 0000000..c68a9787
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-008.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Grid Test: Masonry item placement w/ Images</title>
+  <link rel="author" title="Brandon Stewart" href="mailto:brandonstewart@apple.com">
+  <link rel="help" href="https://drafts.csswg.org/css-grid-2">
+  <link rel="match" href="masonry-item-placement-008-ref.html">
+</head>
+
+<body>
+<style>
+grid {
+  display: inline-grid;
+  grid-template-rows: masonry;
+  grid-template-columns: repeat( auto-fill, minmax(200px, 400px) );
+  gap: 30px;
+  max-width: 50vw;
+}
+
+img {
+  width: 100%;
+  height: auto;
+  background-color: cyan;
+}
+</style>
+
+<grid>
+    <img width="400" height="400" />
+</grid>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-normal-015a.xht b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-normal-015a.xht
index db3ee2a5..d2e0fe34 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-normal-015a.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-normal-015a.xht
@@ -50,7 +50,7 @@
 				<span>サンプルサンプル文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2025;&#x2025;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 		</div>
 		<div class="wrapper">
@@ -59,7 +59,7 @@
 				<span>サンプルサンプル文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2026;&#x2026;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 		</div>
 	</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-strict-015a.xht b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-strict-015a.xht
index 9114120..ad31e4fc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-strict-015a.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-strict-015a.xht
@@ -50,7 +50,7 @@
 				<span>サンプルサンプル文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2025;&#x2025;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 		</div>
 		<div class="wrapper">
@@ -59,7 +59,7 @@
 				<span>サンプルサンプル文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2026;&#x2026;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 		</div>
 	</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-normal-015a-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-normal-015a-ref.xht
index 941e182..23cf148 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-normal-015a-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-normal-015a-ref.xht
@@ -41,19 +41,19 @@
 		<div class="wrapper">
 			<!-- inseparable characters TWO DOT LEADER -->
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2025;&#x2025;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2025;&#x2025;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 		</div>
 		<div class="wrapper">
 			<!-- inseparable characters HORIZONTAL ELLIPSIS -->
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2026;&#x2026;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2026;&#x2026;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 		</div>
 	</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-strict-015a-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-strict-015a-ref.xht
index f8a1222a..252818c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-strict-015a-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/reference/line-break-strict-015a-ref.xht
@@ -41,19 +41,19 @@
 		<div class="wrapper">
 			<!-- inseparable characters TWO DOT LEADER -->
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2025;&#x2025;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2025;&#x2025;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2025;&#x2025;</span>サンプル文</span>
 			</p>
 		</div>
 		<div class="wrapper">
 			<!-- inseparable characters HORIZONTAL ELLIPSIS -->
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2026;&#x2026;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 			<p class="control" lang="ja">
-				<span>サンプルサンプル文<br /><span class="target">&#x2026;&#x2026;</span>サンプル文</span>
+				<span>サンプルサンプル<br />文<span class="target">&#x2026;&#x2026;</span>サンプル文</span>
 			</p>
 		</div>
 	</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-007.html.ini b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-007.html.ini
index a29c683..86896271 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-007.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-007.html.ini
@@ -1,4 +1,4 @@
 [text-transform-capitalize-007.html]
   expected:
-    if (product == "content_shell") and (os == "linux") and (version == "Ubuntu 18.04"): FAIL
+    if (product == "content_shell") and (os == "win") and (processor == "x86_64"): FAIL
     if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-018.html.ini b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-018.html.ini
index 87e5140..5e95654 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-018.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-capitalize-018.html.ini
@@ -1,3 +1,4 @@
 [text-transform-capitalize-018.html]
   expected:
+    if (product == "content_shell") and (os == "win") and (processor == "x86_64"): FAIL
     if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-011.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-011.html
new file mode 100644
index 0000000..8c40a31a3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-011.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: line breaking with white-space: break-spaces and element boundaries</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com" />
+<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property">
+<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-break-spaces">
+<meta name="flags" content="ahem">
+<link rel="match" href="reference/white-space-break-spaces-005-ref.html">
+<meta name="assert" content="An element boundary doesn't allow breaking if white-space is set to break-spaces at both sides of the boundary">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  font: 25px/1 Ahem;
+}
+.fail {
+  position: absolute;
+  color: red;
+  z-index: -1;
+}
+.fail span { color: green; }
+.test {
+  color: green;
+  width: 4ch;
+  white-space: break-spaces;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div class="fail">XXXX<br>X<span>X</span>X<span>X</span><br>XX<span>XX</span><br>X<span>X</span>X<span>X</span></div>
+<div class="test"><span>XXXX</span> X X XX<span> </span><span> </span>X X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-inline-start-color-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-inline-start-color-001.html.ini
new file mode 100644
index 0000000..ba656066
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-inline-start-color-001.html.ini
@@ -0,0 +1,2 @@
+[kind-of-widget-fallback-input-submit-border-inline-start-color-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-block-end-style-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-block-end-style-001.html.ini
new file mode 100644
index 0000000..10d4e093
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-block-end-style-001.html.ini
@@ -0,0 +1,2 @@
+[kind-of-widget-fallback-textarea-border-block-end-style-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-bottom-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-bottom-width-001.html.ini
new file mode 100644
index 0000000..ddeb070
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-textarea-border-bottom-width-001.html.ini
@@ -0,0 +1,2 @@
+[kind-of-widget-fallback-textarea-border-bottom-width-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/outline-025.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/outline-025.html.ini
index c5515ab0..cc571ab0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/outline-025.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/outline-025.html.ini
@@ -1,3 +1,3 @@
 [outline-025.html]
   expected:
-    if (os == "linux") and (version == "Ubuntu 18.04"): FAIL
+    if (os == "win") and (processor == "x86_64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-incoming.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-incoming.html.ini
index b2c8041..9a9a975 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-incoming.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-incoming.html.ini
@@ -1,2 +1,5 @@
 [3d-transform-incoming.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-outgoing.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-outgoing.html.ini
index c3360cd..e44ce420 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-outgoing.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-outgoing.html.ini
@@ -1,2 +1,5 @@
 [3d-transform-outgoing.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-smaller-than-box-size.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-smaller-than-box-size.html.ini
index dd6b575..9ff4ca3e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-smaller-than-box-size.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-smaller-than-box-size.html.ini
@@ -1,2 +1,5 @@
 [content-smaller-than-box-size.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-visibility-auto-shared-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-visibility-auto-shared-element.html.ini
index 17013c5..cf1ea93 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-visibility-auto-shared-element.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-visibility-auto-shared-element.html.ini
@@ -1,2 +1,5 @@
 [content-visibility-auto-shared-element.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-max-texture-size.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-max-texture-size.html.ini
index 9adefd7..243c1b5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-max-texture-size.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-max-texture-size.html.ini
@@ -1,2 +1,5 @@
 [content-with-clip-max-texture-size.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-root.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-root.html.ini
index 19599dc9..39d4ab4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-root.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-root.html.ini
@@ -1,2 +1,5 @@
 [content-with-clip-root.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip.html.ini
index 046323d..dc69b5b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip.html.ini
@@ -1,2 +1,5 @@
 [content-with-clip.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-inline-child.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-inline-child.html.ini
index 3c9eeb0..6451875 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-inline-child.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-inline-child.html.ini
@@ -1,2 +1,5 @@
 [content-with-inline-child.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-new-image.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-new-image.html.ini
index 8ba8457e..632ee128 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-new-image.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-new-image.html.ini
@@ -1,2 +1,5 @@
 [content-with-transform-new-image.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order-with-entry.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order-with-entry.html.ini
index 2baa468..6177a056 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order-with-entry.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order-with-entry.html.ini
@@ -1,2 +1,5 @@
 [css-tags-paint-order-with-entry.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order.html.ini
index 0e7c273..8bfa895e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order.html.ini
@@ -1,2 +1,5 @@
 [css-tags-paint-order.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-shared-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-shared-element.html.ini
index 3c6300d..ce28c4ee 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-shared-element.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-shared-element.html.ini
@@ -1,2 +1,5 @@
 [css-tags-shared-element.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-rtl-iframe.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-rtl-iframe.html.ini
index 162090439..cf33837c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-rtl-iframe.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-rtl-iframe.html.ini
@@ -1,2 +1,4 @@
 [dialog-in-rtl-iframe.html]
-  expected: TIMEOUT
+  expected:
+    if product == "chrome": [FAIL, TIMEOUT]
+    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html.ini
index 17cf0b9..ce48fcbc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html.ini
@@ -1,2 +1,5 @@
 [dialog-in-top-layer-during-transition-new.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html.ini
index 3a4d114b..333ffd9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html.ini
@@ -1,2 +1,5 @@
 [dialog-in-top-layer-during-transition-old.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/duplicate-tag-rejects-start.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/duplicate-tag-rejects-start.html.ini
index 718c4bf9..f734d71 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/duplicate-tag-rejects-start.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/duplicate-tag-rejects-start.html.ini
@@ -1,3 +1,6 @@
 [duplicate-tag-rejects-start.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [Two different elements with the same name in the new DOM should skip the transition]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/element-with-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/element-with-overflow.html.ini
index ad317c23..e399542a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/element-with-overflow.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/element-with-overflow.html.ini
@@ -1,2 +1,5 @@
 [element-with-overflow.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/event-pseudo-name.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/event-pseudo-name.html.ini
index 132fa88b..9f532e5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/event-pseudo-name.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/event-pseudo-name.html.ini
@@ -1,3 +1,6 @@
 [event-pseudo-name.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [verifies pseudo name includes a tag]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/far-away-capture.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/far-away-capture.html.ini
index 01ebbf1..d3070927 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/far-away-capture.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/far-away-capture.html.ini
@@ -1,2 +1,5 @@
 [far-away-capture.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element-from-point.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element-from-point.html.ini
index 07da5c6..83a4891 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element-from-point.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element-from-point.html.ini
@@ -1,3 +1,6 @@
 [hit-test-unpainted-element-from-point.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [hit test should not hit unpainted element, but does hit pseudo and unrelated elements]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element.html.ini
index 816eb7f..36ba25c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element.html.ini
@@ -1,2 +1,5 @@
 [hit-test-unpainted-element.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unrelated-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unrelated-element.html.ini
index dca27cc..1061e7d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unrelated-element.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unrelated-element.html.ini
@@ -1,2 +1,5 @@
 [hit-test-unrelated-element.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/japanese-tag.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/japanese-tag.html.ini
index 3b8aad5a..e8d77cf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/japanese-tag.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/japanese-tag.html.ini
@@ -1,2 +1,5 @@
 [japanese-tag.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/mix-blend-mode-only-on-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/mix-blend-mode-only-on-transition.html.ini
index c2b2bb8b..76ff933 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/mix-blend-mode-only-on-transition.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/mix-blend-mode-only-on-transition.html.ini
@@ -1,3 +1,6 @@
 [mix-blend-mode-only-on-transition.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [Blend modes are set up on paired transitions]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html.ini
index 601e19b5..6b1a3126 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html.ini
@@ -1,2 +1,5 @@
 [new-and-old-sizes-match.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html.ini
index 857d28d..5e70c3f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html.ini
@@ -1,2 +1,5 @@
 [new-content-captures-clip-path.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-opacity.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-opacity.html.ini
index bb2bfdd..d7050b65 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-opacity.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-opacity.html.ini
@@ -1,2 +1,5 @@
 [new-content-captures-opacity.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-root.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-root.html.ini
index c7f61f9..8104106 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-root.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-root.html.ini
@@ -1,2 +1,5 @@
 [new-content-captures-root.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-container-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-container-writing-modes.html.ini
index c3e6f545..1fd8d8a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-container-writing-modes.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-container-writing-modes.html.ini
@@ -1,2 +1,5 @@
 [new-content-container-writing-modes.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-element-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-element-writing-modes.html.ini
index 83d5122a..9ab0bda 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-element-writing-modes.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-element-writing-modes.html.ini
@@ -1,2 +1,5 @@
 [new-content-element-writing-modes.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html.ini
index fa18c600..dd81210 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html.ini
@@ -1,2 +1,5 @@
 [new-content-intrinsic-aspect-ratio.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html.ini
index 39b37c5..d2002da6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html.ini
@@ -1,2 +1,5 @@
 [new-content-is-empty-div.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-fill.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-fill.html.ini
index 222e6b5..aafa827 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-fill.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-fill.html.ini
@@ -1,2 +1,5 @@
 [new-content-object-fit-fill.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-none.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-none.html.ini
index f16f679..9513d2b6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-none.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-none.html.ini
@@ -1,2 +1,5 @@
 [new-content-object-fit-none.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html.ini
index ae0ce744..85a247e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html.ini
@@ -1,2 +1,5 @@
 [new-content-object-view-box-clip-path-reference.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path.html.ini
index 5592e65..574b248 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path.html.ini
@@ -1,2 +1,5 @@
 [new-content-object-view-box-clip-path.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html.ini
index ab854938..4aa3c3ed 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html.ini
@@ -1,2 +1,5 @@
 [new-content-object-view-box-overflow-clipped.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow.html.ini
index 1238122..8007b36 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow.html.ini
@@ -1,2 +1,5 @@
 [new-content-object-view-box-overflow.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-scaling.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-scaling.html.ini
index 5793134f..5829a441 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-scaling.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-scaling.html.ini
@@ -1,2 +1,5 @@
 [new-content-scaling.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow-zoomed.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow-zoomed.html.ini
index 268e9974..e911e36 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow-zoomed.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow-zoomed.html.ini
@@ -1,2 +1,5 @@
 [new-content-with-overflow-zoomed.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow.html.ini
index e5e6fae..1da0e285 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow.html.ini
@@ -1,2 +1,5 @@
 [new-content-with-overflow.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html.ini
index 852b47a..1f994c0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html.ini
@@ -1,2 +1,5 @@
 [new-element-on-start.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-root-vertical-writing-mode.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-root-vertical-writing-mode.html.ini
index 2f7cbaf3..0f259cb 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-root-vertical-writing-mode.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-root-vertical-writing-mode.html.ini
@@ -1,2 +1,5 @@
 [new-root-vertical-writing-mode.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element-mid-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element-mid-transition.html.ini
index ca7dd2e5..3501cc7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element-mid-transition.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element-mid-transition.html.ini
@@ -1,3 +1,6 @@
 [no-containment-on-new-element-mid-transition.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [new element becoming uncontained should skip the transition]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element.html.ini
index 6891685..a188f1c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-containment-on-new-element.html.ini
@@ -1,3 +1,6 @@
 [no-containment-on-new-element.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [uncontained new element should skip the transition]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-crash-set-exception.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-crash-set-exception.html.ini
index df3c99e..d7484cdd 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-crash-set-exception.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-crash-set-exception.html.ini
@@ -1,3 +1,6 @@
 [no-crash-set-exception.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [An exception thrown during a transition shouldn't crash.]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-root-capture.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-root-capture.html.ini
index 17790fa..8a6a28ca 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-root-capture.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-root-capture.html.ini
@@ -1,2 +1,5 @@
 [no-root-capture.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nothing-captured.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nothing-captured.html.ini
index 32b14d1..1210b39 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nothing-captured.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nothing-captured.html.ini
@@ -1,2 +1,5 @@
 [nothing-captured.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-new-image.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-new-image.html.ini
index a944f19..3faa887 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-new-image.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-new-image.html.ini
@@ -1,2 +1,5 @@
 [object-view-box-new-image.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-clip-path.html.ini
index 660a6e5..67fc6d8c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-clip-path.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-clip-path.html.ini
@@ -1,2 +1,5 @@
 [old-content-captures-clip-path.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-opacity.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-opacity.html.ini
index 8c707af..8295d74 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-opacity.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-opacity.html.ini
@@ -1,2 +1,5 @@
 [old-content-captures-opacity.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-root.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-root.html.ini
index 1ad03fc..5c179f0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-root.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-root.html.ini
@@ -1,2 +1,5 @@
 [old-content-captures-root.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-container-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-container-writing-modes.html.ini
index 62b0617..5155113 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-container-writing-modes.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-container-writing-modes.html.ini
@@ -1,2 +1,5 @@
 [old-content-container-writing-modes.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-element-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-element-writing-modes.html.ini
index 27febda8..e77d246 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-element-writing-modes.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-element-writing-modes.html.ini
@@ -1,2 +1,5 @@
 [old-content-element-writing-modes.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html.ini
index 59af5df..943ad7c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html.ini
@@ -1,2 +1,5 @@
 [old-content-intrinsic-aspect-ratio.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-empty-div.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-empty-div.html.ini
index 5739224..cf25b03 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-empty-div.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-empty-div.html.ini
@@ -1,2 +1,5 @@
 [old-content-is-empty-div.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-fill.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-fill.html.ini
index 9b409d7..d0d5888 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-fill.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-fill.html.ini
@@ -1,2 +1,5 @@
 [old-content-object-fit-fill.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-none.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-none.html.ini
index 69a6229..b561acf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-none.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-none.html.ini
@@ -1,2 +1,5 @@
 [old-content-object-fit-none.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html.ini
index 5d2953f..a1662c4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html.ini
@@ -1,2 +1,5 @@
 [old-content-object-view-box-clip-path-reference.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path.html.ini
index f9e6bff6..2d2073b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path.html.ini
@@ -1,2 +1,5 @@
 [old-content-object-view-box-clip-path.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-overflow.html.ini
index 0f369bb..547f9da 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-overflow.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-overflow.html.ini
@@ -1,2 +1,5 @@
 [old-content-object-view-box-overflow.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow-zoomed.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow-zoomed.html.ini
index fd9d6e2b..9786f850 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow-zoomed.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow-zoomed.html.ini
@@ -1,2 +1,5 @@
 [old-content-with-overflow-zoomed.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow.html.ini
index 7381b14..f3c51a4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow.html.ini
@@ -1,2 +1,5 @@
 [old-content-with-overflow.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-root-vertical-writing-mode.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-root-vertical-writing-mode.html.ini
index 4500fd22..92d2dd3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-root-vertical-writing-mode.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-root-vertical-writing-mode.html.ini
@@ -1,2 +1,5 @@
 [old-root-vertical-writing-mode.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/paused-animation-at-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/paused-animation-at-end.html.ini
index eba4b15b..ecfe8d2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/paused-animation-at-end.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/paused-animation-at-end.html.ini
@@ -1,3 +1,6 @@
 [paused-animation-at-end.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [view transition is not over if animations are paused]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html.ini
index d28519d6..4c1391a2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html.ini
@@ -1,3 +1,6 @@
 [pseudo-computed-style-stays-in-sync-with-new-element.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [computed style on pseudo-element stays in sync with the DOM element]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-get-computed-style.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-get-computed-style.html.ini
index a2886dce..8b54ee4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-get-computed-style.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-get-computed-style.html.ini
@@ -1,4 +1,7 @@
 [pseudo-get-computed-style.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [position property of pseudo elements]
     expected: FAIL
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/ready_resolves_after_dom_before_raf.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/ready_resolves_after_dom_before_raf.html.ini
index 8069d342..4b7c244a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/ready_resolves_after_dom_before_raf.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/ready_resolves_after_dom_before_raf.html.ini
@@ -1,3 +1,6 @@
 [ready_resolves_after_dom_before_raf.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [updateCallbackDone resolves, then ready resolves with no rAF in between]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-captured-as-different-tag.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-captured-as-different-tag.html.ini
index 45c9965..da70aa9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-captured-as-different-tag.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-captured-as-different-tag.html.ini
@@ -1,2 +1,5 @@
 [root-captured-as-different-tag.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-scrollbar-with-fixed-background.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-scrollbar-with-fixed-background.html.ini
index c5477ec..25af7d4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-scrollbar-with-fixed-background.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-scrollbar-with-fixed-background.html.ini
@@ -1,2 +1,5 @@
 [root-scrollbar-with-fixed-background.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-style-change-during-animation.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-style-change-during-animation.html.ini
index 4e8a35d7..ff0a6d8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-style-change-during-animation.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-style-change-during-animation.html.ini
@@ -1,2 +1,5 @@
 [root-style-change-during-animation.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-end.html.ini
index 6d4d024b..4cba7218 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-end.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-end.html.ini
@@ -1,2 +1,5 @@
 [root-to-shared-animation-end.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-incoming.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-incoming.html.ini
index 65ef17c..6f70e52 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-incoming.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-incoming.html.ini
@@ -1,2 +1,5 @@
 [root-to-shared-animation-incoming.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-start.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-start.html.ini
index 79aee8a0..31234706 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-start.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-start.html.ini
@@ -1,2 +1,5 @@
 [root-to-shared-animation-start.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/rtl-with-scrollbar.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/rtl-with-scrollbar.html.ini
new file mode 100644
index 0000000..76ca4c5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/rtl-with-scrollbar.html.ini
@@ -0,0 +1,2 @@
+[rtl-with-scrollbar.html]
+  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-universal-specificity.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-universal-specificity.html.ini
index 29a87934..c1b05cf44 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-universal-specificity.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-universal-specificity.html.ini
@@ -1,2 +1,5 @@
 [set-universal-specificity.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html.ini
index 2d055626..e917dbc5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html.ini
@@ -1,3 +1,6 @@
 [style-inheritance.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [style inheritance of pseudo elements]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-after-animation-started.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-after-animation-started.html.ini
index 1fd38637..417aa725 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-after-animation-started.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-after-animation-started.html.ini
@@ -1,3 +1,6 @@
 [transition-skipped-after-animation-started.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [skipTransition() after animations have started running should resolve finished promise]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-from-invalid-callback.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-from-invalid-callback.html.ini
index 19b8e4e..b7aae07 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-from-invalid-callback.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-from-invalid-callback.html.ini
@@ -1,3 +1,6 @@
 [transition-skipped-from-invalid-callback.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [transition skipped because callback has invalid syntax]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/unset-and-initial-view-transition-name.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/unset-and-initial-view-transition-name.html.ini
index 47d69a5c..1927492 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/unset-and-initial-view-transition-name.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/unset-and-initial-view-transition-name.html.ini
@@ -1,3 +1,6 @@
 [unset-and-initial-view-transition-name.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [validates that view-transition-name: unset or initial are ignored]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-on-removed-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-on-removed-element.html.ini
index 1e5f7f9..1778eb8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-on-removed-element.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-on-removed-element.html.ini
@@ -1,3 +1,6 @@
 [view-transition-name-on-removed-element.html]
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
   [view-transition-name on an element removed by script should not be visited when discovering named elements]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animations-api.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animations-api.html.ini
index 48b3c25c..39906bc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animations-api.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animations-api.html.ini
@@ -1,2 +1,5 @@
 [web-animations-api.html]
-  expected: FAIL
+  expected:
+    if (processor == "x86_64") and (os == "linux") and (version == "Ubuntu 18.04"): TIMEOUT
+    if (processor == "x86_64") and (os == "win"): TIMEOUT
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/window-resize-aborts-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/window-resize-aborts-transition.html.ini
new file mode 100644
index 0000000..1a98a8d9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/window-resize-aborts-transition.html.ini
@@ -0,0 +1,4 @@
+[window-resize-aborts-transition.html]
+  expected: ERROR
+  [View transitions: Resizing viewport skips the transition]
+    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/removed-iframe.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/removed-iframe.sub.https.html.ini
new file mode 100644
index 0000000..6ec7e98
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/removed-iframe.sub.https.html.ini
@@ -0,0 +1,3 @@
+[removed-iframe.sub.https.html]
+  [Removing the iframe does not change originAgentCluster]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js.ini b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js.ini
index 2faeab3..a7414b2 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js.ini
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js.ini
@@ -1,5 +1,5 @@
 [performance-navigation-timing-same-origin-bfcache.tentative.window.html]
   [RemoteContextHelper navigation using BFCache]
     expected:
-      if (os == "linux") and (version == "trusty") and (product == "chrome"): FAIL
-      if (os == "linux") and (version == "Ubuntu 18.04"): FAIL
+      if (processor == "x86_64") and (os == "linux") and (product == "chrome"): FAIL
+      if (processor == "x86_64") and (os == "win"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/focus/delegatesFocus-tabindex-change.html b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/delegatesFocus-tabindex-change.html
new file mode 100644
index 0000000..f159c221
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/delegatesFocus-tabindex-change.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+test(() => {
+  const host = document.createElement('div');
+  document.body.appendChild(host);
+
+  const shadowRoot = host.attachShadow({mode: 'open', delegatesFocus: true});
+
+  const shadowInput = document.createElement('input');
+  shadowRoot.appendChild(shadowInput);
+
+  host.focus();
+  assert_equals(document.activeElement, host, 'The shadow host should be focused.');
+
+  host.setAttribute('tabindex', '0');
+  assert_equals(document.activeElement, host, 'The shadow host should remain focused after changing tabindex.');
+}, 'Setting tabindex on the shadow host of a focused element with delegatesFocus should not change focus.');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
index ac43527..eefe105 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
@@ -713,3 +713,10 @@
             'Should not get an icegatheringstatechange right now!');
       });
 };
+
+async function queueAWebrtcTask() {
+  const pc = new RTCPeerConnection();
+  pc.addTransceiver('audio');
+  await new Promise(r => pc.onnegotiationneeded = r);
+}
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-relay-canvas.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-relay-canvas.https.html
index 6e9cd06..7c3c92b 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-relay-canvas.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-relay-canvas.https.html
@@ -79,6 +79,6 @@
 
   // Expected value computed based on GetVideoSignal code, which takes green pixel data
   // with coefficient 0.72.
-  assert_approx_equals(pixelValue, 0.72*255, 2);
+  assert_approx_equals(pixelValue, 0.72*255, 3);
   }, "Two PeerConnections relaying a canvas source");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback-expected.txt
new file mode 100644
index 0000000..42df901
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS setLocalDescription(rollback) from have-local-offer state should reset back to stable state
+PASS setLocalDescription(rollback) from stable state should reject with InvalidStateError
+PASS setLocalDescription(rollback) after setting answer description should reject with InvalidStateError
+FAIL setLocalDescription(rollback) after setting a remote offer should reject with InvalidStateError assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS setLocalDescription(rollback) should ignore invalid sdp content and succeed
+PASS setLocalDescription(rollback) should update internal state with a queued tassk, in the right order
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html
index 06bbcf9b..787edc92 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html
@@ -117,6 +117,14 @@
     });
   }, `setLocalDescription(rollback) after setting answer description should reject with InvalidStateError`);
 
+  promise_test(async t => {
+    const pc = new RTCPeerConnection();
+    t.add_cleanup(() => pc.close());
+    const offer = await generateAudioReceiveOnlyOffer(pc);
+    await pc.setRemoteDescription(offer);
+    await promise_rejects_dom(t, 'InvalidStateError', pc.setLocalDescription({ type: 'rollback' }));
+  }, `setLocalDescription(rollback) after setting a remote offer should reject with InvalidStateError`);
+
   promise_test(t => {
     const pc = new RTCPeerConnection();
     t.add_cleanup(() => pc.close());
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html.ini
new file mode 100644
index 0000000..df9c1ed
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html.ini
@@ -0,0 +1,3 @@
+[RTCPeerConnection-setLocalDescription-rollback.html]
+  [setLocalDescription(rollback) after setting a remote offer should reject with InvalidStateError]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt
new file mode 100644
index 0000000..847a311d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt
@@ -0,0 +1,25 @@
+This is a testharness.js-based test.
+PASS setRemoteDescription(rollback) in have-remote-offer state should revert to stable state
+PASS setRemoteDescription(rollback) from stable state should reject with InvalidStateError
+FAIL setRemoteDescription(rollback) after setting a local offer should reject with InvalidStateError assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS setRemoteDescription(rollback) should ignore invalid sdp content and succeed
+PASS local offer created before setRemoteDescription(remote offer) then rollback should still be usable
+PASS local offer created before setRemoteDescription(remote offer) with different transceiver level assignments then rollback should still be usable
+PASS rollback of a remote offer should remove a transceiver
+PASS rollback of a remote offer should remove touched transceiver
+PASS rollback of a remote offer should keep a transceiver
+PASS rollback of a remote offer should keep a transceiver created by addtrack
+PASS rollback of a remote offer should keep a transceiver without tracks
+PASS explicit rollback of local offer should remove transceivers and transport
+PASS when using addTransceiver, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded until we settle in stable
+PASS when using addTrack, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded
+PASS rollback of a remote offer to negotiated stable state should enable applying of a local offer
+PASS rollback of a local offer to negotiated stable state should enable applying of a remote offer
+PASS rollback a local offer with audio direction change to negotiated stable state and then add video receiver
+PASS two transceivers with same mids
+PASS onremovetrack fires during remote rollback
+PASS rollback of a remote offer with stream changes
+PASS removeTrack() with a sender being rolled back does not crash or throw
+PASS Implicit rollback with only a datachannel works
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html
index 94ed79cd..0e6213d 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html
@@ -103,7 +103,14 @@
       pc.setRemoteDescription({type: 'rollback'}));
   }, `setRemoteDescription(rollback) from stable state should reject with InvalidStateError`);
 
-  promise_test(t => {
+  promise_test(async t => {
+    const pc = new RTCPeerConnection();
+    t.add_cleanup(() => pc.close());
+    await pc.setLocalDescription();
+    await promise_rejects_dom(t, 'InvalidStateError', pc.setRemoteDescription({ type: 'rollback' }));
+  }, `setRemoteDescription(rollback) after setting a local offer should reject with InvalidStateError`);
+
+   promise_test(t => {
     const pc = new RTCPeerConnection();
     t.add_cleanup(() => pc.close());
     return generateAudioReceiveOnlyOffer(pc)
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html.ini
new file mode 100644
index 0000000..5892394
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html.ini
@@ -0,0 +1,3 @@
+[RTCPeerConnection-setRemoteDescription-rollback.html]
+  [setRemoteDescription(rollback) after setting a local offer should reject with InvalidStateError]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt
new file mode 100644
index 0000000..73202644
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS setParameters() when transceiver is stopped should reject with InvalidStateError
+FAIL setParameters() with already used parameters should work if the event loop has not been relinquished promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'setParameters' on 'RTCRtpSender': Failed to set parameters since getParameters() has never been called on this sender"
+PASS setParameters() with already used parameters should reject with InvalidStateError if the event loop has been relinquished
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters.html
index 0d09495..94c5723 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters.html
@@ -3,6 +3,7 @@
 <title>RTCRtpSender.prototype.setParameters</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
 <script>
   'use strict';
 
@@ -27,15 +28,25 @@
       sender.setParameters(param));
   }, `setParameters() when transceiver is stopped should reject with InvalidStateError`);
 
-  promise_test(t => {
+  promise_test(async t => {
     const pc = new RTCPeerConnection();
     t.add_cleanup(() => pc.close());
     const sender = pc.addTransceiver('audio').sender;
     const param = sender.getParameters();
     sender.setParameters(param);
+    await sender.setParameters(param);
+  }, `setParameters() with already used parameters should work if the event loop has not been relinquished`);
 
-    return promise_rejects_dom(t, 'InvalidStateError',
+  promise_test(async t => {
+    const pc = new RTCPeerConnection();
+    t.add_cleanup(() => pc.close());
+    const sender = pc.addTransceiver('audio').sender;
+    const param = sender.getParameters();
+    sender.setParameters(param);
+    await queueAWebrtcTask();
+
+    await promise_rejects_dom(t, 'InvalidStateError',
       sender.setParameters(param));
-  }, `setParameters() with already used parameters should reject with InvalidStateError`);
+  }, `setParameters() with already used parameters should reject with InvalidStateError if the event loop has been relinquished`);
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters.html.ini
new file mode 100644
index 0000000..6a234e6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-setParameters.html.ini
@@ -0,0 +1,3 @@
+[RTCRtpSender-setParameters.html]
+  [setParameters() with already used parameters should work if the event loop has not been relinquished]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RollbackEvents.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RollbackEvents.https.html
index 0207a07..25c8384 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RollbackEvents.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RollbackEvents.https.html
@@ -40,7 +40,7 @@
     });
 
     // Cause track removal due to rollback.
-    await pc2.setLocalDescription({type:'rollback'});
+    await pc2.setRemoteDescription({type:'rollback'});
     // The track was removed.
     await onRemoveTrackPromise;
 
@@ -90,7 +90,7 @@
     assert_not_equals(remoteTrack, null);
 
     // Cause track removal due to rollback.
-    await pc2.setLocalDescription({type:'rollback'});
+    await pc2.setRemoteDescription({type:'rollback'});
     // There's nothing equivalent to stream.onremovetrack when you don't have a
     // stream, but the track should become muted (if it isn't already).
     if (!remoteTrack.muted) {
@@ -151,7 +151,7 @@
 
     // Rolling back the offer revives the track, causing ontrack to fire again.
     remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
-    await pc2.setLocalDescription({type:'rollback'});
+    await pc2.setRemoteDescription({type:'rollback'});
     const revivedRemoteStream = await remoteStreamViaOnTrackPromise;
     // This test only expects IDs to be the same. The same stream object should
     // also be used, but this should be covered by separate tests.
@@ -201,7 +201,7 @@
 
     // Rolling back the offer revives the track, causing ontrack to fire again.
     remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
-    await pc2.setLocalDescription({type:'rollback'});
+    await pc2.setRemoteDescription({type:'rollback'});
     const revivedRemoteTrack = await remoteTrackPromise;
     // We can be sure the same track is used, because the same transceiver is
     // used (and transciever.receiver.track has same lifetime as transceiver).
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html b/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html
index 590571c..dba0b1d2 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html
@@ -27,7 +27,7 @@
     }
   };
 
-  function onIceConnectionStateChange(done, failed) {
+  function onIceConnectionStateChange(done, failed, event) {
     try {
       assert_equals(event.type, 'iceconnectionstatechange');
       assert_not_equals(gFirstConnection.iceConnectionState, "failed",
@@ -59,14 +59,14 @@
       gFirstConnection.onicecandidate =
           (event) => onIceCandidate(gSecondConnection, event, reject);
       gFirstConnection.oniceconnectionstatechange =
-          () => onIceConnectionStateChange(resolve, reject);
+          (event) => onIceConnectionStateChange(resolve, reject, event);
 
       gSecondConnection = new RTCPeerConnection(null);
       test.add_cleanup(() => gSecondConnection.close());
       gSecondConnection.onicecandidate =
           (event) => onIceCandidate(gFirstConnection, event, reject);
       gSecondConnection.oniceconnectionstatechange =
-          () => onIceConnectionStateChange(resolve, reject);
+          (event) => onIceConnectionStateChange(resolve, reject, event);
 
       const offer = await generateVideoReceiveOnlyOffer(gFirstConnection);
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html b/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html
index cff801d..569f1fda 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>RTCPeerConnection BUNDLE</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/msid-generate.html b/third_party/blink/web_tests/external/wpt/webrtc/protocol/msid-generate.html
index 0fcf28ee..29226c7 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/msid-generate.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/msid-generate.html
@@ -31,6 +31,13 @@
   assert_regexp_match(msid_lines[0], /^a=msid:-/);
 }, 'AddTrack without a stream produces MSID with no stream ID');
 
+// token-char from RFC 4566
+// This is printable characters except whitespace, and ["(),/:;<=>?@[\]]
+const token_char = '\\x21\\x23-\\x27\\x2A-\\x2B\\x2D-\\x2E\\x30-\\x39\\x41-\\x5A\\x5E-\\x7E';
+
+// msid-value from RFC 8830
+const msid_attr = RegExp(`^a=msid:[${token_char}]{1,64}( [${token_char}]{1,64})?$`);
+
 promise_test(async t => {
   const pc = new RTCPeerConnection();
   t.add_cleanup(() => pc.close());
@@ -39,7 +46,7 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 1);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
 }, 'AddTrack with a stream produces MSID with a stream ID');
 
 promise_test(async t => {
@@ -51,8 +58,8 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 2);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
-  assert_regexp_match(msid_lines[1], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
+  assert_regexp_match(msid_lines[1], msid_attr);
 }, 'AddTrack with two streams produces two MSID lines');
 
 promise_test(async t => {
@@ -63,7 +70,7 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 1);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
 }, 'AddTrack with the stream twice produces single MSID with a stream ID');
 
 promise_test(async t => {
@@ -85,7 +92,7 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 1);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
 }, 'AddTransceiver with a stream produces MSID with a stream ID');
 
 promise_test(async t => {
@@ -97,8 +104,8 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 2);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
-  assert_regexp_match(msid_lines[1], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
+  assert_regexp_match(msid_lines[1], msid_attr);
 }, 'AddTransceiver with two streams produces two MSID lines');
 
 promise_test(async t => {
@@ -109,7 +116,7 @@
 const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 1);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
 }, 'AddTransceiver with the stream twice produces single MSID with a stream ID');
 
 promise_test(async t => {
@@ -121,7 +128,7 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 1);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
 }, 'SetStreams with a stream produces MSID with a stream ID');
 
 promise_test(async t => {
@@ -134,8 +141,8 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 2);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
-  assert_regexp_match(msid_lines[1], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
+  assert_regexp_match(msid_lines[1], msid_attr);
 }, 'SetStreams with two streams produces two MSID lines');
 
 promise_test(async t => {
@@ -147,7 +154,7 @@
   const desc = await pc.createOffer();
   const msid_lines = msidLines(desc);
   assert_equals(msid_lines.length, 1);
-  assert_regexp_match(msid_lines[0], /^a=msid:[\!#$%&'*+-.0-9a-zA-Z]/);
+  assert_regexp_match(msid_lines[0], msid_attr);
 }, 'SetStreams with the stream twice produces single MSID with a stream ID');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/rtp-extension-support.html b/third_party/blink/web_tests/external/wpt/webrtc/protocol/rtp-extension-support.html
index bf6954e..045701c 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/rtp-extension-support.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/rtp-extension-support.html
@@ -10,7 +10,11 @@
 async function setup() {
   const pc1 = new RTCPeerConnection();
   pc1.addTransceiver('audio');
-  pc1.addTransceiver('video');
+  // Make sure there is more than one rid, since there's no reason to use
+  // rtp-stream-id/repaired-rtp-stream-id otherwise. Some implementations
+  // may use them for unicast anyway, which isn't a spec violation, just
+  // a little silly.
+  pc1.addTransceiver('video', {sendEncodings: [{rid: '0'}, {rid: '1'}]});
   const offer = await pc1.createOffer();
   pc1.close();
   return offer.sdp;
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer-expected.txt
index e58b0c1..1c3638b 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 PASS createAnswer() with multiple send encodings should create simulcast answer
-FAIL Using the ~rid SDP syntax in a remote offer does not control the local encodings active flag assert_not_equals: got disallowed value undefined
+FAIL Using the ~rid SDP syntax in a remote offer does not control the local encodings active flag assert_not_equals: got disallowed value false
 FAIL Disabling encodings locally does not change the SDP assert_not_equals: Could not find simulcast attribute. got disallowed value undefined
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer.html b/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer.html
index 06a6e79..5e19bc0 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/simulcast-answer.html
@@ -64,8 +64,9 @@
   t.add_cleanup(() => pc.close());
   const expected_rids = ['foo', 'bar', 'baz'];
 
-  // Try to disable the `bar` encoding by prefixing it with the `~` character.
-  await pc.setRemoteDescription({type: 'offer', sdp: offer_sdp.replace('bar', '~bar')});
+  // Try to disable the `bar` encoding in a=simulcast by prefixing it with the
+  // `~` character.
+  await pc.setRemoteDescription({type: 'offer', sdp: offer_sdp.replace(/(a=simulcast:.*)bar/, '$1~bar')});
   const transceiver = pc.getTransceivers()[0];
   transceiver.direction = 'sendonly';
   await pc.setLocalDescription();
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-active.https.html b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-active.https.html
index 36f096a..dbe162c 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-active.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-active.https.html
@@ -40,7 +40,7 @@
 
   // Assert (almost) no new frames are received on the first encoding.
   // Without any action we would expect to have received around 30fps.
-  await new Promise(resolve => t.step_timeout(resolve, 100)); // Wait a bit.
+  await new Promise(resolve => t.step_timeout(resolve, 200)); // Wait a bit.
   const initialStats = await queryReceiverStats(pc2);
   await new Promise(resolve => t.step_timeout(resolve, 1000)); // Wait more.
   const subsequentStats = await queryReceiverStats(pc2);
@@ -65,7 +65,7 @@
 
   // Assert (almost) no new frames are received on the second encoding.
   // Without any action we would expect to have received around 30fps.
-  await new Promise(resolve => t.step_timeout(resolve, 100)); // Wait a bit.
+  await new Promise(resolve => t.step_timeout(resolve, 200)); // Wait a bit.
   const initialStats = await queryReceiverStats(pc2);
   await new Promise(resolve => t.step_timeout(resolve, 1000)); // Wait more.
   const subsequentStats = await queryReceiverStats(pc2);
@@ -92,7 +92,7 @@
 
   // Assert (almost) no new frames are received.
   // Without any action we would expect to have received around 30fps.
-  await new Promise(resolve => t.step_timeout(resolve, 100)); // Wait a bit.
+  await new Promise(resolve => t.step_timeout(resolve, 200)); // Wait a bit.
   const initialStats = await queryReceiverStats(pc2);
   await new Promise(resolve => t.step_timeout(resolve, 1000)); // Wait more.
   const subsequentStats = await queryReceiverStats(pc2);
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-encodings.https.html b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-encodings.https.html
index fb33529..ac04ca55 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-encodings.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/setParameters-encodings.https.html
@@ -12,12 +12,6 @@
 <script src="../../mediacapture-streams/permission-helper.js"></script>
 <script>
 
-async function queueAWebrtcTask() {
-  const pc = new RTCPeerConnection();
-  pc.addTransceiver('audio');
-  await new Promise(r => pc.onnegotiationneeded = r);
-}
-
 promise_test(async t => {
   const pc1 = new RTCPeerConnection();
   t.add_cleanup(() => pc1.close());
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 2aee530c..15e77b25 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -556,7 +556,7 @@
     "structures": [2800],
   },
   "<(SHARED_INTERMEDIATE_DIR)/chrome/test/data/webui/resources.grd": {
-    "META": {"sizes": {"includes": [1200],}},
+    "META": {"sizes": {"includes": [1400],}},
     "includes": [2810],
   },
   "chrome/test/data/webui_test_resources.grd": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c061408b..ec5d455 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -41938,6 +41938,7 @@
   <int value="4449" label="WindowManagementPermissionPolicyParsed"/>
   <int value="4450" label="WindowPlacementPermissionPolicyParsed"/>
   <int value="4451" label="ContentDispositionInSvgUse"/>
+  <int value="4452" label="SameDocumentCrossOriginInitiator"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -57574,6 +57575,7 @@
       label="OmniboxOnDeviceHeadProviderIncognito:disabled"/>
   <int value="-2039343702"
       label="KeepAliveRendererForKeepaliveRequests:enabled"/>
+  <int value="-2038973140" label="VideoConference:enabled"/>
   <int value="-2037390759"
       label="IncognitoBrandConsistencyForAndroid:disabled"/>
   <int value="-2037280696" label="EcheSWASendStartSignaling:disabled"/>
@@ -58456,6 +58458,7 @@
   <int value="-1544248549" label="ArcUseAuthEndpoint:enabled"/>
   <int value="-1543316040"
       label="DisplayPersistenceToggleInPermissionPrompts:disabled"/>
+  <int value="-1543066715" label="VideoConference:disabled"/>
   <int value="-1541362086" label="NearbySharing:disabled"/>
   <int value="-1541187160" label="UsernameFirstFlow:disabled"/>
   <int value="-1540007054" label="ArcHostVpn:disabled"/>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index 28021430..e3b7163 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -1488,7 +1488,7 @@
 </histogram>
 
 <histogram name="IOS.Permission.Requests" enum="IOSPermissionRequest"
-    expires_after="2023-03-05">
+    expires_after="2024-01-24">
   <owner>ewannpv@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
   <owner>bling-team@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 1f8156b..149e1dd0 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,16 +5,16 @@
             "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "17f3538978e7d968d9a0df4a3f68b4d9c055582b",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/0b639cd98fb0b22d2761bb2f599cbe8cbc1901de/trace_processor_shell.exe"
+            "hash": "e51500880a1dfa116d8e0a9c9d5b7c6b26f6e282",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/61eeba8d065b8fc69f9dee9b36bc94d9d6a0293c/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "6373f26144aad58f230d11d6a91efda5a09c9873",
             "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "6a840cdee39c2c1ad850174e2ee1af8286338fb2",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/0b639cd98fb0b22d2761bb2f599cbe8cbc1901de/trace_processor_shell"
+            "hash": "55a6e7422a7010087569ee63bb9b5f909c518699",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/61eeba8d065b8fc69f9dee9b36bc94d9d6a0293c/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "5f47ee79e59d00bf3889d30ca52315522c158040",
diff --git a/tools/traffic_annotation/auditor/safe_list.txt b/tools/traffic_annotation/auditor/safe_list.txt
index 1524de6..edddfcc15 100644
--- a/tools/traffic_annotation/auditor/safe_list.txt
+++ b/tools/traffic_annotation/auditor/safe_list.txt
@@ -61,7 +61,6 @@
 missing_new_fields,chrome/browser/apps/app_preload_service/app_preload_server_connector.cc
 missing_new_fields,chrome/browser/ash/app_list/search/files/item_suggest_cache.cc
 missing_new_fields,chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.cc
-missing_new_fields,chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc
 missing_new_fields,chrome/browser/ash/bruschetta/bruschetta_installer.cc
 missing_new_fields,chrome/browser/ash/customization/customization_document.cc
 missing_new_fields,chrome/browser/ash/customization/customization_wallpaper_downloader.cc
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 790654b..3481c46 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -284,7 +284,7 @@
  <item id="image_downloader" added_in_milestone="98" content_hash_code="05b52680" os_list="chromeos" file_path="ash/assistant/assistant_controller_impl.cc" />
  <item id="fast_pair_footprints_request" added_in_milestone="102" type="partial" second_id="oauth2_api_call_flow" content_hash_code="01d3d58d" os_list="chromeos" semantics_fields="1,2,3,4,5" policy_fields="-1,3,4" file_path="ash/quick_pair/repository/fast_pair/footprints_fetcher_impl.cc" />
  <item id="kiosk_app_icon" added_in_milestone="98" content_hash_code="04f02fef" os_list="chromeos" file_path="chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.cc" />
- <item id="arc_auth_code_fetcher" added_in_milestone="98" content_hash_code="057519ca" os_list="chromeos" file_path="chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc" />
+ <item id="arc_auth_code_fetcher" added_in_milestone="98" content_hash_code="021af0fe" os_list="chromeos" file_path="chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc" />
  <item id="customization_wallpaper_downloader" added_in_milestone="98" content_hash_code="03ee8364" os_list="chromeos" file_path="chrome/browser/ash/customization/customization_wallpaper_downloader.cc" />
  <item id="ime_url_downloader" added_in_milestone="98" content_hash_code="00f13105" os_list="chromeos" file_path="chrome/browser/ash/input_method/ime_service_connector.cc" />
  <item id="chromebook_mail_api" added_in_milestone="98" content_hash_code="01bfcf72" os_list="chromeos" file_path="chrome/browser/ash/login/marketing_backend_connector.cc" />
diff --git a/ui/base/ime/ash/input_method_ash.cc b/ui/base/ime/ash/input_method_ash.cc
index 52e52c7..e0553ab4 100644
--- a/ui/base/ime/ash/input_method_ash.cc
+++ b/ui/base/ime/ash/input_method_ash.cc
@@ -553,7 +553,7 @@
     pending_composition_ = absl::nullopt;
     composition_changed_ = false;
   }
-  if (client && client->HasCompositionText()) {
+  if (client) {
     const size_t characters_committed =
         client->ConfirmCompositionText(/*keep_selection*/ true);
     typing_session_manager_.CommitCharacters(characters_committed);
diff --git a/ui/file_manager/file_manager/common/js/trash.ts b/ui/file_manager/file_manager/common/js/trash.ts
index a0844bc..c374779 100644
--- a/ui/file_manager/file_manager/common/js/trash.ts
+++ b/ui/file_manager/file_manager/common/js/trash.ts
@@ -28,7 +28,7 @@
 import {isFileSystemDirectoryEntry, isFileSystemFileEntry} from './entry_utils.js';
 import {FakeEntryImpl} from './files_app_entry_types.js';
 import {metrics} from './metrics.js';
-import {util} from './util.js';
+import {str, util} from './util.js';
 import {VolumeManagerCommon} from './volume_manager_types.js';
 
 /**
@@ -555,7 +555,7 @@
  */
 export class TrashRootEntry extends FakeEntryImpl {
   constructor() {
-    super('Trash', VolumeManagerCommon.RootType.TRASH);
+    super(str('TRASH_ROOT_LABEL'), VolumeManagerCommon.RootType.TRASH);
   }
 }
 
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 5cf6dab7e..29b2dcca 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -411,6 +411,8 @@
     "test/mock_wayland_zcr_color_manager.h",
     "test/mock_wp_presentation.cc",
     "test/mock_wp_presentation.h",
+    "test/mock_xdg_activation_v1.cc",
+    "test/mock_xdg_activation_v1.h",
     "test/mock_xdg_shell.cc",
     "test/mock_xdg_shell.h",
     "test/mock_xdg_surface.cc",
@@ -550,6 +552,7 @@
     "//third_party/wayland-protocols:text_input_extension_protocol",
     "//third_party/wayland-protocols:text_input_protocol",
     "//third_party/wayland-protocols:viewporter_protocol",
+    "//third_party/wayland-protocols:xdg_activation",
     "//third_party/wayland-protocols:xdg_output_protocol",
     "//third_party/wayland-protocols:xdg_shell_protocol",
     "//ui/display:test_support",
@@ -584,6 +587,7 @@
     "host/wayland_zaura_shell_unittest.cc",
     "host/wayland_zcr_color_manager_unittest.cc",
     "host/wayland_zwp_pointer_gestures_unittest.cc",
+    "host/xdg_activation_unittest.cc",
     "host/zwp_text_input_wrapper_v1_unittest.cc",
     "test/wayland_drag_drop_test.cc",
     "test/wayland_drag_drop_test.h",
diff --git a/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/ui/ozone/platform/wayland/host/wayland_clipboard.cc
index 1672e43..898f3282 100644
--- a/ui/ozone/platform/wayland/host/wayland_clipboard.cc
+++ b/ui/ozone/platform/wayland/host/wayland_clipboard.cc
@@ -111,22 +111,23 @@
       offered_data_ = *data;
       source_ = manager_->CreateSource(this);
       source_->Offer(GetOfferedMimeTypes());
-    }
 
-    // TODO(nickdiego): This function should just no-op if no serial is found
-    // (ie: no recent input event has been processed yet), though several unit
-    // and browser tests do not satisfy this precondition so would fail [1].
-    // Revisit this once those tests are fixed.
-    //
-    // [1] https://chromium-review.googlesource.com/c/chromium/src/+/3527605/2
-    auto& serial_tracker = connection_->serial_tracker();
-    auto serial = serial_tracker.GetSerial({wl::SerialType::kTouchPress,
-                                            wl::SerialType::kMousePress,
-                                            wl::SerialType::kKeyPress});
-    if (serial.has_value())
-      GetDevice()->SetSelectionSource(source_.get(), serial->value);
-    else
-      LOG(WARNING) << "No serial found for selection.";
+      // TODO(nickdiego): This function should just no-op if no serial is found
+      // (ie: no recent input event has been processed yet), though several unit
+      // and browser tests do not satisfy this precondition so would fail [1].
+      // Revisit this once those tests are fixed.
+      //
+      // [1] https://chromium-review.googlesource.com/c/chromium/src/+/3527605/2
+      auto& serial_tracker = connection_->serial_tracker();
+      auto serial = serial_tracker.GetSerial({wl::SerialType::kTouchPress,
+                                              wl::SerialType::kMousePress,
+                                              wl::SerialType::kKeyPress});
+      if (serial.has_value()) {
+        GetDevice()->SetSelectionSource(source_.get(), serial->value);
+      } else {
+        LOG(WARNING) << "No serial found for selection.";
+      }
+    }
 
     if (!clipboard_changed_callback_.is_null())
       clipboard_changed_callback_.Run(buffer_);
diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc
index 11fea6e5..b350b9e4 100644
--- a/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -23,7 +23,6 @@
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_output.h"
 #include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
-#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
 #include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
 
 namespace ui {
@@ -135,10 +134,6 @@
   if (child_window())
     child_window()->Hide();
   WaylandWindow::Hide();
-  // Mutter compositor crashes if we don't reset subsurfaces when hiding.
-  if (WaylandWindow::primary_subsurface()) {
-    WaylandWindow::primary_subsurface()->ResetSubsurface();
-  }
 
   if (IsSupportedOnAuraSurface(ZAURA_SURFACE_RELEASE_SINCE_VERSION))
     SetAuraSurface(nullptr);
diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
index 3cc49a0a..f298523 100644
--- a/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
@@ -56,41 +56,27 @@
 }
 
 void WaylandSubsurface::Show() {
-  if (visible_) {
-    return;
-  }
-
-  if (subsurface_) {
-    ResetSubsurface();
-  }
-
-  CreateSubsurface();
-  visible_ = true;
+  if (!subsurface_)
+    CreateSubsurface();
 }
 
 void WaylandSubsurface::Hide() {
-  if (!IsVisible() || !subsurface_) {
+  if (!subsurface_)
     return;
-  }
 
   // Remove it from the stack.
   RemoveFromList();
-  visible_ = false;
-}
 
-void WaylandSubsurface::ResetSubsurface() {
   augmented_subsurface_.reset();
   subsurface_.reset();
-  wayland_surface_.UnsetRootWindow();
 }
 
 bool WaylandSubsurface::IsVisible() const {
-  return visible_;
+  return !!subsurface_;
 }
 
 void WaylandSubsurface::CreateSubsurface() {
   DCHECK(parent_);
-  wayland_surface_.SetRootWindow(parent_);
 
   wl_subcompositor* subcompositor = connection_->subcompositor();
   DCHECK(subcompositor);
diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.h b/ui/ozone/platform/wayland/host/wayland_subsurface.h
index 305e9cd..d830615 100644
--- a/ui/ozone/platform/wayland/host/wayland_subsurface.h
+++ b/ui/ozone/platform/wayland/host/wayland_subsurface.h
@@ -54,11 +54,9 @@
   // Assigns wl_subsurface role to the wl_surface so it is visible when a
   // wl_buffer is attached.
   void Show();
-  // Remove this from the stack to make this invisible.
+  // Remove wl_subsurface role to make this invisible.
   void Hide();
   bool IsVisible() const;
-  // Reset the subsurface objects.
-  void ResetSubsurface();
 
  private:
   // Helper of Show(). It does the role-assigning to wl_surface.
@@ -74,7 +72,6 @@
   // |parent_| refers to the WaylandWindow whose wl_surface is the parent to
   // this subsurface.
   const raw_ptr<WaylandWindow> parent_;
-  bool visible_ = false;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
index 5d95f544..588d621 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -223,10 +223,6 @@
   root_window_ = nullptr;
 }
 
-void WaylandSurface::SetRootWindow(WaylandWindow* window) {
-  root_window_ = window;
-}
-
 void WaylandSurface::set_acquire_fence(gfx::GpuFenceHandle acquire_fence) {
   // WaylandBufferManagerGPU knows if the synchronization is not available and
   // must disallow clients to use explicit synchronization.
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
index 1193fd98..fe57f9d 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -84,7 +84,6 @@
   // the underlying wl_surface must be kept alive with no root window associated
   // (e.g: window/tab dragging sessions).
   void UnsetRootWindow();
-  void SetRootWindow(WaylandWindow* window);
 
   // Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
   // Returns true if wl_surface.attach will be called in ApplyPendingStates().
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index b9901c9..b0e4b29 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -89,8 +89,6 @@
   if (wayland_overlay_delegation_enabled_) {
     connection_->window_manager()->RemoveSubsurface(GetWidget(),
                                                     primary_subsurface_.get());
-    connection_->window_manager()->RecycleSubsurface(
-        std::move(primary_subsurface_));
   }
   for (const auto& widget_subsurface : wayland_subsurfaces()) {
     connection_->window_manager()->RemoveSubsurface(GetWidget(),
@@ -284,6 +282,7 @@
 void WaylandWindow::Hide() {
   received_configure_event_ = false;
 
+  // Mutter compositor crashes if we don't remove subsurface roles when hiding.
   if (primary_subsurface_) {
     primary_subsurface()->Hide();
   }
diff --git a/ui/ozone/platform/wayland/host/wayland_window_manager.cc b/ui/ozone/platform/wayland/host/wayland_window_manager.cc
index d65cc6e..10ff600 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_manager.cc
@@ -228,14 +228,6 @@
     observer.OnSubsurfaceRemoved(window, subsurface);
 }
 
-void WaylandWindowManager::RecycleSubsurface(
-    std::unique_ptr<WaylandSubsurface> subsurface) {
-  // Reset the root window when the corresponding subsurface is invalid,
-  // preventing it from receiving events.
-  subsurface->wayland_surface()->UnsetRootWindow();
-  subsurface_recycle_cache_ = std::move(subsurface);
-}
-
 gfx::AcceleratedWidget WaylandWindowManager::AllocateAcceleratedWidget() {
   return ++last_accelerated_widget_;
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_window_manager.h b/ui/ozone/platform/wayland/host/wayland_window_manager.h
index 08f45404..c95d7dc4 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_window_manager.h
@@ -12,7 +12,6 @@
 #include "base/observer_list.h"
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
 #include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
 
 namespace ui {
@@ -109,8 +108,6 @@
   void RemoveSubsurface(gfx::AcceleratedWidget widget,
                         WaylandSubsurface* subsurface);
 
-  void RecycleSubsurface(std::unique_ptr<WaylandSubsurface> subsurface);
-
   // Creates a new unique gfx::AcceleratedWidget.
   gfx::AcceleratedWidget AllocateAcceleratedWidget();
 
@@ -124,11 +121,6 @@
 
   base::flat_map<gfx::AcceleratedWidget, WaylandWindow*> window_map_;
 
-  // The cache of |primary_subsurface_| of the last closed WaylandWindow. This
-  // will be destroyed lazily to make sure the window closing animation works
-  // well. See crbug.com/1324548.
-  std::unique_ptr<WaylandSubsurface> subsurface_recycle_cache_;
-
   raw_ptr<WaylandWindow> located_events_grabber_ = nullptr;
 
   // Stores strictly monotonically increasing counter for allocating unique
diff --git a/ui/ozone/platform/wayland/host/xdg_activation.cc b/ui/ozone/platform/wayland/host/xdg_activation.cc
index 026bccd2..3d573a2a 100644
--- a/ui/ozone/platform/wayland/host/xdg_activation.cc
+++ b/ui/ozone/platform/wayland/host/xdg_activation.cc
@@ -80,13 +80,13 @@
 XdgActivation::~XdgActivation() = default;
 
 void XdgActivation::Activate(wl_surface* surface) const {
-  const WaylandWindow* const active_window =
-      connection_->window_manager()->GetCurrentActiveWindow();
-  if (!active_window) {
-    LOG(WARNING) << "Cannot activate a window because no active windows found!";
-    return;
-  }
-
+  // The spec isn't clear about what types of surfaces should be used as
+  // the requestor surface, but all implementations of xdg_activation_v1
+  // known to date accept the currently keyboard focused surface for
+  // activation. Update if needed once the upstream issue gets fixed:
+  // https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/129
+  const WaylandWindow* const keyboard_focused_window =
+      connection_->window_manager()->GetCurrentKeyboardFocusedWindow();
   if (token_.get() != nullptr) {
     // If the earlier activation request is still being served, store the
     // incoming request and try to serve it after the current one is done.
@@ -94,12 +94,10 @@
     return;
   }
 
-  wl_surface* const active_surface = active_window->root_surface()->surface();
-  if (!active_surface) {
-    LOG(WARNING) << "Cannot activate a window because the currently active "
-                    "window has no surface!";
-    return;
-  }
+  wl_surface* const keyboard_focused_surface =
+      keyboard_focused_window
+          ? keyboard_focused_window->root_surface()->surface()
+          : nullptr;
 
   auto* const token =
       xdg_activation_v1_get_activation_token(xdg_activation_v1_.get());
@@ -109,7 +107,7 @@
   }
 
   token_ = std::make_unique<Token>(
-      wl::Object<xdg_activation_token_v1>(token), active_surface,
+      wl::Object<xdg_activation_token_v1>(token), keyboard_focused_surface,
       connection_->seat()->wl_object(),
       connection_->serial_tracker().GetSerial(
           {wl::SerialType::kTouchPress, wl::SerialType::kMousePress,
@@ -135,9 +133,12 @@
     : token_(std::move(token)), callback_(std::move(callback)) {
   static constexpr xdg_activation_token_v1_listener kListener = {&Done};
   xdg_activation_token_v1_add_listener(token_.get(), &kListener, this);
-  xdg_activation_token_v1_set_surface(token_.get(), surface);
-  if (serial)
+  if (surface) {
+    xdg_activation_token_v1_set_surface(token_.get(), surface);
+  }
+  if (serial) {
     xdg_activation_token_v1_set_serial(token_.get(), serial->value, seat);
+  }
   xdg_activation_token_v1_commit(token_.get());
 }
 
diff --git a/ui/ozone/platform/wayland/host/xdg_activation_unittest.cc b/ui/ozone/platform/wayland/host/xdg_activation_unittest.cc
new file mode 100644
index 0000000..05d2d09f
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/xdg_activation_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/xdg_activation.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/wayland/host/wayland_seat.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.h"
+#include "ui/ozone/platform/wayland/test/test_keyboard.h"
+#include "ui/ozone/platform/wayland/test/test_util.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+
+using ::testing::_;
+using ::testing::StrEq;
+using ::testing::Values;
+
+namespace ui {
+
+namespace {
+
+constexpr gfx::Rect kDefaultBounds(0, 0, 100, 100);
+const char kMockStaticTestToken[] = "CHROMIUM_MOCK_XDG_ACTIVATION_TOKEN";
+
+}  // namespace
+
+using XdgActivationTest = WaylandTest;
+
+// Tests that XdgActivation uses the proper surface to request window
+// activation.
+TEST_P(XdgActivationTest, WindowActivation) {
+  MockWaylandPlatformWindowDelegate delegate;
+
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    wl_seat_send_capabilities(server->seat()->resource(),
+                              WL_SEAT_CAPABILITY_KEYBOARD);
+  });
+  ASSERT_TRUE(connection_->seat()->keyboard());
+
+  window_.reset();
+
+  auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
+                                               kDefaultBounds, &delegate);
+  auto window2 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
+                                               kDefaultBounds, &delegate);
+
+  // When window is shown, it automatically gets keyboard focus. Reset it
+  connection_->window_manager()->SetKeyboardFocusedWindow(nullptr);
+
+  auto surface_id1 = window1->root_surface()->get_surface_id();
+  auto surface_id2 = window2->root_surface()->get_surface_id();
+
+  ActivateSurface(surface_id1);
+  ActivateSurface(surface_id2);
+
+  PostToServerAndWait([surface_id2](wl::TestWaylandServerThread* server) {
+    auto* const keyboard = server->seat()->keyboard()->resource();
+    auto* const xdg_activation = server->xdg_activation_v1();
+    auto* const surface2 =
+        server->GetObject<wl::MockSurface>(surface_id2)->resource();
+
+    wl::ScopedWlArray empty({});
+    wl_keyboard_send_enter(keyboard, server->GetNextSerial(), surface2,
+                           empty.get());
+
+    EXPECT_CALL(*xdg_activation, TokenSetSurface(_, _, surface2));
+    EXPECT_CALL(*xdg_activation, TokenCommit(_, _));
+  });
+
+  connection_->xdg_activation()->Activate(window1->root_surface()->surface());
+
+  PostToServerAndWait([surface_id1](wl::TestWaylandServerThread* server) {
+    auto* const xdg_activation = server->xdg_activation_v1();
+    auto* const token = xdg_activation->get_token();
+
+    auto* const surface1 =
+        server->GetObject<wl::MockSurface>(surface_id1)->resource();
+
+    xdg_activation_token_v1_send_done(token->resource(), kMockStaticTestToken);
+
+    EXPECT_CALL(*xdg_activation,
+                Activate(_, xdg_activation->resource(),
+                         StrEq(kMockStaticTestToken), surface1));
+  });
+}
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+                         XdgActivationTest,
+                         Values(wl::ServerConfig{}));
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/test/mock_xdg_activation_v1.cc b/ui/ozone/platform/wayland/test/mock_xdg_activation_v1.cc
new file mode 100644
index 0000000..72b6fe3
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/mock_xdg_activation_v1.cc
@@ -0,0 +1,85 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/test/mock_xdg_activation_v1.h"
+
+#include <wayland-server-core.h>
+
+#include "ui/ozone/platform/wayland/test/server_object.h"
+
+namespace wl {
+
+namespace {
+
+void SetSerial(struct wl_client* client,
+               struct wl_resource* resource,
+               uint32_t serial,
+               struct wl_resource* seat) {}
+
+void SetAppId(struct wl_client* client,
+              struct wl_resource* resource,
+              const char* app_id) {}
+
+void SetSurface(struct wl_client* client,
+                struct wl_resource* resource,
+                struct wl_resource* surface) {
+  GetUserDataAs<MockXdgActivationTokenV1>(resource)->SetSurface(
+      client, resource, surface);
+}
+
+void Commit(struct wl_client* client, struct wl_resource* resource) {
+  GetUserDataAs<MockXdgActivationTokenV1>(resource)->Commit(client, resource);
+}
+
+}  // namespace
+
+const struct xdg_activation_token_v1_interface kMockXdgActivationTokenV1Impl = {
+    &SetSerial,        // set_serial
+    &SetAppId,         // set_app_id
+    &SetSurface,       // set_surface
+    &Commit,           // commit
+    &DestroyResource,  // destroy
+};
+
+MockXdgActivationTokenV1::MockXdgActivationTokenV1(wl_resource* resource,
+                                                   MockXdgActivationV1* global)
+    : ServerObject(resource), global_(global) {}
+
+MockXdgActivationTokenV1::~MockXdgActivationTokenV1() = default;
+
+namespace {
+
+void GetActivationToken(struct wl_client* client,
+                        struct wl_resource* resource,
+                        uint32_t id) {
+  auto* global = GetUserDataAs<MockXdgActivationV1>(resource);
+  wl_resource* token = CreateResourceWithImpl<MockXdgActivationTokenV1>(
+      client, &xdg_activation_token_v1_interface, 1,
+      &kMockXdgActivationTokenV1Impl, id, global);
+  global->set_token(GetUserDataAs<MockXdgActivationTokenV1>(token));
+}
+
+void Activate(struct wl_client* client,
+              struct wl_resource* resource,
+              const char* token,
+              struct wl_resource* surface) {
+  GetUserDataAs<MockXdgActivationV1>(resource)->Activate(client, resource,
+                                                         token, surface);
+}
+
+}  // namespace
+
+const struct xdg_activation_v1_interface kMockXdgActivationV1Impl = {
+    &DestroyResource,
+    &GetActivationToken,
+    &Activate,
+};
+
+MockXdgActivationV1::MockXdgActivationV1()
+    : GlobalObject(&xdg_activation_v1_interface, &kMockXdgActivationV1Impl, 1) {
+}
+
+MockXdgActivationV1::~MockXdgActivationV1() = default;
+
+}  // namespace wl
diff --git a/ui/ozone/platform/wayland/test/mock_xdg_activation_v1.h b/ui/ozone/platform/wayland/test/mock_xdg_activation_v1.h
new file mode 100644
index 0000000..b86af19
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/mock_xdg_activation_v1.h
@@ -0,0 +1,79 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_XDG_ACTIVATION_V1_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_XDG_ACTIVATION_V1_H_
+
+#include <xdg-activation-v1-server-protocol.h>
+
+#include "base/check.h"
+#include "base/memory/raw_ptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/ozone/platform/wayland/test/global_object.h"
+#include "ui/ozone/platform/wayland/test/server_object.h"
+
+namespace wl {
+
+extern const struct xdg_activation_token_v1_interface
+    kMockXdgActivationTokenV1Impl;
+extern const struct xdg_activation_v1_interface kMockXdgActivationV1Impl;
+
+class MockXdgActivationTokenV1;
+
+class MockXdgActivationV1 : public GlobalObject {
+ public:
+  MockXdgActivationV1();
+
+  MockXdgActivationV1(const MockXdgActivationV1&) = delete;
+  MockXdgActivationV1& operator=(const MockXdgActivationV1&) = delete;
+
+  ~MockXdgActivationV1() override;
+
+  MockXdgActivationTokenV1* get_token() { return token_; }
+  void set_token(MockXdgActivationTokenV1* token) { token_ = token; }
+
+  MOCK_METHOD4(Activate,
+               void(struct wl_client* client,
+                    struct wl_resource* resource,
+                    const char* token,
+                    struct wl_resource* surface));
+  MOCK_METHOD3(TokenSetSurface,
+               void(struct wl_client* client,
+                    struct wl_resource* resource,
+                    struct wl_resource* surface));
+
+  MOCK_METHOD2(TokenCommit,
+               void(struct wl_client* client, struct wl_resource* resource));
+
+ private:
+  raw_ptr<MockXdgActivationTokenV1> token_ = nullptr;
+};
+
+class MockXdgActivationTokenV1 : public ServerObject {
+ public:
+  explicit MockXdgActivationTokenV1(wl_resource* resource,
+                                    MockXdgActivationV1* global);
+
+  MockXdgActivationTokenV1(const MockXdgActivationTokenV1&) = delete;
+  MockXdgActivationTokenV1& operator=(const MockXdgActivationTokenV1&) = delete;
+
+  ~MockXdgActivationTokenV1() override;
+
+  void SetSurface(struct wl_client* client,
+                  struct wl_resource* resource,
+                  struct wl_resource* surface) {
+    global_->TokenSetSurface(client, resource, surface);
+  }
+
+  void Commit(struct wl_client* client, struct wl_resource* resource) {
+    global_->TokenCommit(client, resource);
+  }
+
+ private:
+  raw_ptr<MockXdgActivationV1> global_ = nullptr;
+};
+
+}  // namespace wl
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_XDG_ACTIVATION_V1_H_
diff --git a/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc b/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
index 1a8c520a..bdf656c 100644
--- a/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
+++ b/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
@@ -147,6 +147,9 @@
   if (!zcr_color_manager_v1_.Initialize(display_.get())) {
     return false;
   }
+  if (!xdg_activation_v1_.Initialize(display_.get())) {
+    return false;
+  }
 
   client_ = wl_client_create(display_.get(), server_fd.release());
   if (!client_)
diff --git a/ui/ozone/platform/wayland/test/test_wayland_server_thread.h b/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
index b463345..a30cb6e 100644
--- a/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
+++ b/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
@@ -19,6 +19,7 @@
 #include "ui/ozone/platform/wayland/test/global_object.h"
 #include "ui/ozone/platform/wayland/test/mock_wayland_zcr_color_manager.h"
 #include "ui/ozone/platform/wayland/test/mock_wp_presentation.h"
+#include "ui/ozone/platform/wayland/test/mock_xdg_activation_v1.h"
 #include "ui/ozone/platform/wayland/test/mock_xdg_shell.h"
 #include "ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.h"
 #include "ui/ozone/platform/wayland/test/test_alpha_compositing.h"
@@ -159,6 +160,8 @@
     return &zcr_color_manager_v1_;
   }
 
+  MockXdgActivationV1* xdg_activation_v1() { return &xdg_activation_v1_; }
+
   void set_output_delegate(OutputDelegate* delegate) {
     output_delegate_ = delegate;
   }
@@ -230,6 +233,7 @@
   MockZwpLinuxDmabufV1 zwp_linux_dmabuf_v1_;
   MockWpPresentation wp_presentation_;
   TestWpPointerGestures wp_pointer_gestures_;
+  MockXdgActivationV1 xdg_activation_v1_;
   std::unique_ptr<TestSelectionDeviceManager> primary_selection_device_manager_;
 
   std::vector<std::unique_ptr<GlobalObject>> globals_;
diff --git a/ui/views/controls/editable_combobox/editable_combobox.cc b/ui/views/controls/editable_combobox/editable_combobox.cc
index a765682..583b72fc 100644
--- a/ui/views/controls/editable_combobox/editable_combobox.cc
+++ b/ui/views/controls/editable_combobox/editable_combobox.cc
@@ -116,7 +116,7 @@
   }
 
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
-    node_data->role = ax::mojom::Role::kComboBoxMenuButton;
+    node_data->role = ax::mojom::Role::kButton;
     node_data->SetName(GetAccessibleName());
     node_data->SetHasPopup(ax::mojom::HasPopup::kMenu);
     if (GetEnabled())
diff --git a/url/origin.h b/url/origin.h
index 5cefee6d..a86b021b 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -13,6 +13,7 @@
 #include "base/component_export.h"
 #include "base/debug/alias.h"
 #include "base/debug/crash_logging.h"
+#include "base/gtest_prod_util.h"
 #include "base/strings/string_piece_forward.h"
 #include "base/strings/string_util.h"
 #include "base/unguessable_token.h"
@@ -40,6 +41,8 @@
 namespace blink {
 class SecurityOrigin;
 class SecurityOriginTest;
+class StorageKey;
+class StorageKeyTest;
 }  // namespace blink
 
 namespace IPC {
@@ -329,6 +332,7 @@
  private:
   friend class blink::SecurityOrigin;
   friend class blink::SecurityOriginTest;
+  friend class blink::StorageKey;
   // SchemefulSite needs access to the serialization/deserialization logic which
   // includes the nonce.
   friend class net::SchemefulSite;
@@ -339,6 +343,7 @@
   friend IPC::ParamTraits<url::Origin>;
   friend COMPONENT_EXPORT(URL) std::ostream& operator<<(std::ostream& out,
                                                         const Origin& origin);
+  friend class blink::StorageKeyTest;
 
   // Origin::Nonce is a wrapper around base::UnguessableToken that generates
   // the random value only when the value is first accessed. The lazy generation