diff --git a/DEPS b/DEPS
index 7acef5c5..cdf0de1 100644
--- a/DEPS
+++ b/DEPS
@@ -304,7 +304,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'e910b73230f69c659acb209018fa7b0c4d92df5a',
+  'skia_revision': 'aedfc8695954891f3d796efbc61360c9d61cb6e2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -312,7 +312,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '9de913077a5fcc3d2f2e327b56bbe30efe2fde96',
+  'angle_revision': '5d1ac2e0d5f61913aad62dadb65a7fea6f1b93ae',
   # 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.20230112.1.1',
+  'fuchsia_version': 'version:11.20230114.0.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.
@@ -351,7 +351,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '397f1ecac4eb0d6810d6ef9ebf66f6540587deae',
+  'nacl_revision': 'b3e21e407441add84bcb5ee6ce90528678c53840',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -375,7 +375,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'a4c817894bde1ea6de4cbe2245a3d2848e1ea601',
+  'catapult_revision': '7a311fe439a587deb189305dd3118261ff2d6fb7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # 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': 'adccf1afe5d585b294dee247f5a4982aca8f5f1e',
+  'devtools_frontend_revision': '504995fbfc3bf21bcaf2718b6a469c5f23814936',
   # 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.
@@ -770,7 +770,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    'ae0ebbba3682d6e0677f277ae9d26370a01f4e9a',
+    'a3eade10e841e432b073be93ac34dfeda6c47991',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1041,7 +1041,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': '7ZPeHZjITxCcJzrEuxb5yznF7h65-RTQrbhzILJz4_gC',
+               'version': 'Oe3FpLcNFdPYOQQYUNnC4ajNSBfgmsFHDUaAimk7m6MC',
           },
       ],
       'condition': 'checkout_android',
@@ -1204,13 +1204,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4f50adb3325cbc0eb19ad3d94fd63a3dc4418817',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '86cfa62b0785d066d4970123a01994f699f2023d',
 
   'src/third_party/devtools-frontend/src':
     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' + '@' + 'fed2a37435f19bd1322341a98d61f60d15a31052',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '23a5686289bf734f7e6e9f3b4d5dd43d8747598a',
     'condition': 'checkout_src_internal',
   },
 
@@ -1497,7 +1497,7 @@
     Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da',
 
   'src/third_party/libwebp/src':
-    Var('chromium_git') + '/webm/libwebp.git' + '@' +  '7366f7f394af26de814296152c50e673ed0a832f',
+    Var('chromium_git') + '/webm/libwebp.git' + '@' +  '603e8d7adb0ccc35237419c2938194623b60e9be',
 
   'src/third_party/libyuv':
     Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '6e4b0acb4b3d5858c77a044aad46132998ac4a76',
@@ -1789,7 +1789,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@34d970c3d4fc94ce95ac037bdb21caefb62a929f',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@be2c232cf95d3c96e381ba527740bfc01fc2c1aa',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1826,7 +1826,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '4f3e800b7e1d384622e7d6dfe0ee192b49e0b739',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '1fdd20f75e0df4fa9a23c7edf31deacb500c7009',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '478f3b786e5d7dacbded7ed4e6346932d32ef0e3',
@@ -1899,7 +1899,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1d2598a8e3ad087738cfac16dcdff3be0217c2a4',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d443fadfd920248795c37d472042ec55ff18141d',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index e1a48d4..f38b46c 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1375,8 +1375,6 @@
     "system/machine_learning/user_settings_event_logger.h",
     "system/media/media_notification_provider.cc",
     "system/media/media_notification_provider.h",
-    "system/media/media_notification_provider_impl.cc",
-    "system/media/media_notification_provider_impl.h",
     "system/media/media_notification_provider_observer.h",
     "system/media/media_tray.cc",
     "system/media/media_tray.h",
@@ -1635,6 +1633,8 @@
     "system/phonehub/phone_hub_notification_controller.h",
     "system/phonehub/phone_hub_nudge.cc",
     "system/phonehub/phone_hub_nudge.h",
+    "system/phonehub/phone_hub_nudge_controller.cc",
+    "system/phonehub/phone_hub_nudge_controller.h",
     "system/phonehub/phone_hub_recent_app_button.cc",
     "system/phonehub/phone_hub_recent_app_button.h",
     "system/phonehub/phone_hub_recent_apps_view.cc",
@@ -3097,7 +3097,6 @@
     "system/locale/locale_detailed_view_unittest.cc",
     "system/locale/locale_feature_pod_controller_unittest.cc",
     "system/machine_learning/user_settings_event_logger_unittest.cc",
-    "system/media/media_notification_provider_impl_unittest.cc",
     "system/media/media_tray_unittest.cc",
     "system/media/unified_media_controls_container_unittest.cc",
     "system/media/unified_media_controls_controller_unittest.cc",
@@ -3154,6 +3153,7 @@
     "system/phonehub/camera_roll_view_unittest.cc",
     "system/phonehub/loading_indicator_view_unittest.cc",
     "system/phonehub/phone_hub_notification_controller_unittest.cc",
+    "system/phonehub/phone_hub_nudge_controller_unittest.cc",
     "system/phonehub/phone_hub_recent_apps_view_unittest.cc",
     "system/phonehub/phone_hub_tray_unittest.cc",
     "system/phonehub/phone_hub_ui_controller_unittest.cc",
diff --git a/ash/app_list/app_list_metrics.cc b/ash/app_list/app_list_metrics.cc
index 3595cc79..f3a704db 100644
--- a/ash/app_list/app_list_metrics.cc
+++ b/ash/app_list/app_list_metrics.cc
@@ -369,9 +369,7 @@
     case CommandId::UNINSTALL:
     case CommandId::REMOVE_FROM_FOLDER:
     case CommandId::INSTALL:
-    case CommandId::USE_LAUNCH_TYPE_PINNED:
     case CommandId::USE_LAUNCH_TYPE_REGULAR:
-    case CommandId::USE_LAUNCH_TYPE_FULLSCREEN:
     case CommandId::USE_LAUNCH_TYPE_WINDOW:
     case CommandId::USE_LAUNCH_TYPE_TABBED_WINDOW:
     case CommandId::USE_LAUNCH_TYPE_COMMAND_END:
@@ -396,6 +394,8 @@
     case CommandId::DEPRECATED_LAUNCH_TYPE_WINDOW:
     case CommandId::DEPRECATED_LAUNCH_TYPE_TABBED_WINDOW:
     case CommandId::DEPRECATED_LAUNCH_TYPE_FULLSCREEN:
+    case CommandId::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case CommandId::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
       NOTREACHED();
       return false;
   }
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.h b/ash/capture_mode/capture_mode_demo_tools_controller.h
index 19443a8e..70b5054 100644
--- a/ash/capture_mode/capture_mode_demo_tools_controller.h
+++ b/ash/capture_mode/capture_mode_demo_tools_controller.h
@@ -29,9 +29,9 @@
 using TouchHighlightLayersMap =
     base::flat_map<ui::PointerId, std::unique_ptr<PointerHighlightLayer>>;
 
-// Observes and decides whether to show a helper widget representing the
-// currently pressed key combination or not. The key combination will be used to
-// construct or modify the `KeyComboViewer`. The
+// Observes and decides whether to show clicks (or taps) highlights and a helper
+// widget that represents the currently pressed key combination or not. The key
+// combination will be used to construct or modify the `KeyComboViewer`. The
 // `CaptureModeDemoToolsController` will only be available during video
 // recording and has to be explicitly enabled by the user.
 class CaptureModeDemoToolsController : public ui::InputMethodObserver {
diff --git a/ash/capture_mode/capture_mode_demo_tools_unittests.cc b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
index 3c9f513..e45f626 100644
--- a/ash/capture_mode/capture_mode_demo_tools_unittests.cc
+++ b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
@@ -123,7 +123,7 @@
   }
 
   // Fires the key combo viewer timer and verifies the existence of the widget
-  // after the timer expires if `should_hide_view` is true.
+  // after the timer expires.
   void FireTimerAndVerifyWidget(bool should_hide_view) {
     auto* demo_tools_controller = GetCaptureModeDemoToolsController();
     DCHECK(demo_tools_controller);
diff --git a/ash/components/arc/arc_features.cc b/ash/components/arc/arc_features.cc
index c9d2546..77067049 100644
--- a/ash/components/arc/arc_features.cc
+++ b/ash/components/arc/arc_features.cc
@@ -40,6 +40,13 @@
              "ArcIdleManager",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+
+// For test purposes, ignore battery status changes, allowing Doze mode to
+// kick in even if we do not receive powerd changes related to battery.
+const base::FeatureParam<bool> kEnableArcIdleManagerIgnoreBatteryForPLT{
+    &kEnableArcIdleManager, "ignore_battery_for_test", false};
+
+
 // Controls whether files shared to ARC Nearby Share are shared through the
 // FuseBox filesystem, instead of the default method (through a temporary path
 // managed by file manager).
diff --git a/ash/components/arc/arc_features.h b/ash/components/arc/arc_features.h
index a43a311d..e6eb73e9 100644
--- a/ash/components/arc/arc_features.h
+++ b/ash/components/arc/arc_features.h
@@ -19,6 +19,7 @@
 BASE_DECLARE_FEATURE(kDocumentsProviderUnknownSizeFeature);
 BASE_DECLARE_FEATURE(kEnableArcHostVpn);
 BASE_DECLARE_FEATURE(kEnableArcIdleManager);
+extern const base::FeatureParam<bool> kEnableArcIdleManagerIgnoreBatteryForPLT;
 BASE_DECLARE_FEATURE(kEnableArcNearbyShareFuseBox);
 BASE_DECLARE_FEATURE(kEnableArcVmDataMigration);
 BASE_DECLARE_FEATURE(kEnableLazyWebViewInit);
diff --git a/ash/components/arc/mojom/net.mojom b/ash/components/arc/mojom/net.mojom
index e8b6c7986..a7368b59 100644
--- a/ash/components/arc/mojom/net.mojom
+++ b/ash/components/arc/mojom/net.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 26
+// Next MinVersion: 27
 
 // This file defines the mojo interface between the ARC networking stack and
 // Chrome OS. There are three different groups of interactions:
@@ -516,6 +516,13 @@
 
     // DNS server IP addresses included in the configuration
   [MinVersion=20] array<string>? dns_servers@13;
+
+  // A list of BSSIDs that control what APs can be connected to.
+  // If null, there are no restrictions and this field is ignored.
+  // If empty, then nothing is allowed and no AP will be connected to.
+  // If non-empty, then only APs whose BSSID is included in the list can be
+  // connected to. BSSIDs should be in MAC address format.
+  [MinVersion=26] array<string>? bssid_allowlist@14;
 };
 
 [Extensible]
diff --git a/ash/components/arc/net/arc_net_host_impl.cc b/ash/components/arc/net/arc_net_host_impl.cc
index e4dbcfe..36d87cc 100644
--- a/ash/components/arc/net/arc_net_host_impl.cc
+++ b/ash/components/arc/net/arc_net_host_impl.cc
@@ -537,6 +537,50 @@
                  << error_name << ", message: " << error_message;
 }
 
+void SetLohsEnabledSuccessCallback(
+    arc::ArcNetHostImpl::StartLohsCallback callback) {
+  std::move(callback).Run(arc::mojom::LohsStatus::kSuccess);
+}
+
+void SetLohsEnabledFailureCallback(
+    arc::ArcNetHostImpl::StartLohsCallback callback,
+    const std::string& dbus_error_name,
+    const std::string& dbus_error_message) {
+  NET_LOG(ERROR) << "SetLohsEnabledFailureCallback, error: " << dbus_error_name
+                 << ", message: " << dbus_error_message;
+  // TODO(b/259162524): Change this to a more specific "shill configuration"
+  // error
+  std::move(callback).Run(arc::mojom::LohsStatus::kErrorGeneric);
+}
+
+void SetLohsConfigPropertySuccessCallback(
+    arc::ArcNetHostImpl::StartLohsCallback callback) {
+  auto callback_split = base::SplitOnceCallback(std::move(callback));
+  ash::ShillManagerClient::Get()->SetLOHSEnabled(
+      true /* enabled */,
+      base::BindOnce(&SetLohsEnabledSuccessCallback,
+                     std::move(callback_split.first)),
+      base::BindOnce(&SetLohsEnabledFailureCallback,
+                     std::move(callback_split.second)));
+}
+
+void SetLohsConfigPropertyFailureCallback(
+    arc::ArcNetHostImpl::StartLohsCallback callback,
+    const std::string& dbus_error_name,
+    const std::string& dbus_error_message) {
+  NET_LOG(ERROR) << "SetLohsConfigPropertyFailureCallback, error: "
+                 << dbus_error_name << ", message: " << dbus_error_message;
+  // TODO(b/259162524): Change this to a more specific "shill configuration"
+  // error
+  std::move(callback).Run(arc::mojom::LohsStatus::kErrorGeneric);
+}
+
+void StopLohsFailureCallback(const std::string& error_name,
+                             const std::string& error_message) {
+  NET_LOG(ERROR) << "StopLohsFailureCallback, error:" << error_name
+                 << ", message: " << error_message;
+}
+
 }  // namespace
 
 namespace arc {
@@ -1437,6 +1481,69 @@
     NetworkPropertiesUpdated(network);
 }
 
+void ArcNetHostImpl::StartLohs(mojom::LohsConfigPtr config,
+                               StartLohsCallback callback) {
+  NET_LOG(USER) << "Starting LOHS";
+  base::Value dict(base::Value::Type::DICTIONARY);
+
+  if (config->hexssid.empty()) {
+    NET_LOG(ERROR) << "Cannot create local only hotspot without hex ssid";
+    std::move(callback).Run(arc::mojom::LohsStatus::kErrorGeneric);
+    return;
+  }
+  dict.GetDict().Set(shill::kTetheringConfSSIDProperty,
+                     base::Value(config->hexssid));
+
+  if (config->band != arc::mojom::WifiBand::k2Ghz) {
+    // TODO(b/257880335): Support 5Ghz band as well
+    NET_LOG(ERROR) << "Unsupported band for LOHS: " << config->band
+                   << "; can only support 2.4GHz";
+    // TODO(b/259162524): Change this to a more specific "invalid argument"
+    // error
+    std::move(callback).Run(arc::mojom::LohsStatus::kErrorGeneric);
+    return;
+  }
+  dict.GetDict().Set(shill::kTetheringConfBandProperty,
+                     base::Value(shill::kBand2GHz));
+
+  if (config->security_type != arc::mojom::SecurityType::WPA_PSK) {
+    NET_LOG(ERROR) << "Unsupported security for LOHS: " << config->security_type
+                   << "; can only support WPA_PSK";
+    // TODO(b/259162524): Change this to a more specific "invalid argument"
+    // error
+    std::move(callback).Run(arc::mojom::LohsStatus::kErrorGeneric);
+    return;
+  }
+  if (!config->passphrase.has_value()) {
+    NET_LOG(ERROR) << "Cannot create local only hotspot without password";
+    // TODO(b/259162524): Change this to a more specific "invalid argument"
+    // error
+    std::move(callback).Run(arc::mojom::LohsStatus::kErrorGeneric);
+    return;
+  }
+  dict.GetDict().Set(shill::kTetheringConfSecurityProperty,
+                     base::Value(shill::kSecurityWpa2));
+  dict.GetDict().Set(shill::kTetheringConfPassphraseProperty,
+                     base::Value(config->passphrase.value()));
+
+  NET_LOG(USER) << "Set Shill Manager property: " << shill::kLOHSConfigProperty
+                << ": " << dict;
+  auto callback_split = base::SplitOnceCallback(std::move(callback));
+  ash::ShillManagerClient::Get()->SetProperty(
+      shill::kLOHSConfigProperty, dict,
+      base::BindOnce(&SetLohsConfigPropertySuccessCallback,
+                     std::move(callback_split.first)),
+      base::BindOnce(&SetLohsConfigPropertyFailureCallback,
+                     std::move(callback_split.second)));
+}
+
+void ArcNetHostImpl::StopLohs() {
+  NET_LOG(USER) << "Stopping LOHS";
+  ash::ShillManagerClient::Get()->SetLOHSEnabled(
+      false /* enabled */, base::DoNothing(),
+      base::BindOnce(&StopLohsFailureCallback));
+}
+
 void ArcNetHostImpl::OnShuttingDown() {
   DCHECK(observing_network_state_);
   GetStateHandler()->RemoveObserver(this, FROM_HERE);
@@ -1444,16 +1551,4 @@
   observing_network_state_ = false;
 }
 
-void ArcNetHostImpl::StartLohs(mojom::LohsConfigPtr config,
-                               StartLohsCallback callback) {
-  // TODO(b/257880335): Retrieve the actual LOHS status.
-  std::move(callback).Run(arc::mojom::LohsStatus::kErrorGeneric);
-  return;
-}
-
-void ArcNetHostImpl::StopLohs() {
-  // TODO(b/257880335): Implement the stop request.
-  return;
-}
-
 }  // namespace arc
diff --git a/ash/components/arc/session/arc_bridge_host_impl.cc b/ash/components/arc/session/arc_bridge_host_impl.cc
index 9e9a76c4..54eb9f482 100644
--- a/ash/components/arc/session/arc_bridge_host_impl.cc
+++ b/ash/components/arc/session/arc_bridge_host_impl.cc
@@ -17,7 +17,6 @@
 #include "ash/components/arc/mojom/bluetooth.mojom.h"
 #include "ash/components/arc/mojom/boot_phase_monitor.mojom.h"
 #include "ash/components/arc/mojom/camera.mojom.h"
-#include "ash/components/arc/mojom/cert_store.mojom.h"
 #include "ash/components/arc/mojom/clipboard.mojom.h"
 #include "ash/components/arc/mojom/compatibility_mode.mojom.h"
 #include "ash/components/arc/mojom/crash_collector.mojom.h"
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 4acc0ad..6f3827a 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -637,11 +637,6 @@
 // If enabled, DriveFS will be used for Drive sync.
 BASE_FEATURE(kDriveFs, "DriveFS", base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Enables duplex native messaging between DriveFS and extensions.
-BASE_FEATURE(kDriveFsBidirectionalNativeMessaging,
-             "DriveFsBidirectionalNativeMessaging",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Enables DriveFS' experimental local files mirroring functionality.
 BASE_FEATURE(kDriveFsMirroring,
              "DriveFsMirroring",
@@ -1026,6 +1021,11 @@
              "GaiaReauthEndpoint",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enable the Game Dashboard.
+BASE_FEATURE(kGameDashboard,
+             "GameDashboard",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Controls gamepad vibration in Exo.
 BASE_FEATURE(kGamepadVibration,
              "ExoGamepadVibration",
@@ -1425,7 +1425,7 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables the full apps list in Phone Hub bubble.
-BASE_FEATURE(kEcheLauncher, "EcheLauncher", base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kEcheLauncher, "EcheLauncher", base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Switch full apps list in Phone Hub from grid view to list view.
 BASE_FEATURE(kEcheLauncherListView,
@@ -2786,6 +2786,10 @@
   return base::FeatureList::IsEnabled(kEducationEnrollmentOobeFlow);
 }
 
+bool IsGameDashboardEnabled() {
+  return base::FeatureList::IsEnabled(kGameDashboard);
+}
+
 bool IsLockScreenInlineReplyEnabled() {
   return base::FeatureList::IsEnabled(kLockScreenInlineReply);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index debcb08..1703076 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -195,8 +195,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDragUnpinnedAppToPin);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDragWindowToNewDesk);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDriveFs);
-COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kDriveFsBidirectionalNativeMessaging);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDriveFsMirroring);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDriveFsChromeNetworking);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDriveFsBulkPinning);
@@ -305,6 +303,7 @@
 extern const base::FeatureParam<std::string> kGalleryAppPdfEditNotificationText;
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kGlanceables);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kGaiaReauthEndpoint);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kGameDashboard);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kGamepadVibration);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kGesturePropertiesDBusService);
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 7a6146a..8417249b 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -744,7 +744,9 @@
     // was reset to 0. Therefore, we will not record it the second time
     // here.
     if (unlock_attempt.second > 0) {
-      RecordAndResetPasswordAttempts(/*success=*/false, unlock_attempt.first);
+      RecordAndResetPasswordAttempts(
+          AuthMetricsRecorder::AuthenticationOutcome::kFailure,
+          unlock_attempt.first);
     }
   }
 
@@ -2149,7 +2151,8 @@
     }
 
     // Times a password was incorrectly entered until user succeeds.
-    RecordAndResetPasswordAttempts(/*success=*/true, account_id);
+    RecordAndResetPasswordAttempts(
+        AuthMetricsRecorder::AuthenticationOutcome::kSuccess, account_id);
   } else {
     ++unlock_attempt_by_user_[account_id];
     if (authenticated_by_pin) {
@@ -2585,6 +2588,8 @@
         .UpdateReauthReason(account_id,
                             static_cast<int>(ReauthReason::kForgotPassword));
   }
+  RecordAndResetPasswordAttempts(
+      AuthMetricsRecorder::AuthenticationOutcome::kRecovery, account_id);
   Shell::Get()->login_screen_controller()->ShowGaiaSignin(account_id);
   HideAuthErrorMessage();
 }
@@ -2823,13 +2828,11 @@
   UpdateKioskDefaultMessageVisibility();
 }
 
-void LockContentsView::RecordAndResetPasswordAttempts(bool success,
-                                                      AccountId account_id) {
-  AuthMetricsRecorder::AuthenticationOutcome exit_type =
-      success ? AuthMetricsRecorder::AuthenticationOutcome::kSuccess
-              : AuthMetricsRecorder::AuthenticationOutcome::kFailure;
+void LockContentsView::RecordAndResetPasswordAttempts(
+    AuthMetricsRecorder::AuthenticationOutcome outcome,
+    AccountId account_id) {
   AuthMetricsRecorder::Get()->OnExistingUserLoginExit(
-      exit_type, unlock_attempt_by_user_[account_id]);
+      outcome, unlock_attempt_by_user_[account_id]);
   unlock_attempt_by_user_[account_id] = 0;
 }
 
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 9360033..3da6fec 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -31,6 +31,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "chromeos/ash/components/login/auth/auth_metrics_recorder.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "components/account_id/account_id.h"
@@ -485,7 +486,9 @@
 
   // Record the number of password attempts for the given account id to UMA.
   // Afterwards reset the number of attempts.
-  void RecordAndResetPasswordAttempts(bool success, AccountId account_id);
+  void RecordAndResetPasswordAttempts(
+      AuthMetricsRecorder::AuthenticationOutcome outcome,
+      AccountId account_id);
 
   const LockScreen::ScreenType screen_type_;
 
diff --git a/ash/public/cpp/app_menu_constants.h b/ash/public/cpp/app_menu_constants.h
index 8be3d1c0..c7d6433 100644
--- a/ash/public/cpp/app_menu_constants.h
+++ b/ash/public/cpp/app_menu_constants.h
@@ -59,9 +59,11 @@
   INSTALL = 108,
   SETTINGS = 109,
   USE_LAUNCH_TYPE_COMMAND_START = 200,
-  USE_LAUNCH_TYPE_PINNED = USE_LAUNCH_TYPE_COMMAND_START,
+  // No longer supported launch type for hosted apps.
+  DEPRECATED_USE_LAUNCH_TYPE_PINNED = USE_LAUNCH_TYPE_COMMAND_START,
   USE_LAUNCH_TYPE_REGULAR = 201,
-  USE_LAUNCH_TYPE_FULLSCREEN = 202,
+  // No longer supported launch type for hosted apps.
+  DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN = 202,
   USE_LAUNCH_TYPE_WINDOW = 203,
   USE_LAUNCH_TYPE_TABBED_WINDOW = 204,
   USE_LAUNCH_TYPE_COMMAND_END,
diff --git a/ash/public/cpp/wallpaper/wallpaper_controller.h b/ash/public/cpp/wallpaper/wallpaper_controller.h
index f1f1fd73..e242dd67 100644
--- a/ash/public/cpp/wallpaper/wallpaper_controller.h
+++ b/ash/public/cpp/wallpaper/wallpaper_controller.h
@@ -7,6 +7,7 @@
 
 #include <cstdint>
 #include <string>
+#include <vector>
 
 #include "ash/public/cpp/ash_public_export.h"
 #include "ash/public/cpp/wallpaper/google_photos_wallpaper_params.h"
@@ -272,6 +273,14 @@
   // |account_id|: The user's account id.
   virtual void RemovePolicyWallpaper(const AccountId& account_id) = 0;
 
+  // Returns the urls of the wallpapers that exist in local file system (i.e.
+  // |SetOnlineWallpaper| was called earlier). The url is used as id
+  // to identify which wallpapers are available to be set offline.
+  using GetOfflineWallpaperListCallback =
+      base::OnceCallback<void(const std::vector<std::string>&)>;
+  virtual void GetOfflineWallpaperList(
+      GetOfflineWallpaperListCallback callback) = 0;
+
   // Sets wallpaper animation duration. Passing an empty value disables the
   // animation.
   virtual void SetAnimationDuration(base::TimeDelta animation_duration) = 0;
diff --git a/ash/shell.cc b/ash/shell.cc
index 4b09755b..e16a9d78 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -136,7 +136,7 @@
 #include "ash/system/keyboard_brightness_control_delegate.h"
 #include "ash/system/locale/locale_update_controller_impl.h"
 #include "ash/system/machine_learning/user_settings_event_logger.h"
-#include "ash/system/media/media_notification_provider_impl.h"
+#include "ash/system/media/media_notification_provider.h"
 #include "ash/system/message_center/message_center_ash_impl.h"
 #include "ash/system/message_center/message_center_controller.h"
 #include "ash/system/model/system_tray_model.h"
@@ -1103,8 +1103,7 @@
           message_center::MessageCenter::Get());
   media_controller_ = std::make_unique<MediaControllerImpl>();
   media_notification_provider_ =
-      std::make_unique<MediaNotificationProviderImpl>(
-          shell_delegate_->GetMediaSessionService());
+      shell_delegate_->CreateMediaNotificationProvider();
 
   tablet_mode_controller_ = std::make_unique<TabletModeController>();
 
diff --git a/ash/shell.h b/ash/shell.h
index b0faafe4..9011828 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -158,7 +158,7 @@
 class LogoutConfirmationController;
 class LoginScreenController;
 class LoginUnlockThroughputRecorder;
-class MediaNotificationProviderImpl;
+class MediaNotificationProvider;
 class TabClusterUIController;
 class TabletModeController;
 class MediaControllerImpl;
@@ -550,7 +550,7 @@
     return logout_confirmation_controller_.get();
   }
   MediaControllerImpl* media_controller() { return media_controller_.get(); }
-  MediaNotificationProviderImpl* media_notification_provider() {
+  MediaNotificationProvider* media_notification_provider() {
     return media_notification_provider_.get();
   }
   MessageCenterAshImpl* message_center_ash_impl() {
@@ -917,7 +917,7 @@
   std::unique_ptr<TabletModeController> tablet_mode_controller_;
   std::unique_ptr<MessageCenterAshImpl> message_center_ash_impl_;
   std::unique_ptr<MediaControllerImpl> media_controller_;
-  std::unique_ptr<MediaNotificationProviderImpl> media_notification_provider_;
+  std::unique_ptr<MediaNotificationProvider> media_notification_provider_;
   std::unique_ptr<MicrophonePrivacySwitchController>
       microphone_privacy_switch_controller_;
   std::unique_ptr<MruWindowTracker> mru_window_tracker_;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index f45a16a9..b5f8e610 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -37,6 +37,7 @@
 class CaptureModeDelegate;
 class GlanceablesController;
 class GlanceablesDelegate;
+class MediaNotificationProvider;
 class NearbyShareController;
 class NearbyShareDelegate;
 class SavedDeskDelegate;
@@ -68,6 +69,9 @@
   CreateBackGestureContextualNudgeDelegate(
       BackGestureContextualNudgeController* controller) = 0;
 
+  virtual std::unique_ptr<MediaNotificationProvider>
+  CreateMediaNotificationProvider() = 0;
+
   virtual std::unique_ptr<NearbyShareDelegate> CreateNearbyShareDelegate(
       NearbyShareController* controller) const = 0;
 
diff --git a/ash/system/media/media_notification_provider.h b/ash/system/media/media_notification_provider.h
index 1b06efd..f428efb1e 100644
--- a/ash/system/media/media_notification_provider.h
+++ b/ash/system/media/media_notification_provider.h
@@ -10,6 +10,10 @@
 #include "ash/ash_export.h"
 #include "third_party/skia/include/core/SkColor.h"
 
+namespace global_media_controls {
+class MediaItemManager;
+}  // namespace global_media_controls
+
 namespace media_message_center {
 struct NotificationTheme;
 }  // namespace media_message_center
@@ -25,6 +29,8 @@
 // Interface used to send media notification info from browser to ash.
 class ASH_EXPORT MediaNotificationProvider {
  public:
+  virtual ~MediaNotificationProvider() = default;
+
   // Get the global instance.
   static MediaNotificationProvider* Get();
 
@@ -59,8 +65,7 @@
   virtual void SetColorTheme(
       const media_message_center::NotificationTheme& color_theme) = 0;
 
- protected:
-  virtual ~MediaNotificationProvider() = default;
+  virtual global_media_controls::MediaItemManager* GetMediaItemManager() = 0;
 };
 
 }  // namespace ash
diff --git a/ash/system/media/media_tray_unittest.cc b/ash/system/media/media_tray_unittest.cc
index 0e84a0f..d236d03 100644
--- a/ash/system/media/media_tray_unittest.cc
+++ b/ash/system/media/media_tray_unittest.cc
@@ -41,10 +41,16 @@
   }
 
   // Medianotificationprovider implementations.
-  MOCK_METHOD2(GetMediaNotificationListView,
-               std::unique_ptr<views::View>(int, bool));
-  MOCK_METHOD0(GetActiveMediaNotificationView, std::unique_ptr<views::View>());
-  MOCK_METHOD0(OnBubbleClosing, void());
+  MOCK_METHOD((std::unique_ptr<views::View>),
+              GetMediaNotificationListView,
+              (int, bool));
+  MOCK_METHOD((std::unique_ptr<views::View>),
+              GetActiveMediaNotificationView,
+              ());
+  MOCK_METHOD(void, OnBubbleClosing, ());
+  MOCK_METHOD(global_media_controls::MediaItemManager*,
+              GetMediaItemManager,
+              ());
   void AddObserver(MediaNotificationProviderObserver* observer) override {}
   void RemoveObserver(MediaNotificationProviderObserver* observer) override {}
   bool HasActiveNotifications() override { return has_active_notifications_; }
diff --git a/ash/system/media/unified_media_controls_detailed_view_controller_unittest.cc b/ash/system/media/unified_media_controls_detailed_view_controller_unittest.cc
index 2c930e64..86ff7ea 100644
--- a/ash/system/media/unified_media_controls_detailed_view_controller_unittest.cc
+++ b/ash/system/media/unified_media_controls_detailed_view_controller_unittest.cc
@@ -38,12 +38,16 @@
   }
 
   // MediaNotificationProvider implementations.
-  MOCK_METHOD2(GetMediaNotificationListView,
-               std::unique_ptr<views::View>(int, bool));
-  MOCK_METHOD0(OnBubbleClosing, void());
+  MOCK_METHOD((std::unique_ptr<views::View>),
+              GetMediaNotificationListView,
+              (int, bool));
+  MOCK_METHOD(void, OnBubbleClosing, ());
   std::unique_ptr<views::View> GetActiveMediaNotificationView() override {
     return std::make_unique<views::View>();
   }
+  MOCK_METHOD(global_media_controls::MediaItemManager*,
+              GetMediaItemManager,
+              ());
   void AddObserver(MediaNotificationProviderObserver* observer) override {}
   void RemoveObserver(MediaNotificationProviderObserver* observer) override {}
   bool HasActiveNotifications() override { return true; }
diff --git a/ash/system/phonehub/phone_hub_nudge_controller.cc b/ash/system/phonehub/phone_hub_nudge_controller.cc
new file mode 100644
index 0000000..b79f61b
--- /dev/null
+++ b/ash/system/phonehub/phone_hub_nudge_controller.cc
@@ -0,0 +1,19 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/phonehub/phone_hub_nudge_controller.h"
+
+#include "ash/system/phonehub/phone_hub_nudge.h"
+
+namespace ash {
+
+PhoneHubNudgeController::PhoneHubNudgeController(std::u16string nudge_content)
+    : nudge_content_(nudge_content) {}
+PhoneHubNudgeController::~PhoneHubNudgeController() = default;
+
+std::unique_ptr<SystemNudge> PhoneHubNudgeController::CreateSystemNudge() {
+  return std::make_unique<PhoneHubNudge>(nudge_content_);
+}
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/phonehub/phone_hub_nudge_controller.h b/ash/system/phonehub/phone_hub_nudge_controller.h
new file mode 100644
index 0000000..c72e467
--- /dev/null
+++ b/ash/system/phonehub/phone_hub_nudge_controller.h
@@ -0,0 +1,29 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_PHONEHUB_PHONE_HUB_NUDGE_CONTROLLER_H_
+#define ASH_SYSTEM_PHONEHUB_PHONE_HUB_NUDGE_CONTROLLER_H_
+
+#include "ash/system/tray/system_nudge_controller.h"
+
+namespace ash {
+
+class ASH_EXPORT PhoneHubNudgeController : public SystemNudgeController {
+ public:
+  explicit PhoneHubNudgeController(std::u16string nudge_content_);
+  PhoneHubNudgeController(const PhoneHubNudgeController&) = delete;
+  PhoneHubNudgeController& operator=(const PhoneHubNudgeController&) = delete;
+  ~PhoneHubNudgeController() override;
+
+ protected:
+  // SystemNudgeController: Creates PhoneHubNudge
+  std::unique_ptr<SystemNudge> CreateSystemNudge() override;
+
+ private:
+  std::u16string nudge_content_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_PHONEHUB_PHONE_HUB_NUDGE_CONTROLLER_H_
\ No newline at end of file
diff --git a/ash/system/phonehub/phone_hub_nudge_controller_unittest.cc b/ash/system/phonehub/phone_hub_nudge_controller_unittest.cc
new file mode 100644
index 0000000..af5fb33
--- /dev/null
+++ b/ash/system/phonehub/phone_hub_nudge_controller_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/phonehub/phone_hub_nudge_controller.h"
+#include "ash/test/ash_test_base.h"
+
+namespace ash {
+class PhoneHubNudgeControllerTest : public AshTestBase {
+ public:
+  PhoneHubNudgeControllerTest() = default;
+  PhoneHubNudgeControllerTest(const PhoneHubNudgeControllerTest&) = delete;
+  PhoneHubNudgeControllerTest& operator=(const PhoneHubNudgeControllerTest&) =
+      delete;
+  ~PhoneHubNudgeControllerTest() override = default;
+
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+    controller_ = std::make_unique<PhoneHubNudgeController>(nudge_content_);
+  }
+
+  PhoneHubNudgeController* GetController() { return controller_.get(); }
+
+ private:
+  std::unique_ptr<PhoneHubNudgeController> controller_;
+  std::u16string nudge_content_;
+};
+
+TEST_F(PhoneHubNudgeControllerTest, PhoneHubNudgeControllerExists) {
+  PhoneHubNudgeController* controller = GetController();
+  ASSERT_TRUE(controller);
+}
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index ae47802..d935ed5 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -48,6 +48,11 @@
   return std::make_unique<TestBackGestureContextualNudgeDelegate>(controller);
 }
 
+std::unique_ptr<MediaNotificationProvider>
+TestShellDelegate::CreateMediaNotificationProvider() {
+  return nullptr;
+}
+
 std::unique_ptr<NearbyShareDelegate>
 TestShellDelegate::CreateNearbyShareDelegate(
     NearbyShareController* controller) const {
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index dc92f28..d0e4a946 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -43,6 +43,8 @@
   std::unique_ptr<BackGestureContextualNudgeDelegate>
   CreateBackGestureContextualNudgeDelegate(
       BackGestureContextualNudgeController* controller) override;
+  std::unique_ptr<MediaNotificationProvider> CreateMediaNotificationProvider()
+      override;
   std::unique_ptr<NearbyShareDelegate> CreateNearbyShareDelegate(
       NearbyShareController* controller) const override;
   std::unique_ptr<SavedDeskDelegate> CreateSavedDeskDelegate() const override;
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index 33d75f9..0c4e1ef6 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -44,6 +44,7 @@
 #include "base/barrier_closure.h"
 #include "base/check.h"
 #include "base/command_line.h"
+#include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -535,6 +536,27 @@
     base::CreateDirectory(user_directory);
 }
 
+// Implementation of |WallpaperControllerImpl::GetOfflineWallpaper|.
+std::vector<std::string> GetOfflineWallpaperListImpl() {
+  DCHECK(!GlobalChromeOSWallpapersDir().empty());
+  std::vector<std::string> url_list;
+  if (base::DirectoryExists(GlobalChromeOSWallpapersDir())) {
+    base::FileEnumerator files(GlobalChromeOSWallpapersDir(),
+                               /*recursive=*/false,
+                               base::FileEnumerator::FILES);
+    for (base::FilePath current = files.Next(); !current.empty();
+         current = files.Next()) {
+      // Do not add file name of small resolution wallpaper to the list.
+      if (!base::EndsWith(current.BaseName().RemoveExtension().value(),
+                          kSmallWallpaperSuffix,
+                          base::CompareCase::SENSITIVE)) {
+        url_list.push_back(current.BaseName().value());
+      }
+    }
+  }
+  return url_list;
+}
+
 // Returns the type of the user with the specified |id| or USER_TYPE_REGULAR.
 user_manager::UserType GetUserType(const AccountId& id) {
   const UserSession* user_session =
@@ -1599,6 +1621,13 @@
   SetDefaultWallpaper(account_id, show_wallpaper, base::DoNothing());
 }
 
+void WallpaperControllerImpl::GetOfflineWallpaperList(
+    GetOfflineWallpaperListCallback callback) {
+  sequenced_task_runner_->PostTaskAndReplyWithResult(
+      FROM_HERE, base::BindOnce(&GetOfflineWallpaperListImpl),
+      std::move(callback));
+}
+
 void WallpaperControllerImpl::SetAnimationDuration(
     base::TimeDelta animation_duration) {
   animation_duration_ = animation_duration;
diff --git a/ash/wallpaper/wallpaper_controller_impl.h b/ash/wallpaper/wallpaper_controller_impl.h
index 009588c..007ebde 100644
--- a/ash/wallpaper/wallpaper_controller_impl.h
+++ b/ash/wallpaper/wallpaper_controller_impl.h
@@ -297,6 +297,8 @@
   void RemoveAlwaysOnTopWallpaper() override;
   void RemoveUserWallpaper(const AccountId& account_id) override;
   void RemovePolicyWallpaper(const AccountId& account_id) override;
+  void GetOfflineWallpaperList(
+      GetOfflineWallpaperListCallback callback) override;
   void SetAnimationDuration(base::TimeDelta animation_duration) override;
   void OpenWallpaperPickerIfAllowed() override;
   void MinimizeInactiveWindows(const std::string& user_id_hash) override;
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index 062130b0..68803b34 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -1214,8 +1214,14 @@
 
   // Verify that the wallpaper with |url| is available offline, and the returned
   // file name should not contain the small wallpaper suffix.
-  EXPECT_TRUE(base::PathExists(online_wallpaper_dir_.GetPath().Append(
-      GURL(kDummyUrl).ExtractFileName())));
+  run_loop = std::make_unique<base::RunLoop>();
+  controller_->GetOfflineWallpaperList(base::BindLambdaForTesting(
+      [&run_loop](const std::vector<std::string>& url_list) {
+        EXPECT_EQ(1U, url_list.size());
+        EXPECT_EQ(GURL(kDummyUrl).ExtractFileName(), url_list[0]);
+        run_loop->Quit();
+      }));
+  run_loop->Run();
 }
 
 TEST_F(WallpaperControllerTest, SetAndRemovePolicyWallpaper) {
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 2c98401..f95986f 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -224,14 +224,10 @@
     "base_switches.h",
     "big_endian.cc",
     "big_endian.h",
-    "bind.h",
     "bit_cast.h",
     "bits.h",
     "build_time.cc",
     "build_time.h",
-    "callback.h",
-    "callback_forward.h",
-    "callback_helpers.h",
     "callback_list.cc",
     "callback_list.h",
     "cancelable_callback.h",
diff --git a/base/allocator/partition_allocator/partition_alloc-inl.h b/base/allocator/partition_allocator/partition_alloc-inl.h
index 327f681f..e5725de 100644
--- a/base/allocator/partition_allocator/partition_alloc-inl.h
+++ b/base/allocator/partition_allocator/partition_alloc-inl.h
@@ -10,6 +10,7 @@
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_ref_count.h"
 #include "base/allocator/partition_allocator/pkey.h"
 #include "base/allocator/partition_allocator/random.h"
@@ -28,7 +29,7 @@
 // This is a `memset` that resists being optimized away. Adapted from
 // boringssl/src/crypto/mem.c. (Copying and pasting is bad, but //base can't
 // depend on //third_party, and this is small enough.)
-#if defined(COMPILER_MSVC) && !defined(__clang__)
+#if PA_CONFIG(IS_NONCLANG_MSVC)
 // MSVC only supports inline assembly on x86. This preprocessor directive
 // is intended to be a replacement for the same.
 //
@@ -39,14 +40,14 @@
 PA_ALWAYS_INLINE void SecureMemset(void* ptr, uint8_t value, size_t size) {
   memset(ptr, value, size);
 
-#if !defined(COMPILER_MSVC) || defined(__clang__)
+#if !PA_CONFIG(IS_NONCLANG_MSVC)
   // As best as we can tell, this is sufficient to break any optimisations that
   // might try to eliminate "superfluous" memsets. If there's an easy way to
   // detect memset_s, it would be better to use that.
   __asm__ __volatile__("" : : "r"(ptr) : "memory");
-#endif  // !defined(COMPILER_MSVC) || defined(__clang__)
+#endif  // !PA_CONFIG(IS_NONCLANG_MSVC)
 }
-#if defined(COMPILER_MSVC) && !defined(__clang__)
+#if PA_CONFIG(IS_NONCLANG_MSVC)
 #pragma optimize("", on)
 #endif
 
diff --git a/base/allocator/partition_allocator/partition_alloc_config.h b/base/allocator/partition_allocator/partition_alloc_config.h
index 35994ff..a8cce36 100644
--- a/base/allocator/partition_allocator/partition_alloc_config.h
+++ b/base/allocator/partition_allocator/partition_alloc_config.h
@@ -360,4 +360,13 @@
 #define PA_CONFIG_POINTER_COMPRESSION() 0
 #endif
 
+// PA_CONFIG(IS_NONCLANG_MSVC): mimics the compound condition used by
+// Chromium's `//base/compiler_specific.h` to detect true (non-Clang)
+// MSVC.
+#if defined(COMPILER_MSVC) && !defined(__clang__)
+#define PA_CONFIG_IS_NONCLANG_MSVC() 1
+#else
+#define PA_CONFIG_IS_NONCLANG_MSVC() 0
+#endif
+
 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONFIG_H_
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index d2d5f80..8387aa98 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -1449,7 +1449,7 @@
   RawFree(slot_start, slot_span);
 }
 
-#if defined(COMPILER_MSVC) && !defined(__clang__)
+#if PA_CONFIG(IS_NONCLANG_MSVC)
 // MSVC only supports inline assembly on x86. This preprocessor directive
 // is intended to be a replacement for the same.
 //
@@ -1491,14 +1491,14 @@
   // OS page. No need to write to the second one as well.
   //
   // Do not move the store above inside the locked section.
-#if !(defined(COMPILER_MSVC) && !defined(__clang__))
+#if !(PA_CONFIG(IS_NONCLANG_MSVC))
   __asm__ __volatile__("" : : "r"(slot_start) : "memory");
 #endif
 
   ::partition_alloc::internal::ScopedGuard guard{lock_};
   FreeInSlotSpan(slot_start, slot_span);
 }
-#if defined(COMPILER_MSVC) && !defined(__clang__)
+#if PA_CONFIG(IS_NONCLANG_MSVC)
 #pragma optimize("", on)
 #endif
 
diff --git a/base/allocator/partition_allocator/reverse_bytes.h b/base/allocator/partition_allocator/reverse_bytes.h
index 52f2e3b..2443d47c 100644
--- a/base/allocator/partition_allocator/reverse_bytes.h
+++ b/base/allocator/partition_allocator/reverse_bytes.h
@@ -12,28 +12,29 @@
 
 #include <cstdint>
 
+#include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal {
 
 constexpr uint32_t ReverseFourBytes(uint32_t value) {
-#if defined(COMPILER_MSVC) && !defined(__clang__)
+#if PA_CONFIG(IS_NONCLANG_MSVC)
   return value >> 24 | (value >> 8 & 0xff00) | (value & 0xff00) << 8 |
          value << 24;
 #else
   return __builtin_bswap32(value);
-#endif  // defined(COMPILER_MSVC) && !defined(__clang__)
+#endif  // PA_CONFIG(IS_NONCLANG_MSVC)
 }
 
 constexpr uint64_t ReverseEightBytes(uint64_t value) {
-#if defined(COMPILER_MSVC) && !defined(__clang__)
+#if PA_CONFIG(IS_NONCLANG_MSVC)
   return value >> 56 | (value >> 40 & 0xff00) | (value >> 24 & 0xff0000) |
          (value >> 8 & 0xff000000) | (value & 0xff000000) << 8 |
          (value & 0xff0000) << 24 | (value & 0xff00) << 40 |
          (value & 0xff) << 56;
 #else
   return __builtin_bswap64(value);
-#endif  // defined(COMPILER_MSVC) && !defined(__clang__)
+#endif  // PA_CONFIG(IS_NONCLANG_MSVC)
 }
 
 constexpr uintptr_t ReverseBytes(uintptr_t value) {
diff --git a/base/allocator/partition_allocator/yield_processor.h b/base/allocator/partition_allocator/yield_processor.h
index 486532c..b94ee1ac1 100644
--- a/base/allocator/partition_allocator/yield_processor.h
+++ b/base/allocator/partition_allocator/yield_processor.h
@@ -5,6 +5,7 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_YIELD_PROCESSOR_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_YIELD_PROCESSOR_H_
 
+#include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "build/build_config.h"
 
 // The PA_YIELD_PROCESSOR macro wraps an architecture specific-instruction that
@@ -16,7 +17,7 @@
 #if BUILDFLAG(IS_NACL)
 // Inline assembly not allowed.
 #define PA_YIELD_PROCESSOR ((void)0)
-#elif defined(COMPILER_MSVC) && !defined(__clang__)
+#elif PA_CONFIG(IS_NONCLANG_MSVC)
 // MSVC is in its own assemblyless world (crbug.com/1351310#c6).
 #include <windows.h>
 #define PA_YIELD_PROCESSOR (YieldProcessor())
diff --git a/base/bind.h b/base/bind.h
deleted file mode 100644
index 721f61a99..0000000
--- a/base/bind.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// TODO(https://crbug.com/1364441): Temporary forwarding header.
-
-#ifndef BASE_BIND_H_
-#define BASE_BIND_H_
-
-#include "base/functional/bind.h"
-
-#endif  // BASE_BIND_H_
diff --git a/base/callback.h b/base/callback.h
deleted file mode 100644
index d561a3d..0000000
--- a/base/callback.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// TODO(https://crbug.com/1364441): Temporary forwarding header.
-
-#ifndef BASE_CALLBACK_H_
-#define BASE_CALLBACK_H_
-
-#include "base/functional/callback.h"
-
-#endif  // BASE_CALLBACK_H_
diff --git a/base/callback_forward.h b/base/callback_forward.h
deleted file mode 100644
index 5d18a25..0000000
--- a/base/callback_forward.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// TODO(https://crbug.com/1364441): Temporary forwarding header.
-
-#ifndef BASE_CALLBACK_FORWARD_H_
-#define BASE_CALLBACK_FORWARD_H_
-
-#include "base/functional/callback_forward.h"
-
-#endif  // BASE_CALLBACK_FORWARD_H_
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
deleted file mode 100644
index 324877d9..0000000
--- a/base/callback_helpers.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// TODO(https://crbug.com/1364441): Temporary forwarding header.
-
-#ifndef BASE_CALLBACK_HELPERS_H_
-#define BASE_CALLBACK_HELPERS_H_
-
-#include "base/functional/callback_helpers.h"
-
-#endif  // BASE_CALLBACK_HELPERS_H_
diff --git a/base/functional/bind_internal.h b/base/functional/bind_internal.h
index 471d1720..c078a3a 100644
--- a/base/functional/bind_internal.h
+++ b/base/functional/bind_internal.h
@@ -35,7 +35,7 @@
 #include "base/mac/scoped_block.h"
 #endif
 
-// See base/callback.h for user documentation.
+// See base/functional/callback.h for user documentation.
 //
 //
 // CONCEPTS:
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
index 66e4280..9e54820 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -765,7 +765,9 @@
 #if (BUILDFLAG(IS_WIN) && defined(ARCH_CPU_X86_64)) || BUILDFLAG(IS_MAC) || \
     (BUILDFLAG(IS_IOS) && defined(ARCH_CPU_64_BITS)) ||                     \
     (BUILDFLAG(IS_ANDROID) &&                                               \
-     (BUILDFLAG(ENABLE_ARM_CFI_TABLE) || defined(ARCH_CPU_ARM64))) ||       \
+     ((defined(ARCH_CPU_ARMEL) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)) ||       \
+      (defined(ARCH_CPU_ARM64) &&                                           \
+       BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)))) ||                      \
     (BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_X86_64) &&                  \
      BUILDFLAG(IS_CHROMEOS_DEVICE))
 #if BUILDFLAG(IS_WIN)
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index d933631..c4397ea 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -2909,7 +2909,6 @@
 
       if (target_name == "chrome_java__header") {
         # Regression test for: https://crbug.com/1154302
-        # Ensures that header jars never depend on non-header jars.
         assert_no_deps = [ "//base:base_java__compile_java" ]
       }
 
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 665d43c2..6f7e816 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -3102,10 +3102,6 @@
         final_dex_path = _final_dex_path
       }
 
-      if (defined(invoker.assert_no_native_deps)) {
-        assert_no_deps = invoker.assert_no_native_deps
-      }
-
       if (_is_bundle_module) {
         proto_resources_path = _proto_resources_path
         if (_optimize_resources) {
@@ -3557,7 +3553,6 @@
                                "apk_under_test",
                                "app_as_shared_lib",
                                "assert_no_deps",
-                               "assert_no_native_deps",
                                "build_config_include_product_version_resource",
                                "bundles_supported",
                                "chromium_code",
@@ -3696,7 +3691,6 @@
                                "annotation_processor_deps",
                                "app_as_shared_lib",
                                "assert_no_deps",
-                               "assert_no_native_deps",
                                "base_module_target",
                                "build_config_include_product_version_resource",
                                "bundle_target",
diff --git a/build/fuchsia/test/run_test.py b/build/fuchsia/test/run_test.py
index 680fc6b..701628df 100755
--- a/build/fuchsia/test/run_test.py
+++ b/build/fuchsia/test/run_test.py
@@ -84,6 +84,8 @@
                 stack.enter_context(tempfile.TemporaryDirectory()))
             stack.enter_context(
                 ScopedFfxConfig('repository.server.listen', '"[::]:0"'))
+        # crbug.com/1408189: overnet.cso causes flakes in overnet.
+        stack.enter_context(ScopedFfxConfig('overnet.cso', 'disabled'))
         log_manager = stack.enter_context(LogManager(runner_args.logs_dir))
         if runner_args.device:
             update(runner_args.system_image_dir, runner_args.os_check,
diff --git a/build/util/action_remote.py b/build/util/action_remote.py
index 1e9517d..09fd569 100755
--- a/build/util/action_remote.py
+++ b/build/util/action_remote.py
@@ -14,6 +14,8 @@
 import sys
 from enum import Enum
 
+from mojo.public.tools.mojom.mojom_parser import RebaseAbsolutePath
+
 
 class CustomProcessor(Enum):
   mojom_parser = 'mojom_parser'
@@ -22,8 +24,8 @@
     return self.value
 
 
-def _process_build_metadata_json(bm_file, exec_root, working_dir, output_root,
-                                 re_outputs, processed_inputs):
+def _process_build_metadata_json(bm_file, input_roots, output_root, re_outputs,
+                                 processed_inputs):
   """Recursively find mojom_parser inputs from a build_metadata file."""
   if bm_file in processed_inputs:
     return
@@ -31,7 +33,6 @@
   processed_inputs.add(bm_file)
 
   bm_dir = os.path.dirname(bm_file)
-  wd_rel = os.path.relpath(working_dir, exec_root)
 
   with open(bm_file) as f:
     bm = json.load(f)
@@ -41,8 +42,9 @@
     src = os.path.normpath(os.path.join(bm_dir, s))
     if src not in processed_inputs and os.path.exists(src):
       processed_inputs.add(src)
-    src_module = os.path.normpath(
-        os.path.join(output_root, os.path.join(wd_rel, src + "-module")))
+    src_module = os.path.join(
+        output_root,
+        RebaseAbsolutePath(os.path.abspath(src), input_roots) + "-module")
     if src_module in re_outputs:
       continue
     if src_module not in processed_inputs and os.path.exists(src_module):
@@ -51,8 +53,8 @@
   # Recurse into build_metadata deps.
   for d in bm["deps"]:
     dep = os.path.normpath(os.path.join(bm_dir, d))
-    _process_build_metadata_json(dep, exec_root, working_dir, output_root,
-                                 re_outputs, processed_inputs)
+    _process_build_metadata_json(dep, input_roots, output_root, re_outputs,
+                                 processed_inputs)
 
 
 def _get_mojom_parser_inputs(exec_root, output_files, extra_args):
@@ -67,12 +69,17 @@
   argparser = argparse.ArgumentParser()
   argparser.add_argument('--check-imports', dest='check_imports', required=True)
   argparser.add_argument('--output-root', dest='output_root', required=True)
+  argparser.add_argument('--input-root',
+                         default=[],
+                         action='append',
+                         dest='input_root_paths')
   mojom_parser_args, _ = argparser.parse_known_args(args=extra_args)
 
+  input_roots = list(map(os.path.abspath, mojom_parser_args.input_root_paths))
+  output_root = os.path.abspath(mojom_parser_args.output_root)
   processed_inputs = set()
-  _process_build_metadata_json(mojom_parser_args.check_imports, exec_root,
-                               os.getcwd(), mojom_parser_args.output_root,
-                               output_files, processed_inputs)
+  _process_build_metadata_json(mojom_parser_args.check_imports, input_roots,
+                               output_root, output_files, processed_inputs)
 
   # Rebase paths onto rewrapper exec root.
   return map(lambda dep: os.path.normpath(os.path.relpath(dep, exec_root)),
diff --git a/buildtools/reclient_cfgs/.gitignore b/buildtools/reclient_cfgs/.gitignore
index 8f00ec9..7b4bd77 100644
--- a/buildtools/reclient_cfgs/.gitignore
+++ b/buildtools/reclient_cfgs/.gitignore
@@ -1,5 +1,7 @@
 /chromium-browser-clang/
 /nacl/
 /python/
+/win-cross/
+# TODO(crbug.com/1407557): remove win-cross-experiments
 /win-cross-experiments/
 reproxy.cfg
diff --git a/buildtools/reclient_cfgs/fetch_reclient_cfgs.py b/buildtools/reclient_cfgs/fetch_reclient_cfgs.py
index 758ec68..347dbb8 100755
--- a/buildtools/reclient_cfgs/fetch_reclient_cfgs.py
+++ b/buildtools/reclient_cfgs/fetch_reclient_cfgs.py
@@ -87,20 +87,24 @@
       CipdEnsure(posixpath.join(cipd_prefix, toolchain),
                   ref=cipd_ref,
                   directory=toolchain_root)
-      if os.path.exists(os.path.join(toolchain_root, 'win-cross-experiments')):
-        # copy in win-cross-experiments/toolchain
-        # as windows may not use symlinks.
-        wcedir = os.path.join(THIS_DIR, 'win-cross-experiments', toolchain)
-        if not os.path.exists(wcedir):
+      # support legacy (win-cross-experiments) and new (win-cross)
+      # TODO(crbug.com/1407557): drop -experiments support
+      wcedir = os.path.join(THIS_DIR, 'win-cross', toolchain)
+      if not os.path.exists(wcedir):
           os.makedirs(wcedir, mode=0o755)
-        for cfg in glob.glob(os.path.join(THIS_DIR, toolchain,
-                                          'win-cross-experiments', '*.cfg')):
-          fname = os.path.join(wcedir, os.path.basename(cfg))
-          if os.path.exists(fname):
-            os.chmod(fname, 0o777)
-            os.remove(fname)
-          print('Copy from %s to %s...' % (cfg, fname))
-          shutil.copy(cfg, fname)
+      for win_cross_cfg_dir in ['win-cross','win-cross-experiments']:
+          if os.path.exists(os.path.join(toolchain_root, win_cross_cfg_dir)):
+              # copy in win-cross*/toolchain
+              # as windows may not use symlinks.
+              for cfg in glob.glob(os.path.join(toolchain_root,
+                                                win_cross_cfg_dir,
+                                                '*.cfg')):
+                  fname = os.path.join(wcedir, os.path.basename(cfg))
+                  if os.path.exists(fname):
+                    os.chmod(fname, 0o777)
+                    os.remove(fname)
+                  print('Copy from %s to %s...' % (cfg, fname))
+                  shutil.copy(cfg, fname)
 
     return 0
 
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index becb537..7d7c45bc 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -241,7 +241,7 @@
       auto* context = canvas->recordingContext();
       const ScopedRasterFlags scoped_flags(
           &flags_op.flags, new_params.image_provider, canvas->getTotalMatrix(),
-          context ? context->maxTextureSize() : 0, iter.alpha() / 255.0f);
+          context ? context->maxTextureSize() : 0, iter.alphaf());
       if (const auto* raster_flags = scoped_flags.flags())
         flags_op.RasterWithFlags(canvas, raster_flags, new_params);
     } else {
diff --git a/cc/paint/paint_op_buffer_iterator.h b/cc/paint/paint_op_buffer_iterator.h
index 750e78c..27c23d0 100644
--- a/cc/paint/paint_op_buffer_iterator.h
+++ b/cc/paint/paint_op_buffer_iterator.h
@@ -231,6 +231,8 @@
     return static_cast<uint8_t>(current_alpha_ * 255.0f);
   }
 
+  float alphaf() const { return current_alpha_; }
+
  private:
   void FindNextOp();
   const PaintOp* NextUnfoldedOp();
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index a94e4bf..d3af2aac 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2497,7 +2497,6 @@
       forward_variables_from(invoker,
                              [
                                "add_view_trace_events",
-                               "assert_no_deps",
                                "apk_name",
                                "bundle_target",
                                "is_base_module",
@@ -2530,7 +2529,6 @@
     target_type = "android_apk"
     apk_name = "ChromePublic"
     enable_multidex = is_java_debug
-    assert_no_deps = [ "//android_webview:v8_snapshot_secondary_abi_assets" ]
   }
 
   chrome_public_apk_or_module_tmpl("chrome_modern_public_base_bundle_module") {
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index e043fec..2e6b04f 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -8,7 +8,6 @@
 import("//build/config/android/rules.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/locales.gni")
-import("//build/toolchain/gcc_toolchain.gni")
 import("//chrome/android/features/dev_ui/dev_ui_module.gni")
 import("//chrome/android/modules/chrome_bundle_tmpl.gni")
 import("//chrome/common/features.gni")
@@ -91,16 +90,6 @@
       min_sdk_version = default_min_sdk_version
     }
 
-    # Resource allowlist creates a dep from .pak files onto native files.
-    if (!enable_resource_allowlist_generation) {
-      # Ensure builds are not slowed down by having any java targets depend
-      # on native targets.
-      assert_no_native_deps = [
-        "//base",
-        "//v8",
-      ]
-    }
-
     resource_exclusion_regex = common_resource_exclusion_regex
     resource_exclusion_exceptions = common_resource_exclusion_exceptions
 
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 6ae4df3..8c341567 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
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.h"
 
-#include "base/callback.h"
+#include "base/functional/callback.h"
 #include "chrome/browser/apps/app_deduplication_service/app_deduplication_mapper.h"
 #include "chrome/browser/apps/app_deduplication_service/proto/app_deduplication.pb.h"
 #include "google_apis/google_api_keys.h"
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.h b/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.h
index 21434f7..bbff8d3 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.h
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.h
@@ -9,7 +9,7 @@
 #include <string>
 #include <vector>
 
-#include "base/callback_forward.h"
+#include "base/functional/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/apps/app_deduplication_service/proto/deduplication_data.pb.h"
diff --git a/chrome/browser/apps/app_service/BUILD.gn b/chrome/browser/apps/app_service/BUILD.gn
index b374a75..5ebe75b1 100644
--- a/chrome/browser/apps/app_service/BUILD.gn
+++ b/chrome/browser/apps/app_service/BUILD.gn
@@ -320,7 +320,6 @@
     "//components/services/app_service/public/cpp:app_types",
     "//components/services/app_service/public/cpp:icon_types",
     "//components/services/app_service/public/cpp:run_on_os_login",
-    "//components/services/app_service/public/mojom",
     "//skia",
   ]
 
diff --git a/chrome/browser/apps/app_service/menu_util.cc b/chrome/browser/apps/app_service/menu_util.cc
index 4e02d274..4eccb2a 100644
--- a/chrome/browser/apps/app_service/menu_util.cc
+++ b/chrome/browser/apps/app_service/menu_util.cc
@@ -64,13 +64,6 @@
   menu_items.items.push_back(std::move(menu_item));
 }
 
-void AddRadioItem(uint32_t command_id,
-                  uint32_t string_id,
-                  int group_id,
-                  MenuItems& menu_items) {
-  menu_items.items.push_back(CreateRadioItem(command_id, string_id, group_id));
-}
-
 void AddSeparator(ui::MenuSeparatorType separator_type, MenuItems& menu_items) {
   MenuItemPtr menu_item =
       std::make_unique<MenuItem>(MenuItemType::kSeparator, separator_type);
@@ -250,6 +243,9 @@
       return IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW;
     case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
       return IDS_APP_LIST_CONTEXT_MENU_NEW_TABBED_WINDOW;
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+      [[fallthrough]];
     default:
       NOTREACHED();
       return 0;
diff --git a/chrome/browser/apps/app_service/menu_util.h b/chrome/browser/apps/app_service/menu_util.h
index 95adb0d..aceba90 100644
--- a/chrome/browser/apps/app_service/menu_util.h
+++ b/chrome/browser/apps/app_service/menu_util.h
@@ -33,12 +33,6 @@
                     uint32_t string_id,
                     MenuItems& menu_items);
 
-// Adds a radio menu item to |menu_items|.
-void AddRadioItem(uint32_t command_id,
-                  uint32_t string_id,
-                  int group_id,
-                  MenuItems& menu_items);
-
 // Adds a separator of the specified type to |menu_items|.
 void AddSeparator(ui::MenuSeparatorType separator_type, MenuItems& menu_items);
 
diff --git a/chrome/browser/apps/platform_apps/BUILD.gn b/chrome/browser/apps/platform_apps/BUILD.gn
index 9fb07ae6..791926d3f 100644
--- a/chrome/browser/apps/platform_apps/BUILD.gn
+++ b/chrome/browser/apps/platform_apps/BUILD.gn
@@ -67,7 +67,6 @@
     "//components/no_state_prefetch/browser",
     "//components/pref_registry",
     "//components/services/app_service/public/cpp:app_types",
-    "//components/services/app_service/public/mojom",
     "//content/public/browser",
     "//content/public/common",
     "//extensions/browser",
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 5aa1332..30c02de 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -412,6 +412,8 @@
     "arc/input_overlay/ui/menu_entry_view.h",
     "arc/input_overlay/ui/message_view.cc",
     "arc/input_overlay/ui/message_view.h",
+    "arc/input_overlay/ui/touch_point.cc",
+    "arc/input_overlay/ui/touch_point.h",
     "arc/input_overlay/util.cc",
     "arc/input_overlay/util.h",
     "arc/instance_throttle/arc_active_window_throttle_observer.cc",
diff --git a/chrome/browser/ash/app_list/app_context_menu.cc b/chrome/browser/ash/app_list/app_context_menu.cc
index 41bbdf7..b3e3470 100644
--- a/chrome/browser/ash/app_list/app_context_menu.cc
+++ b/chrome/browser/ash/app_list/app_context_menu.cc
@@ -111,12 +111,15 @@
       return gfx::kNoneIcon;
     case ash::SETTINGS:
       return vector_icons::kSettingsIcon;
-    case ash::USE_LAUNCH_TYPE_PINNED:
     case ash::USE_LAUNCH_TYPE_REGULAR:
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
     case ash::USE_LAUNCH_TYPE_WINDOW:
+    case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
       // Check items use the default icon.
       return gfx::kNoneIcon;
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+      NOTREACHED();
+      return gfx::kNoneIcon;
     case ash::REORDER_SUBMENU:
       return ash::kReorderIcon;
     case ash::REORDER_BY_NAME_ALPHABETICAL:
@@ -172,10 +175,8 @@
     return;
   }
   // Check items use default icons.
-  if (command_id == ash::USE_LAUNCH_TYPE_PINNED ||
-      command_id == ash::USE_LAUNCH_TYPE_REGULAR ||
-      command_id == ash::USE_LAUNCH_TYPE_FULLSCREEN ||
-      command_id == ash::USE_LAUNCH_TYPE_WINDOW) {
+  if (command_id >= ash::USE_LAUNCH_TYPE_COMMAND_START &&
+      command_id < ash::USE_LAUNCH_TYPE_COMMAND_END) {
     menu_model->AddCheckItemWithStringId(command_id, string_id);
     return;
   }
diff --git a/chrome/browser/ash/app_list/app_context_menu_unittest.cc b/chrome/browser/ash/app_list/app_context_menu_unittest.cc
index 2098dcc..e779e8a 100644
--- a/chrome/browser/ash/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ash/app_list/app_context_menu_unittest.cc
@@ -702,10 +702,11 @@
   EXPECT_EQ(107, ash::APP_CONTEXT_MENU_NEW_INCOGNITO_WINDOW);
   EXPECT_EQ(108, ash::INSTALL);
   EXPECT_EQ(200, ash::USE_LAUNCH_TYPE_COMMAND_START);
-  EXPECT_EQ(200, ash::USE_LAUNCH_TYPE_PINNED);
+  EXPECT_EQ(200, ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED);
   EXPECT_EQ(201, ash::USE_LAUNCH_TYPE_REGULAR);
-  EXPECT_EQ(202, ash::USE_LAUNCH_TYPE_FULLSCREEN);
+  EXPECT_EQ(202, ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN);
   EXPECT_EQ(203, ash::USE_LAUNCH_TYPE_WINDOW);
+  EXPECT_EQ(204, ash::USE_LAUNCH_TYPE_TABBED_WINDOW);
 }
 
 // Tests that internal app's context menu is correct.
diff --git a/chrome/browser/ash/app_list/app_service/app_service_context_menu.cc b/chrome/browser/ash/app_list/app_service/app_service_context_menu.cc
index 740e718d..643706f 100644
--- a/chrome/browser/ash/app_list/app_service/app_service_context_menu.cc
+++ b/chrome/browser/ash/app_list/app_service/app_service_context_menu.cc
@@ -69,9 +69,11 @@
       return apps::WindowMode::kWindow;
     case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
       return apps::WindowMode::kTabbedWindow;
-    case ash::USE_LAUNCH_TYPE_PINNED:
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+      [[fallthrough]];
     default:
+      NOTREACHED();
       return apps::WindowMode::kUnknown;
   }
 }
diff --git a/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc b/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc
index 8f37ecd5..1350633 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc
+++ b/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/arc/idle_manager/arc_idle_manager.h"
 
 #include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "ash/components/arc/arc_features.h"
 #include "ash/components/arc/mojom/power.mojom.h"
 #include "ash/components/arc/power/arc_power_bridge.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
@@ -79,7 +80,11 @@
       delegate_(std::make_unique<DefaultDelegateImpl>()),
       bridge_(bridge) {
   AddObserver(std::make_unique<ArcCpuThrottleObserver>());
-  AddObserver(std::make_unique<ArcOnBatteryObserver>());
+  if (kEnableArcIdleManagerIgnoreBatteryForPLT.Get()) {
+    LOG(WARNING) << "Doze will be enabled regardless of battery status";
+  } else {
+    AddObserver(std::make_unique<ArcOnBatteryObserver>());
+  }
   AddObserver(std::make_unique<ArcDisplayPowerObserver>());
 
   auto* const power_bridge = ArcPowerBridge::GetForBrowserContext(context);
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_move.cc b/chrome/browser/ash/arc/input_overlay/actions/action_move.cc
index 6ce11b2e..e5bcfc43 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action_move.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_move.cc
@@ -80,6 +80,7 @@
   void OnBindingToKeyboard() override { NOTIMPLEMENTED(); }
   void OnBindingToMouse(std::string mouse_action) override { NOTIMPLEMENTED(); }
   void OnMenuEntryPressed() override { NOTIMPLEMENTED(); }
+  void AddTouchPoint() override { NOTIMPLEMENTED(); }
 
   void ChildPreferredSizeChanged(View* child) override {
     if (static_cast<ActionLabel*>(child) != labels_[0])
@@ -190,6 +191,7 @@
   void OnBindingToKeyboard() override { NOTIMPLEMENTED(); }
   void OnBindingToMouse(std::string mouse_action) override { NOTIMPLEMENTED(); }
   void OnMenuEntryPressed() override { NOTIMPLEMENTED(); }
+  void AddTouchPoint() override { ActionView::AddTouchPoint(ActionType::MOVE); }
 
   void ChildPreferredSizeChanged(View* child) override {
     DCHECK_EQ(labels_.size(), kActionMoveKeysSize);
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_tap.cc b/chrome/browser/ash/arc/input_overlay/actions/action_tap.cc
index edc26af..5fa0b74 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action_tap.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_tap.cc
@@ -139,6 +139,8 @@
     menu_entry_->RequestFocus();
   }
 
+  void AddTouchPoint() override { ActionView::AddTouchPoint(ActionType::TAP); }
+
   void ChildPreferredSizeChanged(View* child) override {
     DCHECK_EQ(1u, labels_.size());
     if (static_cast<ActionLabel*>(child) != labels_[0])
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
index bae7300..0d72c9c 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
@@ -205,8 +205,6 @@
   menu_entry->SetSize(gfx::Size(kMenuEntrySize, kMenuEntrySize));
   menu_entry->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
   menu_entry->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
-  // TODO(djacobo): Set proper positioning based on specs and responding to
-  // resize.
   menu_entry->SetPosition(CalculateMenuEntryPosition());
   menu_entry->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_INPUT_OVERLAY_GAME_CONTROLS_ALPHA));
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_view.cc b/chrome/browser/ash/arc/input_overlay/ui/action_view.cc
index f0207af..07fd5ce 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/action_view.cc
+++ b/chrome/browser/ash/arc/input_overlay/ui/action_view.cc
@@ -74,7 +74,7 @@
     if (!IsInputBound(action_->GetCurrentDisplayedInput()))
       SetVisible(false);
     if (allow_reposition_)
-      SetFocusBehavior(FocusBehavior::NEVER);
+      RemoveTouchPoint();
   }
   if (mode == DisplayMode::kEdit) {
     AddEditButton();
@@ -82,7 +82,7 @@
     if (!IsInputBound(*action_->current_input()))
       SetVisible(true);
     if (allow_reposition_)
-      SetFocusBehavior(FocusBehavior::ALWAYS);
+      AddTouchPoint();
   }
 
   if (show_circle() && circle_)
@@ -185,25 +185,25 @@
   return false;
 }
 
-bool ActionView::OnMousePressed(const ui::MouseEvent& event) {
+bool ActionView::ApplyMousePressed(const ui::MouseEvent& event) {
   if (!allow_reposition_)
     return false;
   OnDragStart(event);
   return true;
 }
 
-bool ActionView::OnMouseDragged(const ui::MouseEvent& event) {
+bool ActionView::ApplyMouseDragged(const ui::MouseEvent& event) {
   return allow_reposition_ ? OnDragUpdate(event) : false;
 }
 
-void ActionView::OnMouseReleased(const ui::MouseEvent& event) {
+void ActionView::ApplyMouseReleased(const ui::MouseEvent& event) {
   if (!allow_reposition_)
     return;
   OnDragEnd();
   RecordInputOverlayActionReposition(RepositionType::kMouseDragRepostion);
 }
 
-void ActionView::OnGestureEvent(ui::GestureEvent* event) {
+void ActionView::ApplyGestureEvent(ui::GestureEvent* event) {
   if (!allow_reposition_)
     return;
   switch (event->type()) {
@@ -227,7 +227,7 @@
   }
 }
 
-bool ActionView::OnKeyPressed(const ui::KeyEvent& event) {
+bool ActionView::ApplyKeyPressed(const ui::KeyEvent& event) {
   auto current_pos = origin();
   if (!allow_reposition_ ||
       !UpdatePositionByArrowKey(event.key_code(), current_pos)) {
@@ -238,7 +238,7 @@
   return true;
 }
 
-bool ActionView::OnKeyReleased(const ui::KeyEvent& event) {
+bool ActionView::ApplyKeyReleased(const ui::KeyEvent& event) {
   if (!allow_reposition_ || !ash::IsArrowKeyEvent(event))
     return View::OnKeyReleased(event);
 
@@ -320,6 +320,21 @@
   display_overlay_controller_->OnActionTrashButtonPressed(action_);
 }
 
+void ActionView::AddTouchPoint(ActionType action_type) {
+  if (touch_point_)
+    return;
+
+  touch_point_ = TouchPoint::Show(this, action_type, center_);
+}
+
+void ActionView::RemoveTouchPoint() {
+  if (!touch_point_)
+    return;
+
+  RemoveChildViewT(touch_point_);
+  touch_point_ = nullptr;
+}
+
 void ActionView::UpdateTrashButtonPosition() {
   if (!trash_button_)
     return;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_view.h b/chrome/browser/ash/arc/input_overlay/ui/action_view.h
index dc0d3d7..cbac4a7 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/action_view.h
+++ b/chrome/browser/ash/arc/input_overlay/ui/action_view.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/ash/arc/input_overlay/ui/action_circle.h"
 #include "chrome/browser/ash/arc/input_overlay/ui/action_edit_button.h"
 #include "chrome/browser/ash/arc/input_overlay/ui/action_label.h"
+#include "chrome/browser/ash/arc/input_overlay/ui/touch_point.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/views/view.h"
@@ -29,8 +30,8 @@
 // ActionView is the view for each action.
 class ActionView : public views::View {
  public:
-  explicit ActionView(Action* action,
-                      DisplayOverlayController* display_overlay_controller);
+  ActionView(Action* action,
+             DisplayOverlayController* display_overlay_controller);
   ActionView(const ActionView&) = delete;
   ActionView& operator=(const ActionView&) = delete;
   ~ActionView() override;
@@ -44,6 +45,7 @@
   virtual void OnBindingToMouse(std::string mouse_action) = 0;
   // Each type of the actions shows different edit menu.
   virtual void OnMenuEntryPressed() = 0;
+  virtual void AddTouchPoint() = 0;
 
   // TODO(cuicuiruan): Remove virtual for post MVP once edit menu is ready for
   // |ActionMove|.
@@ -82,18 +84,19 @@
   bool ShouldShowErrorMsg(ui::DomCode code,
                           ActionLabel* editing_label = nullptr);
 
-  // views::View:
-  bool OnMousePressed(const ui::MouseEvent& event) override;
-  bool OnMouseDragged(const ui::MouseEvent& event) override;
-  void OnMouseReleased(const ui::MouseEvent& event) override;
-  void OnGestureEvent(ui::GestureEvent* event) override;
-  bool OnKeyPressed(const ui::KeyEvent& event) override;
-  bool OnKeyReleased(const ui::KeyEvent& event) override;
+  bool ApplyMousePressed(const ui::MouseEvent& event);
+  bool ApplyMouseDragged(const ui::MouseEvent& event);
+  void ApplyMouseReleased(const ui::MouseEvent& event);
+  void ApplyGestureEvent(ui::GestureEvent* event);
+  bool ApplyKeyPressed(const ui::KeyEvent& event);
+  bool ApplyKeyReleased(const ui::KeyEvent& event);
+
   void OnFocus() override;
   void OnBlur() override;
 
   Action* action() { return action_; }
   const std::vector<ActionLabel*>& labels() const { return labels_; }
+  TouchPoint* touch_point() { return touch_point_; }
   void set_editable(bool editable) { editable_ = editable; }
   DisplayOverlayController* display_overlay_controller() {
     return display_overlay_controller_;
@@ -107,6 +110,8 @@
  protected:
   void UpdateTrashButtonPosition();
 
+  void AddTouchPoint(ActionType action_type);
+
   // Reference to the action of this UI.
   raw_ptr<Action> action_ = nullptr;
   // Reference to the owner class.
@@ -134,6 +139,8 @@
   void RemoveTrashButton();
   void OnTrashButtonPressed();
 
+  void RemoveTouchPoint();
+
   // Drag operations.
   void OnDragStart(const ui::LocatedEvent& event);
   bool OnDragUpdate(const ui::LocatedEvent& event);
@@ -145,6 +152,10 @@
   int unbind_label_index_ = kDefaultLabelIndex;
   // The position when starting to drag.
   gfx::Point start_drag_event_pos_;
+  // Touch point only shows up in the edit mode for users to align the position.
+  // This view owns the touch point as one of its children and |touch_point_|
+  // is for quick access.
+  raw_ptr<TouchPoint> touch_point_ = nullptr;
   // TODO(b/250900717): Update when the final UX/UI is ready.
   raw_ptr<views::ImageButton> trash_button_ = nullptr;
 
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_view_unittest.cc b/chrome/browser/ash/arc/input_overlay/ui/action_view_unittest.cc
index c15bfbc..a14ae10d 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/action_view_unittest.cc
+++ b/chrome/browser/ash/arc/input_overlay/ui/action_view_unittest.cc
@@ -61,16 +61,15 @@
   ActionViewTest() = default;
 
   void PressLeftMouseAtActionView() {
-    // Press down at the center of the action view. For ActionMove view, the
-    // center is same as the touch down position.
-    local_location_ = action_view_->bounds().CenterPoint();
+    // Press down at the center of the touch point.
+    local_location_ = action_view_->touch_point()->bounds().CenterPoint();
     const auto root_location = action_->touch_down_positions()[0];
     root_location_ = gfx::Point((int)root_location.x(), (int)root_location.y());
     auto press =
         ui::MouseEvent(ui::ET_MOUSE_PRESSED, local_location_, root_location_,
                        ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
                        ui::EF_LEFT_MOUSE_BUTTON);
-    action_view_->OnMousePressed(press);
+    action_view_->touch_point()->ApplyMousePressed(press);
   }
 
   void MouseDragActionViewBy(const gfx::Vector2d& move) {
@@ -79,7 +78,7 @@
     auto drag =
         ui::MouseEvent(ui::ET_MOUSE_DRAGGED, local_location_, root_location_,
                        ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
-    action_view_->OnMouseDragged(drag);
+    action_view_->touch_point()->ApplyMouseDragged(drag);
   }
 
   void ReleaseLeftMouse() {
@@ -87,10 +86,12 @@
         ui::MouseEvent(ui::ET_MOUSE_RELEASED, local_location_, root_location_,
                        ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
                        ui::EF_LEFT_MOUSE_BUTTON);
-    action_view_->OnMouseReleased(release);
+    action_view_->touch_point()->ApplyMouseReleased(release);
   }
 
   void TouchPressAtActionView() {
+    // Press down at the center of the touch point, which is the touch down
+    // position.
     const auto& root_location = action_->touch_down_positions()[0];
     root_location_ = gfx::Point((int)root_location.x(), (int)root_location.y());
 
@@ -98,7 +99,7 @@
         root_location_.x(), root_location_.y(), ui::EF_NONE,
         base::TimeTicks::Now(),
         ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
-    action_view_->OnGestureEvent(&scroll_begin);
+    action_view_->touch_point()->ApplyGestureEvent(&scroll_begin);
   }
 
   void TouchMoveAtActionViewBy(const gfx::Vector2d& move) {
@@ -108,7 +109,7 @@
                          base::TimeTicks::Now(),
                          ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE,
                                                  move.x(), move.y()));
-    action_view_->OnGestureEvent(&scroll_update);
+    action_view_->touch_point()->ApplyGestureEvent(&scroll_update);
   }
 
   void TouchReleaseAtActionView() {
@@ -116,7 +117,7 @@
         ui::GestureEvent(root_location_.x(), root_location_.y(), ui::EF_NONE,
                          base::TimeTicks::Now(),
                          ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
-    action_view_->OnGestureEvent(&scroll_end);
+    action_view_->touch_point()->ApplyGestureEvent(&scroll_end);
   }
 
   raw_ptr<ActionView> action_view_;
@@ -197,9 +198,9 @@
 TEST_F(ActionViewTest, TestArrowKeyMove) {
   // Arrow key left single press & release.
   auto updated_pos = action_->touch_down_positions()[0];
-  action_view_->OnKeyPressed(
+  action_view_->touch_point()->OnKeyPressed(
       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LEFT, ui::EF_NONE));
-  action_view_->OnKeyReleased(
+  action_view_->touch_point()->OnKeyReleased(
       ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_LEFT, ui::EF_NONE));
   action_->BindPending();
   auto move_left = gfx::Vector2d(-kArrowKeyMoveDistance, 0);
@@ -209,9 +210,9 @@
 
   // Arrow key down single press & release.
   updated_pos = action_->touch_down_positions()[0];
-  action_view_->OnKeyPressed(
+  action_view_->touch_point()->OnKeyPressed(
       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_NONE));
-  action_view_->OnKeyReleased(
+  action_view_->touch_point()->OnKeyReleased(
       ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_DOWN, ui::EF_NONE));
   action_->BindPending();
   auto move_down = gfx::Vector2d(0, kArrowKeyMoveDistance);
@@ -224,11 +225,11 @@
   int key_press_times = 5;
   auto move_right = gfx::Vector2d(kArrowKeyMoveDistance, 0);
   for (int i = 0; i < key_press_times; i++) {
-    action_view_->OnKeyPressed(
+    action_view_->touch_point()->OnKeyPressed(
         ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE));
     updated_pos += move_right;
   }
-  action_view_->OnKeyReleased(
+  action_view_->touch_point()->OnKeyReleased(
       ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_RIGHT, ui::EF_NONE));
   action_->BindPending();
   EXPECT_POINTF_NEAR(updated_pos, action_->touch_down_positions()[0],
diff --git a/chrome/browser/ash/arc/input_overlay/ui/touch_point.cc b/chrome/browser/ash/arc/input_overlay/ui/touch_point.cc
new file mode 100644
index 0000000..1405dd0
--- /dev/null
+++ b/chrome/browser/ash/arc/input_overlay/ui/touch_point.cc
@@ -0,0 +1,604 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/arc/input_overlay/ui/touch_point.h"
+
+#include <cmath>
+
+#include "base/debug/stack_trace.h"
+#include "cc/paint/paint_flags.h"
+#include "chrome/browser/ash/arc/input_overlay/ui/action_view.h"
+#include "ui/color/color_id.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/focus_ring.h"
+
+namespace arc::input_overlay {
+
+namespace {
+
+constexpr int kTouchPointShadowElevation = 5;
+
+constexpr int kDotCenterDiameter = 14;
+constexpr int kDotInsideStrokeThickness = 1;
+constexpr int kDotOutsideStrokeThickness = 3;
+
+constexpr int kCrossCenterLength = 78;
+constexpr int kCrossInsideStrokeThickness = 1;
+constexpr int kCrossOutsideStrokeThickness = 4;
+constexpr int kCrossCornerRadius = 6;
+
+// Gap between focus ring outer edge to label.
+constexpr float kHaloInset = -6;
+// Thickness of focus ring.
+constexpr float kHaloThickness = 3;
+constexpr SkColor kFocusRingColor = gfx::kGoogleBlue300;
+
+constexpr SkColor kOutsideStrokeColor =
+    SkColorSetA(SK_ColorWHITE, /*a=*/0xCC /*80%*/);
+constexpr SkColor kOutsideStrokeColorHover =
+    SkColorSetA(SK_ColorWHITE, /*a=*/0xCC /*80%*/);
+constexpr SkColor kOutsideStrokeColorDrag = gfx::kGoogleBlue200;
+
+constexpr SkColor kInsideStrokeColor =
+    SkColorSetA(SK_ColorBLACK, /*a=*/0x33 /*20%*/);
+constexpr SkColor kInsideStrokeColorHover =
+    SkColorSetA(SK_ColorBLACK, /*a=*/0x33 /*20%*/);
+constexpr SkColor kInsideStrokeColorDrag =
+    SkColorSetA(SK_ColorBLACK, /*a=*/0x66 /*40%*/);
+constexpr SkColor kCenterColor = SkColorSetRGB(0x12, 0x6D, 0xFF);
+constexpr SkColor kCenterColorHover20White =
+    SkColorSetA(SK_ColorWHITE, /*a=*/0x33 /*20%*/);
+constexpr SkColor kCenterColorDrag30White =
+    SkColorSetA(SK_ColorWHITE, /*a=*/0x4D /*30%*/);
+
+// Draw the cross shape path with round corner. It starts from bottom to up on
+// line #0 and draws clock-wisely.
+// |overall_length| is the total length of one side excluding the stroke
+// thickness. |mid_length| is the length of the middle part which is close to
+// the one third of |overall_length|.
+//      __
+//   _0^  |__
+//  |__    __|
+//     |__|
+//
+SkPath DrawCrossPath(SkScalar overall_length,
+                     SkScalar mid_length,
+                     SkScalar corner_radius,
+                     SkScalar out_stroke_thickness) {
+  SkPath path;
+  SkScalar short_length = (overall_length - mid_length) / 2;
+  path.moveTo(short_length + out_stroke_thickness,
+              short_length + out_stroke_thickness);
+  // #0
+  path.rLineTo(0, -(short_length - corner_radius));
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, corner_radius, -corner_radius);
+  // #1
+  path.rLineTo(mid_length - 2 * corner_radius, 0);
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, corner_radius, corner_radius);
+  // #2
+  path.rLineTo(0, short_length - corner_radius);
+  // #3
+  path.rLineTo(short_length - corner_radius, 0);
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, corner_radius, corner_radius);
+  // #4
+  path.rLineTo(0, mid_length - 2 * corner_radius);
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, -corner_radius, +corner_radius);
+  // #5
+  path.rLineTo(-(short_length - corner_radius), 0);
+  // #6
+  path.rLineTo(0, short_length - corner_radius);
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, -corner_radius, corner_radius);
+  // #7
+  path.rLineTo(-(mid_length - 2 * corner_radius), 0);
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, -corner_radius, -corner_radius);
+  // #8
+  path.rLineTo(0, -(short_length - corner_radius));
+  // #9
+  path.rLineTo(-(short_length - corner_radius), 0);
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, -corner_radius, -corner_radius);
+  // #10
+  path.rLineTo(0, -(mid_length - 2 * corner_radius));
+  path.rArcTo(corner_radius, corner_radius, 0, SkPath::kSmall_ArcSize,
+              SkPathDirection::kCW, corner_radius, -corner_radius);
+  // #11
+  path.close();
+  return path;
+}
+
+SkPath DrawCrossCenter(gfx::Canvas* canvas) {
+  return DrawCrossPath(
+      /*overall_length=*/SkIntToScalar(kCrossCenterLength),
+      /*mid_length=*/SkIntToScalar(kCrossCenterLength / 3),
+      /*corner_radius=*/SkIntToScalar(kCrossCornerRadius),
+      /*out_stroke_thickness=*/SkIntToScalar(0));
+}
+
+SkPath DrawCrossInsideStroke(gfx::Canvas* canvas) {
+  return DrawCrossPath(
+      /*overall_length=*/SkIntToScalar(kCrossCenterLength),
+      /*mid_length=*/SkIntToScalar(kCrossCenterLength / 3),
+      /*corner_radius=*/SkIntToScalar(kCrossCornerRadius),
+      /*out_stroke_thickness=*/SkIntToScalar(kCrossInsideStrokeThickness));
+}
+
+SkPath DrawCrossOutsideStroke(gfx::Canvas* canvas) {
+  return DrawCrossPath(
+      /*overall_length=*/SkIntToScalar(kCrossCenterLength +
+                                       2 * kCrossInsideStrokeThickness),
+      /*mid_length=*/
+      SkIntToScalar(kCrossCenterLength / 3 + 2 * kCrossInsideStrokeThickness),
+      /*corner_radius=*/SkIntToScalar(kCrossCornerRadius),
+      /*out_stroke_thickness=*/SkIntToScalar(kCrossOutsideStrokeThickness));
+}
+
+class Background : public views::Background {
+ public:
+  explicit Background(SkColor color) { SetNativeControlColor(color); }
+  ~Background() override = default;
+};
+
+class CrossCenterBackground : public Background {
+ public:
+  explicit CrossCenterBackground(SkColor color) : Background(color) {}
+  ~CrossCenterBackground() override = default;
+
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    flags.setColor(get_color());
+    canvas->DrawPath(DrawCrossCenter(canvas), flags);
+  }
+};
+
+class DotCenterBackground : public Background {
+ public:
+  explicit DotCenterBackground(SkColor color) : Background(color) {}
+  ~DotCenterBackground() override = default;
+
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    flags.setColor(get_color());
+    int radius = kDotCenterDiameter / 2;
+    canvas->DrawCircle(gfx::Point(radius, radius), radius, flags);
+  }
+};
+
+class CrossInsideStrokeBackground : public Background {
+ public:
+  explicit CrossInsideStrokeBackground(SkColor color) : Background(color) {}
+  ~CrossInsideStrokeBackground() override = default;
+
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kStroke_Style);
+    flags.setStrokeWidth(kCrossInsideStrokeThickness);
+    flags.setColor(get_color());
+    canvas->DrawPath(DrawCrossInsideStroke(canvas), flags);
+  }
+};
+
+class DotInsideStrokeBackground : public Background {
+ public:
+  explicit DotInsideStrokeBackground(SkColor color) : Background(color) {}
+  ~DotInsideStrokeBackground() override = default;
+
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kStroke_Style);
+    flags.setStrokeWidth(kDotInsideStrokeThickness);
+    flags.setColor(get_color());
+    int radius = kDotCenterDiameter / 2;
+    int center = radius + kDotInsideStrokeThickness;
+    canvas->DrawCircle(gfx::Point(center, center), radius, flags);
+  }
+};
+
+class CrossOutsideStrokeBackground : public Background {
+ public:
+  explicit CrossOutsideStrokeBackground(SkColor color) : Background(color) {}
+  ~CrossOutsideStrokeBackground() override = default;
+
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kStroke_Style);
+    flags.setStrokeWidth(kCrossOutsideStrokeThickness);
+    flags.setColor(kOutsideStrokeColor);
+    canvas->DrawPath(DrawCrossOutsideStroke(canvas), flags);
+  }
+};
+
+class DotOutsideStrokeBackground : public Background {
+ public:
+  explicit DotOutsideStrokeBackground(SkColor color) : Background(color) {}
+  ~DotOutsideStrokeBackground() override = default;
+
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kStroke_Style);
+    flags.setStrokeWidth(kDotOutsideStrokeThickness);
+    flags.setColor(get_color());
+    int radius = kDotCenterDiameter / 2 + kDotInsideStrokeThickness;
+    int center = radius + kDotOutsideStrokeThickness;
+    canvas->DrawCircle(gfx::Point(center, center), radius, flags);
+  }
+};
+
+class CrossCenter : public TouchPointElement {
+ public:
+  CrossCenter() {
+    SetToDefault();
+    int temp = kCrossInsideStrokeThickness + kCrossOutsideStrokeThickness;
+    SetPosition(gfx::Point(temp, temp));
+    SetSize(gfx::Size(kCrossCenterLength, kCrossCenterLength));
+  }
+  ~CrossCenter() override = default;
+
+  // TouchPointElement:
+  void SetToDefault() override {
+    SetBackground(std::make_unique<CrossCenterBackground>(kCenterColor));
+  }
+
+  void SetToHover() override {
+    SetBackground(std::make_unique<CrossCenterBackground>(
+        color_utils::GetResultingPaintColor(kCenterColorHover20White,
+                                            kCenterColor)));
+  }
+
+  void SetToDrag() override {
+    SetBackground(std::make_unique<CrossCenterBackground>(
+        color_utils::GetResultingPaintColor(kCenterColorDrag30White,
+                                            kCenterColor)));
+  }
+};
+
+class DotCenter : public TouchPointElement {
+ public:
+  DotCenter() {
+    SetToDefault();
+    int temp = kDotOutsideStrokeThickness + kDotInsideStrokeThickness;
+    SetPosition(gfx::Point(temp, temp));
+    SetSize(gfx::Size(kDotCenterDiameter, kDotCenterDiameter));
+  }
+  ~DotCenter() override = default;
+
+  // TouchPointElement:
+  void SetToDefault() override {
+    SetBackground(std::make_unique<DotCenterBackground>(kCenterColor));
+  }
+
+  void SetToHover() override {
+    SetBackground(std::make_unique<DotCenterBackground>(
+        color_utils::GetResultingPaintColor(kCenterColorHover20White,
+                                            kCenterColor)));
+  }
+
+  void SetToDrag() override {
+    SetBackground(std::make_unique<DotCenterBackground>(
+        color_utils::GetResultingPaintColor(kCenterColorDrag30White,
+                                            kCenterColor)));
+  }
+};
+
+// Because inside stroke is on top of the touch point. Use the inside stroke to
+// forward the mouse and gesture events to its parent which is touch point.
+class InsideStroke : public TouchPointElement {
+ public:
+  InsideStroke() = default;
+  ~InsideStroke() override = default;
+
+  // views::View:
+  void OnMouseEntered(const ui::MouseEvent& event) override {
+    static_cast<TouchPoint*>(parent())->ApplyMouseEntered(event);
+  }
+
+  void OnMouseExited(const ui::MouseEvent& event) override {
+    static_cast<TouchPoint*>(parent())->ApplyMouseExited(event);
+  }
+
+  bool OnMousePressed(const ui::MouseEvent& event) override {
+    return static_cast<TouchPoint*>(parent())->ApplyMousePressed(event);
+  }
+
+  bool OnMouseDragged(const ui::MouseEvent& event) override {
+    return static_cast<TouchPoint*>(parent())->ApplyMouseDragged(event);
+  }
+
+  void OnMouseReleased(const ui::MouseEvent& event) override {
+    static_cast<TouchPoint*>(parent())->ApplyMouseReleased(event);
+  }
+
+  void OnGestureEvent(ui::GestureEvent* event) override {
+    return static_cast<TouchPoint*>(parent())->ApplyGestureEvent(event);
+  }
+};
+
+class CrossInsideStroke : public InsideStroke {
+ public:
+  CrossInsideStroke() {
+    SetToDefault();
+    int temp = kCrossOutsideStrokeThickness;
+    SetPosition(gfx::Point(temp, temp));
+    temp = kCrossCenterLength + 2 * kCrossInsideStrokeThickness;
+    SetSize(gfx::Size(temp, temp));
+  }
+  ~CrossInsideStroke() override = default;
+
+  // TouchPointElement:
+  void SetToDefault() override {
+    SetBackground(
+        std::make_unique<CrossInsideStrokeBackground>(kInsideStrokeColor));
+  }
+
+  void SetToHover() override {
+    SetBackground(
+        std::make_unique<CrossInsideStrokeBackground>(kInsideStrokeColorHover));
+  }
+
+  void SetToDrag() override {
+    SetBackground(
+        std::make_unique<CrossInsideStrokeBackground>(kInsideStrokeColorDrag));
+  }
+};
+
+class DotInsideStroke : public InsideStroke {
+ public:
+  DotInsideStroke() {
+    SetToDefault();
+    int temp = kDotOutsideStrokeThickness;
+    SetPosition(gfx::Point(temp, temp));
+    temp = kDotCenterDiameter + 2 * kDotInsideStrokeThickness;
+    SetSize(gfx::Size(temp, temp));
+  }
+  ~DotInsideStroke() override = default;
+
+  // TouchPointElement:
+  void SetToDefault() override {
+    SetBackground(
+        std::make_unique<DotInsideStrokeBackground>(kInsideStrokeColor));
+  }
+
+  void SetToHover() override {
+    SetBackground(
+        std::make_unique<DotInsideStrokeBackground>(kInsideStrokeColorHover));
+  }
+
+  void SetToDrag() override {
+    SetBackground(
+        std::make_unique<DotInsideStrokeBackground>(kInsideStrokeColorDrag));
+  }
+};
+
+class CrossOutsideStroke : public TouchPointElement {
+ public:
+  CrossOutsideStroke() {
+    SetToDefault();
+    SetPosition(gfx::Point(0, 0));
+    int temp = kCrossCenterLength + 2 * kCrossInsideStrokeThickness +
+               2 * kCrossOutsideStrokeThickness;
+    SetSize(gfx::Size(temp, temp));
+  }
+  ~CrossOutsideStroke() override = default;
+
+  // TouchPointElement:
+  void SetToDefault() override {
+    SetBackground(
+        std::make_unique<CrossOutsideStrokeBackground>(kOutsideStrokeColor));
+  }
+
+  void SetToHover() override {
+    SetBackground(std::make_unique<CrossOutsideStrokeBackground>(
+        kOutsideStrokeColorHover));
+  }
+
+  void SetToDrag() override {
+    SetBackground(std::make_unique<CrossOutsideStrokeBackground>(
+        kOutsideStrokeColorDrag));
+  }
+};
+
+class DotOutsideStroke : public TouchPointElement {
+ public:
+  DotOutsideStroke() {
+    SetToDefault();
+    SetPosition(gfx::Point(0, 0));
+    int temp = kDotCenterDiameter + 2 * kDotInsideStrokeThickness +
+               2 * kDotOutsideStrokeThickness;
+    SetSize(gfx::Size(temp, temp));
+  }
+  ~DotOutsideStroke() override = default;
+
+  // TouchPointElement:
+  void SetToDefault() override {
+    SetBackground(
+        std::make_unique<DotOutsideStrokeBackground>(kOutsideStrokeColor));
+  }
+
+  void SetToHover() override {
+    SetBackground(
+        std::make_unique<DotOutsideStrokeBackground>(kOutsideStrokeColorHover));
+  }
+
+  void SetToDrag() override {
+    SetBackground(
+        std::make_unique<DotOutsideStrokeBackground>(kOutsideStrokeColorDrag));
+  }
+};
+
+class CrossTouchPoint : public TouchPoint {
+ public:
+  explicit CrossTouchPoint(const gfx::Point& center_pos)
+      : TouchPoint(center_pos) {}
+  ~CrossTouchPoint() override = default;
+
+  void Init() override {
+    touch_outside_stroke_ =
+        AddChildView(std::make_unique<CrossOutsideStroke>());
+    touch_center_ = AddChildView(std::make_unique<CrossCenter>());
+    // Put the inside stroke on top purposely because the thickness is only 1
+    // and it doesn't show up obviously probably due to the round issue.
+    touch_inside_stroke_ = AddChildView(std::make_unique<CrossInsideStroke>());
+    TouchPoint::Init();
+  }
+};
+
+class DotTouchPoint : public TouchPoint {
+ public:
+  explicit DotTouchPoint(const gfx::Point& center_pos)
+      : TouchPoint(center_pos) {}
+  ~DotTouchPoint() override = default;
+
+  void Init() override {
+    touch_outside_stroke_ = AddChildView(std::make_unique<DotOutsideStroke>());
+    touch_center_ = AddChildView(std::make_unique<DotCenter>());
+    // Put the inside stroke on top purposely because the thickness is only 1
+    // and it doesn't show up obviously probably due to the round issue.
+    touch_inside_stroke_ = AddChildView(std::make_unique<DotInsideStroke>());
+    TouchPoint::Init();
+  }
+};
+
+}  // namespace
+
+TouchPointElement::TouchPointElement() = default;
+TouchPointElement::~TouchPointElement() = default;
+
+// static
+TouchPoint* TouchPoint::Show(views::View* parent,
+                             ActionType action_type,
+                             const gfx::Point& center_pos) {
+  std::unique_ptr<TouchPoint> touch_point;
+  switch (action_type) {
+    case ActionType::TAP:
+      touch_point = std::make_unique<DotTouchPoint>(center_pos);
+      break;
+    case ActionType::MOVE:
+      touch_point = std::make_unique<CrossTouchPoint>(center_pos);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  auto* touch_point_ptr =
+      parent->AddChildViewAt(std::move(touch_point), /*index=*/0);
+  touch_point_ptr->Init();
+  return touch_point_ptr;
+}
+
+TouchPoint::TouchPoint(const gfx::Point& center_pos)
+    : center_pos_(center_pos) {}
+
+TouchPoint::~TouchPoint() = default;
+
+void TouchPoint::Init() {
+  GetViewAccessibility().OverrideRole(ax::mojom::Role::kGroup);
+  // TODO(b/260868602): Update the name.
+  GetViewAccessibility().OverrideName(u"touch point");
+
+  SetFocusBehavior(FocusBehavior::ALWAYS);
+  views::FocusRing::Install(this);
+  auto* focus_ring = views::FocusRing::Get(this);
+  focus_ring->SetColorId(kFocusRingColor);
+  focus_ring->SetHaloInset(kHaloInset);
+  focus_ring->SetHaloThickness(kHaloThickness);
+
+  auto size = touch_outside_stroke_->size();
+  SetSize(size);
+  SetPosition(gfx::Point(std::max(0, center_pos_.x() - size.width() / 2),
+                         std::max(0, center_pos_.y() - size.height() / 2)));
+
+  std::make_unique<ash::ViewShadow>(this, kTouchPointShadowElevation);
+}
+
+void TouchPoint::SetToDefault() {
+  touch_outside_stroke_->SetToDefault();
+  touch_inside_stroke_->SetToDefault();
+  touch_center_->SetToDefault();
+}
+
+void TouchPoint::SetToHover() {
+  touch_outside_stroke_->SetToHover();
+  touch_inside_stroke_->SetToHover();
+  touch_center_->SetToHover();
+}
+
+void TouchPoint::SetToDrag() {
+  touch_outside_stroke_->SetToDrag();
+  touch_inside_stroke_->SetToDrag();
+  touch_center_->SetToDrag();
+}
+
+void TouchPoint::ApplyMouseEntered(const ui::MouseEvent& event) {
+  SetToHover();
+}
+
+void TouchPoint::ApplyMouseExited(const ui::MouseEvent& event) {
+  SetToDefault();
+}
+
+bool TouchPoint::ApplyMousePressed(const ui::MouseEvent& event) {
+  return static_cast<ActionView*>(parent())->ApplyMousePressed(event);
+}
+
+bool TouchPoint::ApplyMouseDragged(const ui::MouseEvent& event) {
+  auto* widget = GetWidget();
+  // widget is null for test.
+  if (widget)
+    widget->SetCursor(ui::mojom::CursorType::kGrabbing);
+  SetToDrag();
+  return static_cast<ActionView*>(parent())->ApplyMouseDragged(event);
+}
+
+void TouchPoint::ApplyMouseReleased(const ui::MouseEvent& event) {
+  auto* widget = GetWidget();
+  // widget is null for test.
+  if (widget)
+    widget->SetCursor(ui::mojom::CursorType::kGrab);
+  SetToHover();
+  static_cast<ActionView*>(parent())->ApplyMouseReleased(event);
+}
+
+void TouchPoint::ApplyGestureEvent(ui::GestureEvent* event) {
+  switch (event->type()) {
+    case ui::ET_GESTURE_SCROLL_BEGIN:
+      SetToDrag();
+      event->SetHandled();
+      break;
+    case ui::ET_GESTURE_SCROLL_END:
+    case ui::ET_SCROLL_FLING_START:
+      SetToDefault();
+      event->SetHandled();
+      break;
+    default:
+      break;
+  }
+
+  static_cast<ActionView*>(parent())->ApplyGestureEvent(event);
+}
+
+bool TouchPoint::OnKeyPressed(const ui::KeyEvent& event) {
+  return static_cast<ActionView*>(parent())->ApplyKeyPressed(event);
+}
+
+bool TouchPoint::OnKeyReleased(const ui::KeyEvent& event) {
+  return static_cast<ActionView*>(parent())->ApplyKeyReleased(event);
+}
+
+}  // namespace arc::input_overlay
diff --git a/chrome/browser/ash/arc/input_overlay/ui/touch_point.h b/chrome/browser/ash/arc/input_overlay/ui/touch_point.h
new file mode 100644
index 0000000..a38f02f
--- /dev/null
+++ b/chrome/browser/ash/arc/input_overlay/ui/touch_point.h
@@ -0,0 +1,66 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_TOUCH_POINT_H_
+#define CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_TOUCH_POINT_H_
+
+#include "chrome/browser/ash/arc/input_overlay/db/proto/app_data.pb.h"
+#include "ui/views/view.h"
+
+namespace arc::input_overlay {
+
+// Represent elements in the TouchPoint. It can be touch point center, inside
+// stroke or outside stroke.
+class TouchPointElement : public views::View {
+ public:
+  TouchPointElement();
+  ~TouchPointElement() override;
+
+  virtual void SetToDefault() = 0;
+  virtual void SetToHover() = 0;
+  virtual void SetToDrag() = 0;
+};
+
+// TouchPoint indicates the touch point for each action and shows up in the edit
+// mode.
+class TouchPoint : public views::View {
+ public:
+  static TouchPoint* Show(views::View* parent,
+                          ActionType action_type,
+                          const gfx::Point& center_pos);
+
+  explicit TouchPoint(const gfx::Point& center_pos);
+  TouchPoint(const TouchPoint&) = delete;
+  TouchPoint& operator=(const TouchPoint&) = delete;
+  ~TouchPoint() override;
+
+  virtual void Init();
+
+  void SetToDefault();
+  void SetToHover();
+  void SetToDrag();
+
+  void ApplyMouseEntered(const ui::MouseEvent& event);
+  void ApplyMouseExited(const ui::MouseEvent& event);
+  bool ApplyMousePressed(const ui::MouseEvent& event);
+  bool ApplyMouseDragged(const ui::MouseEvent& event);
+  void ApplyMouseReleased(const ui::MouseEvent& event);
+  void ApplyGestureEvent(ui::GestureEvent* event);
+
+  // views::View:
+  bool OnKeyPressed(const ui::KeyEvent& event) override;
+  bool OnKeyReleased(const ui::KeyEvent& event) override;
+
+ protected:
+  raw_ptr<TouchPointElement> touch_center_;
+  raw_ptr<TouchPointElement> touch_inside_stroke_;
+  raw_ptr<TouchPointElement> touch_outside_stroke_;
+
+ private:
+  gfx::Point center_pos_;
+};
+
+}  // namespace arc::input_overlay
+
+#endif  // CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_UI_TOUCH_POINT_H_
diff --git a/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc b/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc
index 06b9e78e2..5129c5b 100644
--- a/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc
+++ b/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc
@@ -114,7 +114,6 @@
 void ArcKeymasterBridge::OnBootstrapMojoConnection(
     BootstrapMojoConnectionCallback callback,
     bool result) {
-  cert_store_bridge_->OnBootstrapMojoConnection(result);
   if (result) {
     DVLOG(1) << "Success bootstrapping Mojo in arc-keymasterd.";
   } else {
diff --git a/chrome/browser/ash/arc/keymaster/cert_store_bridge.cc b/chrome/browser/ash/arc/keymaster/cert_store_bridge.cc
index b34e3187..1191c40 100644
--- a/chrome/browser/ash/arc/keymaster/cert_store_bridge.cc
+++ b/chrome/browser/ash/arc/keymaster/cert_store_bridge.cc
@@ -12,7 +12,6 @@
 #include "base/logging.h"
 #include "mojo/core/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/platform/platform_channel.h"
 
 namespace arc {
 namespace keymaster {
@@ -39,13 +38,6 @@
   }
 }
 
-void CertStoreBridge::GetSecurityTokenOperation(
-    mojo::PendingReceiver<mojom::SecurityTokenOperation> operation_receiver,
-    GetSecurityTokenOperationCallback callback) {
-  VLOG(2) << "CertStoreBridge::GetSecurityTokenOperation";
-  std::move(callback).Run();
-}
-
 void CertStoreBridge::BindToInvitation(mojo::OutgoingInvitation* invitation) {
   VLOG(2) << "CertStoreBridge::BootstrapMojoConnection";
 
@@ -71,37 +63,5 @@
                      base::Unretained(&cert_store_proxy_)));
 }
 
-void CertStoreBridge::OnBootstrapMojoConnection(bool result) {
-  if (!result) {
-    cert_store_proxy_.reset();
-    return;
-  }
-
-  auto receiver =
-      std::make_unique<mojo::Receiver<keymaster::mojom::CertStoreHost>>(this);
-  mojo::PendingRemote<keymaster::mojom::CertStoreHost> host_proxy;
-  receiver->Bind(host_proxy.InitWithNewPipeAndPassReceiver());
-
-  cert_store_proxy_->Init(
-      std::move(host_proxy),
-      base::BindOnce(&CertStoreBridge::OnConnectionReady,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(receiver)));
-}
-
-void CertStoreBridge::OnConnectionReady(
-    std::unique_ptr<mojo::Receiver<mojom::CertStoreHost>> receiver) {
-  VLOG(2) << "CertStoreBridge::OnConnectionReady";
-  DCHECK(!receiver_);
-  receiver->set_disconnect_handler(base::BindOnce(
-      &CertStoreBridge::OnConnectionClosed, base::Unretained(this)));
-  receiver_ = std::move(receiver);
-}
-
-void CertStoreBridge::OnConnectionClosed() {
-  VLOG(2) << "CertStoreBridge::OnConnectionClosed";
-  DCHECK(receiver_);
-  receiver_.reset();
-}
-
 }  // namespace keymaster
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/keymaster/cert_store_bridge.h b/chrome/browser/ash/arc/keymaster/cert_store_bridge.h
index a8f1f60f..83c729af 100644
--- a/chrome/browser/ash/arc/keymaster/cert_store_bridge.h
+++ b/chrome/browser/ash/arc/keymaster/cert_store_bridge.h
@@ -9,8 +9,6 @@
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/services/keymaster/public/mojom/cert_store.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/invitation.h"
 
@@ -23,17 +21,16 @@
 namespace arc {
 namespace keymaster {
 
-class CertStoreBridge : public mojom::CertStoreHost {
+class CertStoreBridge {
  public:
   explicit CertStoreBridge(content::BrowserContext* context);
   CertStoreBridge(const CertStoreBridge&) = delete;
   CertStoreBridge& operator=(const CertStoreBridge&) = delete;
-  ~CertStoreBridge() override;
+  ~CertStoreBridge();
 
   // Attaches a new message pipe to the invitation and binds it to the cert
   // store instance proxy.
   void BindToInvitation(mojo::OutgoingInvitation* invitation);
-  void OnBootstrapMojoConnection(bool result);
 
   bool is_proxy_bound() const { return cert_store_proxy_.is_bound(); }
 
@@ -42,21 +39,10 @@
       std::vector<mojom::ChromeOsKeyPtr> keys,
       mojom::CertStoreInstance::UpdatePlaceholderKeysCallback callback);
 
-  // CertStoreHost overrides.
-  void GetSecurityTokenOperation(
-      mojo::PendingReceiver<mojom::SecurityTokenOperation> operation_receiver,
-      GetSecurityTokenOperationCallback callback) override;
-
  private:
-  void OnConnectionReady(
-      std::unique_ptr<mojo::Receiver<mojom::CertStoreHost>> receiver);
-  void OnConnectionClosed();
-
   // Points to a proxy bound to the implementation in arc-keymasterd.
   mojo::Remote<keymaster::mojom::CertStoreInstance> cert_store_proxy_;
 
-  std::unique_ptr<mojo::Receiver<mojom::CertStoreHost>> receiver_;
-
   base::WeakPtrFactory<CertStoreBridge> weak_ptr_factory_;
 };
 
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
index 194542e..af103fab 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
@@ -143,7 +143,7 @@
   NotifyObserver(State::kDlcInstall);
 
   dlcservice::InstallRequest request;
-  request.set_id(crostini::kCrostiniDlcName);
+  request.set_id(kToolsDlc);
   ash::DlcserviceClient::Get()->Install(
       request,
       base::BindOnce(&BruschettaInstallerImpl::OnToolsDlcInstalled,
@@ -482,7 +482,7 @@
 
   request.set_name(kBruschettaVmName);
   request.set_owner_id(std::move(user_hash));
-  request.mutable_vm()->set_tools_dlc_id("termina-dlc");
+  request.mutable_vm()->set_tools_dlc_id(kToolsDlc);
   request.set_start_termina(false);
 
   auto* disk = request.add_disks();
diff --git a/chrome/browser/ash/bruschetta/bruschetta_launcher.cc b/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
index fa4d042..d583594 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
@@ -64,7 +64,7 @@
 
 void BruschettaLauncher::EnsureDlcInstalled() {
   dlcservice::InstallRequest request;
-  request.set_id(crostini::kCrostiniDlcName);
+  request.set_id(kToolsDlc);
   ash::DlcserviceClient::Get()->Install(
       request,
       base::BindOnce(&BruschettaLauncher::OnMountDlc,
@@ -109,7 +109,7 @@
   vm_tools::concierge::StartVmRequest request;
   request.set_start_termina(false);
   request.set_name(vm_name_);
-  *request.mutable_vm()->mutable_tools_dlc_id() = "termina-dlc";
+  *request.mutable_vm()->mutable_tools_dlc_id() = kToolsDlc;
   *request.mutable_owner_id() = user_hash;
   request.set_start_termina(false);
   request.set_timeout(240);
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.cc b/chrome/browser/ash/bruschetta/bruschetta_util.cc
index 7ce12c7..9d61be4d 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_util.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_util.cc
@@ -27,6 +27,8 @@
 }
 }  // namespace
 
+const char kToolsDlc[] = "termina-tools-dlc";
+
 const char kBruschettaVmName[] = "bru";
 const char kBruschettaDisplayName[] = "Bruschetta";
 
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.h b/chrome/browser/ash/bruschetta/bruschetta_util.h
index 301e9cb..a524da6 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_util.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_util.h
@@ -12,6 +12,8 @@
 
 namespace bruschetta {
 
+extern const char kToolsDlc[];
+
 extern const char kBruschettaVmName[];
 extern const char kBruschettaDisplayName[];
 
diff --git a/chrome/browser/ash/drive/drivefs_native_message_host.cc b/chrome/browser/ash/drive/drivefs_native_message_host.cc
index b41caa7b..a974f556 100644
--- a/chrome/browser/ash/drive/drivefs_native_message_host.cc
+++ b/chrome/browser/ash/drive/drivefs_native_message_host.cc
@@ -50,9 +50,7 @@
           extension_receiver,
       mojo::PendingRemote<drivefs::mojom::NativeMessagingHost> drivefs_remote)
       : pending_receiver_(std::move(extension_receiver)),
-        drivefs_remote_(std::move(drivefs_remote)) {
-    DCHECK(UseBidirectionalNativeMessaging());
-  }
+        drivefs_remote_(std::move(drivefs_remote)) {}
 
   explicit DriveFsNativeMessageHost(
       drivefs::mojom::DriveFs* drivefs_for_testing)
@@ -66,29 +64,14 @@
   void OnMessage(const std::string& message) override {
     DCHECK(client_);
 
-    if (UseBidirectionalNativeMessaging()) {
-      if (drivefs_remote_) {
-        drivefs_remote_->HandleMessageFromExtension(message);
-      }
-    } else {
-      if (!drive_service_ || !drive_service_->GetDriveFsInterface()) {
-        OnDriveFsResponse(FILE_ERROR_SERVICE_UNAVAILABLE, "");
-        return;
-      }
-
-      drive_service_->GetDriveFsInterface()->SendNativeMessageRequest(
-          message, base::BindOnce(&DriveFsNativeMessageHost::OnDriveFsResponse,
-                                  weak_ptr_factory_.GetWeakPtr()));
+    if (drivefs_remote_) {
+      drivefs_remote_->HandleMessageFromExtension(message);
     }
   }
 
   void Start(Client* client) override {
     client_ = client;
 
-    if (!UseBidirectionalNativeMessaging()) {
-      return;
-    }
-
     if (!pending_receiver_) {
       // The session was initiated by the extension.
       mojo::PendingRemote<drivefs::mojom::NativeMessagingPort> extension_port;
@@ -98,7 +81,8 @@
       if (drivefs_for_testing_) {
         drivefs = drivefs_for_testing_;
       } else if (!drive_service_ || !drive_service_->GetDriveFsInterface()) {
-        OnDriveFsResponse(FILE_ERROR_SERVICE_UNAVAILABLE, "");
+        client_->CloseChannel(
+            FileErrorToString(FILE_ERROR_SERVICE_UNAVAILABLE));
         return;
       } else {
         drivefs = drive_service_->GetDriveFsInterface();
@@ -120,15 +104,6 @@
   }
 
  private:
-  void OnDriveFsResponse(FileError error, const std::string& response) {
-    if (error == FILE_ERROR_OK) {
-      client_->PostMessageFromNativeHost(response);
-    } else {
-      LOG(WARNING) << "DriveFS returned error " << FileErrorToString(error);
-      client_->CloseChannel(FileErrorToString(error));
-    }
-  }
-
   void PostMessageToExtension(const std::string& message) override {
     client_->PostMessageFromNativeHost(message);
   }
@@ -140,11 +115,6 @@
     drivefs_remote_.reset();
   }
 
-  bool UseBidirectionalNativeMessaging() {
-    return base::FeatureList::IsEnabled(
-        ash::features::kDriveFsBidirectionalNativeMessaging);
-  }
-
   DriveIntegrationService* drive_service_ = nullptr;
   drivefs::mojom::DriveFs* drivefs_for_testing_ = nullptr;
 
@@ -157,8 +127,6 @@
 
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_ =
       base::SingleThreadTaskRunner::GetCurrentDefault();
-
-  base::WeakPtrFactory<DriveFsNativeMessageHost> weak_ptr_factory_{this};
 };
 
 std::unique_ptr<extensions::NativeMessageHost> CreateDriveFsNativeMessageHost(
@@ -172,10 +140,6 @@
     mojo::PendingReceiver<drivefs::mojom::NativeMessagingPort>
         extension_receiver,
     mojo::PendingRemote<drivefs::mojom::NativeMessagingHost> drivefs_remote) {
-  if (!base::FeatureList::IsEnabled(
-          ash::features::kDriveFsBidirectionalNativeMessaging)) {
-    return nullptr;
-  }
   return std::make_unique<DriveFsNativeMessageHost>(
       std::move(extension_receiver), std::move(drivefs_remote));
 }
diff --git a/chrome/browser/ash/drive/drivefs_native_message_host_unittest.cc b/chrome/browser/ash/drive/drivefs_native_message_host_unittest.cc
index 7fbfad1b..7c9a89f1 100644
--- a/chrome/browser/ash/drive/drivefs_native_message_host_unittest.cc
+++ b/chrome/browser/ash/drive/drivefs_native_message_host_unittest.cc
@@ -48,10 +48,7 @@
       public drivefs::mojom::DriveFsInterceptorForTesting,
       public drivefs::mojom::NativeMessagingHost {
  public:
-  DriveFsNativeMessageHostTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        ash::features::kDriveFsBidirectionalNativeMessaging);
-  }
+  DriveFsNativeMessageHostTest() = default;
 
   DriveFsNativeMessageHostTest(const DriveFsNativeMessageHostTest&) = delete;
   DriveFsNativeMessageHostTest& operator=(const DriveFsNativeMessageHostTest&) =
@@ -166,29 +163,5 @@
   base::RunLoop().RunUntilIdle();
 }
 
-class DriveFsNativeMessageHostTestWithoutFlag
-    : public DriveFsNativeMessageHostTest {
- public:
-  DriveFsNativeMessageHostTestWithoutFlag() {
-    scoped_feature_list_.InitAndDisableFeature(
-        ash::features::kDriveFsBidirectionalNativeMessaging);
-  }
-
-  DriveFsNativeMessageHostTestWithoutFlag(
-      const DriveFsNativeMessageHostTestWithoutFlag&) = delete;
-  DriveFsNativeMessageHostTestWithoutFlag& operator=(
-      const DriveFsNativeMessageHostTestWithoutFlag&) = delete;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(DriveFsNativeMessageHostTestWithoutFlag,
-       DriveFsCannotInitiateMessaging) {
-  ASSERT_FALSE(CreateDriveFsInitiatedNativeMessageHost(
-      extension_port_.BindNewPipeAndPassReceiver(),
-      receiver_.BindNewPipeAndPassRemote()));
-}
-
 }  // namespace
 }  // namespace drive
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_drive.cc b/chrome/browser/ash/extensions/file_manager/private_api_drive.cc
index 2415f12..b592201 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_drive.cc
@@ -824,8 +824,6 @@
       extensions::ExtensionRegistry::Get(browser_context())
           ->enabled_extensions();
   result.can_pin_hosted_files =
-      base::FeatureList::IsEnabled(
-          ash::features::kDriveFsBidirectionalNativeMessaging) &&
       enabled_extensions.Contains(extension_misc::kDocsOfflineExtensionId) &&
       enabled_extensions.Contains(
           GURL(drive::kDriveFsNativeMessageHostOrigins[0]).host());
@@ -965,14 +963,11 @@
 
 ExtensionFunction::ResponseAction
 FileManagerPrivatePollDriveHostedFilePinStatesFunction::Run() {
-  if (base::FeatureList::IsEnabled(
-          ash::features::kDriveFsBidirectionalNativeMessaging)) {
-    Profile* const profile = Profile::FromBrowserContext(browser_context());
-    drive::DriveIntegrationService* integration_service =
-        drive::util::GetIntegrationServiceByProfile(profile);
-    if (integration_service) {
-      integration_service->PollHostedFilePinStates();
-    }
+  Profile* const profile = Profile::FromBrowserContext(browser_context());
+  drive::DriveIntegrationService* integration_service =
+      drive::util::GetIntegrationServiceByProfile(profile);
+  if (integration_service) {
+    integration_service->PollHostedFilePinStates();
   }
   return RespondNow(WithArguments());
 }
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 5afd2712..b567b87 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -141,11 +141,6 @@
     return *this;
   }
 
-  TestCase& EnableDriveDssPin() {
-    options.drive_dss_pin = true;
-    return *this;
-  }
-
   TestCase& EnableTrash() {
     options.enable_trash = true;
     return *this;
@@ -224,9 +219,6 @@
     if (options.photos_documents_provider)
       full_name += "_PhotosDocumentsProvider";
 
-    if (options.drive_dss_pin)
-      full_name += "_DriveDssPin";
-
     if (options.single_partition_format)
       full_name += "_SinglePartitionFormat";
 
@@ -1325,8 +1317,7 @@
         TestCase("driveLinkOpenFileThroughLinkedDirectory"),
         TestCase("driveLinkOpenFileThroughTransitiveLink"),
         TestCase("driveWelcomeBanner"),
-        TestCase("driveOfflineInfoBanner").EnableDriveDssPin(),
-        TestCase("driveOfflineInfoBannerWithoutFlag"),
+        TestCase("driveOfflineInfoBanner"),
         TestCase("driveDeleteDialogDoesntMentionPermanentDelete"),
         TestCase("driveInlineSyncStatusSingleFile").EnableInlineStatusSync(),
         TestCase("driveInlineSyncStatusParentFolder").EnableInlineStatusSync()
@@ -1811,7 +1802,9 @@
         TestCase("searchHidingTextEntryField").EnableSearchV2(),
         TestCase("searchButtonToggles"),
         TestCase("searchButtonToggles").EnableSearchV2(),
-        TestCase("searchOptions").EnableSearchV2()
+        TestCase("searchWithLocationOptions").EnableSearchV2(),
+        TestCase("searchWithTypeOptions").EnableSearchV2(),
+        TestCase("searchWithRecencyOptions").EnableSearchV2()
         // TODO(b/189173190): Enable
         // TestCase("searchQueryLaunchParam")
         ));
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
index be1d4843..15a1c3a1 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -853,7 +853,6 @@
 
   PRINT_IF_NOT_DEFAULT(arc)
   PRINT_IF_NOT_DEFAULT(browser)
-  PRINT_IF_NOT_DEFAULT(drive_dss_pin)
   PRINT_IF_NOT_DEFAULT(files_experimental)
   PRINT_IF_NOT_DEFAULT(generic_documents_provider)
   PRINT_IF_NOT_DEFAULT(mount_volumes)
@@ -1932,14 +1931,6 @@
     arc::SetArcAvailableCommandLineForTesting(command_line);
   }
 
-  if (options.drive_dss_pin) {
-    enabled_features.push_back(
-        ash::features::kDriveFsBidirectionalNativeMessaging);
-  } else {
-    disabled_features.push_back(
-        ash::features::kDriveFsBidirectionalNativeMessaging);
-  }
-
   if (options.single_partition_format) {
     enabled_features.push_back(ash::features::kFilesSinglePartitionFormat);
   }
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
index 87577b0c..e5d1736 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -78,9 +78,6 @@
     // Whether test requires a browser to be started.
     bool browser = false;
 
-    // Whether test should enable drive dss pinning.
-    bool drive_dss_pin = false;
-
     // Whether Drive should act as if offline.
     bool offline = false;
 
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc
index ea8ca879..7df4b033 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -1118,9 +1118,6 @@
             base::FeatureList::IsEnabled(ash::features::kFilesSearchV2));
   dict->Set("FILES_TRASH_ENABLED",
             base::FeatureList::IsEnabled(ash::features::kFilesTrash));
-  dict->Set("DRIVE_DSS_PIN_ENABLED",
-            base::FeatureList::IsEnabled(
-                ash::features::kDriveFsBidirectionalNativeMessaging));
   dict->Set(
       "FILES_SINGLE_PARTITION_FORMAT_ENABLED",
       base::FeatureList::IsEnabled(ash::features::kFilesSinglePartitionFormat));
diff --git a/chrome/browser/ash/mojo_service_manager/connection_helper.h b/chrome/browser/ash/mojo_service_manager/connection_helper.h
index eda8c29c..ca8aeb7 100644
--- a/chrome/browser/ash/mojo_service_manager/connection_helper.h
+++ b/chrome/browser/ash/mojo_service_manager/connection_helper.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_ASH_MOJO_SERVICE_MANAGER_CONNECTION_HELPER_H_
 #define CHROME_BROWSER_ASH_MOJO_SERVICE_MANAGER_CONNECTION_HELPER_H_
 
-#include <base/callback_helpers.h>
+#include "base/functional/callback_helpers.h"
 
 namespace ash {
 namespace mojo_service_manager {
diff --git a/chrome/browser/ash/system_extensions/api/window_management/BUILD.gn b/chrome/browser/ash/system_extensions/api/window_management/BUILD.gn
index 9d94969..02a09f8 100644
--- a/chrome/browser/ash/system_extensions/api/window_management/BUILD.gn
+++ b/chrome/browser/ash/system_extensions/api/window_management/BUILD.gn
@@ -31,7 +31,6 @@
     "//chrome/browser/ui",
     "//components/keyed_service/content",
     "//components/services/app_service/public/cpp:instance_update",
-    "//components/services/app_service/public/mojom",
     "//content/public/browser",
     "//third_party/blink/public/mojom:mojom_platform",
     "//ui/aura",
diff --git a/chrome/browser/content_index/content_index_provider_impl.cc b/chrome/browser/content_index/content_index_provider_impl.cc
index 6772f80..b3a77f4 100644
--- a/chrome/browser/content_index/content_index_provider_impl.cc
+++ b/chrome/browser/content_index/content_index_provider_impl.cc
@@ -273,7 +273,7 @@
 void ContentIndexProviderImpl::GetAllItems(MultipleItemCallback callback) {
   // Get the number of Storage Paritions.
   std::vector<content::StoragePartition*> storage_paritions;
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](std::vector<content::StoragePartition*>* storage_paritions,
          content::StoragePartition* storage_partition) {
         storage_paritions->push_back(storage_partition);
diff --git a/chrome/browser/google/google_brand_code_map_chromeos.cc b/chrome/browser/google/google_brand_code_map_chromeos.cc
index 8fea854..7492688 100644
--- a/chrome/browser/google/google_brand_code_map_chromeos.cc
+++ b/chrome/browser/google/google_brand_code_map_chromeos.cc
@@ -494,6 +494,7 @@
                      {"UGCB", {"OFRA", "PZBT", "HYKB"}},
                      {"UMAU", {"FKAK", "JCTZ", "GDUU"}},
                      {"UPPG", {"HYSS", "KHZT", "QQZJ"}},
+                     {"UPWS", {"ORJS", "ODPG", "KEZI"}},
                      {"UQDN", {"LWWF", "SCDS", "IKKY"}},
                      {"UQUC", {"YLQO", "IDZV", "PXQW"}},
                      {"URZD", {"QDAL", "YLWB", "XCCP"}},
@@ -511,6 +512,7 @@
                      {"VJXU", {"ANLP", "KACE", "KWVH"}},
                      {"VRWC", {"OGMF", "GYJX", "NOBB"}},
                      {"VUEX", {"BUER", "MAHW", "GSYB"}},
+                     {"VVBN", {"AHMF", "WIWE", "AADO"}},
                      {"VVUC", {"WQCU", "YUMW", "YHYC"}},
                      {"VYNC", {"MBDE", "ZHLY", "EESD"}},
                      {"VYRC", {"VKSO", "NKTO", "ZPZX"}},
diff --git a/chrome/browser/headless/headless_command_processor.cc b/chrome/browser/headless/headless_command_processor.cc
index f635dfaa..5ef93ee 100644
--- a/chrome/browser/headless/headless_command_processor.cc
+++ b/chrome/browser/headless/headless_command_processor.cc
@@ -6,8 +6,8 @@
 
 #include <memory>
 
-#include "base/bind.h"
 #include "base/command_line.h"
+#include "base/functional/bind.h"
 #include "chrome/browser/headless/headless_mode_util.h"
 #include "components/headless/command_handler/headless_command_handler.h"
 #include "content/public/browser/browser_context.h"
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index 59b2924..6af146b 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -201,7 +201,7 @@
   ContentSettingsForOneType settings;
   HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
       ContentSettingsType::COOKIES, &settings);
-  profile->ForEachStoragePartition(base::BindRepeating(
+  profile->ForEachLoadedStoragePartition(base::BindRepeating(
       [](ContentSettingsForOneType settings,
          content::StoragePartition* storage_partition) {
         storage_partition->GetCookieManagerForBrowserProcess()
@@ -214,7 +214,7 @@
   ContentSettingsForOneType settings;
   HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
       ContentSettingsType::LEGACY_COOKIE_ACCESS, &settings);
-  profile->ForEachStoragePartition(base::BindRepeating(
+  profile->ForEachLoadedStoragePartition(base::BindRepeating(
       [](ContentSettingsForOneType settings,
          content::StoragePartition* storage_partition) {
         storage_partition->GetCookieManagerForBrowserProcess()
@@ -229,7 +229,7 @@
     HostContentSettingsMapFactory::GetForProfile(profile)
         ->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS, &settings);
 
-    profile->ForEachStoragePartition(base::BindRepeating(
+    profile->ForEachLoadedStoragePartition(base::BindRepeating(
         [](ContentSettingsForOneType settings,
            content::StoragePartition* storage_partition) {
           storage_partition->GetCookieManagerForBrowserProcess()
@@ -249,7 +249,7 @@
         ->GetSettingsForOneType(ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS,
                                 &settings);
 
-    profile->ForEachStoragePartition(base::BindRepeating(
+    profile->ForEachLoadedStoragePartition(base::BindRepeating(
         [](ContentSettingsForOneType settings,
            content::StoragePartition* storage_partition) {
           storage_partition->GetCookieManagerForBrowserProcess()
@@ -362,7 +362,7 @@
       policy::PolicyCertServiceFactory::GetForProfile(profile_);
   if (!policy_cert_service)
     return;
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](const policy::PolicyCertService* policy_cert_service,
          content::StoragePartition* storage_partition) {
         auto additional_certificates = GetAdditionalCertificates(
@@ -409,7 +409,7 @@
 }
 
 void ProfileNetworkContextService::UpdateAcceptLanguage() {
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](const std::string& accept_language,
          content::StoragePartition* storage_partition) {
         storage_partition->GetNetworkContext()->SetAcceptLanguage(
@@ -420,7 +420,7 @@
 
 void ProfileNetworkContextService::OnThirdPartyCookieBlockingChanged(
     bool block_third_party_cookies) {
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](bool block_third_party_cookies,
          content::StoragePartition* storage_partition) {
         storage_partition->GetCookieManagerForBrowserProcess()
@@ -440,7 +440,7 @@
 
 void ProfileNetworkContextService::OnTrustTokenBlockingChanged(
     bool block_trust_tokens) {
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](bool block_trust_tokens,
          content::StoragePartition* storage_partition) {
         storage_partition->GetNetworkContext()->SetBlockTrustTokens(
@@ -473,7 +473,7 @@
 }
 
 void ProfileNetworkContextService::UpdateReferrersEnabled() {
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](bool enable_referrers, content::StoragePartition* storage_partition) {
         storage_partition->GetNetworkContext()->SetEnableReferrers(
             enable_referrers);
@@ -484,7 +484,7 @@
 void ProfileNetworkContextService::UpdatePreconnect() {
   bool enable_preconnect =
       ChromeContentBrowserClient::ShouldPreconnect(profile_);
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](bool enable_preconnect, content::StoragePartition* storage_partition) {
         storage_partition->GetNetworkContext()->SetEnablePreconnect(
             enable_preconnect);
@@ -524,7 +524,7 @@
 
 void ProfileNetworkContextService::UpdateCTPolicy() {
   std::vector<network::mojom::NetworkContext*> contexts;
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](std::vector<network::mojom::NetworkContext*>* contexts_ptr,
          content::StoragePartition* storage_partition) {
         contexts_ptr->push_back(storage_partition->GetNetworkContext());
@@ -552,7 +552,7 @@
   bool split_auth_cache_by_network_isolation_key =
       ShouldSplitAuthCacheByNetworkIsolationKey();
 
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](bool split_auth_cache_by_network_anonymization_key,
          content::StoragePartition* storage_partition) {
         storage_partition->GetNetworkContext()
@@ -567,7 +567,7 @@
   const bool value = profile_->GetPrefs()->GetBoolean(
       prefs::kCorsNonWildcardRequestHeadersSupport);
 
-  profile_->ForEachStoragePartition(base::BindRepeating(
+  profile_->ForEachLoadedStoragePartition(base::BindRepeating(
       [](bool value, content::StoragePartition* storage_partition) {
         storage_partition->GetNetworkContext()
             ->SetCorsNonWildcardRequestHeadersSupport(value);
diff --git a/chrome/browser/notifications/notification_trigger_scheduler.cc b/chrome/browser/notifications/notification_trigger_scheduler.cc
index 3247475..d3e29d7 100644
--- a/chrome/browser/notifications/notification_trigger_scheduler.cc
+++ b/chrome/browser/notifications/notification_trigger_scheduler.cc
@@ -100,9 +100,10 @@
   profile->GetPrefs()->SetTime(prefs::kNotificationNextTriggerTime,
                                base::Time::Max());
 
-  // Unretained is safe here because BrowserContext::ForEachStoragePartition is
-  // synchronous and the profile just got fetched via GetLoadedProfiles.
-  profile->ForEachStoragePartition(base::BindRepeating(
+  // Unretained is safe here because
+  // BrowserContext::ForEachLoadedStoragePartition is synchronous and the
+  // profile just got fetched via GetLoadedProfiles.
+  profile->ForEachLoadedStoragePartition(base::BindRepeating(
       &NotificationTriggerScheduler::TriggerNotificationsForStoragePartition,
       base::Unretained(service->GetNotificationTriggerScheduler())));
 }
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index 8072ae6..39d85278 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -179,7 +179,7 @@
     return;
 
   auto recorder = base::MakeRefCounted<RevokeDeleteCountRecorder>();
-  profile_->ForEachStoragePartition(
+  profile_->ForEachLoadedStoragePartition(
       base::BindRepeating(
           [](scoped_refptr<RevokeDeleteCountRecorder> recorder,
              content::StoragePartition* partition) {
diff --git a/chrome/browser/password_manager/android/password_manager_lifecycle_helper_impl.h b/chrome/browser/password_manager/android/password_manager_lifecycle_helper_impl.h
index c279d7d..7bbcf67 100644
--- a/chrome/browser/password_manager/android/password_manager_lifecycle_helper_impl.h
+++ b/chrome/browser/password_manager/android/password_manager_lifecycle_helper_impl.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_MANAGER_LIFECYCLE_HELPER_IMPL_H_
 
 #include "base/android/scoped_java_ref.h"
-#include "base/callback.h"  // callback_forward doesn't suffice for members.
+#include "base/functional/callback.h"  // callback_forward doesn't suffice for members.
 #include "chrome/browser/password_manager/android/password_manager_lifecycle_helper.h"
 
 // Simple JNI bridge to implement the PasswordManagerLifecycleHelper interface.
diff --git a/chrome/browser/profiles/android/profile_manager_utils.cc b/chrome/browser/profiles/android/profile_manager_utils.cc
index 931e812..7a991cf 100644
--- a/chrome/browser/profiles/android/profile_manager_utils.cc
+++ b/chrome/browser/profiles/android/profile_manager_utils.cc
@@ -35,7 +35,8 @@
       ->GetCookieManagerForBrowserProcess()
       ->FlushCookieStore(
           network::mojom::CookieManager::FlushCookieStoreCallback());
-  profile->ForEachStoragePartition(base::BindRepeating(FlushStoragePartition));
+  profile->ForEachLoadedStoragePartition(
+      base::BindRepeating(FlushStoragePartition));
 }
 
 void RemoveSessionCookiesForProfile(Profile* profile) {
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 ad3e579..7472189 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -191,6 +191,7 @@
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
 #include "ui/base/emoji/emoji_panel_helper.h"
+#include "ui/base/interaction/element_identifier.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
 #include "ui/base/window_open_disposition_utils.h"
@@ -714,6 +715,9 @@
   }
 }
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(RenderViewContextMenu,
+                                      kExitFullscreenMenuItem);
+
 RenderViewContextMenu::RenderViewContextMenu(
     content::RenderFrameHost& render_frame_host,
     const content::ContextMenuParams& params)
@@ -1843,6 +1847,10 @@
 
   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_EXIT_FULLSCREEN,
                                   IDS_CONTENT_CONTEXT_EXIT_FULLSCREEN);
+  menu_model_.SetElementIdentifierAt(
+      menu_model_.GetIndexOfCommandId(IDC_CONTENT_CONTEXT_EXIT_FULLSCREEN)
+          .value(),
+      kExitFullscreenMenuItem);
   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
 }
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index 3c8fe2b..f0c2e640e 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -30,6 +30,7 @@
 #include "ppapi/buildflags/buildflags.h"
 #include "printing/buildflags/buildflags.h"
 #include "third_party/blink/public/mojom/frame/frame.mojom-forward.h"
+#include "ui/base/interaction/element_identifier.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/geometry/vector2d.h"
@@ -94,6 +95,8 @@
     : public RenderViewContextMenuBase,
       public custom_handlers::ProtocolHandlerRegistry::Observer {
  public:
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kExitFullscreenMenuItem);
+
   using ExecutePluginActionCallback =
       base::OnceCallback<void(content::RenderFrameHost*,
                               blink::mojom::PluginActionType)>;
diff --git a/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy_test.js b/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy_test.js
index 66adb0e..5a29869c 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy_test.js
@@ -24,6 +24,8 @@
 };
 
 
+// TODO(https://issuetracker.google.com/issues/263127143) Recovery can likely be
+// simplified now that most ids are stable.
 AX_TEST_F(
     'AccessibilityExtensionRecoveryStrategyTest', 'ReparentedRecovery',
     async function() {
@@ -54,30 +56,21 @@
       assertFalse(
           bAncestryRecovery.requiresRecovery(),
           'bAncestryRecovery.requiresRecovery');
-      assertTrue(
+      assertFalse(
           pAncestryRecovery.requiresRecovery(),
           'pAncestryRecovery.requiresRecovery()');
-      assertTrue(
+      assertFalse(
           sAncestryRecovery.requiresRecovery(),
           'sAncestryRecovery.requiresRecovery()');
       assertFalse(
           bTreePathRecovery.requiresRecovery(),
           'bTreePathRecovery.requiresRecovery()');
-      assertTrue(
+      assertFalse(
           pTreePathRecovery.requiresRecovery(),
           'pTreePathRecovery.requiresRecovery()');
-      assertTrue(
+      assertFalse(
           sTreePathRecovery.requiresRecovery(),
           'sTreePathRecovery.requiresRecovery()');
-
-      assertEquals(RoleType.BUTTON, bAncestryRecovery.node.role);
-      assertEquals(root, pAncestryRecovery.node);
-      assertEquals(root, sAncestryRecovery.node);
-
-      assertEquals(b, bTreePathRecovery.node);
-      assertEquals(b, pTreePathRecovery.node);
-      assertEquals(b, sTreePathRecovery.node);
-
       assertFalse(
           bAncestryRecovery.requiresRecovery(),
           'bAncestryRecovery.requiresRecovery()');
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
index 7f0e43c..12f654eb 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
@@ -565,21 +565,28 @@
       const maxPagination =
           this.getPaginationArray(this.emojiGroupTabs).pop() ?? 0;
       this.pagination = Math.min(this.pagination + 1, maxPagination);
-
-      const nextTab =
-          this.emojiGroupTabs.find((tab) => tab.pagination === this.pagination);
-      this.scrollToGroup(nextTab?.groupId);
-      this.groupTabsMoving = true;
+      this.updateCurrentGroupTabs();
     }
   }
 
   onLeftChevronClick() {
     this.pagination = Math.max(this.pagination - 1, 1);
+    this.updateCurrentGroupTabs();
+  }
 
+  updateCurrentGroupTabs() {
     const nextTab =
         this.emojiGroupTabs.find((tab) => tab.pagination === this.pagination);
-    this.scrollToGroup(nextTab?.groupId);
-    this.groupTabsMoving = true;
+    if (this.category === CategoryEnum.GIF) {
+      // GIF group tabs movement isn't affected by scrolling
+      this.groupTabsMoving = false;
+
+      // TODO(b/265731647) Set the GIF elements for the first GIF tab group
+      // Awaiting (b/263920562) to be merged in
+    } else {
+      this.scrollToGroup(nextTab?.groupId);
+      this.groupTabsMoving = true;
+    }
   }
 
   scrollToGroup(newGroup?: string) {
@@ -592,6 +599,13 @@
   }
 
   private onGroupsScroll() {
+    // GIF group tabs movement isn't affected by scrolling.
+    // This stops the GIF group tabs bar from bouncing back
+    // when clicking on left/right chevron.
+    if (this.category === CategoryEnum.GIF) {
+      return;
+    }
+
     this.updateChevrons();
     this.groupTabsMoving = true;
 
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
index ae6b392..e3fdf66 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
@@ -1027,7 +1027,7 @@
   // Simulate the user dismissing the dialog. The navigation should be resumed.
   DismissModalDialog(WarningAction::IGNORE_WARNING);
 
-  navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation.WaitForNavigationFinished());
   ASSERT_TRUE(navigation.was_successful());
 }
 
@@ -1062,7 +1062,7 @@
   FinishRequest(request.get(), LoginReputationClientResponse::SAFE);
   ASSERT_FALSE(request->is_modal_warning_showing());
 
-  navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation.WaitForNavigationFinished());
   ASSERT_TRUE(navigation.was_successful());
 }
 
@@ -1101,7 +1101,7 @@
   // Simulate the user dismissing the dialog. The navigation should be resumed.
   DismissModalDialog(WarningAction::IGNORE_WARNING);
 
-  navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation.WaitForNavigationFinished());
   ASSERT_TRUE(navigation.was_successful());
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
index 8b37885..cde5de20 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -3280,7 +3280,7 @@
       referrer_chain.Get(2));
 
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
   ASSERT_EQ(0U, nav_list->PendingNavigationEventsSize());
 }
 
@@ -3334,7 +3334,7 @@
                            referrer_chain.Get(0));
 
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
   ASSERT_EQ(0U, nav_list->PendingNavigationEventsSize());
 }
 
diff --git a/chrome/browser/ssl/sct_reporting_service.cc b/chrome/browser/ssl/sct_reporting_service.cc
index 413d277..2ae51b5 100644
--- a/chrome/browser/ssl/sct_reporting_service.cc
+++ b/chrome/browser/ssl/sct_reporting_service.cc
@@ -231,7 +231,7 @@
 
   // Iterate over StoragePartitions for this Profile, and for each get the
   // NetworkContext and set the SCT auditing mode.
-  profile_->ForEachStoragePartition(
+  profile_->ForEachLoadedStoragePartition(
       base::BindRepeating(&SetSCTAuditingEnabledForStoragePartition, mode));
 
   if (mode == network::mojom::SCTAuditingMode::kDisabled)
diff --git a/chrome/browser/support_tool/screenshot_data_collector.cc b/chrome/browser/support_tool/screenshot_data_collector.cc
index 01af174..c38b608 100644
--- a/chrome/browser/support_tool/screenshot_data_collector.cc
+++ b/chrome/browser/support_tool/screenshot_data_collector.cc
@@ -7,8 +7,8 @@
 #include <vector>
 
 #include "base/base64.h"
-#include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/functional/bind.h"
 #include "base/strings/strcat.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/task_traits.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4d1c5cbdf..587cf94 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1839,7 +1839,6 @@
       "//components/services/app_service/public/cpp:preferred_apps",
       "//components/services/app_service/public/cpp:run_on_os_login",
       "//components/services/app_service/public/cpp:types",
-      "//components/services/app_service/public/mojom",
       "//components/ui_metrics",
       "//components/url_formatter",
       "//components/user_education/common",
@@ -2302,6 +2301,8 @@
       "ash/global_media_controls/cast_media_notification_producer_keyed_service.h",
       "ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.cc",
       "ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.h",
+      "ash/global_media_controls/media_notification_provider_impl.cc",
+      "ash/global_media_controls/media_notification_provider_impl.h",
       "ash/google_one_offer_iph_tab_helper.cc",
       "ash/google_one_offer_iph_tab_helper.h",
       "ash/google_one_offer_iph_tab_helper_constants.h",
@@ -3322,7 +3323,6 @@
       "//components/services/app_service/public/cpp:app_update",
       "//components/services/app_service/public/cpp:icon_loader",
       "//components/services/app_service/public/cpp:instance_update",
-      "//components/services/app_service/public/mojom",
       "//components/session_manager/core",
       "//components/tab_groups",
       "//components/user_manager",
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index f85c0564..e1bd628 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ui/ash/chrome_accessibility_delegate.h"
 #include "chrome/browser/ui/ash/desks/chrome_saved_desk_delegate.h"
 #include "chrome/browser/ui/ash/glanceables/chrome_glanceables_delegate.h"
+#include "chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_ui.h"
 #include "chrome/browser/ui/ash/session_util.h"
 #include "chrome/browser/ui/ash/system_sounds_delegate_impl.h"
@@ -135,6 +136,12 @@
   return std::make_unique<BackGestureContextualNudgeDelegate>(controller);
 }
 
+std::unique_ptr<ash::MediaNotificationProvider>
+ChromeShellDelegate::CreateMediaNotificationProvider() {
+  return std::make_unique<ash::MediaNotificationProviderImpl>(
+      GetMediaSessionService());
+}
+
 std::unique_ptr<ash::NearbyShareDelegate>
 ChromeShellDelegate::CreateNearbyShareDelegate(
     ash::NearbyShareController* controller) const {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 0cbe791..0d94381 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -31,6 +31,8 @@
   std::unique_ptr<ash::BackGestureContextualNudgeDelegate>
   CreateBackGestureContextualNudgeDelegate(
       ash::BackGestureContextualNudgeController* controller) override;
+  std::unique_ptr<ash::MediaNotificationProvider>
+  CreateMediaNotificationProvider() override;
   std::unique_ptr<ash::NearbyShareDelegate> CreateNearbyShareDelegate(
       ash::NearbyShareController* controller) const override;
   std::unique_ptr<ash::SavedDeskDelegate> CreateSavedDeskDelegate()
diff --git a/chrome/browser/ui/ash/desks/chrome_saved_desk_delegate.h b/chrome/browser/ui/ash/desks/chrome_saved_desk_delegate.h
index b5f9e69..b2b8448e 100644
--- a/chrome/browser/ui/ash/desks/chrome_saved_desk_delegate.h
+++ b/chrome/browser/ui/ash/desks/chrome_saved_desk_delegate.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "ash/public/cpp/saved_desk_delegate.h"
-#include "base/callback_forward.h"
+#include "base/functional/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/crosapi/mojom/desk_template.mojom-forward.h"
 #include "components/favicon_base/favicon_types.h"
diff --git a/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service.cc b/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service.cc
index 90303c78..0602eeeb 100644
--- a/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service.cc
+++ b/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service.h"
 
 #include "ash/shell.h"
-#include "ash/system/media/media_notification_provider_impl.h"
+#include "ash/system/media/media_notification_provider.h"
 #include "components/global_media_controls/public/media_item_manager.h"
 
 namespace {
@@ -16,7 +16,9 @@
   if (!ash::Shell::HasInstance())
     return nullptr;
 
-  return ash::Shell::Get()->media_notification_provider()->item_manager();
+  return ash::Shell::Get()
+      ->media_notification_provider()
+      ->GetMediaItemManager();
 }
 
 }  // namespace
diff --git a/ash/system/media/media_notification_provider_impl.cc b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.cc
similarity index 89%
rename from ash/system/media/media_notification_provider_impl.cc
rename to chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.cc
index 732bd13..b5a9e5b 100644
--- a/ash/system/media/media_notification_provider_impl.cc
+++ b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/media/media_notification_provider_impl.h"
+#include "chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h"
 
 #include "ash/system/media/media_notification_provider.h"
 #include "ash/system/media/media_notification_provider_observer.h"
@@ -25,9 +25,9 @@
 
   item_manager_->AddObserver(this);
 
-  if (!service)
+  if (!service) {
     return;
-
+  }
   mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote;
   mojo::Remote<media_session::mojom::MediaControllerManager>
       controller_manager_remote;
@@ -67,14 +67,16 @@
 }
 
 bool MediaNotificationProviderImpl::HasActiveNotifications() {
-  if (!item_manager_)
+  if (!item_manager_) {
     return false;
+  }
   return item_manager_->HasActiveItems();
 }
 
 bool MediaNotificationProviderImpl::HasFrozenNotifications() {
-  if (!item_manager_)
+  if (!item_manager_) {
     return false;
+  }
   return item_manager_->HasFrozenItems();
 }
 
@@ -111,13 +113,18 @@
   color_theme_ = color_theme;
 }
 
+global_media_controls::MediaItemManager*
+MediaNotificationProviderImpl::GetMediaItemManager() {
+  return item_manager_.get();
+}
+
 global_media_controls::MediaItemUI*
 MediaNotificationProviderImpl::ShowMediaItem(
     const std::string& id,
     base::WeakPtr<media_message_center::MediaNotificationItem> item) {
-  if (!active_session_view_)
+  if (!active_session_view_) {
     return nullptr;
-
+  }
   auto item_ui = std::make_unique<global_media_controls::MediaItemUIView>(
       id, item, /*footer_view=*/nullptr, /*device_selector_view=*/nullptr,
       color_theme_);
@@ -125,29 +132,32 @@
   item_ui_observer_set_.Observe(id, item_ui_ptr);
 
   active_session_view_->ShowItem(id, std::move(item_ui));
-  for (auto& observer : observers_)
+  for (auto& observer : observers_) {
     observer.OnNotificationListViewSizeChanged();
-
+  }
   return item_ui_ptr;
 }
 
 void MediaNotificationProviderImpl::HideMediaItem(const std::string& id) {
-  if (!active_session_view_)
+  if (!active_session_view_) {
     return;
-
+  }
   active_session_view_->HideItem(id);
-  for (auto& observer : observers_)
+  for (auto& observer : observers_) {
     observer.OnNotificationListViewSizeChanged();
+  }
 }
 
 void MediaNotificationProviderImpl::OnItemListChanged() {
-  for (auto& observer : observers_)
+  for (auto& observer : observers_) {
     observer.OnNotificationListChanged();
+  }
 }
 
 void MediaNotificationProviderImpl::OnMediaItemUISizeChanged() {
-  for (auto& observer : observers_)
+  for (auto& observer : observers_) {
     observer.OnNotificationListViewSizeChanged();
+  }
 }
 
 void MediaNotificationProviderImpl::OnMediaItemUIDestroyed(
diff --git a/ash/system/media/media_notification_provider_impl.h b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h
similarity index 90%
rename from ash/system/media/media_notification_provider_impl.h
rename to chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h
index 02e67c3..b6be8d2 100644
--- a/ash/system/media/media_notification_provider_impl.h
+++ b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_MEDIA_MEDIA_NOTIFICATION_PROVIDER_IMPL_H_
-#define ASH_SYSTEM_MEDIA_MEDIA_NOTIFICATION_PROVIDER_IMPL_H_
+#ifndef CHROME_BROWSER_UI_ASH_GLOBAL_MEDIA_CONTROLS_MEDIA_NOTIFICATION_PROVIDER_IMPL_H_
+#define CHROME_BROWSER_UI_ASH_GLOBAL_MEDIA_CONTROLS_MEDIA_NOTIFICATION_PROVIDER_IMPL_H_
 
 #include "ash/ash_export.h"
 #include "ash/system/media/media_notification_provider.h"
@@ -50,6 +50,7 @@
   void OnBubbleClosing() override;
   void SetColorTheme(
       const media_message_center::NotificationTheme& color_theme) override;
+  global_media_controls::MediaItemManager* GetMediaItemManager() override;
 
   // global_media_controls::MediaDialogDelegate:
   global_media_controls::MediaItemUI* ShowMediaItem(
@@ -72,10 +73,6 @@
   void OnMediaItemUISizeChanged() override;
   void OnMediaItemUIDestroyed(const std::string& id) override;
 
-  global_media_controls::MediaItemManager* item_manager() {
-    return item_manager_.get();
-  }
-
   global_media_controls::MediaSessionItemProducer*
   media_session_item_producer_for_testing() {
     return media_session_item_producer_.get();
@@ -99,4 +96,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_MEDIA_MEDIA_NOTIFICATION_PROVIDER_IMPL_H_
+#endif  // CHROME_BROWSER_UI_ASH_GLOBAL_MEDIA_CONTROLS_MEDIA_NOTIFICATION_PROVIDER_IMPL_H_
diff --git a/ash/system/media/media_notification_provider_impl_unittest.cc b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc
similarity index 91%
rename from ash/system/media/media_notification_provider_impl_unittest.cc
rename to chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc
index ac46fdfd..734bd6d 100644
--- a/ash/system/media/media_notification_provider_impl_unittest.cc
+++ b/chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/media/media_notification_provider_impl.h"
+#include "chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h"
 
 #include "ash/system/media/media_notification_provider_observer.h"
 #include "ash/test/ash_test_base.h"
@@ -54,15 +54,20 @@
           receiver) override {}
 };
 
-class MediaSessionShellDelegate : public TestShellDelegate {
+class MediaTestShellDelegate : public TestShellDelegate {
  public:
-  MediaSessionShellDelegate() = default;
-  ~MediaSessionShellDelegate() override = default;
+  MediaTestShellDelegate() = default;
+  ~MediaTestShellDelegate() override = default;
 
   // ShellDelegate:
   media_session::MediaSessionService* GetMediaSessionService() override {
     return &media_session_service_;
   }
+  std::unique_ptr<MediaNotificationProvider> CreateMediaNotificationProvider()
+      override {
+    return std::make_unique<MediaNotificationProviderImpl>(
+        GetMediaSessionService());
+  }
 
  private:
   FakeMediaSessionService media_session_service_;
@@ -76,7 +81,7 @@
   ~MediaNotificationProviderImplTest() override {}
 
   void SetUp() override {
-    AshTestBase::SetUp(std::make_unique<MediaSessionShellDelegate>());
+    AshTestBase::SetUp(std::make_unique<MediaTestShellDelegate>());
 
     provider_ = static_cast<MediaNotificationProviderImpl*>(
         MediaNotificationProvider::Get());
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc
index e5d7372..a9b2098 100644
--- a/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/app_service_shelf_context_menu.cc
@@ -68,15 +68,18 @@
 extensions::LaunchType ConvertLaunchTypeCommandToExtensionLaunchType(
     int command_id) {
   switch (command_id) {
-    case ash::USE_LAUNCH_TYPE_PINNED:
-      return extensions::LAUNCH_TYPE_PINNED;
     case ash::USE_LAUNCH_TYPE_REGULAR:
       return extensions::LAUNCH_TYPE_REGULAR;
     case ash::USE_LAUNCH_TYPE_WINDOW:
       return extensions::LAUNCH_TYPE_WINDOW;
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
-      return extensions::LAUNCH_TYPE_FULLSCREEN;
+    case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
+      // Not supported for extensions.
+      [[fallthrough]];
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+      [[fallthrough]];
     default:
+      NOTREACHED();
       return extensions::LAUNCH_TYPE_INVALID;
   }
 }
@@ -203,17 +206,18 @@
 
     case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
       [[fallthrough]];
-    case ash::USE_LAUNCH_TYPE_PINNED:
-      [[fallthrough]];
     case ash::USE_LAUNCH_TYPE_REGULAR:
       [[fallthrough]];
     case ash::USE_LAUNCH_TYPE_WINDOW:
-      [[fallthrough]];
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
       launch_new_string_id_ = apps::StringIdForUseLaunchTypeCommand(command_id);
       SetLaunchType(command_id);
       break;
 
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+      NOTREACHED();
+      break;
+
     case ash::CROSTINI_USE_LOW_DENSITY:
     case ash::CROSTINI_USE_HIGH_DENSITY: {
       auto* registry_service =
@@ -547,10 +551,6 @@
 
 void AppServiceShelfContextMenu::SetExtensionLaunchType(int command_id) {
   switch (static_cast<ash::CommandId>(command_id)) {
-    case ash::USE_LAUNCH_TYPE_PINNED:
-      extensions::SetLaunchType(controller()->profile(), item().id.app_id,
-                                extensions::LAUNCH_TYPE_PINNED);
-      break;
     case ash::USE_LAUNCH_TYPE_REGULAR:
       extensions::SetLaunchType(controller()->profile(), item().id.app_id,
                                 extensions::LAUNCH_TYPE_REGULAR);
@@ -566,9 +566,10 @@
                                 launch_type);
       break;
     }
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
-      extensions::SetLaunchType(controller()->profile(), item().id.app_id,
-                                extensions::LAUNCH_TYPE_FULLSCREEN);
+    case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+      NOTREACHED();
       break;
     default:
       return;
diff --git a/chrome/browser/ui/ash/shelf/extension_shelf_context_menu.cc b/chrome/browser/ui/ash/shelf/extension_shelf_context_menu.cc
index 31e7fa5..3f0ce5dc 100644
--- a/chrome/browser/ui/ash/shelf/extension_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/shelf/extension_shelf_context_menu.cc
@@ -126,14 +126,17 @@
 
 bool ExtensionShelfContextMenu::IsCommandIdChecked(int command_id) const {
   switch (command_id) {
-    case ash::USE_LAUNCH_TYPE_PINNED:
-      return GetLaunchType() == extensions::LAUNCH_TYPE_PINNED;
     case ash::USE_LAUNCH_TYPE_REGULAR:
       return GetLaunchType() == extensions::LAUNCH_TYPE_REGULAR;
     case ash::USE_LAUNCH_TYPE_WINDOW:
       return GetLaunchType() == extensions::LAUNCH_TYPE_WINDOW;
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
-      return GetLaunchType() == extensions::LAUNCH_TYPE_FULLSCREEN;
+    case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
+      // Tabbed window is not supported for extension based items.
+      [[fallthrough]];
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+      NOTREACHED();
+      return false;
     default:
       if (command_id < ash::COMMAND_ID_COUNT)
         return ShelfContextMenu::IsCommandIdChecked(command_id);
@@ -183,9 +186,6 @@
       controller()->DoShowAppInfoFlow(controller()->profile(),
                                       item().id.app_id);
       break;
-    case ash::USE_LAUNCH_TYPE_PINNED:
-      SetLaunchType(extensions::LAUNCH_TYPE_PINNED);
-      break;
     case ash::USE_LAUNCH_TYPE_REGULAR:
       SetLaunchType(extensions::LAUNCH_TYPE_REGULAR);
       break;
@@ -198,8 +198,12 @@
       SetLaunchType(launch_type);
       break;
     }
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
-      SetLaunchType(extensions::LAUNCH_TYPE_FULLSCREEN);
+    case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
+      // Tabbed window is not supported for extension based items.
+      [[fallthrough]];
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+      NOTREACHED();
       break;
     case ash::APP_CONTEXT_MENU_NEW_WINDOW:
       ash::NewWindowDelegate::GetInstance()->NewWindow(
diff --git a/chrome/browser/ui/ash/shelf/shelf_context_menu.cc b/chrome/browser/ui/ash/shelf/shelf_context_menu.cc
index b3b5622..6e43b73 100644
--- a/chrome/browser/ui/ash/shelf/shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/shelf/shelf_context_menu.cc
@@ -209,12 +209,15 @@
       return views::kNewWindowIcon;
     case ash::APP_CONTEXT_MENU_NEW_INCOGNITO_WINDOW:
       return views::kNewIncognitoWindowIcon;
-    case ash::USE_LAUNCH_TYPE_PINNED:
     case ash::USE_LAUNCH_TYPE_REGULAR:
-    case ash::USE_LAUNCH_TYPE_FULLSCREEN:
     case ash::USE_LAUNCH_TYPE_WINDOW:
+    case ash::USE_LAUNCH_TYPE_TABBED_WINDOW:
       // Check items use a default icon in touchable and default context menus.
       return gfx::kNoneIcon;
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED:
+    case ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN:
+      NOTREACHED();
+      return gfx::kNoneIcon;
     case ash::NOTIFICATION_CONTAINER:
       NOTREACHED() << "NOTIFICATION_CONTAINER does not have an icon, and it is "
                       "added to the model by NotificationMenuController.";
diff --git a/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc b/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc
index 6c9fc05..9bb36407 100644
--- a/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/shelf_context_menu_unittest.cc
@@ -540,9 +540,9 @@
   EXPECT_EQ(101, ash::TOGGLE_PIN);
   EXPECT_EQ(106, ash::APP_CONTEXT_MENU_NEW_WINDOW);
   EXPECT_EQ(107, ash::APP_CONTEXT_MENU_NEW_INCOGNITO_WINDOW);
-  EXPECT_EQ(200, ash::USE_LAUNCH_TYPE_PINNED);
+  EXPECT_EQ(200, ash::DEPRECATED_USE_LAUNCH_TYPE_PINNED);
   EXPECT_EQ(201, ash::USE_LAUNCH_TYPE_REGULAR);
-  EXPECT_EQ(202, ash::USE_LAUNCH_TYPE_FULLSCREEN);
+  EXPECT_EQ(202, ash::DEPRECATED_USE_LAUNCH_TYPE_FULLSCREEN);
   EXPECT_EQ(203, ash::USE_LAUNCH_TYPE_WINDOW);
   EXPECT_EQ(204, ash::USE_LAUNCH_TYPE_TABBED_WINDOW);
 }
diff --git a/chrome/browser/ui/ash/system_web_apps/BUILD.gn b/chrome/browser/ui/ash/system_web_apps/BUILD.gn
index 98ac107..a6c3123 100644
--- a/chrome/browser/ui/ash/system_web_apps/BUILD.gn
+++ b/chrome/browser/ui/ash/system_web_apps/BUILD.gn
@@ -28,7 +28,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/web_applications",
     "//chrome/common",
-    "//components/services/app_service/public/mojom",
     "//content/public/browser",
     "//ui/base",
     "//ui/display",
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.cc b/chrome/browser/ui/ash/test_wallpaper_controller.cc
index 2f194d35..5f000d58 100644
--- a/chrome/browser/ui/ash/test_wallpaper_controller.cc
+++ b/chrome/browser/ui/ash/test_wallpaper_controller.cc
@@ -225,6 +225,11 @@
   NOTIMPLEMENTED();
 }
 
+void TestWallpaperController::GetOfflineWallpaperList(
+    GetOfflineWallpaperListCallback callback) {
+  NOTIMPLEMENTED();
+}
+
 void TestWallpaperController::SetAnimationDuration(
     base::TimeDelta animation_duration) {
   NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.h b/chrome/browser/ui/ash/test_wallpaper_controller.h
index 0d4ee397..b372f23 100644
--- a/chrome/browser/ui/ash/test_wallpaper_controller.h
+++ b/chrome/browser/ui/ash/test_wallpaper_controller.h
@@ -140,6 +140,8 @@
   void RemoveAlwaysOnTopWallpaper() override;
   void RemoveUserWallpaper(const AccountId& account_id) override;
   void RemovePolicyWallpaper(const AccountId& account_id) override;
+  void GetOfflineWallpaperList(
+      GetOfflineWallpaperListCallback callback) override;
   void SetAnimationDuration(base::TimeDelta animation_duration) override;
   void OpenWallpaperPickerIfAllowed() override;
   void MinimizeInactiveWindows(const std::string& user_id_hash) override;
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
index 4ce81360c..a319996 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
@@ -378,6 +378,11 @@
   wallpaper_controller_->RemovePolicyWallpaper(account_id);
 }
 
+void WallpaperControllerClientImpl::GetOfflineWallpaperList(
+    ash::WallpaperController::GetOfflineWallpaperListCallback callback) {
+  wallpaper_controller_->GetOfflineWallpaperList(std::move(callback));
+}
+
 void WallpaperControllerClientImpl::SetAnimationDuration(
     const base::TimeDelta& animation_duration) {
   wallpaper_controller_->SetAnimationDuration(animation_duration);
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
index bd8a050..18fc083 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
@@ -125,6 +125,8 @@
   void RemoveAlwaysOnTopWallpaper();
   void RemoveUserWallpaper(const AccountId& account_id);
   void RemovePolicyWallpaper(const AccountId& account_id);
+  void GetOfflineWallpaperList(
+      ash::WallpaperController::GetOfflineWallpaperListCallback callback);
   void SetAnimationDuration(const base::TimeDelta& animation_duration);
   void OpenWallpaperPickerIfAllowed();
   void MinimizeInactiveWindows(const std::string& user_id_hash);
diff --git a/chrome/browser/ui/browser_element_identifiers.cc b/chrome/browser/ui/browser_element_identifiers.cc
index 381e694..f0cb53d 100644
--- a/chrome/browser/ui/browser_element_identifiers.cc
+++ b/chrome/browser/ui/browser_element_identifiers.cc
@@ -19,6 +19,7 @@
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kBookmarkStarViewElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kBrowserViewElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kEnhancedProtectionSettingElementId);
+DEFINE_ELEMENT_IDENTIFIER_VALUE(kExclusiveAccessBubbleViewElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kForwardButtonElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kHighEfficiencyChipElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kInstallPwaElementId);
diff --git a/chrome/browser/ui/browser_element_identifiers.h b/chrome/browser/ui/browser_element_identifiers.h
index 937c362..5420d79 100644
--- a/chrome/browser/ui/browser_element_identifiers.h
+++ b/chrome/browser/ui/browser_element_identifiers.h
@@ -28,6 +28,7 @@
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kBookmarkStarViewElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kBrowserViewElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kEnhancedProtectionSettingElementId);
+DECLARE_ELEMENT_IDENTIFIER_VALUE(kExclusiveAccessBubbleViewElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kForwardButtonElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kHighEfficiencyChipElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kInstallPwaElementId);
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 8da6470d..6840b3f 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -534,6 +534,9 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
   policy::DlpContentTabHelper::MaybeCreateForWebContents(web_contents);
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
   webapps::PreRedirectionURLObserver::CreateForWebContents(web_contents);
 #endif
 
diff --git a/chrome/browser/ui/toolbar/app_menu_fullscreen_interactive_uitest.cc b/chrome/browser/ui/toolbar/app_menu_fullscreen_interactive_uitest.cc
new file mode 100644
index 0000000..6fe7ae827
--- /dev/null
+++ b/chrome/browser/ui/toolbar/app_menu_fullscreen_interactive_uitest.cc
@@ -0,0 +1,210 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/test/bind.h"
+#include "base/test/gtest_util.h"
+#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
+#include "chrome/browser/ui/accelerator_utils.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
+#include "chrome/browser/ui/exclusive_access/exclusive_access_test.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
+#include "chrome/browser/ui/toolbar/app_menu_model.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/interaction/interactive_browser_test.h"
+#include "chrome/test/interaction/tracked_element_webcontents.h"
+#include "chrome/test/interaction/webcontents_interaction_test_util.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/interaction/element_identifier.h"
+#include "ui/base/interaction/element_tracker.h"
+#include "ui/base/interaction/expect_call_in_scope.h"
+#include "ui/base/interaction/interaction_sequence.h"
+#include "ui/display/screen.h"
+#include "ui/views/view_observer.h"
+#include "url/gurl.h"
+
+namespace {
+class ViewBoundsChangeWaiter : public views::ViewObserver {
+ public:
+  explicit ViewBoundsChangeWaiter(views::View* view) {
+    observation_.Observe(view);
+  }
+  ViewBoundsChangeWaiter(const ViewBoundsChangeWaiter&) = delete;
+  ViewBoundsChangeWaiter& operator=(const ViewBoundsChangeWaiter&) = delete;
+
+  void Wait() { run_loop_.Run(); }
+
+ private:
+  void OnViewBoundsChanged(views::View* view) override { run_loop_.Quit(); }
+  base::RunLoop run_loop_;
+  base::ScopedObservation<views::View, views::ViewObserver> observation_{this};
+};
+}  // namespace
+
+// Tests for Chrome Menu - Fullscreen manual test cases.
+class AppMenuFullscreenInteractiveTest : public InteractiveBrowserTest {
+ public:
+  AppMenuFullscreenInteractiveTest() = default;
+  ~AppMenuFullscreenInteractiveTest() override = default;
+  AppMenuFullscreenInteractiveTest(const AppMenuFullscreenInteractiveTest&) =
+      delete;
+  void operator=(const AppMenuFullscreenInteractiveTest&) = delete;
+
+  void SetUp() override {
+    set_open_about_blank_on_browser_launch(true);
+    InteractiveBrowserTest::SetUp();
+  }
+
+  void SetUpOnMainThread() override {
+    InteractiveBrowserTest::SetUpOnMainThread();
+#if BUILDFLAG(IS_MAC)
+    // SendAccelerator or ui_controls::SendKeyPress doesn't support fn key on
+    // Mac, that the default fullscreen hotkey wouldn't work.
+    // TODO: When SendAccelerator fixed on mac, remove this hard coded key.
+    fullscreen_accelerator_ =
+        ui::Accelerator(ui::VKEY_F, ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN);
+#else
+    chrome::AcceleratorProviderForBrowser(browser())
+        ->GetAcceleratorForCommandId(IDC_FULLSCREEN, &fullscreen_accelerator_);
+#endif
+    chrome::AcceleratorProviderForBrowser(browser())
+        ->GetAcceleratorForCommandId(IDC_CLOSE_TAB, &close_tab_accelerator_);
+  }
+
+ protected:
+  ui::Accelerator fullscreen_accelerator_;
+  ui::Accelerator close_tab_accelerator_;
+
+  auto CheckFullscreenForBrowser(bool is_fullscreen) {
+    return CheckView(
+        kBrowserViewElementId,
+        base::BindOnce(
+            [](bool is_fullscreen, Browser* browser,
+               views::View* browser_view) {
+              auto* fullscreen_controller =
+                  browser->exclusive_access_manager()->fullscreen_controller();
+
+              // Wait for fullscreen transition complete.
+              // Fullscreen transition is an async process on Mac, which
+              // browser_window->IsFullscreen() might changed before transition
+              // completed.
+              if (fullscreen_controller->IsControllerInitiatedFullscreen() !=
+                  is_fullscreen) {
+                FullscreenNotificationObserver(browser).Wait();
+              }
+              if (fullscreen_controller->IsControllerInitiatedFullscreen() !=
+                  is_fullscreen) {
+                return false;
+              }
+
+              if (is_fullscreen) {
+                do {
+                  auto display =
+                      display::Screen::GetScreen()->GetDisplayNearestWindow(
+                          browser->window()->GetNativeWindow());
+                  auto display_size = display.bounds().size();
+                  auto workarea_size = display.work_area().size();
+                  auto window_size = browser->window()->GetBounds().size();
+                  DLOG(INFO) << "display_size = " << display_size.ToString()
+                             << " workspace_size = " << workarea_size.ToString()
+                             << " window_size = " << window_size.ToString();
+                  if (display_size == window_size ||
+                      workarea_size == window_size) {
+                    return true;
+                  }
+
+                  ViewBoundsChangeWaiter(browser_view).Wait();
+                } while (true);
+              }
+
+              return true;
+            },
+            is_fullscreen, browser()));
+  }
+};
+
+// Check Toggle Fullscreen
+IN_PROC_BROWSER_TEST_F(AppMenuFullscreenInteractiveTest, ToggleFullscreen) {
+  RunTestSequence(
+      // P1. Launch Chrome
+      // P2. Hit F11/⌘-Ctrl-F/Full screen button
+      SendAccelerator(kBrowserViewElementId, fullscreen_accelerator_),
+      // V2. Make sure chrome is in full screen mode
+      CheckFullscreenForBrowser(true),
+      // P3. Hit F11/⌘-Ctrl-F/Full screen button again
+      SendAccelerator(kBrowserViewElementId, fullscreen_accelerator_),
+      // V3. Chrome should exit the full screen upon hitting F11 again when in
+      // the full screen mode.
+      CheckFullscreenForBrowser(false));
+}
+
+// Check Full screen Notification
+// The original manual test doesn't work on ChromeOS.
+#if !BUILDFLAG(IS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(AppMenuFullscreenInteractiveTest, Notification) {
+  RunTestSequence(
+      // 1. Launch Chrome
+      // 2. Hit F11/⌘-Ctrl-F/Full screen button
+      SendAccelerator(kBrowserViewElementId, fullscreen_accelerator_),
+      // 3. Verify the notification shown on the top in the full screen mode.
+      CheckFullscreenForBrowser(true),
+      InAnyContext(WaitForShow(kExclusiveAccessBubbleViewElementId)));
+}
+#endif
+
+// TODO (crbug.com/1408248): This test is failing on Lacros version skew test.
+// The BrowserView is not immediately accepting mouse event after fullscreen.
+// Trace event showing there were BrowserView::Layout and Composite happened
+// after being full screen. And the right mouse click doesn't work during this
+// period.
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#define MAYBE_ContextMenu DISABLED_ContextMenu
+#else
+#define MAYBE_ContextMenu ContextMenu
+#endif
+
+// Check Context menu in full screen mode
+IN_PROC_BROWSER_TEST_F(AppMenuFullscreenInteractiveTest, MAYBE_ContextMenu) {
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kPrimaryTabId);
+  RunTestSequence(
+      // 1. Wait for the default page to load.
+      InstrumentTab(kPrimaryTabId),
+      // 2. Hit F11/⌘-Ctrl-F/Full screen button
+      SendAccelerator(kBrowserViewElementId, fullscreen_accelerator_),
+      // 3. Make sure the chrome window is in full screen mode
+      CheckFullscreenForBrowser(true),
+      // 4. Right click anywhere on the page to open the context menu. This
+      // chooses the center of the browser window, which is fine.
+      MoveMouseTo(kBrowserViewElementId), ClickMouse(ui_controls::RIGHT),
+      // 5. Make sure context menu is displayed correctly at the expected
+      // location when chrome is in full screen mode.
+      // WaitForShow and FlushEvents is required to prevent re-enter
+      // views::MenuController::OpenMenu from the same call stack during the
+      // NotifyElementShown.
+      InAnyContext(WaitForShow(RenderViewContextMenu::kExitFullscreenMenuItem)),
+      FlushEvents(),
+      InAnyContext(
+          SelectMenuItem(RenderViewContextMenu::kExitFullscreenMenuItem)),
+      CheckFullscreenForBrowser(false));
+}
+
+// Check Closing the tab in full screen mode
+IN_PROC_BROWSER_TEST_F(AppMenuFullscreenInteractiveTest, ClosingTab) {
+  RunTestSequence(
+      // 1. Launch Chrome and navigate to few web pages.
+      PressButton(kNewTabButtonElementId),
+      // 2. Hit F11/⌘-Ctrl-F/Full screen button
+      SendAccelerator(kBrowserViewElementId, fullscreen_accelerator_),
+      CheckFullscreenForBrowser(true),
+      // 3. Hit Ctrl+W / Ctrl+F4 [Windows & Linux], ⌘-W [Mac], Ctrl+W [CrOS]
+      // when chrome is in the full screen mode. Current tab should be closed
+      SendAccelerator(kBrowserViewElementId, close_tab_accelerator_),
+      // Chrome should not exit full screen mode when you close a tab in full
+      // screen mode.
+      CheckFullscreenForBrowser(true));
+}
diff --git a/chrome/browser/ui/views/BUILD.gn b/chrome/browser/ui/views/BUILD.gn
index 9046c76..72e756b9 100644
--- a/chrome/browser/ui/views/BUILD.gn
+++ b/chrome/browser/ui/views/BUILD.gn
@@ -34,7 +34,6 @@
     "//components/keep_alive_registry",
     "//components/lens",
     "//components/lens:buildflags",
-    "//components/services/app_service/public/mojom",
     "//components/services/screen_ai/buildflags",
     "//components/vector_icons",
     "//content/public/browser",
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
index d5bec54..ab78ddd8 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
@@ -91,6 +91,7 @@
                              DownloadBubbleRowView* row_view)
       : Button(callback), row_view_(row_view) {
     views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF);
+    SetInstallFocusRingOnFocus(false);
   }
   ~TransparentButton() override = default;
 
@@ -575,6 +576,7 @@
     bool visible,
     bool request_focus_on_last_quick_action) {
   quick_action_holder_->SetVisible(visible);
+  views::InkDrop::Get(this)->GetInkDrop()->SetFocused(visible);
   // Update focus only if focus received from a different row.
   bool should_set_focus = request_focus_on_last_quick_action &&
                           GetFocusManager() &&
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
index 67afb997..23265a1 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h"
@@ -29,6 +30,7 @@
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/view.h"
+#include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
 
@@ -51,6 +53,8 @@
   // Create the contents view.
   auto content_view = std::make_unique<SubtleNotificationView>();
   view_ = content_view.get();
+  view_->SetProperty(views::kElementIdentifierKey,
+                     kExclusiveAccessBubbleViewElementId);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Technically the exit fullscreen key on ChromeOS is F11 and the
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc
index 40ce48fc3..a06399a 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/browser_test.h"
 
 namespace {
@@ -39,18 +40,22 @@
                        TestSelectedKeywordViewIsExtensionShortname) {
   const extensions::Extension* extension =
       InstallExtension(test_data_dir_.AppendASCII("omnibox"), 1);
-  ASSERT_TRUE(extension);
+  ASSERT_NE(extension, nullptr);
 
-  chrome::FocusLocationBar(browser());
-  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
+  Browser* current_browser = browser();
+  chrome::FocusLocationBar(current_browser);
+  ASSERT_TRUE(ui_test_utils::IsViewFocused(current_browser, VIEW_ID_OMNIBOX));
 
   // Activate the extension's omnibox keyword.
-  InputKeys(browser(), {ui::VKEY_K, ui::VKEY_E, ui::VKEY_Y, ui::VKEY_TAB});
+  InputKeys(current_browser, {ui::VKEY_K, ui::VKEY_E, ui::VKEY_Y});
+  ui_test_utils::WaitForAutocompleteDone(current_browser);
+  InputKeys(current_browser, {ui::VKEY_TAB});
 
-  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
+  BrowserView* browser_view =
+      BrowserView::GetBrowserViewForBrowser(current_browser);
   SelectedKeywordView* selected_keyword_view =
       browser_view->toolbar()->location_bar()->selected_keyword_view();
-  ASSERT_TRUE(selected_keyword_view);
+  ASSERT_NE(selected_keyword_view, nullptr);
 
   // Verify that the label in the omnibox is the extension's shortname.
   EXPECT_EQ(extension->short_name(),
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
index c241f574d..e881b24 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.h"
 
-#include "base/bind.h"
 #include "base/functional/bind.h"
 #include "chrome/browser/lookalikes/safety_tip_ui_helper.h"
 #include "chrome/browser/platform_util.h"
diff --git a/chrome/browser/ui/views/user_education/help_bubble_factory_webui_interactive_uitest.cc b/chrome/browser/ui/views/user_education/help_bubble_factory_webui_interactive_uitest.cc
index 48d9f2c..e9e863c 100644
--- a/chrome/browser/ui/views/user_education/help_bubble_factory_webui_interactive_uitest.cc
+++ b/chrome/browser/ui/views/user_education/help_bubble_factory_webui_interactive_uitest.cc
@@ -4,7 +4,7 @@
 
 #include <utility>
 
-#include "base/callback_forward.h"
+#include "base/functional/callback_forward.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
index f1baf48..bb085de 100644
--- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -69,9 +69,9 @@
 }
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
 namespace {
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // SystemWebAppDelegate provides menu.
 class SystemAppTabMenuModelFactory : public TabMenuModelFactory {
  public:
@@ -94,9 +94,14 @@
  private:
   raw_ptr<const ash::SystemWebAppDelegate> system_app_;
 };
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+base::OnceClosure& IconLoadCallbackForTesting() {
+  static base::NoDestructor<base::OnceClosure> callback;
+  return *callback;
+}
 
 }  // namespace
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace web_app {
 
@@ -292,11 +297,6 @@
   install_manager_observation_.Reset();
 }
 
-void WebAppBrowserController::SetReadIconCallbackForTesting(
-    base::OnceClosure callback) {
-  callback_for_testing_ = std::move(callback);
-}
-
 ui::ImageModel WebAppBrowserController::GetWindowAppIcon() const {
   if (app_icon_)
     return *app_icon_;
@@ -501,6 +501,11 @@
   return registrar().IsInstalled(app_id());
 }
 
+void WebAppBrowserController::SetIconLoadCallbackForTesting(
+    base::OnceClosure callback) {
+  IconLoadCallbackForTesting() = std::move(callback);
+}
+
 void WebAppBrowserController::OnTabInserted(content::WebContents* contents) {
   AppBrowserController::OnTabInserted(contents);
   SetAppPrefsForWebContents(contents);
@@ -552,8 +557,9 @@
 
   if (auto* contents = web_contents())
     contents->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
-  if (callback_for_testing_)
-    std::move(callback_for_testing_).Run();
+  if (IconLoadCallbackForTesting()) {
+    std::move(IconLoadCallbackForTesting()).Run();
+  }
 }
 
 void WebAppBrowserController::OnReadIcon(IconPurpose purpose, SkBitmap bitmap) {
@@ -569,8 +575,9 @@
       ui::ImageModel::FromImageSkia(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
   if (auto* contents = web_contents())
     contents->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
-  if (callback_for_testing_)
-    std::move(callback_for_testing_).Run();
+  if (IconLoadCallbackForTesting()) {
+    std::move(IconLoadCallbackForTesting()).Run();
+  }
 }
 
 void WebAppBrowserController::PerformDigitalAssetLinkVerification(
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.h b/chrome/browser/ui/web_applications/web_app_browser_controller.h
index 5645ff7..84648143 100644
--- a/chrome/browser/ui/web_applications/web_app_browser_controller.h
+++ b/chrome/browser/ui/web_applications/web_app_browser_controller.h
@@ -117,7 +117,7 @@
   void OnWebAppUninstalled(const AppId& app_id) override;
   void OnWebAppInstallManagerDestroyed() override;
 
-  void SetReadIconCallbackForTesting(base::OnceClosure callback);
+  static void SetIconLoadCallbackForTesting(base::OnceClosure callback);
 
  protected:
   // AppBrowserController:
@@ -170,7 +170,6 @@
   base::ScopedObservation<WebAppInstallManager, WebAppInstallManagerObserver>
       install_manager_observation_{this};
 
-  base::OnceClosure callback_for_testing_;
   mutable base::WeakPtrFactory<WebAppBrowserController> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
index 3b69d05..07c23a2 100644
--- a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
+++ b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
@@ -1,10 +1,9 @@
 // Copyright 2022 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
 #include "chrome/browser/ui/webui/app_home/app_home_page_handler.h"
 
-#include "base/bind.h"
-#include "base/callback_helpers.h"
 #include "base/containers/flat_set.h"
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
diff --git a/chrome/browser/ui/webui/ash/network_ui.cc b/chrome/browser/ui/webui/ash/network_ui.cc
index 197dfda..46a2517 100644
--- a/chrome/browser/ui/webui/ash/network_ui.cc
+++ b/chrome/browser/ui/webui/ash/network_ui.cc
@@ -631,7 +631,7 @@
     ShillManagerClient::Get()->SetTetheringEnabled(
         enabled,
         base::BindOnce(&HotspotConfigMessageHandler::RespondStringResult,
-                       weak_ptr_factory_.GetWeakPtr(), callback_id, "success"),
+                       weak_ptr_factory_.GetWeakPtr(), callback_id),
         base::BindOnce(&HotspotConfigMessageHandler::RespondError,
                        weak_ptr_factory_.GetWeakPtr(), callback_id,
                        kSetTetheringEnabled));
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
index 0c5b53a..6ff1763 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -9,7 +9,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/functional/callback_helpers.h"
diff --git a/chrome/browser/ui/webui/web_app_internals/web_app_internals_ui.cc b/chrome/browser/ui/webui/web_app_internals/web_app_internals_ui.cc
index f528c6c77..5e66c35 100644
--- a/chrome/browser/ui/webui/web_app_internals/web_app_internals_ui.cc
+++ b/chrome/browser/ui/webui/web_app_internals/web_app_internals_ui.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/webui/web_app_internals/web_app_internals_ui.h"
 
-#include "base/bind.h"
+#include "base/functional/bind.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/web_app_internals/web_app_internals_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 9ee0b5e..d7dffea 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -377,7 +377,6 @@
     "//components/services/app_service/public/cpp:protocol_handling",
     "//components/services/app_service/public/cpp:run_on_os_login",
     "//components/services/app_service/public/cpp:types",
-    "//components/services/app_service/public/mojom",
     "//components/site_engagement/content",
     "//components/site_engagement/core/mojom:mojo_bindings",
     "//components/sync",
@@ -773,6 +772,7 @@
     "isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc",
     "manifest_update_manager_browsertest.cc",
     "os_integration/shortcut_sub_manager_browsertest.cc",
+    "policy/web_app_policy_manager_browsertest.cc",
     "preinstalled_web_app_manager_browsertest.cc",
     "preinstalled_web_apps_browsertest.cc",
     "user_uninstalled_preinstalled_web_app_prefs_browsertest.cc",
@@ -790,10 +790,6 @@
     ]
   }
 
-  if (is_chromeos) {
-    sources += [ "policy/web_app_policy_manager_browsertest.cc" ]
-  }
-
   if (is_chromeos_ash) {
     sources += [ "isolated_web_apps/policy/isolated_web_app_policy_manager_ash_browsertest.cc" ]
   }
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn
index 167ae1e1..dba14ec 100644
--- a/chrome/browser/web_applications/extensions/BUILD.gn
+++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -37,7 +37,6 @@
     "//components/services/app_service/public/cpp:app_types",
     "//components/services/app_service/public/cpp:app_update",
     "//components/services/app_service/public/cpp:types",
-    "//components/services/app_service/public/mojom",
     "//components/sync/model",
     "//components/webapps/browser:browser",
     "//content/public/browser",
diff --git a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
index 9f633a21..0f21412 100644
--- a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
+++ b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
@@ -92,12 +92,10 @@
 constexpr char kTabbedUrl[] = "https://tabbed.example/";
 constexpr char kNoContainerUrl[] = "https://no-container.example/";
 
-#if BUILDFLAG(IS_CHROMEOS)
 const char kDefaultCustomAppName[] = "custom app name";
 constexpr char kDefaultCustomIconUrl[] = "https://windowed.example/icon.png";
 constexpr char kUnsecureIconUrl[] = "http://windowed.example/icon.png";
 constexpr char kDefaultCustomIconHash[] = "abcdef";
-#endif  // BUILDFLAG(IS_CHROMEOS)
 
 base::Value GetWindowedItem() {
   base::Value item(base::Value::Type::DICTIONARY);
@@ -258,7 +256,6 @@
   return options;
 }
 
-#if BUILDFLAG(IS_CHROMEOS)
 base::Value GetCustomAppNameItem(std::string name) {
   base::Value item(base::Value::Type::DICTIONARY);
   item.SetKey(kUrlKey, base::Value(kWindowedUrl));
@@ -308,7 +305,6 @@
   options.override_icon_url = GURL(kDefaultCustomIconUrl);
   return options;
 }
-#endif  // BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace
 
@@ -787,7 +783,6 @@
   EXPECT_EQ(install_requests, expected_install_options_list);
 }
 
-#if BUILDFLAG(IS_CHROMEOS)
 TEST_P(WebAppPolicyManagerTest, ForceInstallAppWithCustomAppIcon) {
   if (ShouldSkipPWASpecificTest())
     return;
@@ -892,7 +887,6 @@
   EXPECT_EQ(kPrefix + kDefaultCustomAppName,
             app_registrar().GetAppShortName(apps.begin()->first));
 }
-#endif  // BUILDFLAG(IS_CHROMEOS)
 
 TEST_P(WebAppPolicyManagerTest, DynamicRefresh) {
   if (ShouldSkipPWASpecificTest())
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc
index d91a9b3..b07e6f9 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc
@@ -425,7 +425,7 @@
   request->url = kDevAppStartUrl;
   CreateLoaderAndRun(std::move(request));
 
-  EXPECT_THAT(profile()->GetStoragePartitionCount(), Eq(2UL));
+  EXPECT_THAT(profile()->GetLoadedStoragePartitionCount(), Eq(2UL));
 }
 
 TEST_F(IsolatedWebAppURLLoaderFactoryTest,
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager.cc b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
index 78cc325..4e32b8637 100644
--- a/chrome/browser/web_applications/policy/web_app_policy_manager.cc
+++ b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
@@ -508,7 +508,6 @@
   install_options.install_as_shortcut =
       install_as_shortcut ? install_as_shortcut->GetBool() : false;
 
-#if BUILDFLAG(IS_CHROMEOS)
   const base::Value* custom_name = entry.FindKey(kCustomNameKey);
   if (custom_name) {
     install_options.override_name = custom_name->GetString();
@@ -533,7 +532,6 @@
       }
     }
   }
-#endif  // BUILDFLAG(IS_CHROMEOS)
 
   return install_options;
 }
@@ -582,7 +580,6 @@
 void WebAppPolicyManager::MaybeOverrideManifest(
     content::RenderFrameHost* frame_host,
     blink::mojom::ManifestPtr& manifest) const {
-#if BUILDFLAG(IS_CHROMEOS)
   // This doesn't override the manifest properly on a non primary page since it
   // checks the url from PreRedirectionURLObserver that works only on a primary
   // page.
@@ -628,7 +625,6 @@
   GURL install_url = pre_redirect->last_url();
   if (base::Contains(custom_manifest_values_by_url_, install_url))
     OverrideManifest(install_url, manifest);
-#endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 void WebAppPolicyManager::OnAppsSynchronized(
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc b/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc
index ef22e92..2f7c1ab 100644
--- a/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc
+++ b/chrome/browser/web_applications/policy/web_app_policy_manager_browsertest.cc
@@ -153,28 +153,6 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-#if BUILDFLAG(IS_CHROMEOS)
-
-IN_PROC_BROWSER_TEST_P(WebAppPolicyManagerBrowserTest, DontOverrideManifest) {
-  WebAppPolicyManager& policy_manager =
-      WebAppProvider::GetForTest(profile())->policy_manager();
-
-  base::Value::List list;
-  list.Append(GetCustomAppIconAndNameItem());
-  profile()->GetPrefs()->SetList(prefs::kWebAppInstallForceList,
-                                 std::move(list));
-
-  // Policy is for kInstallUrl, but we pretend to get a manifest
-  // from kStartUrl.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(kStartUrl)));
-
-  blink::mojom::ManifestPtr manifest = blink::mojom::Manifest::New();
-  policy_manager.MaybeOverrideManifest(RenderFrameHost(), manifest);
-
-  EXPECT_EQ(std::u16string(), manifest->name.value_or(std::u16string()));
-  EXPECT_EQ(0u, manifest->icons.size());
-}
-
 IN_PROC_BROWSER_TEST_P(WebAppPolicyManagerBrowserTest,
                        OverrideManifestWithCustomName) {
   WebAppPolicyManager& policy_manager =
@@ -211,6 +189,26 @@
   EXPECT_EQ(GURL(kDefaultCustomIconUrl), manifest->icons[0].src);
 }
 
+IN_PROC_BROWSER_TEST_P(WebAppPolicyManagerBrowserTest, DontOverrideManifest) {
+  WebAppPolicyManager& policy_manager =
+      WebAppProvider::GetForTest(profile())->policy_manager();
+
+  base::Value::List list;
+  list.Append(GetCustomAppIconAndNameItem());
+  profile()->GetPrefs()->SetList(prefs::kWebAppInstallForceList,
+                                 std::move(list));
+
+  // Policy is for kInstallUrl, but we pretend to get a manifest
+  // from kStartUrl.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(kStartUrl)));
+
+  blink::mojom::ManifestPtr manifest = blink::mojom::Manifest::New();
+  policy_manager.MaybeOverrideManifest(RenderFrameHost(), manifest);
+
+  EXPECT_EQ(std::u16string(), manifest->name.value_or(std::u16string()));
+  EXPECT_EQ(0u, manifest->icons.size());
+}
+
 // Scenario: App with install_url kInstallUrl has a start_url kStartUrl
 // specified in manifest. Next time we navigate to kStartUrl, but we still
 // need to override the manifest even though the policy key is kInstallUrl.
@@ -267,8 +265,6 @@
   EXPECT_EQ(GURL(kDefaultCustomIconUrl), manifest->icons[0].src);
 }
 
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Scenario: A policy installed web app is replacing an existing app causing it
diff --git a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
index d43be6d..32019097 100644
--- a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/ui/web_applications/web_app_browser_controller.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
@@ -104,48 +105,24 @@
     run_loop.Run();
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  gfx::ImageSkia image_skia;
-  image_skia = app_service_test().LoadAppIconBlocking(apps::AppType::kWeb,
-                                                      app_id, kWebAppIconSmall);
-#endif
-
-  WebAppBrowserController* controller;
-  {
-    apps::AppLaunchParams params(
-        app_id, apps::LaunchContainer::kLaunchContainerWindow,
-        WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest);
-    content::WebContents* contents =
-        apps::AppServiceProxyFactory::GetForProfile(browser()->profile())
-            ->BrowserAppLauncher()
-            ->LaunchAppWithParamsForTesting(std::move(params));
-    controller = chrome::FindBrowserWithWebContents(contents)
-                     ->app_controller()
-                     ->AsWebAppBrowserController();
-  }
-
   base::RunLoop run_loop;
+  WebAppBrowserController::SetIconLoadCallbackForTesting(
+      run_loop.QuitClosure());
+  Browser* app_browser = LaunchWebAppBrowser(browser()->profile(), app_id);
+  run_loop.Run();
+
+  gfx::ImageSkia app_icon =
+      app_browser->app_controller()->GetWindowAppIcon().Rasterize(nullptr);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  controller->SetReadIconCallbackForTesting(
-      base::BindLambdaForTesting([controller, &image_skia, &run_loop, this]() {
-        EXPECT_TRUE(app_service_test().AreIconImageEqual(
-            image_skia, controller->GetWindowAppIcon().Rasterize(nullptr)));
-        run_loop.Quit();
-      }));
-  run_loop.Run();
+  gfx::ImageSkia image_skia = app_service_test().LoadAppIconBlocking(
+      apps::AppType::kWeb, app_id, kWebAppIconSmall);
+  EXPECT_TRUE(app_service_test().AreIconImageEqual(image_skia, app_icon));
 #else
-  controller->SetReadIconCallbackForTesting(
-      base::BindLambdaForTesting([controller, &run_loop]() {
-        const SkBitmap* bitmap =
-            controller->GetWindowAppIcon().Rasterize(nullptr).bitmap();
-        EXPECT_EQ(SK_ColorBLUE, bitmap->getColor(0, 0));
-        EXPECT_EQ(32, bitmap->width());
-        EXPECT_EQ(32, bitmap->height());
-        run_loop.Quit();
-      }));
-
-  run_loop.Run();
+  const SkBitmap* bitmap = app_icon.bitmap();
+  EXPECT_EQ(SK_ColorBLUE, bitmap->getColor(0, 0));
+  EXPECT_EQ(32, bitmap->width());
+  EXPECT_EQ(32, bitmap->height());
 #endif
 }
 
diff --git a/chrome/browser/web_applications/web_app_install_utils.cc b/chrome/browser/web_applications/web_app_install_utils.cc
index 512896c..56f8906 100644
--- a/chrome/browser/web_applications/web_app_install_utils.cc
+++ b/chrome/browser/web_applications/web_app_install_utils.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
 #include "chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h"
+#include "chrome/browser/web_applications/policy/pre_redirection_url_observer.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_chromeos_data.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
@@ -71,10 +72,6 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-#if BUILDFLAG(IS_CHROMEOS)
-#include "chrome/browser/web_applications/policy/pre_redirection_url_observer.h"
-#endif
-
 namespace web_app {
 
 class WebAppRegistrar;
@@ -1055,9 +1052,7 @@
   webapps::InstallableManager::CreateForWebContents(web_contents);
   SecurityStateTabHelper::CreateForWebContents(web_contents);
   favicon::CreateContentFaviconDriverForWebContents(web_contents);
-#if BUILDFLAG(IS_CHROMEOS)
   webapps::PreRedirectionURLObserver::CreateForWebContents(web_contents);
-#endif
 }
 
 void MaybeRegisterOsUninstall(const WebApp* web_app,
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 013f0a7b..b361b76 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1673978375-041eb5d1962c91f17791f3ce4037790d141e8a73.profdata
+chrome-linux-main-1673999884-48e95b6b5cdfcc7f6e68f1e628b56e27fab36155.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 0cc010b..89613ac4 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1673978375-5c8e5d44fd658e8bb140047fb819c0d72955f58d.profdata
+chrome-mac-arm-main-1673999884-b4e9bef1de92a2f0d80baf53ad5609bd1995b4ae.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index ff69ae1..835a287 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1673978375-05628ff83ad244eb6d5feefe1ea9e3212c9e055a.profdata
+chrome-mac-main-1673999884-148f71ecfd49b58320680e96a89c04318cb8c183.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 8cebc7e..49cfff069 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1673978375-04ded555d8b60436d473c3eb2b6673f8d556837a.profdata
+chrome-win32-main-1673999884-5f53f97756386636f797c45907a2025239185e52.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index ee12260..ee17030 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1673978375-61b0309bd27c18d5954d4c648c7ecacf62281b9a.profdata
+chrome-win64-main-1673999884-ba9dfb908970ccbfd4ed12c43553c8f537307aaf.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index f79228a..0017566 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -331,7 +331,6 @@
     deps += [
       "//chrome/common/apps/platform_apps",
       "//components/app_constants",
-      "//components/services/app_service/public/mojom",
     ]
     public_deps += [
       "//chrome/common/extensions/api",
diff --git a/chrome/services/keymaster/public/mojom/cert_store.mojom b/chrome/services/keymaster/public/mojom/cert_store.mojom
index 7ebf4ef..6a65fba6 100644
--- a/chrome/services/keymaster/public/mojom/cert_store.mojom
+++ b/chrome/services/keymaster/public/mojom/cert_store.mojom
@@ -42,28 +42,11 @@
   KeyData key_data;
 };
 
-// Interface exposed by Chrome.
-// Next method ID: 1
-interface CertStoreHost {
-  // Returns an interface to SecurityTokenOperation.
-  GetSecurityTokenOperation@0(
-      pending_receiver<SecurityTokenOperation> operation) => ();
-};
 
 // Interface exposed by arc-keymaster daemon.
 // Next method ID: 2
+// Deprecated method IDs: 0
 interface CertStoreInstance {
-  // Establishes full-duplex communication with the host.
-  Init@0(pending_remote<CertStoreHost> host_remote) => ();
-
   // Updates info about the latest set of keys owned by Chrome OS.
   UpdatePlaceholderKeys@1(array<ChromeOsKey> keys) => (bool success);
 };
-
-// Implemented in Chrome.
-// Nothing is using this interface. It is only kept to avoid changing
-// CertStoreHost.
-// Deprecated method IDs: 0
-// Next method ID: 1
-interface SecurityTokenOperation {
-};
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cba568f..9a75a3e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1449,7 +1449,6 @@
       "//components/segmentation_platform/public",
       "//components/services/app_service/public/cpp:protocol_handling",
       "//components/services/app_service/public/cpp:test_support",
-      "//components/services/app_service/public/mojom",
       "//components/services/language_detection/public/cpp",
       "//components/services/language_detection/public/mojom",
       "//components/services/patch/content",
@@ -7536,6 +7535,7 @@
       "../browser/ui/ash/desks/chrome_desks_templates_delegate_unittest.cc",
       "../browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_unittest.cc",
       "../browser/ui/ash/device_scheduled_reboot/scheduled_reboot_dialog_unittest.cc",
+      "../browser/ui/ash/global_media_controls/media_notification_provider_impl_unittest.cc",
       "../browser/ui/ash/google_one_offer_iph_tab_helper_unittest.cc",
       "../browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc",
       "../browser/ui/ash/ime_controller_client_impl_unittest.cc",
@@ -9284,7 +9284,6 @@
       "//components/security_interstitials/content:security_interstitial_page",
       "//components/services/app_service/public/cpp:app_types",
       "//components/services/app_service/public/cpp:run_on_os_login",
-      "//components/services/app_service/public/mojom",
       "//components/signin/public/base",
       "//components/signin/public/identity_manager",
       "//components/storage_monitor:test_support",
@@ -9772,6 +9771,7 @@
       sources += [
         "../browser/ui/commerce/price_tracking/mock_shopping_list_ui_tab_helper.cc",
         "../browser/ui/commerce/price_tracking/mock_shopping_list_ui_tab_helper.h",
+        "../browser/ui/toolbar/app_menu_fullscreen_interactive_uitest.cc",
         "../browser/ui/toolbar/app_menu_model_interactive_uitest.cc",
         "../browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc",
         "../browser/ui/views/autofill/payments/virtual_card_enroll_bubble_views_interactive_uitest.cc",
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index ea60dad..da9d80c1 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -523,7 +523,7 @@
     host_content_settings_map_->ShutdownOnUIThread();
 
   // Make sure SharedProtoDatabase doesn't post delayed tasks anymore.
-  ForEachStoragePartition(
+  ForEachLoadedStoragePartition(
       base::BindRepeating([](content::StoragePartition* storage_partition) {
         if (auto* provider =
                 storage_partition->GetProtoDatabaseProviderForTesting()) {
diff --git a/chrome/test/chromedriver/net/sync_websocket.h b/chrome/test/chromedriver/net/sync_websocket.h
index e35b4216..ac4c564 100644
--- a/chrome/test/chromedriver/net/sync_websocket.h
+++ b/chrome/test/chromedriver/net/sync_websocket.h
@@ -5,9 +5,10 @@
 #ifndef CHROME_TEST_CHROMEDRIVER_NET_SYNC_WEBSOCKET_H_
 #define CHROME_TEST_CHROMEDRIVER_NET_SYNC_WEBSOCKET_H_
 
-#include <base/callback.h>
 #include <string>
 
+#include "base/functional/callback.h"
+
 class GURL;
 class Timeout;
 
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/document_selection.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/document_selection.js
index 016128c..429122bf 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/document_selection.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/document_selection.js
@@ -33,19 +33,26 @@
   },
 
   function selectInTextField() {
-    listenOnce(rootNode, EventType.DOCUMENT_SELECTION_CHANGED, function(evt1) {
-      listenOnce(textField, EventType.TEXT_SELECTION_CHANGED, function(evt2) {
-        assertTrue(evt1.target === rootNode);
-        assertTrue(evt2.target == textField);
-        assertEq(textField, rootNode.anchorObject);
-        assertEq(0, rootNode.anchorOffset);
-        assertEq(textField, rootNode.focusObject);
-        assertEq(0, rootNode.focusOffset);
-        chrome.automation.setDocumentSelection({anchorObject: textField,
-                                                anchorOffset: 1,
-                                                focusObject: textField,
-                                                focusOffset: 3});
-        listenOnce(rootNode, EventType.DOCUMENT_SELECTION_CHANGED,
+    var textField = rootNode.find({role: RoleType.TEXT_FIELD});
+    textField.focus();
+    assertTrue(!!textField);
+    // Focusing the textfield will cause a text selection changed event in it.
+    listenOnce(textField, EventType.TEXT_SELECTION_CHANGED, function(evt2) {
+      assertTrue(evt2.target == textField);
+      assertEq(textField, rootNode.anchorObject);
+      assertEq(0, rootNode.anchorOffset);
+      assertEq(textField, rootNode.focusObject);
+      assertEq(0, rootNode.focusOffset);
+
+      // Setting selection within the textfield causes a document selection and
+      // a textfield selection event.
+      chrome.automation.setDocumentSelection({anchorObject: textField,
+                                              anchorOffset: 1,
+                                              focusObject: textField,
+                                              focusOffset: 3});
+      listenOnce(rootNode, EventType.DOCUMENT_SELECTION_CHANGED,
+                 function(evt) {
+        listenOnce(textField, EventType.TEXT_SELECTION_CHANGED,
                    function(evt) {
           assertEq(textField, rootNode.anchorObject);
           assertEq(1, rootNode.anchorOffset);
@@ -55,10 +62,6 @@
         });
       });
     });
-
-    var textField = rootNode.find({role: RoleType.TEXT_FIELD});
-    assertTrue(!!textField);
-    textField.focus();
   },
 ];
 
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/force_layout.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/force_layout.js
index 09bd60ec..0bfdc0a 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/force_layout.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/force_layout.js
@@ -9,10 +9,8 @@
     rootNode.addEventListener('focus', (evt) => {
       // The underlying DOM button has not changed, but its layout has. This
       // listener ensures we at least get a focus event on a new valid
-      // accessibility object. Once display none nodes are in the tree, it's
-      // likely that |node| == |evt.target|.
-      assertFalse(evt.target == node);
-      assertEq(undefined, node.role);
+      // accessibility object.
+      assertEq(evt.target, node);
       assertEq('button', evt.target.role);
       chrome.test.succeed();
     });
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 55e4f815..f04ea92 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -275,7 +275,6 @@
     "//components/proxy_config",
     "//components/safe_search_api",
     "//components/safe_search_api:safe_search_client",
-    "//components/services/app_service/public/mojom",
     "//components/services/heap_profiling",
     "//components/services/heap_profiling/public/cpp",
     "//components/services/heap_profiling/public/mojom",
diff --git a/chromecast/browser/cast_web_service.cc b/chromecast/browser/cast_web_service.cc
index 3e3c1e1..4fba071 100644
--- a/chromecast/browser/cast_web_service.cc
+++ b/chromecast/browser/cast_web_service.cc
@@ -94,7 +94,7 @@
 }
 
 void CastWebService::FlushDomLocalStorage() {
-  browser_context_->ForEachStoragePartition(
+  browser_context_->ForEachLoadedStoragePartition(
       base::BindRepeating([](content::StoragePartition* storage_partition) {
         DVLOG(1) << "Starting DOM localStorage flush.";
         storage_partition->Flush();
@@ -102,7 +102,7 @@
 }
 
 void CastWebService::ClearLocalStorage(ClearLocalStorageCallback callback) {
-  browser_context_->ForEachStoragePartition(
+  browser_context_->ForEachLoadedStoragePartition(
       base::BindRepeating(
           [](base::OnceClosure cb, content::StoragePartition* partition) {
             auto cookie_delete_filter =
diff --git a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc
index 9457905..2d02ec69 100644
--- a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc
+++ b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc
@@ -504,17 +504,17 @@
     ErrorCallback error_callback) {}
 
 void FakeShillManagerClient::SetTetheringEnabled(bool enabled,
-                                                 base::OnceClosure callback,
+                                                 StringCallback callback,
                                                  ErrorCallback error_callback) {
   switch (simulate_tethering_enable_result_) {
     case FakeShillSimulatedResult::kSuccess:
       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-          FROM_HERE, std::move(callback));
+          FROM_HERE, base::BindOnce(std::move(callback),
+                                    simulate_enable_tethering_result_string_));
       return;
     case FakeShillSimulatedResult::kFailure:
       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(error_callback),
-                                    simulate_enable_tethering_error_,
+          FROM_HERE, base::BindOnce(std::move(error_callback), "Error",
                                     "Simulated failure"));
       return;
     case FakeShillSimulatedResult::kTimeout:
@@ -543,6 +543,15 @@
   }
 }
 
+void FakeShillManagerClient::SetLOHSEnabled(bool enabled,
+                                            base::OnceClosure callback,
+                                            ErrorCallback error_callback) {
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(error_callback), "Error", "Fake failure"));
+  return;
+}
+
 ShillManagerClient::TestInterface* FakeShillManagerClient::GetTestInterface() {
   return this;
 }
@@ -842,10 +851,10 @@
 
 void FakeShillManagerClient::SetSimulateTetheringEnableResult(
     FakeShillSimulatedResult tethering_enable_result,
-    const std::string& tethering_enable_error) {
+    const std::string& result_string) {
   simulate_tethering_enable_result_ = tethering_enable_result;
-  if (simulate_tethering_enable_result_ == FakeShillSimulatedResult::kFailure) {
-    simulate_enable_tethering_error_ = tethering_enable_error;
+  if (simulate_tethering_enable_result_ == FakeShillSimulatedResult::kSuccess) {
+    simulate_enable_tethering_result_string_ = result_string;
   }
 }
 
diff --git a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.h b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.h
index b4ed73d..a1bcdbe 100644
--- a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.h
+++ b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.h
@@ -77,10 +77,13 @@
                                   base::OnceClosure callback,
                                   ErrorCallback error_callback) override;
   void SetTetheringEnabled(bool enabled,
-                           base::OnceClosure callback,
+                           StringCallback callback,
                            ErrorCallback error_callback) override;
   void CheckTetheringReadiness(StringCallback callback,
                                ErrorCallback error_callback) override;
+  void SetLOHSEnabled(bool enabled,
+                      base::OnceClosure callback,
+                      ErrorCallback error_callback) override;
 
   ShillManagerClient::TestInterface* GetTestInterface() override;
 
@@ -120,7 +123,7 @@
       FakeShillSimulatedResult configuration_result) override;
   void SetSimulateTetheringEnableResult(
       FakeShillSimulatedResult tethering_enable_result,
-      const std::string& tethering_enable_error) override;
+      const std::string& result_string) override;
   void SetSimulateCheckTetheringReadinessResult(
       FakeShillSimulatedResult tethering_readiness_result,
       const std::string& readiness_status) override;
@@ -194,7 +197,7 @@
       FakeShillSimulatedResult::kSuccess;
   FakeShillSimulatedResult simulate_tethering_enable_result_ =
       FakeShillSimulatedResult::kSuccess;
-  std::string simulate_enable_tethering_error_;
+  std::string simulate_enable_tethering_result_string_;
   FakeShillSimulatedResult simulate_check_tethering_readiness_result_ =
       FakeShillSimulatedResult::kSuccess;
   std::string simulate_tethering_readiness_status_;
diff --git a/chromeos/ash/components/dbus/shill/shill_manager_client.cc b/chromeos/ash/components/dbus/shill/shill_manager_client.cc
index 5f47bec..3c493635 100644
--- a/chromeos/ash/components/dbus/shill/shill_manager_client.cc
+++ b/chromeos/ash/components/dbus/shill/shill_manager_client.cc
@@ -203,14 +203,14 @@
   }
 
   void SetTetheringEnabled(bool enabled,
-                           base::OnceClosure callback,
+                           StringCallback callback,
                            ErrorCallback error_callback) override {
     dbus::MethodCall method_call(shill::kFlimflamManagerInterface,
                                  shill::kSetTetheringEnabledFunction);
     dbus::MessageWriter writer(&method_call);
     writer.AppendBool(enabled);
-    helper_->CallVoidMethodWithErrorCallback(&method_call, std::move(callback),
-                                             std::move(error_callback));
+    helper_->CallStringMethodWithErrorCallback(
+        &method_call, std::move(callback), std::move(error_callback));
   }
 
   void CheckTetheringReadiness(StringCallback callback,
@@ -221,6 +221,17 @@
         &method_call, std::move(callback), std::move(error_callback));
   }
 
+  void SetLOHSEnabled(bool enabled,
+                      base::OnceClosure callback,
+                      ErrorCallback error_callback) override {
+    dbus::MethodCall method_call(shill::kFlimflamManagerInterface,
+                                 shill::kSetLOHSEnabledFunction);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendBool(enabled);
+    helper_->CallVoidMethodWithErrorCallback(&method_call, std::move(callback),
+                                             std::move(error_callback));
+  }
+
   TestInterface* GetTestInterface() override { return nullptr; }
 
   void Init(dbus::Bus* bus) {
diff --git a/chromeos/ash/components/dbus/shill/shill_manager_client.h b/chromeos/ash/components/dbus/shill/shill_manager_client.h
index 3c917fc..71317ade 100644
--- a/chromeos/ash/components/dbus/shill/shill_manager_client.h
+++ b/chromeos/ash/components/dbus/shill/shill_manager_client.h
@@ -251,7 +251,7 @@
   // Enables or disables tethering hotspot. Only supports cellular as the
   // upstream technologies and WiFi as the downstream technology.
   virtual void SetTetheringEnabled(bool enabled,
-                                   base::OnceClosure callback,
+                                   StringCallback callback,
                                    ErrorCallback error_callback) = 0;
 
   // Checks whether the upstream technology is ready to tether. Returns a status
@@ -261,6 +261,11 @@
   virtual void CheckTetheringReadiness(StringCallback callback,
                                        ErrorCallback error_callback) = 0;
 
+  // Enables or disables local only hotspot.
+  virtual void SetLOHSEnabled(bool enabled,
+                              base::OnceClosure callback,
+                              ErrorCallback error_callback) = 0;
+
   // Returns an interface for testing (stub only), or returns null.
   virtual TestInterface* GetTestInterface() = 0;
 
diff --git a/chromeos/ash/components/dbus/shill/shill_manager_client_unittest.cc b/chromeos/ash/components/dbus/shill/shill_manager_client_unittest.cc
index f76e4462..e46fc63 100644
--- a/chromeos/ash/components/dbus/shill/shill_manager_client_unittest.cc
+++ b/chromeos/ash/components/dbus/shill/shill_manager_client_unittest.cc
@@ -328,8 +328,14 @@
 }
 
 TEST_F(ShillManagerClientTest, SetTetheringEnabled) {
+  const char kEnabledResult[] = "success";
+
   // Create response.
   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
+  dbus::MessageWriter writer(response.get());
+  writer.AppendString(kEnabledResult);
+
+  // Set expectation.
   PrepareForMethodCall(shill::kSetTetheringEnabledFunction,
                        base::BindRepeating(&ExpectBoolArgument, true),
                        response.get());
@@ -338,7 +344,12 @@
   base::MockCallback<ShillManagerClient::ErrorCallback> mock_error_callback;
   EXPECT_CALL(mock_error_callback, Run(_, _)).Times(0);
   client_->SetTetheringEnabled(
-      /*enabled=*/true, run_loop.QuitClosure(), mock_error_callback.Get());
+      /*enabled=*/true,
+      base::BindLambdaForTesting([&](const std::string& enabled_result) {
+        EXPECT_EQ(kEnabledResult, enabled_result);
+        run_loop.QuitClosure();
+      }),
+      mock_error_callback.Get());
 
   // Run the message loop.
   run_loop.RunUntilIdle();
diff --git a/chromeos/ash/components/login/auth/auth_metrics_recorder.cc b/chromeos/ash/components/login/auth/auth_metrics_recorder.cc
index b1649a8..8073d1b 100644
--- a/chromeos/ash/components/login/auth/auth_metrics_recorder.cc
+++ b/chromeos/ash/components/login/auth/auth_metrics_recorder.cc
@@ -87,6 +87,8 @@
       return "UntilSuccess";
     case AuthenticationOutcome::kFailure:
       return "UntilFailure";
+    case AuthenticationOutcome::kRecovery:
+      return "UntilRecovery";
   }
   NOTREACHED();
   return "";
diff --git a/chromeos/ash/components/login/auth/auth_metrics_recorder.h b/chromeos/ash/components/login/auth/auth_metrics_recorder.h
index 24f22314..918d088 100644
--- a/chromeos/ash/components/login/auth/auth_metrics_recorder.h
+++ b/chromeos/ash/components/login/auth/auth_metrics_recorder.h
@@ -31,6 +31,8 @@
     kSuccess,
     // User exited the login screen without successfully logging in.
     kFailure,
+    // User opened the account recovery flow from the login screen.
+    kRecovery
   };
 
   AuthMetricsRecorder(const AuthMetricsRecorder&) = delete;
diff --git a/chromeos/ash/components/login/auth/auth_metrics_recorder_unittest.cc b/chromeos/ash/components/login/auth/auth_metrics_recorder_unittest.cc
index bb92724..1a0bceb 100644
--- a/chromeos/ash/components/login/auth/auth_metrics_recorder_unittest.cc
+++ b/chromeos/ash/components/login/auth/auth_metrics_recorder_unittest.cc
@@ -136,6 +136,14 @@
   histogram_tester.ExpectBucketCount(
       "Ash.OSAuth.Login.NbPasswordAttempts.UntilFailure", three_attempts, 1);
 
+  int eleven_attempts = 11;
+  recorder_->OnExistingUserLoginExit(
+      AuthMetricsRecorder::AuthenticationOutcome::kRecovery, eleven_attempts);
+  histogram_tester.ExpectTotalCount(
+      "Ash.OSAuth.Login.NbPasswordAttempts.UntilRecovery", 1);
+  histogram_tester.ExpectBucketCount(
+      "Ash.OSAuth.Login.NbPasswordAttempts.UntilRecovery", eleven_attempts, 1);
+
   int five_attempts = 5;
   recorder_->OnAuthenticationSurfaceChange(
       AuthMetricsRecorder::AuthenticationSurface::kLock);
diff --git a/chromeos/ash/components/network/hotspot_allowed_flag_handler.cc b/chromeos/ash/components/network/hotspot_allowed_flag_handler.cc
index d647f246..5161a9e 100644
--- a/chromeos/ash/components/network/hotspot_allowed_flag_handler.cc
+++ b/chromeos/ash/components/network/hotspot_allowed_flag_handler.cc
@@ -5,8 +5,8 @@
 #include "chromeos/ash/components/network/hotspot_allowed_flag_handler.h"
 
 #include "ash/constants/ash_features.h"
-#include "base/bind.h"
-#include "base/callback_helpers.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
 #include "chromeos/ash/components/network/network_event_log.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
diff --git a/chromeos/ash/components/network/hotspot_controller.cc b/chromeos/ash/components/network/hotspot_controller.cc
index 481531e..c98b822 100644
--- a/chromeos/ash/components/network/hotspot_controller.cc
+++ b/chromeos/ash/components/network/hotspot_controller.cc
@@ -93,8 +93,9 @@
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-void HotspotController::OnSetTetheringEnabledSuccess() {
-  CompleteCurrentRequest(hotspot_config::mojom::HotspotControlResult::kSuccess);
+void HotspotController::OnSetTetheringEnabledSuccess(
+    const std::string& result) {
+  CompleteCurrentRequest(SetTetheringEnabledResultToMojom(result));
 }
 
 void HotspotController::OnSetTetheringEnabledFailure(
@@ -102,7 +103,8 @@
     const std::string& error_message) {
   NET_LOG(ERROR) << "Enable/disable tethering failed: " << error_name
                  << ", message: " << error_message;
-  CompleteCurrentRequest(SetTetheringEnabledResultToMojom(error_name));
+  CompleteCurrentRequest(
+      hotspot_config::mojom::HotspotControlResult::kShillOperationFailed);
 }
 
 void HotspotController::CompleteCurrentRequest(
diff --git a/chromeos/ash/components/network/hotspot_controller.h b/chromeos/ash/components/network/hotspot_controller.h
index 16b5f2470..adf7577 100644
--- a/chromeos/ash/components/network/hotspot_controller.h
+++ b/chromeos/ash/components/network/hotspot_controller.h
@@ -59,7 +59,7 @@
   void OnCheckTetheringReadiness(
       HotspotStateHandler::CheckTetheringReadinessResult result);
   void PerformSetTetheringEnabled(bool enabled);
-  void OnSetTetheringEnabledSuccess();
+  void OnSetTetheringEnabledSuccess(const std::string& result);
   void OnSetTetheringEnabledFailure(const std::string& error_name,
                                     const std::string& error_message);
   void CompleteCurrentRequest(
diff --git a/chromeos/ash/components/network/hotspot_controller_unittest.cc b/chromeos/ash/components/network/hotspot_controller_unittest.cc
index 8e08b1d..2d2c104 100644
--- a/chromeos/ash/components/network/hotspot_controller_unittest.cc
+++ b/chromeos/ash/components/network/hotspot_controller_unittest.cc
@@ -142,6 +142,8 @@
 TEST_F(HotspotControllerTest, EnableTetheringSuccess) {
   SetValidTetheringCapabilities();
   AddActiveCellularServivce();
+  network_state_test_helper_.manager_test()->SetSimulateTetheringEnableResult(
+      FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(hotspot_config::mojom::HotspotControlResult::kSuccess,
@@ -179,7 +181,7 @@
   // Simulate enable tethering operation fail with kShillNetworkingFailure
   // error.
   network_state_test_helper_.manager_test()->SetSimulateTetheringEnableResult(
-      FakeShillSimulatedResult::kFailure, kShillNetworkingFailure);
+      FakeShillSimulatedResult::kSuccess, kShillNetworkingFailure);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(hotspot_config::mojom::HotspotControlResult::kNetworkSetupFailure,
@@ -187,6 +189,8 @@
 }
 
 TEST_F(HotspotControllerTest, DisableTetheringSuccess) {
+  network_state_test_helper_.manager_test()->SetSimulateTetheringEnableResult(
+      FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess);
   EXPECT_EQ(hotspot_config::mojom::HotspotControlResult::kSuccess,
             DisableHotspot());
 }
@@ -194,6 +198,8 @@
 TEST_F(HotspotControllerTest, QueuedRequests) {
   SetValidTetheringCapabilities();
   AddActiveCellularServivce();
+  network_state_test_helper_.manager_test()->SetSimulateTetheringEnableResult(
+      FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess);
   base::RunLoop().RunUntilIdle();
 
   hotspot_config::mojom::HotspotControlResult enable_result, disable_result;
diff --git a/chromeos/ash/components/network/hotspot_util.cc b/chromeos/ash/components/network/hotspot_util.cc
index 03ca31d..deac22bf 100644
--- a/chromeos/ash/components/network/hotspot_util.cc
+++ b/chromeos/ash/components/network/hotspot_util.cc
@@ -18,13 +18,9 @@
 // TODO (jiajunz): Use shill constants after they are added.
 const char kShillTetheringBand2_4GHz[] = "2.4GHz";
 const char kShillTetheringBand5GHz[] = "5GHz";
-const char kShillInvalidProperties[] = "invalid_properties";
-const char kShillUpstreamNotReady[] = "upstream_not_ready";
 const char kShillNetworkingFailure[] = "network_failure";
 const char kShillWifiDriverFailure[] = "wifi_driver_failure";
 const char kShillCellularAttachFailure[] = "cellular_attach_failure";
-const char kShillNoUpstreamConnection[] = "no_upstream";
-const char kShillEnableTetheringSuccess[] = "success";
 
 hotspot_config::mojom::WiFiBand ShillBandToMojom(
     const std::string& shill_band) {
@@ -197,14 +193,15 @@
     const std::string& shill_enabled_result) {
   using hotspot_config::mojom::HotspotControlResult;
 
-  if (shill_enabled_result == kShillEnableTetheringSuccess) {
+  if (shill_enabled_result == shill::kTetheringEnableResultSuccess) {
     return HotspotControlResult::kSuccess;
   }
-  if (shill_enabled_result == kShillInvalidProperties) {
+  if (shill_enabled_result == shill::kTetheringEnableResultInvalidProperties) {
     return HotspotControlResult::kInvalidConfiguration;
   }
-  if (shill_enabled_result == kShillUpstreamNotReady) {
-    return HotspotControlResult::kUpstreamNotReady;
+  if (shill_enabled_result ==
+      shill::kTetheringEnableResultUpstreamNotAvailable) {
+    return HotspotControlResult::kUpstreamNotAvailable;
   }
   if (shill_enabled_result == kShillNetworkingFailure) {
     return HotspotControlResult::kNetworkSetupFailure;
@@ -215,9 +212,6 @@
   if (shill_enabled_result == kShillCellularAttachFailure) {
     return HotspotControlResult::kCellularAttachFailure;
   }
-  if (shill_enabled_result == kShillNoUpstreamConnection) {
-    return HotspotControlResult::kNoUpstreamConnection;
-  }
 
   NET_LOG(ERROR) << "Unknown enable/disable tethering error: "
                  << shill_enabled_result;
diff --git a/chromeos/ash/services/cros_healthd/testing/bindings/templates/connectivity.cc.j2 b/chromeos/ash/services/cros_healthd/testing/bindings/templates/connectivity.cc.j2
index feb81a5..37c5293 100644
--- a/chromeos/ash/services/cros_healthd/testing/bindings/templates/connectivity.cc.j2
+++ b/chromeos/ash/services/cros_healthd/testing/bindings/templates/connectivity.cc.j2
@@ -16,10 +16,9 @@
 
 #include "{{module.path}}-connectivity.h"
 
-#include <base/callback_helpers.h>
-#include <base/check.h>
-#include <base/logging.h>
-
+#include "base/check.h"
+#include "base/functional/callback_helpers.h"
+#include "base/logging.h"
 #include "chromeos/ash/services/cros_healthd/testing/bindings/local_state.h"
 #include "chromeos/ash/services/cros_healthd/testing/bindings/remote_state.h"
 #include "chromeos/ash/services/cros_healthd/testing/bindings/utils.h"
diff --git a/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc b/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc
index 3421343..58ac9d2 100644
--- a/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc
+++ b/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc
@@ -260,6 +260,8 @@
   SetReadinessCheckResultReady();
   SetValidHotspotCapabilities();
   AddActiveCellularService();
+  helper()->manager_test()->SetSimulateTetheringEnableResult(
+      FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(mojom::HotspotControlResult::kSuccess, EnableHotspot());
@@ -275,6 +277,10 @@
 }
 
 TEST_F(CrosHotspotConfigTest, DisableHotspot) {
+  helper()->manager_test()->SetSimulateTetheringEnableResult(
+      FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess);
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(mojom::HotspotControlResult::kSuccess, DisableHotspot());
 }
 
diff --git a/chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom b/chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom
index 0cad397..8f2373c5 100644
--- a/chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom
+++ b/chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom
@@ -81,16 +81,16 @@
   kReadinessCheckFailed,
   // Invalid tethering configuration.
   kInvalidConfiguration,
-  // Upstream is not ready.
-  kUpstreamNotReady,
+  // Upstream network is not available.
+  kUpstreamNotAvailable,
   // Network setup failure
   kNetworkSetupFailure,
   // Wifi driver setup failure.
   kWifiDriverFailure,
   // Cellular attach failure.
   kCellularAttachFailure,
-  // No upstream cellular connection.
-  kNoUpstreamConnection,
+  // Failed due to Shill operation error,
+  kShillOperationFailed,
   kUnknownFailure,
 };
 
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 328206e..fa82b7c2 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -304,6 +304,11 @@
   # https://crbug.com/1236234
   "lacros.AudioPlay",
 
+  # b/265844024
+  "inputs.PhysicalKeyboardPinyinTyping.traditional",
+  "inputs.PhysicalKeyboardShapeBasedChineseTyping.array",
+  "inputs.PhysicalKeyboardShapeBasedChineseTyping.cangjie",
+
   # READ COMMENT AT TOP BEFORE ADDING NEW TESTS HERE.
 ]
 
diff --git a/components/app_restore/BUILD.gn b/components/app_restore/BUILD.gn
index b3079f80..4d48a2b 100644
--- a/components/app_restore/BUILD.gn
+++ b/components/app_restore/BUILD.gn
@@ -51,7 +51,6 @@
     "//components/services/app_service/public/cpp:app_types",
     "//components/services/app_service/public/cpp:app_update",
     "//components/services/app_service/public/cpp:intents",
-    "//components/services/app_service/public/mojom",
     "//components/sessions:session_id",
     "//components/tab_groups",
     "//ui/aura",
diff --git a/components/creator/public/creator_api.h b/components/creator/public/creator_api.h
index 32d0d67c..1800de68 100644
--- a/components/creator/public/creator_api.h
+++ b/components/creator/public/creator_api.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "base/callback.h"
+#include "base/functional/callback.h"
 
 namespace creator {
 
diff --git a/components/desks_storage/core/desk_template_conversion.cc b/components/desks_storage/core/desk_template_conversion.cc
index 49df7e1..3310e02 100644
--- a/components/desks_storage/core/desk_template_conversion.cc
+++ b/components/desks_storage/core/desk_template_conversion.cc
@@ -27,6 +27,10 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/gfx/geometry/rect.h"
 
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chromeos/crosapi/cpp/lacros_startup_state.h"  // nogncheck
+#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
+
 namespace {
 
 using SyncWindowOpenDisposition =
@@ -217,16 +221,19 @@
 
   if (app_type == kAppTypeBrowser) {
     // Return the primary browser's known app ID.
-    // Note that we will launch the browser as lacros if it is enabled,
-    // even if it was saved as a non-lacros window, during template launch
-    // (and vice-versa). `crosapi::lacros_startup_state::IsLacrosEnabled()` &&
-    // `crosapi::lacros_startup_state::IsLacrosPrimaryEnabled()` cannot be used
-    // to determine lacros state at start up since the values are set and
-    // propagated until later. We will determine the chrome app type during
-    // template launch instead. As such, we will default to ash chrome for now.
+    const bool is_lacros =
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+        true;
+#else
+        // Note that this will launch the browser as lacros if it is enabled,
+        // even if it was saved as a non-lacros window (and vice-versa).
+        crosapi::lacros_startup_state::IsLacrosEnabled() &&
+        crosapi::lacros_startup_state::IsLacrosPrimaryEnabled();
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
     // Browser app has a known app ID.
-    return std::string(app_constants::kChromeAppId);
+    return std::string(is_lacros ? app_constants::kLacrosAppId
+                                 : app_constants::kChromeAppId);
   } else if (app_type == kAppTypeChrome || app_type == kAppTypeProgressiveWeb ||
              app_type == kAppTypeArc) {
     // Read the provided app ID
@@ -1174,18 +1181,19 @@
       // Return an empty string to indicate this app is unsupported.
       return std::string();
     case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kBrowserAppWindow: {
-      // Return the primary browser's known app ID.
-      // Note that we will launch the browser as lacros if it is enabled,
-      // even if it was saved as a non-lacros window, during template launch
-      // (and vice-versa). `crosapi::lacros_startup_state::IsLacrosEnabled()` &&
-      // `crosapi::lacros_startup_state::IsLacrosPrimaryEnabled()` cannot be
-      // used to determine lacros state at start up since the values are set and
-      // propagated until later. We will determine the chrome app type during
-      // template launch instead. As such, we will default to ash chrome for
-      // now.
+      const bool is_lacros =
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+          true;
+#else
+          // Note that this will launch the browser as lacros if it is enabled,
+          // even if it was saved as a non-lacros window (and vice-versa).
+          crosapi::lacros_startup_state::IsLacrosEnabled() &&
+          crosapi::lacros_startup_state::IsLacrosPrimaryEnabled();
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
       // Browser app has a known app ID.
-      return std::string(app_constants::kChromeAppId);
+      return std::string(is_lacros ? app_constants::kLacrosAppId
+                                   : app_constants::kChromeAppId);
     }
     case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kChromeApp:
       return app.app().chrome_app().app_id();
diff --git a/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm b/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm
index 4e6c726..c17bddf 100644
--- a/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm
+++ b/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm
@@ -6,9 +6,9 @@
 
 #include <memory>
 
-#import "base/callback_helpers.h"
 #import "base/files/file_util.h"
 #import "base/files/scoped_temp_dir.h"
+#import "base/functional/callback_helpers.h"
 #import "base/guid.h"
 #import "base/run_loop.h"
 #import "base/sequence_checker.h"
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index 4d90bd0..f7f8f064 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -195,7 +195,7 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-  content::ZygoteHandle GetZygote() override {
+  content::ZygoteCommunication* GetZygote() override {
     return content::GetGenericZygote();
   }
 #endif  // BUILDFLAG(USE_ZYGOTE_HANDLE)
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index ed2f417..4630c29 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -456,7 +456,7 @@
 // necessary.
 BASE_FEATURE(kDefaultTypedNavigationsToHttps,
              "OmniboxDefaultTypedNavigationsToHttps",
-             enabled_by_default_desktop_android);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Parameter name used to look up the delay before falling back to the HTTP URL
 // while trying an HTTPS URL. The parameter is treated as a TimeDelta, so the
diff --git a/components/password_manager/core/browser/affiliation/affiliations_prefetcher.cc b/components/password_manager/core/browser/affiliation/affiliations_prefetcher.cc
index cc4856f..74743dcbd9 100644
--- a/components/password_manager/core/browser/affiliation/affiliations_prefetcher.cc
+++ b/components/password_manager/core/browser/affiliation/affiliations_prefetcher.cc
@@ -8,8 +8,6 @@
 #include <utility>
 
 #include "base/barrier_callback.h"
-#include "base/bind.h"
-#include "base/callback.h"
 #include "base/check_op.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/WebAppInstallForceList.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/WebAppInstallForceList.yaml
index ab0908dc..3b93fdb 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/WebAppInstallForceList.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/WebAppInstallForceList.yaml
@@ -24,18 +24,16 @@
         the latter will be ignored.)
 
         - <ph name="OVERRIDE_APP_NAME_LABEL">custom_name</ph>
-        (Starting with <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
-        version 99, allows you to permanently override the app name for all web
-        apps and PWAs. Currently only supported on
-        <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph>.)
+        (Starting with <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph>
+        version 99, and version 111 on all other operating systems, allows you to
+        permanently override the app name for all web apps and PWAs.)
 
         - <ph name="CUSTOM_ICON_LABEL">custom_icon</ph>
-        (Starting with <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
-        version 99, allows you to override the app icon of installed apps. The
-        icons have to be square, maximal 1 MB in size, and in one of the following
-        formats: jpeg, png, gif, webp, ico. The hash value has to be the SHA256
-        hash of the icon file. Currently only supported on
-        <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph>.)
+        (Starting with <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph>
+        version 99, and version 111 on all other operating systems, allows you to
+        override the app icon of installed apps. The icons have to be square,
+        maximal 1 MB in size, and in one of the following formats: jpeg, png, gif, webp, ico.
+        The hash value has to be the SHA256 hash of the icon file.)
 
         - <ph name="INSTALL_AS_SHORTCUT_LABEL">install_as_shortcut</ph>
         (Starting with <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>
diff --git a/components/safe_browsing/content/resources/download_file_types.asciipb b/components/safe_browsing/content/resources/download_file_types.asciipb
index 54afc625..530e246 100644
--- a/components/safe_browsing/content/resources/download_file_types.asciipb
+++ b/components/safe_browsing/content/resources/download_file_types.asciipb
@@ -8,7 +8,7 @@
 ##
 ## Top level settings
 ##
-version_id: 56
+version_id: 57
 sampled_ping_probability: 0.01
 max_archived_binaries_to_report: 10
 default_file_type {
@@ -2907,6 +2907,17 @@
     auto_open_hint: DISALLOW_AUTO_OPEN
   }
 }
+file_types {
+  # Can lead to code execution if BGINFO is installed, which is fairly common.
+  extension: "bgi"
+  uma_value: 403
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_TYPE_WINDOWS
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
 
 ##
 ## MacOS-specific files
diff --git a/components/safe_browsing/content/resources/download_file_types_experiment.asciipb b/components/safe_browsing/content/resources/download_file_types_experiment.asciipb
index 51d1128..6a159788 100644
--- a/components/safe_browsing/content/resources/download_file_types_experiment.asciipb
+++ b/components/safe_browsing/content/resources/download_file_types_experiment.asciipb
@@ -12,7 +12,7 @@
 ## version id is larger than the version id in download_file_types.asciipb. If
 ## there isn't an ongoing experiment, this version id is equal to the version id
 ## in download_file_types.asciipb.
-version_id: 56
+version_id: 57
 sampled_ping_probability: 0.01
 max_archived_binaries_to_report: 10
 default_file_type {
@@ -2911,6 +2911,17 @@
     auto_open_hint: DISALLOW_AUTO_OPEN
   }
 }
+file_types {
+  # Can lead to code execution if BGINFO is installed, which is fairly common.
+  extension: "bgi"
+  uma_value: 403
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_TYPE_WINDOWS
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
 
 ##
 ## MacOS-specific files
diff --git a/components/services/app_service/public/cpp/BUILD.gn b/components/services/app_service/public/cpp/BUILD.gn
index d4a1595..9e0f4b3 100644
--- a/components/services/app_service/public/cpp/BUILD.gn
+++ b/components/services/app_service/public/cpp/BUILD.gn
@@ -68,10 +68,7 @@
 
   defines = [ "IS_APP_TYPES_IMPL" ]
 
-  public_deps = [
-    "//components/services/app_service/public/mojom",
-    "//components/services/app_service/public/protos",
-  ]
+  public_deps = [ "//components/services/app_service/public/protos" ]
 
   deps = [
     ":icon_types",
@@ -102,10 +99,7 @@
 
   defines = [ "IS_APP_UPDATE_IMPL" ]
 
-  public_deps = [
-    "//components/account_id:account_id",
-    "//components/services/app_service/public/mojom",
-  ]
+  public_deps = [ "//components/account_id:account_id" ]
 
   deps = [
     ":app_types",
@@ -168,8 +162,6 @@
     "icon_loader.h",
   ]
 
-  public_deps = [ "//components/services/app_service/public/mojom" ]
-
   deps = [
     ":app_types",
     ":icon_types",
@@ -199,8 +191,6 @@
 
   defines = [ "IS_ICON_TYPES_IMPL" ]
 
-  public_deps = [ "//components/services/app_service/public/mojom" ]
-
   deps = [ "//ui/gfx" ]
 }
 
@@ -214,7 +204,7 @@
 
   defines = [ "IS_LOGIN_MODE_IMPL" ]
 
-  public_deps = [ "//components/services/app_service/public/mojom" ]
+  deps = [ "//base:base" ]
 }
 
 source_set("intents") {
@@ -230,7 +220,6 @@
   deps = [
     ":app_types",
     "//base",
-    "//components/services/app_service/public/mojom",
     "//third_party/blink/public/common",
     "//url",
   ]
@@ -253,7 +242,8 @@
 
   deps = [
     ":app_types",
-    "//components/services/app_service/public/mojom",
+    "//base:base",
+    "//third_party/abseil-cpp:absl",
   ]
 }
 
@@ -274,7 +264,6 @@
     ":intents",
     ":preferred_app",
     "//base",
-    "//components/services/app_service/public/mojom",
     "//content/public/browser",
     "//url",
   ]
@@ -291,7 +280,7 @@
   deps = [
     ":app_types",
     ":intents",
-    "//components/services/app_service/public/mojom",
+    "//third_party/abseil-cpp:absl",
   ]
 }
 
@@ -303,14 +292,12 @@
 
   deps = [
     ":app_types",
-    "//components/services/app_service/public/mojom",
+    "//third_party/abseil-cpp:absl",
   ]
 }
 
 source_set("crosapi_utils") {
   sources = [ "crosapi_utils.h" ]
-
-  deps = [ "//components/services/app_service/public/mojom" ]
 }
 
 source_set("unit_tests") {
diff --git a/components/services/app_service/public/mojom/BUILD.gn b/components/services/app_service/public/mojom/BUILD.gn
deleted file mode 100644
index 530dfea0..0000000
--- a/components/services/app_service/public/mojom/BUILD.gn
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojom") {
-  sources = [ "app_service.mojom" ]
-  webui_module_path = "/"
-}
diff --git a/components/services/app_service/public/mojom/OWNERS b/components/services/app_service/public/mojom/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/components/services/app_service/public/mojom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/services/app_service/public/mojom/app_service.mojom b/components/services/app_service/public/mojom/app_service.mojom
deleted file mode 100644
index 7af5e9e..0000000
--- a/components/services/app_service/public/mojom/app_service.mojom
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module apps.mojom;
diff --git a/components/translate/content/android/translate_message.cc b/components/translate/content/android/translate_message.cc
index 7546960..bdb47105 100644
--- a/components/translate/content/android/translate_message.cc
+++ b/components/translate/content/android/translate_message.cc
@@ -381,9 +381,10 @@
             messages::DismissReason::GESTURE &&
         ui_delegate_->ShouldAutoNeverTranslate();
 
-    ui_delegate_->TranslationDeclined(
-        static_cast<messages::DismissReason>(dismiss_reason) ==
-        messages::DismissReason::GESTURE);
+    if (static_cast<messages::DismissReason>(dismiss_reason) ==
+        messages::DismissReason::GESTURE) {
+      ui_delegate_->TranslationDeclined(true);
+    }
 
     if (should_auto_never_translate) {
       RecordCompactInfobarEvent(
diff --git a/components/translate/content/android/translate_message_unittest.cc b/components/translate/content/android/translate_message_unittest.cc
index fd990e77..f43a15b8 100644
--- a/components/translate/content/android/translate_message_unittest.cc
+++ b/components/translate/content/android/translate_message_unittest.cc
@@ -1232,7 +1232,10 @@
 
   EXPECT_EQ(100, translate_prefs_->GetTranslationAcceptedCount("fr"));
   EXPECT_EQ(100, translate_prefs_->GetTranslationDeniedCount("fr"));
-  EXPECT_EQ(1, translate_prefs_->GetTranslationIgnoredCount("fr"));
+
+  // TODO(crbug.com/1408277): Change this back to 1 after re-enabling the
+  // counting of ignored cases.
+  EXPECT_EQ(0, translate_prefs_->GetTranslationIgnoredCount("fr"));
 }
 
 TEST_F(TranslateMessageTest, TranslationNotIgnoredBecauseOverflowMenuOpened) {
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 3d3d0be..842d157 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -360,7 +360,7 @@
   if (!parsed_command_line.HasSwitch(switches::kNoUnsandboxedZygote)) {
     CreateUnsandboxedZygote(base::BindOnce(LaunchZygoteHelper));
   }
-  ZygoteHandle generic_zygote =
+  ZygoteCommunication* generic_zygote =
       CreateGenericZygote(base::BindOnce(LaunchZygoteHelper));
 
   // This operation is done through the ZygoteHostImpl as a proxy because of
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
index ad5c1449..1644c86 100644
--- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -2589,18 +2589,19 @@
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
                           L"Before frame\nText in iframe\nAfter frame");
 
+  // Traversing by word should include trailing whitespace.
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ 2,
                   /*expected_text*/ L"Text ",
                   /*expected_count*/ 2);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ -1,
-                  /*expected_text*/ L"frame",
+                  /*expected_text*/ L"frame\n",
                   /*expected_count*/ -1);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
       text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Character,
       /*count*/ 2,
-      /*expected_text*/ L"frame\nT",
+      /*expected_text*/ L"frame\nTe",
       /*expected_count*/ 2);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
                   /*count*/ 7,
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index e162b05..fe6691c 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -907,6 +907,9 @@
   // This is not the same as GetData().id which comes from Blink, because
   // those ids are only unique within the Blink process. We need one that is
   // unique for the browser process.
+  // TODO(accessibility) We should be able to get rid of this, because node IDs
+  // are actually unique within their renderer process, and each renderer
+  // process has its own OS-level window, which is all the uniqueness we need.
   return unique_id_;
 }
 
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index d1209ac..1d52e0c 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -551,6 +551,9 @@
   static bool HasInvalidAttribute(const ui::TextAttributeList& attributes);
 
   // A unique ID, since node IDs are frame-local.
+  // TODO(accessibility) We should be able to get rid of this, because node IDs
+  // are actually local to the renderer process, and each renderer process has
+  // its own OS-level window, which is all the uniqueness we need.
   ui::AXUniqueId unique_id_;
 };
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index 6d7c853..41f0132 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -314,6 +314,8 @@
       if (android_node->IsSlider())
         wcax->HandleSliderChanged(android_node->unique_id());
       break;
+    case ui::AXEventGenerator::Event::ROLE_CHANGED:
+      break;
     case ui::AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED:
     case ui::AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED:
       wcax->HandleScrollPositionChanged(android_node->unique_id());
@@ -394,7 +396,6 @@
     case ui::AXEventGenerator::Event::READONLY_CHANGED:
     case ui::AXEventGenerator::Event::RELATED_NODE_CHANGED:
     case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
-    case ui::AXEventGenerator::Event::ROLE_CHANGED:
     case ui::AXEventGenerator::Event::ROW_COUNT_CHANGED:
     case ui::AXEventGenerator::Event::SELECTED_CHANGED:
     case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
index e1fc7fd..e482a436 100644
--- a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
@@ -276,9 +276,19 @@
       FireReadonlyChangedEvent(wrapper);
       break;
     case ui::AXEventGenerator::Event::RANGE_VALUE_CHANGED:
-      DCHECK(wrapper->GetData().IsRangeValueSupported());
-      FireEvent(wrapper, ax::mojom::Event::kValueChanged);
+      if (wrapper->GetData().IsRangeValueSupported()) {
+        FireEvent(wrapper, ax::mojom::Event::kValueChanged);
+      }
       break;
+    case ui::AXEventGenerator::Event::ALERT:
+    case ui::AXEventGenerator::Event::ROLE_CHANGED: {
+      // Manually fire removal and addition of the object.
+      ui::AXPlatformNodeAuraLinux* platform_node =
+          ToBrowserAccessibilityAuraLinux(wrapper)->GetNode();
+      platform_node->OnSubtreeWillBeDeleted();
+      platform_node->OnSubtreeCreated();
+      break;
+    }
     case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
       FireEvent(wrapper, ax::mojom::Event::kSelectedChildrenChanged);
       break;
@@ -307,7 +317,6 @@
     // Currently unused events on this platform.
     case ui::AXEventGenerator::Event::NONE:
     case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
-    case ui::AXEventGenerator::Event::ALERT:
     case ui::AXEventGenerator::Event::ATOMIC_CHANGED:
     case ui::AXEventGenerator::Event::AUTO_COMPLETE_CHANGED:
     case ui::AXEventGenerator::Event::AUTOFILL_AVAILABILITY_CHANGED:
@@ -349,7 +358,6 @@
     case ui::AXEventGenerator::Event::RANGE_VALUE_STEP_CHANGED:
     case ui::AXEventGenerator::Event::RELATED_NODE_CHANGED:
     case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
-    case ui::AXEventGenerator::Event::ROLE_CHANGED:
     case ui::AXEventGenerator::Event::ROW_COUNT_CHANGED:
     case ui::AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED:
     case ui::AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index 42846c3f..300e88d 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -423,6 +423,7 @@
       HandleAriaPropertiesChangedEvent(*wrapper);
       break;
     case ui::AXEventGenerator::Event::ROLE_CHANGED:
+      FireWinAccessibilityEvent(IA2_EVENT_ROLE_CHANGED, wrapper);
       FireUiaPropertyChangedEvent(UIA_AriaRolePropertyId, wrapper);
       break;
     case ui::AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED:
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index 0d446fe..7f625c1 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -251,6 +251,10 @@
   }
 }
 
+void WebContentsAccessibilityAndroid::UnInitialize(JNIEnv* env) {
+  // TODO(jacklynch): Implement teardown of native accessibility
+}
+
 jboolean WebContentsAccessibilityAndroid::IsEnabled(JNIEnv* env) {
   return !!GetRootBrowserAccessibilityManager();
 }
diff --git a/content/browser/accessibility/web_contents_accessibility_android.h b/content/browser/accessibility/web_contents_accessibility_android.h
index 0ac33da..774f672 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.h
+++ b/content/browser/accessibility/web_contents_accessibility_android.h
@@ -79,6 +79,7 @@
   // --------------------------------------------------------------------------
 
   void DeleteEarly(JNIEnv* env);
+  void UnInitialize(JNIEnv* env);
 
   // Global methods.
   jboolean IsEnabled(JNIEnv* env);
diff --git a/content/browser/back_forward_cache_basics_browsertest.cc b/content/browser/back_forward_cache_basics_browsertest.cc
index 94c6fc9..52bea9d 100644
--- a/content/browser/back_forward_cache_basics_browsertest.cc
+++ b/content/browser/back_forward_cache_basics_browsertest.cc
@@ -599,7 +599,7 @@
       "<html><body> ... ");
 
   // The navigation finishes while the body is still loading.
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
   RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
 
   // 2) Navigate away.
@@ -628,7 +628,7 @@
   shell()->LoadURL(url);
 
   // The navigation finishes while the iframe is still loading.
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   // Wait for the iframe request to arrive, and leave it hanging with no
   // response.
@@ -669,7 +669,7 @@
   shell()->LoadURL(url);
 
   // The navigation finishes while the iframe within an iframe is still loading.
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   // Wait for the innermost iframe request to arrive, and leave it hanging with
   // no response.
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 08339bc..76807a5 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -29,8 +29,10 @@
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h"
+#include "content/browser/renderer_host/back_forward_cache_disable.h"
 #include "content/browser/renderer_host/back_forward_cache_impl.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/should_swap_browsing_instance.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/content_navigation_policy.h"
@@ -66,6 +68,8 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
@@ -2345,7 +2349,7 @@
       testing::Property(
           "disabled_reasons",
           &BackForwardCacheCanStoreDocumentResult::disabled_reasons,
-          std::set<BackForwardCache::DisabledReason>()),
+          BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap()),
       testing::Property(
           "disallow_activation_reasons",
           &BackForwardCacheCanStoreDocumentResult::disallow_activation_reasons,
@@ -2724,6 +2728,46 @@
   ExpectRestored(FROM_HERE);
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DisableForRenderFrameHost) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostWrapper rfh_wrapper_a(current_frame_host());
+
+  // 2) Navigate to B.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostWrapper rfh_wrapper_b(current_frame_host());
+
+  // Regardless of whether the source Id is set or not, it shouldn't affect the
+  // result of the BFCache eviction.
+  BackForwardCache::DisabledReason test_reason =
+      BackForwardCacheDisable::DisabledReason(
+          BackForwardCacheDisable::DisabledReasonId::kUnknown);
+
+  // 3) Disable BFCache for A with UKM source Id and go back.
+  BackForwardCache::DisableForRenderFrameHost(
+      rfh_wrapper_a.get(), test_reason, ukm::UkmRecorder::GetNewSourceID());
+  ASSERT_TRUE(HistoryGoBack(web_contents()));
+  ASSERT_TRUE(rfh_wrapper_a.WaitUntilRenderFrameDeleted());
+  // Page A should be evicted properly.
+  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
+                         kDisableForRenderFrameHostCalled},
+                    {}, {}, {test_reason}, {}, FROM_HERE);
+
+  // 4) Disable BFCache for B without UKM source Id and go forward.
+  BackForwardCache::DisableForRenderFrameHost(rfh_wrapper_b.get(), test_reason);
+  ASSERT_TRUE(HistoryGoForward(web_contents()));
+  ASSERT_TRUE(rfh_wrapper_b.WaitUntilRenderFrameDeleted());
+  // Page B should be evicted properly.
+  ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
+                         kDisableForRenderFrameHostCalled},
+                    {}, {}, {test_reason}, {}, FROM_HERE);
+}
+
 namespace {
 enum class SubframeType { SameSite, CrossSite };
 }
diff --git a/content/browser/back_forward_cache_features_browsertest.cc b/content/browser/back_forward_cache_features_browsertest.cc
index bf4d3b5..f629d47 100644
--- a/content/browser/back_forward_cache_features_browsertest.cc
+++ b/content/browser/back_forward_cache_features_browsertest.cc
@@ -2315,7 +2315,7 @@
   ASSERT_TRUE(rfh_receiving.get()->GetBackForwardCacheDisablingFeatures().Has(
       tracked_feature));
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   ASSERT_TRUE(queue_sending_version_change.WaitForMessage(
       &message_sending_version_change));
@@ -2400,7 +2400,7 @@
       tracked_feature));
 
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   ASSERT_TRUE(queue_sending_version_change.WaitForMessage(
       &message_sending_version_change));
diff --git a/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc b/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc
index 6d2e6cdc..00c1260 100644
--- a/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc
+++ b/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc
@@ -383,7 +383,7 @@
   auto* reasons_after_redirect =
       navigation_request->commit_params().not_restored_reasons.get();
   EXPECT_THAT(reasons_after_redirect, nullptr);
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   // Eviction reasons should be recorded internally.
   ExpectNotRestored({NotRestoredReason::kJavaScriptExecution}, {}, {}, {}, {},
diff --git a/content/browser/background_sync/background_sync_launcher.cc b/content/browser/background_sync/background_sync_launcher.cc
index 5bb1e360..b1b9d4e 100644
--- a/content/browser/background_sync/background_sync_launcher.cc
+++ b/content/browser/background_sync/background_sync_launcher.cc
@@ -67,11 +67,11 @@
   if (sync_type == blink::mojom::BackgroundSyncType::PERIODIC)
     last_browser_wakeup_for_periodic_sync_ = base::Time::Now();
   base::RepeatingClosure done_closure = base::BarrierClosure(
-      browser_context->GetStoragePartitionCount(),
+      browser_context->GetLoadedStoragePartitionCount(),
       base::BindOnce(base::android::RunRunnableAndroid,
                      base::android::ScopedJavaGlobalRef<jobject>(j_runnable)));
 
-  browser_context->ForEachStoragePartition(base::BindRepeating(
+  browser_context->ForEachLoadedStoragePartition(base::BindRepeating(
       [](blink::mojom::BackgroundSyncType sync_type,
          base::OnceClosure done_closure, StoragePartition* storage_partition) {
         BackgroundSyncContext* sync_context =
@@ -113,7 +113,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   SetGlobalSoonestWakeupDelta(sync_type, base::TimeDelta::Max());
-  browser_context->ForEachStoragePartition(base::BindRepeating(
+  browser_context->ForEachLoadedStoragePartition(base::BindRepeating(
       &BackgroundSyncLauncher::GetSoonestWakeupDeltaForStoragePartition,
       base::Unretained(this), sync_type));
 
diff --git a/content/browser/background_sync/background_sync_launcher_unittest.cc b/content/browser/background_sync/background_sync_launcher_unittest.cc
index 2483c8c..1a802af 100644
--- a/content/browser/background_sync/background_sync_launcher_unittest.cc
+++ b/content/browser/background_sync/background_sync_launcher_unittest.cc
@@ -98,7 +98,7 @@
     auto done_closure = base::BindLambdaForTesting(
         [&]() { num_invocations_fire_background_sync_events_++; });
 
-    test_browser_context_.ForEachStoragePartition(
+    test_browser_context_.ForEachLoadedStoragePartition(
         base::BindRepeating(
             [](base::OnceClosure done_closure,
                StoragePartition* storage_partition) {
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 44d8c3a..aba67ba 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -148,7 +148,7 @@
   return GetStoragePartition(storage_partition_config, can_create);
 }
 
-void BrowserContext::ForEachStoragePartition(
+void BrowserContext::ForEachLoadedStoragePartition(
     StoragePartitionCallback callback) {
   StoragePartitionImplMap* partition_map = impl()->storage_partition_map();
   if (!partition_map)
@@ -166,7 +166,7 @@
   partition_map->DisposeInMemory(storage_partition);
 }
 
-size_t BrowserContext::GetStoragePartitionCount() {
+size_t BrowserContext::GetLoadedStoragePartitionCount() {
   StoragePartitionImplMap* partition_map = impl()->storage_partition_map();
   return partition_map ? partition_map->size() : 0;
 }
diff --git a/content/browser/browser_context_impl.cc b/content/browser/browser_context_impl.cc
index c532198c..7bf734c 100644
--- a/content/browser/browser_context_impl.cc
+++ b/content/browser/browser_context_impl.cc
@@ -137,9 +137,9 @@
   // Shut down service worker and shared worker machinery because these can keep
   // RenderProcessHosts and SiteInstances alive, and the codebase assumes these
   // are destroyed before the BrowserContext is destroyed.
-  self_->ForEachStoragePartition(
+  self_->ForEachLoadedStoragePartition(
       base::BindRepeating(ShutdownServiceWorkerContext));
-  self_->ForEachStoragePartition(
+  self_->ForEachLoadedStoragePartition(
       base::BindRepeating(ShutdownSharedWorkerContext));
 
   // Also forcibly release keep alive refcounts on RenderProcessHosts, to ensure
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h
index f7fbd4e..67aa157 100644
--- a/content/browser/child_process_launcher_helper.h
+++ b/content/browser/child_process_launcher_helper.h
@@ -98,7 +98,7 @@
     base::Process process;
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-    ZygoteHandle zygote = nullptr;
+    ZygoteCommunication* zygote = nullptr;
 #endif  // BUILDFLAG(USE_ZYGOTE_HANDLE)
 
 #if BUILDFLAG(IS_FUCHSIA)
@@ -234,7 +234,7 @@
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
   // Returns the zygote handle for this particular launch, if any.
-  ZygoteHandle GetZygoteHandle();
+  ZygoteCommunication* GetZygoteForLaunch();
 #endif  // BUILDFLAG(USE_ZYGOTE_HANDLE)
 
   base::CommandLine* command_line() { return command_line_.get(); }
diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc
index f866050..b7f2123 100644
--- a/content/browser/child_process_launcher_helper_linux.cc
+++ b/content/browser/child_process_launcher_helper_linux.cc
@@ -45,14 +45,14 @@
 }
 
 bool ChildProcessLauncherHelper::IsUsingLaunchOptions() {
-  return !GetZygoteHandle();
+  return !GetZygoteForLaunch();
 }
 
 bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
     PosixFileDescriptorInfo& files_to_register,
     base::LaunchOptions* options) {
   if (options) {
-    DCHECK(!GetZygoteHandle());
+    DCHECK(!GetZygoteForLaunch());
     // Convert FD mapping to FileHandleMappingVector
     options->fds_to_remap = files_to_register.GetMappingWithIDAdjustment(
         base::GlobalDescriptors::kBaseDescriptor);
@@ -64,7 +64,7 @@
 
     options->environment = delegate_->GetEnvironment();
   } else {
-    DCHECK(GetZygoteHandle());
+    DCHECK(GetZygoteForLaunch());
     // Environment variables could be supported in the future, but are not
     // currently supported when launching with the zygote.
     DCHECK(delegate_->GetEnvironment().empty());
@@ -81,7 +81,7 @@
     int* launch_result) {
   *is_synchronous_launch = true;
   Process process;
-  ZygoteHandle zygote_handle = GetZygoteHandle();
+  ZygoteCommunication* zygote_handle = GetZygoteForLaunch();
   if (zygote_handle) {
     // TODO(crbug.com/569191): If chrome supported multiple zygotes they could
     // be created lazily here, or in the delegate GetZygote() implementations.
@@ -174,7 +174,7 @@
     process.SetProcessBackgrounded(is_background);
 }
 
-ZygoteHandle ChildProcessLauncherHelper::GetZygoteHandle() {
+ZygoteCommunication* ChildProcessLauncherHelper::GetZygoteForLaunch() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoZygote)
              ? nullptr
              : delegate_->GetZygote();
diff --git a/content/browser/cross_origin_opener_policy_browsertest.cc b/content/browser/cross_origin_opener_policy_browsertest.cc
index ab5d114a..20ec123 100644
--- a/content/browser/cross_origin_opener_policy_browsertest.cc
+++ b/content/browser/cross_origin_opener_policy_browsertest.cc
@@ -1081,7 +1081,7 @@
     crash_observer.reset();
 
     // Finish the navigation to the COOP page.
-    coop_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(coop_navigation.WaitForNavigationFinished());
     EXPECT_TRUE(coop_navigation.was_successful());
     EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
         initial_site_instance.get()));
@@ -1178,7 +1178,7 @@
     crash_observer.reset();
 
     // Finish the navigation to the non COOP page.
-    non_coop_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(non_coop_navigation.WaitForNavigationFinished());
     EXPECT_TRUE(non_coop_navigation.was_successful());
     EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
         initial_site_instance.get()));
@@ -1277,7 +1277,7 @@
     crash_observer.reset();
 
     // Finish the navigation to the COOP page.
-    coop_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(coop_navigation.WaitForNavigationFinished());
     EXPECT_TRUE(coop_navigation.was_successful());
     EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
         initial_site_instance.get()));
@@ -1434,7 +1434,7 @@
                        "iframe.src = $1;"
                        "document.body.appendChild(iframe);",
                        cross_site_iframe)));
-  iframe_navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(iframe_navigation.WaitForNavigationFinished());
   EXPECT_EQ(web_contents()
                 ->GetPrimaryMainFrame()
                 ->browsing_context_state()
@@ -1548,7 +1548,7 @@
                      ->render_manager()
                      ->speculative_frame_host());
 
-    non_coop_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(non_coop_navigation.WaitForNavigationFinished());
 
     EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
         initial_site_instance.get()));
@@ -1582,7 +1582,7 @@
       EXPECT_FALSE(speculative_rfh);
     }
 
-    coop_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(coop_navigation.WaitForNavigationFinished());
 
     EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
         initial_site_instance.get()));
@@ -1617,7 +1617,7 @@
       EXPECT_FALSE(speculative_rfh);
     }
 
-    non_coop_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(non_coop_navigation.WaitForNavigationFinished());
 
     EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
         initial_site_instance.get()));
@@ -1646,7 +1646,7 @@
                      ->render_manager()
                      ->speculative_frame_host());
 
-    coop_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(coop_navigation.WaitForNavigationFinished());
 
     EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
         initial_site_instance.get()));
@@ -2959,7 +2959,7 @@
                          "document.body.appendChild(iframe);",
                          isolated_page)));
 
-    same_origin_iframe_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(same_origin_iframe_navigation.WaitForNavigationFinished());
     EXPECT_TRUE(same_origin_iframe_navigation.was_successful());
     RenderFrameHostImpl* iframe_rfh =
         current_frame_host()->child_at(0)->current_frame_host();
@@ -2979,7 +2979,7 @@
                          "document.body.appendChild(iframe);",
                          isolated_page_b)));
 
-    cross_origin_iframe_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(cross_origin_iframe_navigation.WaitForNavigationFinished());
     EXPECT_TRUE(cross_origin_iframe_navigation.was_successful());
     RenderFrameHostImpl* iframe_rfh =
         current_frame_host()->child_at(1)->current_frame_host();
@@ -3085,7 +3085,7 @@
                          "document.body.appendChild(iframe);",
                          invalid_url)));
 
-    iframe_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(iframe_navigation.WaitForNavigationFinished());
     EXPECT_FALSE(iframe_navigation.was_successful());
     RenderFrameHostImpl* iframe_rfh =
         current_frame_host()->child_at(0)->current_frame_host();
@@ -3109,7 +3109,7 @@
                          "document.body.appendChild(iframe);",
                          error_url)));
 
-    iframe_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(iframe_navigation.WaitForNavigationFinished());
     EXPECT_FALSE(iframe_navigation.was_successful());
     RenderFrameHostImpl* iframe_rfh =
         current_frame_host()->child_at(0)->current_frame_host();
@@ -3134,7 +3134,7 @@
                          "document.body.appendChild(iframe);",
                          non_coep_page)));
 
-    iframe_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(iframe_navigation.WaitForNavigationFinished());
     EXPECT_FALSE(iframe_navigation.was_successful());
     RenderFrameHostImpl* iframe_rfh =
         current_frame_host()->child_at(0)->current_frame_host();
@@ -3424,7 +3424,7 @@
                        "document.body.appendChild(iframe);",
                        isolated_page_b)));
 
-  cross_origin_iframe_navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(cross_origin_iframe_navigation.WaitForNavigationFinished());
   EXPECT_TRUE(cross_origin_iframe_navigation.was_successful());
   RenderFrameHostImpl* iframe_rfh =
       current_frame_host()->child_at(0)->current_frame_host();
diff --git a/content/browser/cross_site_transfer_browsertest.cc b/content/browser/cross_site_transfer_browsertest.cc
index f567178..42c1406 100644
--- a/content/browser/cross_site_transfer_browsertest.cc
+++ b/content/browser/cross_site_transfer_browsertest.cc
@@ -84,7 +84,7 @@
     if (should_wait_for_navigation) {
       EXPECT_TRUE(navigation_manager->WaitForRequestStart());
       EXPECT_TRUE(navigation_manager->WaitForResponse());
-      navigation_manager->WaitForNavigationFinished();
+      ASSERT_TRUE(navigation_manager->WaitForNavigationFinished());
       EXPECT_TRUE(navigation_manager->was_successful());
     }
   }
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index a21d81c..9cf9f2d2 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -1931,7 +1931,8 @@
     const BackForwardCacheCanStoreDocumentResult::NotRestoredReasons
         not_restored_reasons,
     const blink::scheduler::WebSchedulerTrackedFeatures blocklisted_features,
-    const std::set<BackForwardCache::DisabledReason>& disabled_reasons) {
+    const BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap&
+        disabled_reasons) {
   auto reasons = std::make_unique<
       protocol::Array<Page::BackForwardCacheNotRestoredExplanation>>();
 
@@ -1951,7 +1952,7 @@
     } else if (not_restored_reason ==
                BackForwardCacheMetrics::NotRestoredReason::
                    kDisableForRenderFrameHostCalled) {
-      for (auto disabled_reason : disabled_reasons) {
+      for (const auto& [disabled_reason, _] : disabled_reasons) {
         auto reason =
             Page::BackForwardCacheNotRestoredExplanation::Create()
                 .SetType(
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 60f0f97..50ddf39 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -465,7 +465,7 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-  ZygoteHandle GetZygote() override {
+  ZygoteCommunication* GetZygote() override {
     if (sandbox::policy::IsUnsandboxedSandboxType(GetSandboxType()))
       return nullptr;
 
diff --git a/content/browser/indexed_db/indexed_db_internals_ui.cc b/content/browser/indexed_db/indexed_db_internals_ui.cc
index f28b767..b45de43 100644
--- a/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -78,7 +78,7 @@
   BrowserContext* browser_context =
       web_ui()->GetWebContents()->GetBrowserContext();
   auto collect_partitions = base::BarrierCallback<IdbPartitionMetadataPtr>(
-      browser_context->GetStoragePartitionCount(),
+      browser_context->GetLoadedStoragePartitionCount(),
       base::BindOnce(
           [](GetAllBucketsAcrossAllStorageKeysCallback callback,
              std::vector<IdbPartitionMetadataPtr> partitions) {
@@ -86,7 +86,7 @@
           },
           std::move(callback)));
 
-  browser_context->ForEachStoragePartition(base::BindRepeating(
+  browser_context->ForEachLoadedStoragePartition(base::BindRepeating(
       [](base::WeakPtr<IndexedDBInternalsUI> handler,
          base::RepeatingCallback<void(IdbPartitionMetadataPtr)>
              collect_partitions,
@@ -140,7 +140,7 @@
       web_ui()->GetWebContents()->GetBrowserContext();
 
   storage::mojom::IndexedDBControl* control = nullptr;
-  browser_context->ForEachStoragePartition(base::BindRepeating(
+  browser_context->ForEachLoadedStoragePartition(base::BindRepeating(
       [](const base::FilePath& partition_path,
          storage::mojom::IndexedDBControl** control,
          StoragePartition* storage_partition) {
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index 43a73563..78b5676 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -2479,7 +2479,7 @@
   EXPECT_TRUE(NavigateToURL(tab2, isolated_origin_url));
 
   // Now commit the non-isolated navigation.
-  non_isolated_delayer.WaitForNavigationFinished();
+  ASSERT_TRUE(non_isolated_delayer.WaitForNavigationFinished());
 
   FrameTreeNode* tab1_root = web_contents()->GetPrimaryFrameTree().root();
   SiteInstanceImpl* tab1_site_instance =
@@ -3162,7 +3162,7 @@
     TestNavigationManager manager(new_shell->web_contents(), isolated_url);
     EXPECT_TRUE(ExecJs(
         child, "window.w.location.href = '" + isolated_url.spec() + "';"));
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
   }
 
   // Simulate the isolated origin in the popup navigating back to bar.com.
@@ -3171,7 +3171,7 @@
     TestNavigationManager manager(new_shell->web_contents(), bar_url2);
     EXPECT_TRUE(
         ExecJs(new_shell, "location.href = '" + bar_url2.spec() + "';"));
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
   }
 
   // Check that the popup ended up in the same SiteInstance as its same-site
@@ -3217,7 +3217,7 @@
     TestNavigationManager manager(new_shell->web_contents(), isolated_url);
     EXPECT_TRUE(ExecJs(
         root, "window.w.location.href = '" + isolated_url.spec() + "';"));
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
   }
 
   // Simulate the isolated origin in the popup navigating to bar.com.
@@ -3225,7 +3225,7 @@
   {
     TestNavigationManager manager(new_shell->web_contents(), bar_url);
     EXPECT_TRUE(ExecJs(new_shell, "location.href = '" + bar_url.spec() + "';"));
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
   }
 
   const SiteInstanceImpl* const root_site_instance_impl =
@@ -3251,7 +3251,7 @@
   {
     TestNavigationManager manager(new_shell->web_contents(), foo_url);
     EXPECT_TRUE(ExecJs(new_shell, "location.href = '" + foo_url.spec() + "';"));
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
   }
 
   // The popup should now be in the same SiteInstance as its same-site opener.
@@ -3470,10 +3470,10 @@
   // Now, proceed with the response and commit the non-isolated URL.  This
   // should notice that the process that was picked for this navigation is not
   // suitable anymore, as it should have been locked to isolated.foo.com.
-  foo_delayer.WaitForNavigationFinished();
+  ASSERT_TRUE(foo_delayer.WaitForNavigationFinished());
 
   // Commit the isolated origin.
-  isolated_delayer.WaitForNavigationFinished();
+  ASSERT_TRUE(isolated_delayer.WaitForNavigationFinished());
 
   // Ensure that the isolated origin did not share a process with the first
   // tab.
@@ -3522,7 +3522,7 @@
   // process is no longer suitable for the final destination (which is an
   // unisolated URL) and transfer to another process.  In
   // https://crbug.com/773809, this led to a CHECK due to origin lock mismatch.
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
 
   // Ensure that the isolated origin did not share a process with the first
   // tab.
@@ -3574,7 +3574,7 @@
   // Wait for response in the first tab.  This should notice that the first
   // process is no longer suitable for the isolated origin because it should
   // already be marked as used, and transfer to another process.
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
 
   // Ensure that the isolated origin did not share a process with the second
   // tab.
@@ -3613,7 +3613,7 @@
   EXPECT_TRUE(NavigateToURL(new_shell, isolated_url));
 
   // Finish loading the foo.com URL.
-  foo_delayer.WaitForNavigationFinished();
+  ASSERT_TRUE(foo_delayer.WaitForNavigationFinished());
 
   // Ensure that the isolated origin did not share a process with the first
   // tab.
@@ -5675,7 +5675,7 @@
     TestNavigationManager manager(new_shell->web_contents(), isolated_url);
     EXPECT_TRUE(ExecJs(
         root, "window.w.location.href = '" + isolated_url.spec() + "';"));
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
   }
 
   // The popup and the opener should not share a SiteInstance, but should
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index e9184f9e..4c4c64a 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -685,7 +685,7 @@
 
   // The navigation should commit without being blocked.
   EXPECT_TRUE(manager.WaitForResponse());
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
   EXPECT_EQ(kInsecureUrl, web_contents()->GetLastCommittedURL());
 }
 
@@ -733,7 +733,7 @@
 
   // The navigation should commit without being blocked.
   EXPECT_TRUE(manager.WaitForResponse());
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
   EXPECT_EQ(kDestination, web_contents()->GetLastCommittedURL());
 }
 
@@ -869,7 +869,7 @@
 
   // The renderer commits the navigation and the browser deletes its
   // NavigationRequest.
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
   EXPECT_FALSE(main_frame()->navigation_request());
 
   // The NavigationURLLoader has been deleted by now. Check that the renderer
@@ -1334,10 +1334,10 @@
     // begins and ends.
     TestNavigationManager push_state_navigation(web_contents(), main_url);
     ExecuteScriptAsync(shell(), "window.history.pushState({}, null);");
-    push_state_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(push_state_navigation.WaitForNavigationFinished());
 
     // The iframe navigation is resumed.
-    iframe_navigation.WaitForNavigationFinished();
+    ASSERT_TRUE(iframe_navigation.WaitForNavigationFinished());
   }
 
   // 3) history.back() must work.
@@ -1601,7 +1601,7 @@
   shell()->LoadURL(url_2);
   run_loop.Run();
 
-  navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation.WaitForNavigationFinished());
 
   EXPECT_TRUE(navigation.was_successful());
 }
@@ -1626,7 +1626,7 @@
                      EXECUTE_SCRIPT_NO_USER_GESTURE));
 
   // 3) The first pending navigation is not canceled and can continue.
-  navigation.WaitForNavigationFinished();  // Resume navigation.
+  ASSERT_TRUE(navigation.WaitForNavigationFinished());  // Resume navigation.
   EXPECT_TRUE(navigation.was_successful());
 }
 
@@ -1649,7 +1649,7 @@
                      "history.back();"));
 
   // 3) Check the first pending navigation has been canceled.
-  navigation.WaitForNavigationFinished();  // Resume navigation.
+  ASSERT_TRUE(navigation.WaitForNavigationFinished());  // Resume navigation.
   EXPECT_FALSE(navigation.was_successful());
 }
 
@@ -1776,7 +1776,7 @@
   TestNavigationManager manager(web_contents(), data_url);
   EXPECT_TRUE(ExecJs(popup, base::StringPrintf("window.opener.location ='%s'",
                                                data_url.spec().c_str())));
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
 
   EXPECT_FALSE(manager.was_successful());
 
@@ -2142,7 +2142,7 @@
 
   // Wait for navigation in new WebContents to finish.
   NewWebContentsData data = crash_observer.TakeNewWebContentsData();
-  data.manager->WaitForNavigationFinished();
+  ASSERT_TRUE(data.manager->WaitForNavigationFinished());
 
   // Test passes if renderer is still alive.
   EXPECT_TRUE(ExecJs(data.new_web_contents.get(), "true;"));
@@ -2326,7 +2326,7 @@
       let subwindow = document.querySelector('iframe').contentWindow;
       subwindow.location.search = "1";
     )"));
-    commit_waiter.WaitForNavigationFinished();
+    ASSERT_TRUE(commit_waiter.WaitForNavigationFinished());
   }
 
   //  3) Cross-document navigation to about:srcdoc?2.
@@ -2336,7 +2336,7 @@
       let subwindow = document.querySelector('iframe').contentWindow;
       subwindow.location.search = "2";
     )"));
-    commit_waiter.WaitForNavigationFinished();
+    ASSERT_TRUE(commit_waiter.WaitForNavigationFinished());
   }
 
   // Inspect the session history.
@@ -2628,7 +2628,7 @@
       main_frame()->navigation_request()->GetNextPageUkmSourceId();
 
   EXPECT_TRUE(manager.WaitForResponse());
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
   EXPECT_EQ(current_frame_host()->GetPageUkmSourceId(), nav_request_id);
 }
 
@@ -2653,7 +2653,7 @@
       subframe->navigation_request()->GetNextPageUkmSourceId();
 
   EXPECT_TRUE(manager.WaitForResponse());
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
 
   // Should have the same page UKM ID in navigation as page post commit, and as
   // the top-level frame.
@@ -4068,7 +4068,7 @@
 
   EXPECT_TRUE(navigation_manager.WaitForResponse());
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
   EXPECT_TRUE(WaitForLoadStop(web_contents()));
   EXPECT_TRUE(WaitForRenderFrameReady(current_frame_host()));
 
@@ -4124,7 +4124,7 @@
 
   EXPECT_TRUE(navigation_manager.WaitForResponse());
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
   EXPECT_TRUE(WaitForLoadStop(web_contents()));
   EXPECT_TRUE(WaitForRenderFrameReady(current_frame_host()));
 
@@ -4179,7 +4179,7 @@
 
   EXPECT_TRUE(navigation_manager.WaitForResponse());
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   EXPECT_TRUE(WaitForLoadStop(web_contents()));
   EXPECT_TRUE(WaitForRenderFrameReady(current_frame_host()));
@@ -4226,7 +4226,7 @@
 
   EXPECT_TRUE(navigation_manager.WaitForResponse());
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   EXPECT_TRUE(WaitForLoadStop(web_contents()));
   EXPECT_TRUE(WaitForRenderFrameReady(current_frame_host()));
@@ -4247,7 +4247,7 @@
   absl::optional<url::Origin> origin_to_commit =
       navigation->GetOriginToCommit();
   ASSERT_TRUE(origin_to_commit.has_value());
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
   url::Origin origin_committed = current_frame_host()->GetLastCommittedOrigin();
 
   EXPECT_FALSE(origin_to_commit->opaque());
@@ -4265,7 +4265,7 @@
   absl::optional<url::Origin> origin_to_commit =
       navigation->GetOriginToCommit();
   EXPECT_FALSE(origin_to_commit.has_value());
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
 }
 
 IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
@@ -4277,7 +4277,7 @@
   EXPECT_TRUE(manager.WaitForResponse());
   NavigationRequest* navigation = main_frame()->navigation_request();
   url::Origin origin_to_commit = navigation->GetOriginToCommit().value();
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
   url::Origin origin_committed = current_frame_host()->GetLastCommittedOrigin();
 
   EXPECT_TRUE(origin_to_commit.opaque());
@@ -4302,7 +4302,7 @@
   FrameTreeNode* iframe = current_frame_host()->child_at(0);
   NavigationRequest* navigation = iframe->navigation_request();
   url::Origin origin_to_commit = navigation->GetOriginToCommit().value();
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
   url::Origin origin_committed =
       iframe->current_frame_host()->GetLastCommittedOrigin();
 
@@ -4329,7 +4329,7 @@
       "a.com", "/set-header?Content-Security-Policy: sandbox");
   TestNavigationManager manager(web_contents(), url);
   shell()->LoadURL(url);
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
 
   // An error page committed. It doesn't have any sandbox flags, despite the
   // original response headers.
@@ -4464,7 +4464,7 @@
     iframe.sandbox = "allow-orientation-lock";
     document.body.appendChild(iframe);
   )");
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
 
   RenderFrameHostImpl* child_rfh =
       current_frame_host()->child_at(0)->current_frame_host();
@@ -4488,7 +4488,7 @@
   FrameTreeNode* iframe = current_frame_host()->child_at(0);
   NavigationRequest* navigation = iframe->navigation_request();
   url::Origin origin_to_commit = navigation->GetOriginToCommit().value();
-  manager.WaitForNavigationFinished();
+  ASSERT_TRUE(manager.WaitForNavigationFinished());
   url::Origin origin_committed =
       iframe->current_frame_host()->GetLastCommittedOrigin();
 
@@ -4514,8 +4514,8 @@
   TestNavigationManager manager_1(popup_contents, url_b);
   TestNavigationManager manager_2(popup_contents, GURL("about:blank"));
 
-  manager_1.WaitForNavigationFinished();
-  manager_2.WaitForNavigationFinished();
+  ASSERT_TRUE(manager_1.WaitForNavigationFinished());
+  ASSERT_TRUE(manager_2.WaitForNavigationFinished());
 
   EXPECT_EQ(popup_contents->GetLastCommittedURL(), "about:blank");
 }
diff --git a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc
index ea83b0a..0b9ab56 100644
--- a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc
+++ b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc
@@ -65,7 +65,7 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-ZygoteHandle PpapiPluginSandboxedProcessLauncherDelegate::GetZygote() {
+ZygoteCommunication* PpapiPluginSandboxedProcessLauncherDelegate::GetZygote() {
   const base::CommandLine& browser_command_line =
       *base::CommandLine::ForCurrentProcess();
   base::CommandLine::StringType plugin_launcher =
diff --git a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.h b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.h
index bda4cad..efe50a9 100644
--- a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.h
+++ b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.h
@@ -34,7 +34,7 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-  ZygoteHandle GetZygote() override;
+  ZygoteCommunication* GetZygote() override;
 #endif  // BUILDFLAG(USE_ZYGOTE_HANDLE)
 
   sandbox::mojom::Sandbox GetSandboxType() override;
diff --git a/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc b/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc
index 9d061adc..cd2e8d2 100644
--- a/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc
+++ b/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc
@@ -271,10 +271,10 @@
 
 namespace {
 std::string DisabledReasonsToString(
-    const std::set<BackForwardCache::DisabledReason>& reasons,
+    const BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap& reasons,
     bool for_not_restored_reasons = false) {
   std::vector<std::string> descriptions;
-  for (const auto& reason : reasons) {
+  for (const auto& [reason, _] : reasons) {
     std::string string_to_add;
     if (for_not_restored_reasons) {
       // When |for_not_restored_reasons| is true, prepare a string to report to
@@ -564,10 +564,11 @@
 
 void BackForwardCacheCanStoreDocumentResult::
     NoDueToDisableForRenderFrameHostCalled(
-        const std::set<BackForwardCache::DisabledReason>& reasons) {
+        const BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap&
+            reasons) {
   // This should only be called with non-empty reasons.
   DCHECK(reasons.size());
-  for (const BackForwardCache::DisabledReason& reason : reasons) {
+  for (const auto& reason : reasons) {
     disabled_reasons_.insert(reason);
     // This will be a no-op after the first time but it's written like this to
     // guarantee that we do not set it without a reason.
@@ -605,8 +606,7 @@
     const BackForwardCacheCanStoreDocumentResult& other) {
   not_restored_reasons_.PutAll(other.not_restored_reasons_);
   blocklisted_features_.PutAll(other.blocklisted_features());
-  for (const BackForwardCache::DisabledReason& reason :
-       other.disabled_reasons()) {
+  for (const auto& reason : other.disabled_reasons()) {
     disabled_reasons_.insert(reason);
   }
   if (other.browsing_instance_swap_result_)
diff --git a/content/browser/renderer_host/back_forward_cache_can_store_document_result.h b/content/browser/renderer_host/back_forward_cache_can_store_document_result.h
index 96f14b7a66..302e28c 100644
--- a/content/browser/renderer_host/back_forward_cache_can_store_document_result.h
+++ b/content/browser/renderer_host/back_forward_cache_can_store_document_result.h
@@ -16,6 +16,7 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/render_frame_host.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 #include "ui/accessibility/ax_event.h"
@@ -36,6 +37,18 @@
                     BackForwardCacheMetrics::NotRestoredReason::kMinValue,
                     BackForwardCacheMetrics::NotRestoredReason::kMaxValue>;
 
+  // This data structure stores the set of `BackForwardCache::DisabledReason`s
+  // and their associated UKM source ID which indicate the source of the
+  // `DisabledReason`. The associated source ID is optional and is only set
+  // under certain scenarios like when the disabling call comes from an
+  // extension, in this case, the source ID will be the one bound to the
+  // extension URL. If the source ID value is not set, it means we should fall
+  // back to use the information that is obtained elsewhere. For example, if the
+  // source ID is set, then it will be reported to UKM metrics; if it's not set,
+  // then the source id from the navigation itself will be used.
+  using DisabledReasonsMap = std::map<BackForwardCache::DisabledReason,
+                                      std::set<absl::optional<ukm::SourceId>>>;
+
   BackForwardCacheCanStoreDocumentResult();
   BackForwardCacheCanStoreDocumentResult(
       BackForwardCacheCanStoreDocumentResult&);
@@ -59,7 +72,7 @@
   // TODO(hajimehoshi): Replace the arbitrary strings with base::Location /
   // FROM_HERE for privacy reasons.
   void NoDueToDisableForRenderFrameHostCalled(
-      const std::set<BackForwardCache::DisabledReason>& reasons);
+      const DisabledReasonsMap& reasons);
   void NoDueToDisallowActivation(uint64_t reason);
   // TODO(crbug.com/1341507): Remove this function.
   void NoDueToAXEvents(const std::vector<ui::AXEvent>& events);
@@ -77,7 +90,7 @@
     return blocklisted_features_;
   }
 
-  const std::set<BackForwardCache::DisabledReason>& disabled_reasons() const {
+  const DisabledReasonsMap& disabled_reasons() const {
     return disabled_reasons_;
   }
 
@@ -111,7 +124,7 @@
 
   NotRestoredReasons not_restored_reasons_;
   BlockListedFeatures blocklisted_features_;
-  std::set<BackForwardCache::DisabledReason> disabled_reasons_;
+  DisabledReasonsMap disabled_reasons_;
   absl::optional<ShouldSwapBrowsingInstance> browsing_instance_swap_result_;
   std::set<uint64_t> disallow_activation_reasons_;
   // The list of the accessibility events that made the page bfcache ineligible.
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc
index b34044e2..3b856b7 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -37,6 +37,7 @@
 #include "content/public/browser/visibility.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 #include "third_party/blink/public/mojom/frame/sudden_termination_disabler_type.mojom-shared.h"
@@ -1217,20 +1218,23 @@
 // static
 void BackForwardCache::DisableForRenderFrameHost(
     RenderFrameHost* render_frame_host,
-    BackForwardCache::DisabledReason reason) {
-  DisableForRenderFrameHost(render_frame_host->GetGlobalId(), reason);
+    DisabledReason reason,
+    absl::optional<ukm::SourceId> source_id) {
+  DisableForRenderFrameHost(render_frame_host->GetGlobalId(), reason,
+                            source_id);
 }
 
 // static
 void BackForwardCache::DisableForRenderFrameHost(
     GlobalRenderFrameHostId id,
-    BackForwardCache::DisabledReason reason) {
+    DisabledReason reason,
+    absl::optional<ukm::SourceId> source_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (g_bfcache_disabled_test_observer)
     g_bfcache_disabled_test_observer->OnDisabledForFrameWithReason(id, reason);
 
   if (auto* rfh = RenderFrameHostImpl::FromID(id))
-    rfh->DisableBackForwardCache(reason);
+    rfh->DisableBackForwardCache(reason, source_id);
 }
 
 void BackForwardCacheImpl::DisableForTesting(DisableForTestingReason reason) {
diff --git a/content/browser/renderer_host/back_forward_cache_metrics.cc b/content/browser/renderer_host/back_forward_cache_metrics.cc
index b59f46fc..cb2bf86 100644
--- a/content/browser/renderer_host/back_forward_cache_metrics.cc
+++ b/content/browser/renderer_host/back_forward_cache_metrics.cc
@@ -17,11 +17,13 @@
 #include "content/browser/renderer_host/should_swap_browsing_instance.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/common/debug_utils.h"
+#include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/reload_type.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 #include "ui/accessibility/ax_event.h"
 #include "url/gurl.h"
@@ -235,8 +237,19 @@
   browsing_instance_swap_result_ = absl::nullopt;
 }
 
+namespace {
+
+void RecordDisabledForRenderFrameHostReasonUKM(ukm::SourceId source_id,
+                                               uint64_t reason) {
+  ukm::builders::BackForwardCacheDisabledForRenderFrameHostReason(source_id)
+      .SetReason2(reason)
+      .Record(ukm::UkmRecorder::Get());
+}
+
+}  // namespace
+
 void BackForwardCacheMetrics::RecordHistoryNavigationUKM(
-    NavigationRequest* navigation) const {
+    NavigationRequest* navigation) {
   DCHECK(IsCrossDocumentMainFrameHistoryNavigation(navigation));
   // We've visited an entry associated with this main frame document before,
   // so record metrics to determine whether it might be a back-forward cache
@@ -288,12 +301,19 @@
 
   builder.Record(ukm::UkmRecorder::Get());
 
-  for (const BackForwardCache::DisabledReason& reason :
+  for (const auto& [reason, associated_source_ids] :
        page_store_result_->disabled_reasons()) {
-    ukm::builders::BackForwardCacheDisabledForRenderFrameHostReason
-        rfh_reason_builder(source_id);
-    rfh_reason_builder.SetReason2(MetricValue(reason));
-    rfh_reason_builder.Record(ukm::UkmRecorder::Get());
+    uint64_t reason_value = MetricValue(reason);
+    // We always record the event under the source id that was obtained from
+    // the navigation.
+    RecordDisabledForRenderFrameHostReasonUKM(source_id, reason_value);
+
+    for (const auto& associated_source_id : associated_source_ids) {
+      if (associated_source_id.has_value()) {
+        RecordDisabledForRenderFrameHostReasonUKM(associated_source_id.value(),
+                                                  reason_value);
+      }
+    }
   }
 
   for (const uint64_t reason :
@@ -486,8 +506,7 @@
         feature);
   }
 
-  for (const BackForwardCache::DisabledReason& reason :
-       page_store_result_->disabled_reasons()) {
+  for (const auto& [reason, _] : page_store_result_->disabled_reasons()) {
     // Use SparseHistogram instead of other simple macros for metrics. The
     // reasons cannot be represented as a unified enum because they come from
     // multiple sources. At first they were represented as strings but that
diff --git a/content/browser/renderer_host/back_forward_cache_metrics.h b/content/browser/renderer_host/back_forward_cache_metrics.h
index 10a05cf..39a6167 100644
--- a/content/browser/renderer_host/back_forward_cache_metrics.h
+++ b/content/browser/renderer_host/back_forward_cache_metrics.h
@@ -287,7 +287,7 @@
   void RecordHistoryNavigationUMA(NavigationRequest* navigation,
                                   bool back_forward_cache_allowed) const;
   // Records UKM for a history navigation.
-  void RecordHistoryNavigationUKM(NavigationRequest* navigation) const;
+  void RecordHistoryNavigationUKM(NavigationRequest* navigation);
 
   // Record metrics for the number of reloads after history navigation. In
   // particular we are interested in number of reloads after a restore from
@@ -302,8 +302,8 @@
   // (`browsing_instance_swap_result_` is not set).  Returns false otherwise.
   bool DidSwapBrowsingInstance() const;
 
-  // Main frame document sequence number that identifies all NavigationEntries
-  // this metrics object is associated with.
+  // Main frame document sequence number that identifies all
+  // NavigationEntries this metrics object is associated with.
   const int64_t document_sequence_number_;
 
   // NavigationHandle's ID for the last cross-document main frame navigation
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 33c6c9b..485750a7 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1984,8 +1984,9 @@
 }
 
 void RenderFrameHostImpl::DisableBackForwardCache(
-    BackForwardCache::DisabledReason reason) {
-  back_forward_cache_disabled_reasons_.insert(reason);
+    BackForwardCache::DisabledReason reason,
+    absl::optional<ukm::SourceId> source_id) {
+  back_forward_cache_disabled_reasons_[reason].insert(source_id);
   MaybeEvictFromBackForwardCache();
 }
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 814caa2..52b28e6 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -71,6 +71,7 @@
 #include "content/common/input/input_injector.mojom-forward.h"
 #include "content/common/navigation_client.mojom-forward.h"
 #include "content/common/navigation_client.mojom.h"
+#include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/global_request_id.h"
@@ -1628,15 +1629,17 @@
   // Prevents this frame (along with its parents/children) from being added to
   // the BackForwardCache. If the frame is already in the cache an eviction is
   // triggered.
-  void DisableBackForwardCache(BackForwardCache::DisabledSource source,
-                               BackForwardCache::DisabledReasonType reason);
-  void DisableBackForwardCache(BackForwardCache::DisabledReason reason);
+  // For what `source_id` means and when it's set, see `DisabledReasonsMap` from
+  // `back_forward_cache_can_store_document_result.h`.
+  void DisableBackForwardCache(
+      BackForwardCache::DisabledReason reason,
+      absl::optional<ukm::SourceId> source_id = absl::nullopt);
 
   bool is_evicted_from_back_forward_cache() {
     return is_evicted_from_back_forward_cache_;
   }
 
-  const std::set<BackForwardCache::DisabledReason>&
+  const BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap&
   back_forward_cache_disabled_reasons() const {
     return back_forward_cache_disabled_reasons_;
   }
@@ -4359,9 +4362,10 @@
   bool is_evicted_from_back_forward_cache_ = false;
   base::OneShotTimer back_forward_cache_eviction_timer_;
 
-  // The reasons given in BackForwardCache::DisableForRenderFrameHost. This is a
-  // breakdown of NotRestoredReason::kDisableForRenderFrameHostCalled.
-  std::set<BackForwardCache::DisabledReason>
+  // The map that stores the disabled reasons and the associated UKM source ID.
+  // The reasons are given in BackForwardCache::DisableForRenderFrameHost, which
+  // is a breakdown of NotRestoredReason::kDisableForRenderFrameHostCalled.
+  BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap
       back_forward_cache_disabled_reasons_;
 
   // Tracks whether the RenderFrameHost had ever been restored from back/forward
diff --git a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc
index 099ded6..ce87fdf 100644
--- a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc
+++ b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc
@@ -32,7 +32,7 @@
 namespace content {
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-ZygoteHandle RendererSandboxedProcessLauncherDelegate::GetZygote() {
+ZygoteCommunication* RendererSandboxedProcessLauncherDelegate::GetZygote() {
   const base::CommandLine& browser_command_line =
       *base::CommandLine::ForCurrentProcess();
   base::CommandLine::StringType renderer_prefix =
diff --git a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h
index 736b46e..1d011ff 100644
--- a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h
+++ b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h
@@ -21,7 +21,7 @@
   ~RendererSandboxedProcessLauncherDelegate() override = default;
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-  ZygoteHandle GetZygote() override;
+  ZygoteCommunication* GetZygote() override;
 #endif  // BUILDFLAG(USE_ZYGOTE_HANDLE)
 
 #if BUILDFLAG(IS_MAC)
diff --git a/content/browser/screen_orientation/screen_orientation_browsertest.cc b/content/browser/screen_orientation/screen_orientation_browsertest.cc
index 594b0336..5a297963 100644
--- a/content/browser/screen_orientation/screen_orientation_browsertest.cc
+++ b/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -370,7 +370,7 @@
                                        screen_info.orientation_type);
 
   // Let the navigation finish and make sure it succeeded.
-  delayer.WaitForNavigationFinished();
+  ASSERT_TRUE(delayer.WaitForNavigationFinished());
   EXPECT_EQ(second_url,
             web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
 
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 2ef8e3da..7224c0c 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -1353,7 +1353,7 @@
   RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
       shell()->web_contents()->GetPrimaryMainFrame());
   main_frame->GetFrameBindingsControl()->EnableMojoJsBindings(nullptr);
-  navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation.WaitForNavigationFinished());
 
   // Open a popup so that the process won't exit on its own when leaving.
   OpenBlankWindow(static_cast<WebContentsImpl*>(shell()->web_contents()));
diff --git a/content/browser/service_worker/service_worker_internals_ui.cc b/content/browser/service_worker/service_worker_internals_ui.cc
index 32fa3911..9e9239e 100644
--- a/content/browser/service_worker/service_worker_internals_ui.cc
+++ b/content/browser/service_worker/service_worker_internals_ui.cc
@@ -405,9 +405,9 @@
 void ServiceWorkerInternalsHandler::OnJavascriptDisallowed() {
   BrowserContext* browser_context =
       web_ui()->GetWebContents()->GetBrowserContext();
-  // Safe to use base::Unretained(this) because ForEachStoragePartition is
+  // Safe to use base::Unretained(this) because ForEachLoadedStoragePartition is
   // synchronous.
-  browser_context->ForEachStoragePartition(base::BindRepeating(
+  browser_context->ForEachLoadedStoragePartition(base::BindRepeating(
       &ServiceWorkerInternalsHandler::RemoveObserverFromStoragePartition,
       base::Unretained(this)));
   weak_ptr_factory_.InvalidateWeakPtrs();
@@ -506,8 +506,8 @@
   BrowserContext* browser_context =
       web_ui()->GetWebContents()->GetBrowserContext();
   // Safe to use base::Unretained(this) because
-  // ForEachStoragePartition is synchronous.
-  browser_context->ForEachStoragePartition(base::BindRepeating(
+  // ForEachLoadedStoragePartition is synchronous.
+  browser_context->ForEachLoadedStoragePartition(base::BindRepeating(
       &ServiceWorkerInternalsHandler::AddContextFromStoragePartition,
       base::Unretained(this)));
 }
@@ -567,7 +567,7 @@
   BrowserContext* browser_context =
       web_ui()->GetWebContents()->GetBrowserContext();
   StoragePartition* result_partition(nullptr);
-  browser_context->ForEachStoragePartition(base::BindRepeating(
+  browser_context->ForEachLoadedStoragePartition(base::BindRepeating(
       &ServiceWorkerInternalsHandler::FindStoragePartitionById,
       base::Unretained(this), partition_id, &result_partition));
   if (!result_partition)
diff --git a/content/browser/service_worker/service_worker_registry.cc b/content/browser/service_worker/service_worker_registry.cc
index 9cd62a2..d6ad9b2f 100644
--- a/content/browser/service_worker/service_worker_registry.cc
+++ b/content/browser/service_worker/service_worker_registry.cc
@@ -255,6 +255,10 @@
   // trace event id.
   int64_t trace_event_id =
       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds();
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerRegistry::FindRegistrationForClientUrl",
+      TRACE_ID_WITH_SCOPE("ServiceWorkerRegistry", trace_event_id),
+      TRACE_EVENT_FLAG_FLOW_OUT, "URL", client_url.spec());
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
       "ServiceWorker", "ServiceWorkerRegistry::FindRegistrationForClientUrl",
       TRACE_ID_WITH_SCOPE("ServiceWorkerRegistry::FindRegistrationForClientUrl",
@@ -977,6 +981,10 @@
     int64_t trace_event_id,
     storage::mojom::ServiceWorkerDatabaseStatus database_status,
     storage::mojom::ServiceWorkerFindRegistrationResultPtr result) {
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerRegistry::DidFindRegistrationForClientUrl",
+      TRACE_ID_WITH_SCOPE("ServiceWorkerRegistry", trace_event_id),
+      TRACE_EVENT_FLAG_FLOW_IN);
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (database_status != storage::mojom::ServiceWorkerDatabaseStatus::kOk &&
       database_status !=
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 2c60b3d..94c3218 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -3500,7 +3500,7 @@
         document.body.appendChild(fenced_frame);
     })";
     EXPECT_TRUE(ExecJs(parent, content::JsReplace(kAddFencedFrameScript, url)));
-    navigation.WaitForNavigationFinished();
+    EXPECT_TRUE(navigation.WaitForNavigationFinished());
 
     return ChildFrameAt(parent, 0);
   }
@@ -6601,11 +6601,11 @@
 
   // Now have the cross-process navigation commit and mark the current RFH as
   // pending deletion.
-  cross_site_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(cross_site_manager.WaitForNavigationFinished());
 
   // Resume the navigation in the previous RFH that has just been marked as
   // pending deletion. We should not crash.
-  transfer_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(transfer_manager.WaitForNavigationFinished());
 }
 
 class NavigationHandleWatcher : public WebContentsObserver {
@@ -8226,7 +8226,7 @@
   EXPECT_TRUE(child_proxy->is_render_frame_proxy_live());
 
   // Now let the main frame commit.
-  manager1.WaitForNavigationFinished();
+  ASSERT_TRUE(manager1.WaitForNavigationFinished());
 
   // Make sure the process is live and at the new URL.
   EXPECT_TRUE(b_root_site_instance->GetProcess()->IsInitializedAndNotDead());
@@ -8236,7 +8236,7 @@
 
   // The subframe should be gone, so the second navigation should have no
   // effect.
-  manager2.WaitForNavigationFinished();
+  ASSERT_TRUE(manager2.WaitForNavigationFinished());
 
   // The new commit should have detached the old child frame.
   EXPECT_EQ(0U, root->child_count());
@@ -8329,7 +8329,7 @@
   }
 
   // Now let the subframe commit.
-  manager2.WaitForNavigationFinished();
+  ASSERT_TRUE(manager2.WaitForNavigationFinished());
 
   // Make sure the process is live and at the new URL.
   EXPECT_TRUE(b_site_instance->GetProcess()->IsInitializedAndNotDead());
@@ -8529,7 +8529,7 @@
   NavigationCanceller canceller(
       web_contents(), *first_child->render_manager()->current_frame_host());
 
-  nav_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
   // The navigation should be committed if and only if it committed in a new
   // RFH (i.e. if the navigation used a speculative RFH).
   EXPECT_EQ(using_speculative_rfh, nav_manager.was_committed());
@@ -8588,7 +8588,7 @@
   EXPECT_EQ(using_speculative_rfh,
             GetRenderDocumentLevel() == RenderDocumentLevel::kSubframe);
 
-  nav_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
   // There should be no commit...
   EXPECT_FALSE(nav_manager.was_committed());
   // .. and the navigation should have been aborted.
@@ -8634,7 +8634,7 @@
   // Cross-site navigations always force a speculative RFH to be created.
   EXPECT_TRUE(first_child->render_manager()->speculative_frame_host());
 
-  nav_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
   // There should be no commit...
   EXPECT_FALSE(nav_manager.was_committed());
   // .. and the navigation should have been aborted.
@@ -8715,7 +8715,7 @@
   EXPECT_EQ(using_speculative_rfh,
             GetRenderDocumentLevel() == RenderDocumentLevel::kSubframe);
 
-  nav_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
   // There should be no commit...
   EXPECT_FALSE(nav_manager.was_committed());
   // .. and the navigation should have been aborted.
@@ -8797,7 +8797,7 @@
   // Cross-site navigations always force a speculative RFH to be created.
   EXPECT_TRUE(first_child->render_manager()->speculative_frame_host());
 
-  nav_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
   // There should be no commit...
   EXPECT_FALSE(nav_manager.was_committed());
   // .. and the navigation should have been aborted.
@@ -8849,7 +8849,7 @@
   // the URLLoaderInterceptor forces a network error.
   EXPECT_FALSE(nav_manager.WaitForResponse());
 
-  nav_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
   EXPECT_FALSE(nav_manager.was_committed());
 
   // Make sure that the speculative RFH has been cleaned up, if needed.
@@ -8887,7 +8887,7 @@
   // the URLLoaderInterceptor forces a network error.
   EXPECT_FALSE(nav_manager.WaitForResponse());
 
-  nav_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
   EXPECT_FALSE(nav_manager.was_committed());
 
   // Make sure that the speculative RFH has been cleaned up, if needed.
@@ -11674,7 +11674,7 @@
 
   // Resume and finish the cross-process navigation.
   cross_site_navigation.ResumeNavigation();
-  cross_site_navigation.WaitForNavigationFinished();
+  ASSERT_TRUE(cross_site_navigation.WaitForNavigationFinished());
   EXPECT_TRUE(cross_site_navigation.was_successful());
   EXPECT_EQ(url2, web_contents()->GetLastCommittedURL());
 }
@@ -12443,7 +12443,7 @@
             rfh_b->lifecycle_state());
 
   // The navigation has been canceled.
-  navigation_observer.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_observer.WaitForNavigationFinished());
   EXPECT_FALSE(navigation_observer.was_successful());
 
   // |rfh_b| will complete its deletion at some point:
@@ -12507,7 +12507,7 @@
             rfh_c->GetLifecycleState());
 
   // The navigation has been canceled.
-  navigation_observer.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_observer.WaitForNavigationFinished());
   EXPECT_FALSE(navigation_observer.was_successful());
 
   // |rfh_b| and |rfh_c| will complete their deletion at some point:
@@ -12659,7 +12659,7 @@
 
   // Resume the cross-site navigation and ensure it commits in a new
   // SiteInstance and process.
-  delayer.WaitForNavigationFinished();
+  ASSERT_TRUE(delayer.WaitForNavigationFinished());
   EXPECT_TRUE(web_contents()->GetPrimaryMainFrame()->IsRenderFrameLive());
   EXPECT_NE(web_contents()->GetPrimaryMainFrame()->GetProcess(), first_process);
   EXPECT_NE(web_contents()->GetPrimaryMainFrame()->GetSiteInstance(),
@@ -12841,7 +12841,7 @@
     TestNavigationManager navigation_manager(web_contents(),
                                              GURL("about:blank"));
     EXPECT_TRUE(ExecJs(b2_rfh, "location.href = 'about:blank';"));
-    navigation_manager.WaitForNavigationFinished();
+    ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
     RenderFrameHostImpl* b3_rfh = a1_rfh->child_at(0)->current_frame_host();
     DCHECK_EQ(b3_rfh->GetSiteInstance(), b2_site_instance);
@@ -12855,7 +12855,7 @@
     EXPECT_TRUE(ExecJs(a1_rfh, R"(
       document.querySelector("iframe").src = "about:blank";
     )"));
-    navigation_manager.WaitForNavigationFinished();
+    ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
     RenderFrameHostImpl* b4_rfh = a1_rfh->child_at(0)->current_frame_host();
     DCHECK_EQ(a1_rfh->GetSiteInstance(), b4_rfh->GetSiteInstance());
diff --git a/content/browser/site_per_process_sad_frame_browsertest.cc b/content/browser/site_per_process_sad_frame_browsertest.cc
index f2ffa302..236fb31 100644
--- a/content/browser/site_per_process_sad_frame_browsertest.cc
+++ b/content/browser/site_per_process_sad_frame_browsertest.cc
@@ -356,7 +356,7 @@
                                   1);
 
     // Ensure no new metrics are logged after the reload completes.
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
     EXPECT_TRUE(manager.was_successful());
     EXPECT_FALSE(controller.NeedsReload());
     EXPECT_EQ(1, controller.GetEntryCount());
@@ -410,7 +410,7 @@
                                   1);
 
     // Ensure no new metrics are logged after the navigation completes.
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
     EXPECT_TRUE(manager.was_successful());
     histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility",
                                   CrashVisibility::kShownWhileAncestorIsLoading,
@@ -490,7 +490,7 @@
                                   1);
 
     // Ensure no new metrics are logged after the navigation completes.
-    manager.WaitForNavigationFinished();
+    ASSERT_TRUE(manager.WaitForNavigationFinished());
     EXPECT_TRUE(manager.was_successful());
     histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility",
                                   CrashVisibility::kShownWhileAncestorIsLoading,
diff --git a/content/browser/text_fragment_browsertest.cc b/content/browser/text_fragment_browsertest.cc
index bc13ada..c52ce90 100644
--- a/content/browser/text_fragment_browsertest.cc
+++ b/content/browser/text_fragment_browsertest.cc
@@ -667,7 +667,7 @@
 
   EXPECT_TRUE(navigation_manager.WaitForResponse());
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   WaitForPageLoad(main_contents);
   frame_observer.WaitForScrollOffsetAtTop(
@@ -712,7 +712,7 @@
 
   EXPECT_TRUE(navigation_manager.WaitForResponse());
   navigation_manager.ResumeNavigation();
-  navigation_manager.WaitForNavigationFinished();
+  ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
   WaitForPageLoad(main_contents);
   // Wait a short amount of time to ensure the page does not scroll.
@@ -808,7 +808,7 @@
 
     ASSERT_TRUE(navigation_manager.WaitForResponse());
     navigation_manager.ResumeNavigation();
-    navigation_manager.WaitForNavigationFinished();
+    ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
 
     WaitForPageLoad(shell()->web_contents());
   }
diff --git a/content/browser/utility_sandbox_delegate.cc b/content/browser/utility_sandbox_delegate.cc
index ce7d3a9..5d7e660 100644
--- a/content/browser/utility_sandbox_delegate.cc
+++ b/content/browser/utility_sandbox_delegate.cc
@@ -103,7 +103,7 @@
 #endif  // BUILDFLAG(IS_POSIX)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-ZygoteHandle UtilitySandboxedProcessLauncherDelegate::GetZygote() {
+ZygoteCommunication* UtilitySandboxedProcessLauncherDelegate::GetZygote() {
   // If the sandbox has been disabled for a given type, don't use a zygote.
   if (sandbox::policy::IsUnsandboxedSandboxType(sandbox_type_))
     return nullptr;
diff --git a/content/browser/utility_sandbox_delegate.h b/content/browser/utility_sandbox_delegate.h
index 41d93b4..0d50bd9 100644
--- a/content/browser/utility_sandbox_delegate.h
+++ b/content/browser/utility_sandbox_delegate.h
@@ -42,7 +42,7 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-  ZygoteHandle GetZygote() override;
+  ZygoteCommunication* GetZygote() override;
 #endif  // BUILDFLAG(USE_ZYGOTE_HANDLE)
 
 #if BUILDFLAG(IS_POSIX)
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7f5170b..25e7826 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2194,6 +2194,11 @@
   NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
   observers_.NotifyObservers(&WebContentsObserver::MediaPictureInPictureChanged,
                              has_picture_in_picture);
+  if (has_picture_in_picture) {
+    pip_capture_handle_ = IncrementCapturerCount({}, true, false);
+  } else {
+    pip_capture_handle_.RunAndReset();
+  }
 
   // Picture-in-picture state can affect how we notify visibility for non-
   // visible pages.
@@ -3688,8 +3693,7 @@
   if (visibility == Visibility::VISIBLE || visible_capturer_count_ > 0 ||
       web_contents_visible_in_vr) {
     return PageVisibilityState::kVisible;
-  } else if (hidden_capturer_count_ > 0 || has_picture_in_picture_video_ ||
-             has_picture_in_picture_document_) {
+  } else if (hidden_capturer_count_ > 0) {
     return PageVisibilityState::kHiddenButPainting;
   }
   return PageVisibilityState::kHidden;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index e1a76ff..8d30bd7 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -2348,6 +2348,10 @@
   // Stores WebContents::CreateParams::lock_picture_in_picture_aspect_ratio.
   bool pip_lock_aspect_ratio_ = false;
 
+  // Pip might require the content window to continue rendering. This handle
+  // ensures that rendering continues despite occlusion or hidden window state.
+  base::ScopedClosureRunner pip_capture_handle_;
+
   VisibleTimeRequestTrigger visible_time_request_trigger_;
 
   // Stores the information whether last navigation was prerender activation for
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 9a9bc91..51fa919 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -416,13 +416,13 @@
   // Let B finish and wait for another load stop.  A will still be loading due
   // to D.
   LoadFinishedWaiter load_waiter_b(web_contents, url_b);
-  delayer_b.WaitForNavigationFinished();
+  ASSERT_TRUE(delayer_b.WaitForNavigationFinished());
   load_waiter_b.Wait();
   EXPECT_TRUE(web_contents->IsLoading());
 
   // Let D finish.  We should get a load stop in the main frame.
   LoadFinishedWaiter load_waiter_d(web_contents, url_d);
-  delayer_d.WaitForNavigationFinished();
+  ASSERT_TRUE(delayer_d.WaitForNavigationFinished());
   load_waiter_d.Wait();
   EXPECT_TRUE(WaitForLoadStop(web_contents));
   EXPECT_FALSE(web_contents->IsLoading());
@@ -1466,7 +1466,7 @@
 
   // Have the cross-site navigation commit. The main RenderFrameHost should
   // still be loading after that.
-  cross_site_delayer.WaitForNavigationFinished();
+  ASSERT_TRUE(cross_site_delayer.WaitForNavigationFinished());
   EXPECT_TRUE(shell()->web_contents()->IsLoading());
 }
 
@@ -5869,7 +5869,7 @@
   EXPECT_TRUE(partition_alloc::internal::PCScan::IsEnabled());
 
   // Wait for navigation to finish and check that PCScan is disabled.
-  navigation_manager.WaitForNavigationFinished();
+  EXPECT_TRUE(navigation_manager.WaitForNavigationFinished());
   EXPECT_FALSE(partition_alloc::internal::PCScan::IsEnabled());
 
   // Complete load and check that PCScan is enabled again.
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index c026db9f..93a177c 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -1892,6 +1892,22 @@
   EXPECT_FALSE(view->is_showing());
 }
 
+TEST_F(WebContentsImplTest, PictureInPictureSetsCapture) {
+  // Setting pip on a content should create a capture lock and ending it should
+  // clear the associated lock.
+  ASSERT_FALSE(contents()->IsBeingCaptured());
+
+  contents()->SetHasPictureInPictureVideo(true);
+  ASSERT_TRUE(contents()->IsBeingCaptured());
+  contents()->SetHasPictureInPictureVideo(false);
+  ASSERT_FALSE(contents()->IsBeingCaptured());
+
+  contents()->SetHasPictureInPictureDocument(true);
+  ASSERT_TRUE(contents()->IsBeingCaptured());
+  contents()->SetHasPictureInPictureDocument(false);
+  ASSERT_FALSE(contents()->IsBeingCaptured());
+}
+
 namespace {
 
 void HideOrOccludeWithCapturerTest(WebContentsImpl* contents,
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 98ce501..4d6411b 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -830,7 +830,7 @@
       gfx::Point(bounds.right() - 10, bounds.y() + 10),
       gfx::Point(bounds.x() + 2, bounds.y() + 10), base::Milliseconds(2000),
       10);
-  nav_watcher.WaitForNavigationFinished();
+  ASSERT_TRUE(nav_watcher.WaitForNavigationFinished());
 
   generator.GestureScrollSequence(
       gfx::Point(bounds.x() + 2, bounds.y() + 10),
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index 7bc5e4a..bc47448 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -297,8 +297,9 @@
 #if BUILDFLAG(IS_CHROMEOS)
 void ZygoteHostImpl::ReinitializeLogging(uint32_t logging_dest,
                                          base::PlatformFile log_file_fd) {
-  content::ZygoteHandle generic_zygote = content::GetGenericZygote();
-  content::ZygoteHandle unsandboxed_zygote = content::GetUnsandboxedZygote();
+  content::ZygoteCommunication* generic_zygote = content::GetGenericZygote();
+  content::ZygoteCommunication* unsandboxed_zygote =
+      content::GetUnsandboxedZygote();
   if (generic_zygote)
     generic_zygote->ReinitializeLogging(logging_dest, log_file_fd);
   if (unsandboxed_zygote)
diff --git a/content/common/zygote/zygote_handle_impl_linux.h b/content/common/zygote/zygote_handle_impl_linux.h
index 9768cea..79b049c3 100644
--- a/content/common/zygote/zygote_handle_impl_linux.h
+++ b/content/common/zygote/zygote_handle_impl_linux.h
@@ -14,18 +14,18 @@
     base::OnceCallback<pid_t(base::CommandLine*, base::ScopedFD*)>;
 
 // Allocates and initializes the global generic zygote process, and returns the
-// ZygoteHandle used to communicate with it. |launch_cb| is a callback that
-// should actually launch the process, after adding additional command line
+// ZygoteCommunication* used to communicate with it. |launch_cb| is a callback
+// that should actually launch the process, after adding additional command line
 // switches to the ones composed by this function. It returns the pid created,
 // and provides a control fd for it.
 CONTENT_EXPORT
-ZygoteHandle CreateGenericZygote(ZygoteLaunchCallback launch_cb);
+ZygoteCommunication* CreateGenericZygote(ZygoteLaunchCallback launch_cb);
 
 // Similar to the above but for creating an unsandboxed zygote from which
 // processes which need non-generic sandboxes can be derived.
 CONTENT_EXPORT
-ZygoteHandle CreateUnsandboxedZygote(ZygoteLaunchCallback launch_cb);
-CONTENT_EXPORT ZygoteHandle GetUnsandboxedZygote();
+ZygoteCommunication* CreateUnsandboxedZygote(ZygoteLaunchCallback launch_cb);
+CONTENT_EXPORT ZygoteCommunication* GetUnsandboxedZygote();
 
 }  // namespace content
 
diff --git a/content/common/zygote/zygote_handle_linux.cc b/content/common/zygote/zygote_handle_linux.cc
index a692eea..2c832c3 100644
--- a/content/common/zygote/zygote_handle_linux.cc
+++ b/content/common/zygote/zygote_handle_linux.cc
@@ -13,12 +13,12 @@
 namespace {
 
 // Intentionally leaked.
-ZygoteHandle g_generic_zygote = nullptr;
-ZygoteHandle g_unsandboxed_zygote = nullptr;
+ZygoteCommunication* g_generic_zygote = nullptr;
+ZygoteCommunication* g_unsandboxed_zygote = nullptr;
 
 }  // namespace
 
-ZygoteHandle CreateGenericZygote(ZygoteLaunchCallback launch_cb) {
+ZygoteCommunication* CreateGenericZygote(ZygoteLaunchCallback launch_cb) {
   CHECK(!g_generic_zygote);
   g_generic_zygote =
       new ZygoteCommunication(ZygoteCommunication::ZygoteType::kSandboxed);
@@ -26,12 +26,12 @@
   return g_generic_zygote;
 }
 
-ZygoteHandle GetGenericZygote() {
+ZygoteCommunication* GetGenericZygote() {
   CHECK(g_generic_zygote);
   return g_generic_zygote;
 }
 
-ZygoteHandle CreateUnsandboxedZygote(ZygoteLaunchCallback launch_cb) {
+ZygoteCommunication* CreateUnsandboxedZygote(ZygoteLaunchCallback launch_cb) {
   CHECK(!g_unsandboxed_zygote);
   g_unsandboxed_zygote =
       new ZygoteCommunication(ZygoteCommunication::ZygoteType::kUnsandboxed);
@@ -39,7 +39,7 @@
   return g_unsandboxed_zygote;
 }
 
-ZygoteHandle GetUnsandboxedZygote() {
+ZygoteCommunication* GetUnsandboxedZygote() {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kNoUnsandboxedZygote)) {
     CHECK(!g_unsandboxed_zygote);
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
index dd9d9f8..2c863f8 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -612,6 +612,12 @@
         }
     }
 
+    private void unInitialize() {
+        if (mNativeObj != 0) {
+            WebContentsAccessibilityImplJni.get().unInitialize(mNativeObj);
+        }
+    }
+
     /**
      * Refresh a11y state with that of {@link AccessibilityManager}.
      */
@@ -2330,5 +2336,6 @@
                 long nativeWebContentsAccessibilityAndroid, float x, float y);
         boolean getImageData(long nativeWebContentsAccessibilityAndroid,
                 AccessibilityNodeInfoCompat info, int id, boolean hasSentPreviousRequest);
+        void unInitialize(long nativeWebContentsAccessibilityAndroid);
     }
 }
diff --git a/content/public/browser/back_forward_cache.h b/content/public/browser/back_forward_cache.h
index 637c22c..f5ee507 100644
--- a/content/public/browser/back_forward_cache.h
+++ b/content/public/browser/back_forward_cache.h
@@ -6,10 +6,14 @@
 #define CONTENT_PUBLIC_BROWSER_BACK_FORWARD_CACHE_H_
 
 #include <cstdint>
+#include <map>
+#include <set>
 
 #include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/global_routing_id.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace content {
 
@@ -75,7 +79,7 @@
     bool operator!=(const DisabledReason&) const;
   };
 
-  // Prevents the |render_frame_host| from entering the BackForwardCache. A
+  // Prevents the `render_frame_host` from entering the BackForwardCache. A
   // RenderFrameHost can only enter the BackForwardCache if the main one and all
   // its children can. This action can not be undone. Any document that is
   // assigned to this same RenderFrameHost in the future will not be cached
@@ -88,15 +92,25 @@
   //
   // If the page is already in the cache an eviction is triggered.
   //
-  // |render_frame_host|: non-null.
-  // |reason|: Describes who is disabling this and why.
-  static void DisableForRenderFrameHost(RenderFrameHost* render_frame_host,
-                                        DisabledReason reason);
+  // `render_frame_host`: non-null.
+  // `reason`: Describes who is disabling this and why.
+  // `source_id`: see
+  // `BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap` for what it
+  // means and when it's set.
+  static void DisableForRenderFrameHost(
+      RenderFrameHost* render_frame_host,
+      DisabledReason reason,
+      absl::optional<ukm::SourceId> source_id = absl::nullopt);
+
   // Helper function to be used when it is not always possible to guarantee the
-  // |render_frame_host| to be still alive when this is called. In this case,
-  // its |id| can be used.
-  static void DisableForRenderFrameHost(GlobalRenderFrameHostId id,
-                                        DisabledReason reason);
+  // `render_frame_host` to be still alive when this is called. In this case,
+  // its `id` can be used.
+  // For what `source_id` means and when it's set, see
+  // `BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap`.
+  static void DisableForRenderFrameHost(
+      GlobalRenderFrameHostId id,
+      DisabledReason reason,
+      absl::optional<ukm::SourceId> source_id = absl::nullopt);
 
   // List of reasons the BackForwardCache was disabled for a specific test. If a
   // test needs to be disabled for a reason not covered below, please add to
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index 06e6c9f..3d8fd49 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -156,29 +156,38 @@
   StoragePartition* GetStoragePartitionForUrl(const GURL& url,
                                               bool can_create = true);
 
+  // Synchronously invokes |callback| for each loaded StoragePartition.
+  // Persisted StoragePartitions (not in-memory) are loaded lazily on first
+  // use, at which point a StoragePartition object will be created that's
+  // backed by the on-disk storage. StoragePartitions will not be unloaded for
+  // the remainder of the BrowserContext's lifetime.
   using StoragePartitionCallback =
       base::RepeatingCallback<void(StoragePartition*)>;
-  void ForEachStoragePartition(StoragePartitionCallback callback);
+  void ForEachLoadedStoragePartition(StoragePartitionCallback callback);
+
+  // Returns the number of loaded StoragePartitions that exist for `this`
+  // BrowserContext.
+  // See |ForEachLoadedStoragePartition| for details about loaded
+  // StoragePartitions.
+  size_t GetLoadedStoragePartitionCount();
 
   // Disposes the given StoragePartition. Only in-memory storage partition
   // disposal is supported. Caller needs to be careful that no outstanding
   // references are left to access the disposed storage partition.
   void DisposeStoragePartition(StoragePartition* storage_partition);
 
-  // Returns the number of StoragePartitions that exist for `this`
-  // BrowserContext.
-  size_t GetStoragePartitionCount();
-
   // Starts an asynchronous best-effort attempt to delete all on-disk storage
   // related to |partition_domain| and synchronously invokes |done_callback|
-  // once all on-disk storage is deleted.
+  // once all deletable on-disk storage is deleted. |on_gc_required| will be
+  // invoked if |partition_domain| corresponds to any StoragePartitions that
+  // are loaded and can't safely be deleted. In this case the caller should
+  // attempt to delete the StoragePartition again at next browser launch.
   void AsyncObliterateStoragePartition(const std::string& partition_domain,
                                        base::OnceClosure on_gc_required,
                                        base::OnceClosure done_callback);
 
-  // Examines the on-disk storage and removes any entries that are not listed
-  // in the `active_paths`, or in use by current entries in the storage
-  // partition.
+  // Examines all on-disk StoragePartitions and removes any entries that are
+  // not loaded or listed in `active_paths`.
   //
   // The `done` closure is executed on the calling thread when garbage
   // collection is complete.
diff --git a/content/public/browser/cors_origin_pattern_setter.cc b/content/public/browser/cors_origin_pattern_setter.cc
index 58199ba..ef57a459 100644
--- a/content/public/browser/cors_origin_pattern_setter.cc
+++ b/content/public/browser/cors_origin_pattern_setter.cc
@@ -53,7 +53,7 @@
       base::MakeRefCounted<CorsOriginPatternSetter>(
           PassKey(), source_origin, mojo::Clone(allow_patterns),
           mojo::Clone(block_patterns), barrier_closure);
-  browser_context->ForEachStoragePartition(
+  browser_context->ForEachLoadedStoragePartition(
       base::BindRepeating(&CorsOriginPatternSetter::SetForStoragePartition,
                           base::RetainedRef(setter)));
 
diff --git a/content/public/common/sandboxed_process_launcher_delegate.cc b/content/public/common/sandboxed_process_launcher_delegate.cc
index ee7cdddb..3d4033c 100644
--- a/content/public/common/sandboxed_process_launcher_delegate.cc
+++ b/content/public/common/sandboxed_process_launcher_delegate.cc
@@ -46,7 +46,7 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
-ZygoteHandle SandboxedProcessLauncherDelegate::GetZygote() {
+ZygoteCommunication* SandboxedProcessLauncherDelegate::GetZygote() {
   // Default to the sandboxed zygote. If a more lax sandbox is needed, then the
   // child class should override this method and use the unsandboxed zygote.
   return GetGenericZygote();
diff --git a/content/public/common/sandboxed_process_launcher_delegate.h b/content/public/common/sandboxed_process_launcher_delegate.h
index 1e8f3994..0f21137 100644
--- a/content/public/common/sandboxed_process_launcher_delegate.h
+++ b/content/public/common/sandboxed_process_launcher_delegate.h
@@ -45,7 +45,7 @@
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
   // Returns the zygote used to launch the process.
-  virtual ZygoteHandle GetZygote();
+  virtual ZygoteCommunication* GetZygote();
 #endif  // BUILDFLAG(USE_ZYGOTE_HANDLE)
 
 #if BUILDFLAG(IS_POSIX)
diff --git a/content/public/common/zygote/zygote_handle.h b/content/public/common/zygote/zygote_handle.h
index cfd7c7a..debd30e 100644
--- a/content/public/common/zygote/zygote_handle.h
+++ b/content/public/common/zygote/zygote_handle.h
@@ -20,14 +20,13 @@
 
 #if BUILDFLAG(IS_POSIX)
 class ZygoteCommunication;
-using ZygoteHandle = ZygoteCommunication*;
 #else
 // Perhaps other ports may USE_ZYGOTE_HANDLE here somdeday.
 #error "Can not use zygote handles on this platform"
 #endif  // BUILDFLAG(IS_POSIX)
 
 // Gets the generic global zygote used to launch sandboxed children.
-CONTENT_EXPORT ZygoteHandle GetGenericZygote();
+CONTENT_EXPORT ZygoteCommunication* GetGenericZygote();
 
 }  // namespace content
 
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index bbe14bd2..2b2de38 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -4000,7 +4000,7 @@
 }
 
 void EnsureCookiesFlushed(BrowserContext* browser_context) {
-  browser_context->ForEachStoragePartition(
+  browser_context->ForEachLoadedStoragePartition(
       base::BindRepeating([](StoragePartition* partition) {
         base::RunLoop run_loop;
         partition->GetCookieManagerForBrowserProcess()->FlushCookieStore(
diff --git a/content/test/data/accessibility/event/add-alert-with-role-change-expected-auralinux.txt b/content/test/data/accessibility/event/add-alert-with-role-change-expected-auralinux.txt
index ae22e7a..78506fda 100644
--- a/content/test/data/accessibility/event/add-alert-with-role-change-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/add-alert-with-role-change-expected-auralinux.txt
@@ -1,5 +1,2 @@
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_NOTIFICATION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-PARENT-CHANGED PARENT:(role=ROLE_NOTIFICATION name='(null)') role=ROLE_STATIC name='This is an alert' ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
-TEXT-INSERT (start=0 length=16 'This is an alert') role=ROLE_NOTIFICATION name='(null)' ENABLED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
+CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_NOTIFICATION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-dialog-described-by-expected-auralinux.txt b/content/test/data/accessibility/event/add-dialog-described-by-expected-auralinux.txt
index 2b44d48..080df73 100644
--- a/content/test/data/accessibility/event/add-dialog-described-by-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/add-dialog-described-by-expected-auralinux.txt
@@ -1 +1,2 @@
-CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_DIALOG) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
+CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_DIALOG) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:INVALID-ENTRY:FALSE role=ROLE_ENTRY name='(null)' EDITABLE,ENABLED,FOCUSABLE,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SELECTABLE-TEXT
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-dialog-described-by-expected-mac.txt b/content/test/data/accessibility/event/add-dialog-described-by-expected-mac.txt
index e54d63a1..f1d41ec 100644
--- a/content/test/data/accessibility/event/add-dialog-described-by-expected-mac.txt
+++ b/content/test/data/accessibility/event/add-dialog-described-by-expected-mac.txt
@@ -1 +1 @@
-AXValueChanged on AXTextField
\ No newline at end of file
+AXInvalidStatusChanged on AXTextField
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-dialog-expected-auralinux.txt b/content/test/data/accessibility/event/add-dialog-expected-auralinux.txt
index 2b44d48..080df73 100644
--- a/content/test/data/accessibility/event/add-dialog-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/add-dialog-expected-auralinux.txt
@@ -1 +1,2 @@
-CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_DIALOG) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
+CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_DIALOG) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:INVALID-ENTRY:FALSE role=ROLE_ENTRY name='(null)' EDITABLE,ENABLED,FOCUSABLE,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SELECTABLE-TEXT
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-dialog-expected-mac.txt b/content/test/data/accessibility/event/add-dialog-expected-mac.txt
index e54d63a1..f1d41ec 100644
--- a/content/test/data/accessibility/event/add-dialog-expected-mac.txt
+++ b/content/test/data/accessibility/event/add-dialog-expected-mac.txt
@@ -1 +1 @@
-AXValueChanged on AXTextField
\ No newline at end of file
+AXInvalidStatusChanged on AXTextField
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-dialog-no-info-expected-auralinux.txt b/content/test/data/accessibility/event/add-dialog-no-info-expected-auralinux.txt
index 2b44d48..080df73 100644
--- a/content/test/data/accessibility/event/add-dialog-no-info-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/add-dialog-no-info-expected-auralinux.txt
@@ -1 +1,2 @@
-CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_DIALOG) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
+CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_DIALOG) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:INVALID-ENTRY:FALSE role=ROLE_ENTRY name='(null)' EDITABLE,ENABLED,FOCUSABLE,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SELECTABLE-TEXT
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-dialog-no-info-expected-mac.txt b/content/test/data/accessibility/event/add-dialog-no-info-expected-mac.txt
index e54d63a1..f1d41ec 100644
--- a/content/test/data/accessibility/event/add-dialog-no-info-expected-mac.txt
+++ b/content/test/data/accessibility/event/add-dialog-no-info-expected-mac.txt
@@ -1 +1 @@
-AXValueChanged on AXTextField
\ No newline at end of file
+AXInvalidStatusChanged on AXTextField
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt b/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt
index dac2ebc4..f745549a 100644
--- a/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt
+++ b/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt
@@ -1,3 +1,3 @@
-EVENT_OBJECT_HIDE on <div#item3> role=ROLE_SYSTEM_LISTITEM name="Item 3" level=1 PosInSet=3 SetSize=3
+EVENT_OBJECT_HIDE on <div> role=ROLE_SYSTEM_LISTITEM INVISIBLE
 EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_LIST SetSize=2
-IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_LIST SetSize=2 old_text={'<obj>' start=2 end=3}
+IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_LIST SetSize=2 old_text={'<obj>' start=2 end=3}
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt b/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt
index 239d0ec4..de58ebb 100644
--- a/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt
+++ b/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt
@@ -1,3 +1,3 @@
-EVENT_OBJECT_HIDE on <li#item3> role=ROLE_SYSTEM_LISTITEM level=1 PosInSet=3 SetSize=3
+EVENT_OBJECT_HIDE on <li> role=ROLE_SYSTEM_GROUPING INVISIBLE
 EVENT_OBJECT_REORDER on <ul> role=ROLE_SYSTEM_LIST SetSize=2
 IA2_EVENT_TEXT_REMOVED on <ul> role=ROLE_SYSTEM_LIST SetSize=2 old_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-auralinux.txt b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-auralinux.txt
index dfea3a4..6adb7a1 100644
--- a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-auralinux.txt
@@ -3,6 +3,7 @@
 FOCUS-EVENT:FALSE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,EXPANDED,FOCUSABLE,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT,HAS-POPUP
 FOCUS-EVENT:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
 PARENT-CHANGED PARENT:(role=ROLE_DOCUMENT_WEB name='(null)') role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,EXPANDED,FOCUSABLE,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT,HAS-POPUP
-PARENT-CHANGED PARENT:(role=ROLE_DOCUMENT_WEB name='(null)') role=ROLE_LIST_BOX name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
+SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 STATE-CHANGE:FOCUSED:FALSE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,EXPANDED,FOCUSABLE,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT,HAS-POPUP
-STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
+STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt
index ec33813..2da0fdf 100644
--- a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt
+++ b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt
@@ -1,2 +1,3 @@
 AXFocusedUIElementChanged on AXStaticText AXValue='Apple'
-AXSelectedChildrenChanged on AXComboBox AXAutocompleteValue='list'
\ No newline at end of file
+AXSelectedChildrenChanged on AXComboBox AXAutocompleteValue='list'
+AXSelectedChildrenChanged on AXList
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt
index da197e0..615747b 100644
--- a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt
+++ b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt
@@ -1,5 +1,6 @@
 EVENT_OBJECT_FOCUS on <li#op1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=1
 EVENT_OBJECT_HIDE on <body> role=ROLE_SYSTEM_GROUPING INVISIBLE
+EVENT_OBJECT_SELECTION on <li#op1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=1
 IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <input> role=ROLE_SYSTEM_COMBOBOX EXPANDED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION
 IA2_EVENT_TEXT_INSERTED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSABLE new_text={'<obj><obj>' start=0 end=2}
 IA2_EVENT_TEXT_REMOVED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSABLE old_text={'<obj>' start=0 end=1}
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-android.txt b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-android.txt
index e69de29..aec4f94b 100644
--- a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-android.txt
+++ b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-android.txt
@@ -0,0 +1 @@
+TYPE_WINDOW_CONTENT_CHANGED - [contentTypes=64]
diff --git a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-auralinux.txt b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-auralinux.txt
index c2baee73..e9082d7f 100644
--- a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-auralinux.txt
@@ -1,7 +1,7 @@
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_TOGGLE_BUTTON) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE
-CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
+CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_TOGGLE_BUTTON) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:PRESSED:TRUE role=ROLE_TOGGLE_BUTTON name='(null)' ENABLED,FOCUSABLE,PRESSED,SENSITIVE,SHOWING,VISIBLE
 === Start Continuation ===
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE
-CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_TOGGLE_BUTTON) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
+CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_SECTION ENABLED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:PRESSED:TRUE role=ROLE_PUSH_BUTTON name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-mac.txt b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-mac.txt
index 6838414..918902b 100644
--- a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-mac.txt
+++ b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-mac.txt
@@ -1 +1,3 @@
+AXValueChanged on AXCheckBox AXSubrole=AXToggleButton AXValue=1
 === Start Continuation ===
+AXValueChanged on AXButton
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-uia-win.txt b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-uia-win.txt
index ca8cdff..fd801e6 100644
--- a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-uia-win.txt
@@ -1,7 +1,7 @@
-StructureChanged/ChildAdded on role=button
-StructureChanged/ChildRemoved on role=document
-StructureChanged/ChildrenReordered on role=document
+AriaProperties changed on role=button
+AriaRole changed on role=button
+ToggleToggleState changed on role=button
 === Start Continuation ===
-StructureChanged/ChildAdded on role=button
-StructureChanged/ChildRemoved on role=document
-StructureChanged/ChildrenReordered on role=document
+AriaProperties changed on role=button
+AriaRole changed on role=button
+ToggleToggleState changed on role=button
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-win.txt b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-win.txt
index c1f1345..fe7cb46c 100644
--- a/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-win.txt
+++ b/content/test/data/accessibility/event/aria-pressed-changes-button-role-expected-win.txt
@@ -1,11 +1,5 @@
-EVENT_OBJECT_HIDE on <button#test> role=ROLE_SYSTEM_PUSHBUTTON FOCUSABLE
-EVENT_OBJECT_REORDER on <body> role=ROLE_SYSTEM_GROUPING
-EVENT_OBJECT_SHOW on <button#test> role=ROLE_SYSTEM_PUSHBUTTON PRESSED,FOCUSABLE
-IA2_EVENT_TEXT_INSERTED on <body> role=ROLE_SYSTEM_GROUPING new_text={'<obj>' start=0 end=1}
-IA2_EVENT_TEXT_REMOVED on <body> role=ROLE_SYSTEM_GROUPING old_text={'<obj>' start=0 end=1}
+EVENT_OBJECT_STATECHANGE on <button#test> role=ROLE_SYSTEM_PUSHBUTTON PRESSED,FOCUSABLE
+IA2_EVENT_ROLE_CHANGED on <button#test> role=ROLE_SYSTEM_PUSHBUTTON PRESSED,FOCUSABLE
 === Start Continuation ===
-EVENT_OBJECT_HIDE on <button#test> role=ROLE_SYSTEM_PUSHBUTTON PRESSED,FOCUSABLE
-EVENT_OBJECT_REORDER on <body> role=ROLE_SYSTEM_GROUPING
-EVENT_OBJECT_SHOW on <button#test> role=ROLE_SYSTEM_PUSHBUTTON FOCUSABLE
-IA2_EVENT_TEXT_INSERTED on <body> role=ROLE_SYSTEM_GROUPING new_text={'<obj>' start=0 end=1}
-IA2_EVENT_TEXT_REMOVED on <body> role=ROLE_SYSTEM_GROUPING old_text={'<obj>' start=0 end=1}
+EVENT_OBJECT_STATECHANGE on <button#test> role=ROLE_SYSTEM_PUSHBUTTON FOCUSABLE
+IA2_EVENT_ROLE_CHANGED on <button#test> role=ROLE_SYSTEM_PUSHBUTTON FOCUSABLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-textbox-children-change-expected-auralinux.txt b/content/test/data/accessibility/event/aria-textbox-children-change-expected-auralinux.txt
index be72da9..f734d430 100644
--- a/content/test/data/accessibility/event/aria-textbox-children-change-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/aria-textbox-children-change-expected-auralinux.txt
@@ -4,5 +4,4 @@
 === Start Continuation ===
 CHILDREN-CHANGED:REMOVE index:1 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_ENTRY EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
 === Start Continuation ===
-CHILDREN-CHANGED:ADD index:1 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_ENTRY ENABLED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SELECTABLE-TEXT
-CHILDREN-CHANGED:REMOVE index:4 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+PARENT-CHANGED PARENT:(role=ROLE_ENTRY name='role only, plain') role=ROLE_PUSH_BUTTON name='ok' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/aria-textbox-children-change-expected-win.txt b/content/test/data/accessibility/event/aria-textbox-children-change-expected-win.txt
index 5863299..33c20402 100644
--- a/content/test/data/accessibility/event/aria-textbox-children-change-expected-win.txt
+++ b/content/test/data/accessibility/event/aria-textbox-children-change-expected-win.txt
@@ -7,6 +7,4 @@
 EVENT_OBJECT_HIDE on <button#btn3> role=ROLE_SYSTEM_PUSHBUTTON name="ok" FOCUSABLE IA2_STATE_EDITABLE
 EVENT_OBJECT_VALUECHANGE on <div> role=ROLE_SYSTEM_TEXT name="editable" value="foo" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT
 === Start Continuation ===
-EVENT_OBJECT_HIDE on <button#btn4> role=ROLE_SYSTEM_PUSHBUTTON name="ok" FOCUSABLE
-EVENT_OBJECT_SHOW on <button#btn4> role=ROLE_SYSTEM_PUSHBUTTON name="ok" FOCUSABLE
-EVENT_OBJECT_VALUECHANGE on <div#txt4> role=ROLE_SYSTEM_TEXT name="role only, plain" value="foook" IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
+EVENT_OBJECT_VALUECHANGE on <div#txt4> role=ROLE_SYSTEM_TEXT name="role only, plain" value="foook" IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/css-display-descendants-expected-win.txt b/content/test/data/accessibility/event/css-display-descendants-expected-win.txt
index 89fa29f..de51619b 100644
--- a/content/test/data/accessibility/event/css-display-descendants-expected-win.txt
+++ b/content/test/data/accessibility/event/css-display-descendants-expected-win.txt
@@ -1,3 +1,3 @@
-EVENT_OBJECT_HIDE on <div#heading-root.a> role=ROLE_SYSTEM_GROUPING name="Heading" level=2
+EVENT_OBJECT_HIDE on <div.a> role=ROLE_SYSTEM_GROUPING INVISIBLE
 EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL
-EVENT_OBJECT_SHOW on <div#banner-root.b> role=ROLE_SYSTEM_GROUPING name="Banner"
+EVENT_OBJECT_SHOW on <div#banner-root.b> role=ROLE_SYSTEM_GROUPING name="Banner"
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/css-display-expected-win.txt b/content/test/data/accessibility/event/css-display-expected-win.txt
index 8201f639..c9b50d61 100644
--- a/content/test/data/accessibility/event/css-display-expected-win.txt
+++ b/content/test/data/accessibility/event/css-display-expected-win.txt
@@ -1,5 +1,5 @@
-EVENT_OBJECT_HIDE on <div.a> role=ROLE_SYSTEM_GROUPING name="Heading" level=2
+EVENT_OBJECT_HIDE on <div.a> role=ROLE_SYSTEM_GROUPING INVISIBLE
 EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL
 EVENT_OBJECT_SHOW on <div.b> role=ROLE_SYSTEM_GROUPING name="Banner"
-IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=0 end=1}
+IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=1 end=2}
 IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL old_text={'<obj>' start=0 end=1}
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/individual-nodes-become-ignored-but-included-expected-auralinux.txt b/content/test/data/accessibility/event/individual-nodes-become-ignored-but-included-expected-auralinux.txt
index e5a52a0..c1f819b 100644
--- a/content/test/data/accessibility/event/individual-nodes-become-ignored-but-included-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/individual-nodes-become-ignored-but-included-expected-auralinux.txt
@@ -2,6 +2,3 @@
 CHILDREN-CHANGED:REMOVE index:1 CHILD:(role=ROLE_PANEL) role=ROLE_LANDMARK ENABLED,SENSITIVE,SHOWING,VISIBLE
 PARENT-CHANGED PARENT:(role=ROLE_LANDMARK name='(null)') role=ROLE_LINK name='1' ENABLED,SENSITIVE,SHOWING,VISIBLE
 PARENT-CHANGED PARENT:(role=ROLE_LANDMARK name='(null)') role=ROLE_STATIC name='2' ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
diff --git a/content/test/data/accessibility/event/live-region-change-on-freshly-unignored-node-expected-uia-win.txt b/content/test/data/accessibility/event/live-region-change-on-freshly-unignored-node-expected-uia-win.txt
index dc31662..7a8dc99 100644
--- a/content/test/data/accessibility/event/live-region-change-on-freshly-unignored-node-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/live-region-change-on-freshly-unignored-node-expected-uia-win.txt
@@ -1,3 +1,5 @@
+AriaProperties changed on role=description, name=After
+AriaProperties changed on role=group
 LiveRegionChanged on role=group
 StructureChanged/ChildAdded on role=group
 StructureChanged/ChildrenReordered on role=document
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/live-region-elem-reparent-expected-auralinux.txt b/content/test/data/accessibility/event/live-region-elem-reparent-expected-auralinux.txt
index 3ba3ddf..742742d 100644
--- a/content/test/data/accessibility/event/live-region-elem-reparent-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/live-region-elem-reparent-expected-auralinux.txt
@@ -3,6 +3,4 @@
 CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
 PARENT-CHANGED PARENT:(role=ROLE_DOCUMENT_WEB name='(null)') role=ROLE_PUSH_BUTTON name='Click' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
 PARENT-CHANGED PARENT:(role=ROLE_DOCUMENT_WEB name='(null)') role=ROLE_SECTION name='(null)' ENABLED,SENSITIVE,SHOWING,VISIBLE
-PARENT-CHANGED PARENT:(role=ROLE_DOCUMENT_WEB name='(null)') role=ROLE_SECTION name='(null)' ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
 TEXT-INSERT (start=0 length=18 'This is important!') role=ROLE_PARAGRAPH name='(null)' ENABLED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/menu-opened-closed-expected-auralinux.txt b/content/test/data/accessibility/event/menu-opened-closed-expected-auralinux.txt
index 2cfd989cb..eb50724 100644
--- a/content/test/data/accessibility/event/menu-opened-closed-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/menu-opened-closed-expected-auralinux.txt
@@ -1,9 +1,9 @@
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_MENU) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:SHOWING:TRUE role=ROLE_MENU name='menu' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 === Start Continuation ===
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_MENU) role=ROLE_MENU_ITEM ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:SHOWING:TRUE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 === Start Continuation ===
 CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_MENU) role=ROLE_MENU_ITEM ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 === Start Continuation ===
-CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_MENU) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='menu' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
\ No newline at end of file
+CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_MENU) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/menu-opened-closed-expected-mac.txt b/content/test/data/accessibility/event/menu-opened-closed-expected-mac.txt
index 92227e4..e1b762c 100644
--- a/content/test/data/accessibility/event/menu-opened-closed-expected-mac.txt
+++ b/content/test/data/accessibility/event/menu-opened-closed-expected-mac.txt
@@ -1,7 +1,5 @@
-AXMenuClosed on AXWebArea
+AXMenuOpened on AXMenu AXDescription='menu'
 === Start Continuation ===
-AXMenuClosed on AXWebArea
+AXMenuOpened on AXMenu
 === Start Continuation ===
-AXMenuClosed on AXWebArea
-=== Start Continuation ===
-AXMenuClosed on AXWebArea
\ No newline at end of file
+=== Start Continuation ===
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt b/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt
index f85ad30..7db8406 100644
--- a/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt
+++ b/content/test/data/accessibility/event/menu-opened-closed-expected-win.txt
@@ -1,5 +1,7 @@
+EVENT_SYSTEM_MENUPOPUPSTART on <div#menu> role=ROLE_SYSTEM_MENUPOPUP name="menu" IA2_STATE_VERTICAL SetSize=2
 === Start Continuation ===
+EVENT_SYSTEM_MENUPOPUPSTART on <div#submenu> role=ROLE_SYSTEM_MENUPOPUP IA2_STATE_VERTICAL SetSize=1
 === Start Continuation ===
-EVENT_SYSTEM_MENUPOPUPEND on <div#submenu> role=ROLE_SYSTEM_MENUPOPUP IA2_STATE_VERTICAL SetSize=1
+EVENT_SYSTEM_MENUPOPUPEND on <div> role=ROLE_SYSTEM_MENUPOPUP INVISIBLE
 === Start Continuation ===
-EVENT_SYSTEM_MENUPOPUPEND on <div#menu> role=ROLE_SYSTEM_MENUPOPUP name="menu" IA2_STATE_VERTICAL SetSize=2
\ No newline at end of file
+EVENT_SYSTEM_MENUPOPUPEND on <div> role=ROLE_SYSTEM_MENUPOPUP INVISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-auralinux.txt b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-auralinux.txt
index b5bb721..a3037b2 100644
--- a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-auralinux.txt
@@ -1,16 +1,18 @@
 STATE-CHANGE:EXPANDED:TRUE role=ROLE_MENU_ITEM name='File' ENABLED,EXPANDABLE,EXPANDED,SENSITIVE,SHOWING,VISIBLE,HAS-POPUP
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
+STATE-CHANGE:EXPANDED:TRUE role=ROLE_MENU_ITEM name='New' ENABLED,EXPANDABLE,EXPANDED,SENSITIVE,SHOWING,VISIBLE,HAS-POPUP
+STATE-CHANGE:SHOWING:TRUE role=ROLE_MENU name='File' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
+STATE-CHANGE:SHOWING:TRUE role=ROLE_MENU name='New' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 === Start Continuation ===
 STATE-CHANGE:EXPANDED:FALSE role=ROLE_MENU_ITEM name='File' ENABLED,EXPANDABLE,SENSITIVE,SHOWING,VISIBLE,HAS-POPUP
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='File' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='New' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
+STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
+STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
 === Start Continuation ===
 === Start Continuation ===
 STATE-CHANGE:EXPANDED:TRUE role=ROLE_MENU_ITEM name='File' ENABLED,EXPANDABLE,EXPANDED,SENSITIVE,SHOWING,VISIBLE,HAS-POPUP
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
+STATE-CHANGE:EXPANDED:TRUE role=ROLE_MENU_ITEM name='New' ENABLED,EXPANDABLE,EXPANDED,SENSITIVE,SHOWING,VISIBLE,HAS-POPUP
+STATE-CHANGE:SHOWING:TRUE role=ROLE_MENU name='File' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
+STATE-CHANGE:SHOWING:TRUE role=ROLE_MENU name='New' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 === Start Continuation ===
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='File' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
-STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='New' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
+STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
+STATE-CHANGE:SHOWING:FALSE role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
 === Start Continuation ===
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-mac.txt b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-mac.txt
index 4b6c8da..b27d8048 100644
--- a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-mac.txt
+++ b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-mac.txt
@@ -1,6 +1,7 @@
 AXExpandedChanged on AXMenuItem AXDescription='File'
-AXMenuClosed on AXWebArea
-AXMenuClosed on AXWebArea
+AXExpandedChanged on AXMenuItem AXDescription='New'
+AXMenuOpened on AXMenu AXDescription='File'
+AXMenuOpened on AXMenu AXDescription='New'
 === Start Continuation ===
 AXExpandedChanged on AXMenuItem AXDescription='File'
 AXMenuClosed on AXWebArea
@@ -8,8 +9,9 @@
 === Start Continuation ===
 === Start Continuation ===
 AXExpandedChanged on AXMenuItem AXDescription='File'
-AXMenuClosed on AXWebArea
-AXMenuClosed on AXWebArea
+AXExpandedChanged on AXMenuItem AXDescription='New'
+AXMenuOpened on AXMenu AXDescription='File'
+AXMenuOpened on AXMenu AXDescription='New'
 === Start Continuation ===
 AXMenuClosed on AXWebArea
 AXMenuClosed on AXWebArea
diff --git a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-uia-win.txt b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-uia-win.txt
index 0d8abac..c0b5cd0 100644
--- a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-uia-win.txt
@@ -1,22 +1,22 @@
 ExpandCollapseExpandCollapseState changed on role=menuitem, name=File
+ExpandCollapseExpandCollapseState changed on role=menuitem, name=New
+MenuOpened on role=menu, name=File
+MenuOpened on role=menu, name=New
 Name changed on role=group, name=open file and new done
 === Start Continuation ===
 ExpandCollapseExpandCollapseState changed on role=menuitem, name=File
 MenuClosed 
 MenuClosed 
-MenuClosed 
-MenuClosed 
 Name changed on role=group, name=close file and new done
 === Start Continuation ===
 Name changed on role=group, name=open new done
 === Start Continuation ===
 ExpandCollapseExpandCollapseState changed on role=menuitem, name=File
+ExpandCollapseExpandCollapseState changed on role=menuitem, name=New
+MenuOpened on role=menu, name=File
+MenuOpened on role=menu, name=New
 Name changed on role=group, name=open file done
 === Start Continuation ===
-MenuClosed 
-MenuClosed 
-MenuClosed 
-MenuClosed 
 Name changed on role=group, name=hide menubar done
 === Start Continuation ===
 Name changed on role=group, name=show menubar done
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-win.txt b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-win.txt
index df5728f..06cb8ca 100644
--- a/content/test/data/accessibility/event/menubar-show-hide-menus-expected-win.txt
+++ b/content/test/data/accessibility/event/menubar-show-hide-menus-expected-win.txt
@@ -1,12 +1,13 @@
 EVENT_OBJECT_STATECHANGE on <li#file-menuitem> role=ROLE_SYSTEM_MENUITEM name="File" EXPANDED,HASPOPUP PosInSet=1 SetSize=2
+EVENT_SYSTEM_MENUPOPUPSTART on <ul#file-menu> role=ROLE_SYSTEM_MENUPOPUP name="File" IA2_STATE_VERTICAL SetSize=3
+EVENT_SYSTEM_MENUPOPUPSTART on <ul#new-menu> role=ROLE_SYSTEM_MENUPOPUP name="New" IA2_STATE_VERTICAL SetSize=3
 === Start Continuation ===
 EVENT_OBJECT_STATECHANGE on <li#file-menuitem> role=ROLE_SYSTEM_MENUITEM name="File" COLLAPSED,HASPOPUP PosInSet=1 SetSize=2
-EVENT_SYSTEM_MENUPOPUPEND on <ul#file-menu> role=ROLE_SYSTEM_MENUPOPUP name="File" IA2_STATE_VERTICAL SetSize=3
-EVENT_SYSTEM_MENUPOPUPEND on <ul#new-menu> role=ROLE_SYSTEM_MENUPOPUP name="New" IA2_STATE_VERTICAL SetSize=3
+EVENT_SYSTEM_MENUPOPUPEND on <ul> role=ROLE_SYSTEM_MENUPOPUP INVISIBLE
 === Start Continuation ===
 === Start Continuation ===
 EVENT_OBJECT_STATECHANGE on <li#file-menuitem> role=ROLE_SYSTEM_MENUITEM name="File" EXPANDED,HASPOPUP PosInSet=1 SetSize=2
+EVENT_SYSTEM_MENUPOPUPSTART on <ul#file-menu> role=ROLE_SYSTEM_MENUPOPUP name="File" IA2_STATE_VERTICAL SetSize=3
+EVENT_SYSTEM_MENUPOPUPSTART on <ul#new-menu> role=ROLE_SYSTEM_MENUPOPUP name="New" IA2_STATE_VERTICAL SetSize=3
 === Start Continuation ===
-EVENT_SYSTEM_MENUPOPUPEND on <ul#file-menu> role=ROLE_SYSTEM_MENUPOPUP name="File" IA2_STATE_VERTICAL SetSize=3
-EVENT_SYSTEM_MENUPOPUPEND on <ul#new-menu> role=ROLE_SYSTEM_MENUPOPUP name="New" IA2_STATE_VERTICAL SetSize=3
 === Start Continuation ===
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/remove-hidden-attribute-expected-auralinux.txt b/content/test/data/accessibility/event/remove-hidden-attribute-expected-auralinux.txt
index 2b23f4e8b..a5ad72e6 100644
--- a/content/test/data/accessibility/event/remove-hidden-attribute-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/remove-hidden-attribute-expected-auralinux.txt
@@ -1,2 +1 @@
-CHILDREN-CHANGED:ADD index:2 CHILD:(role=ROLE_LIST_ITEM) role=ROLE_LIST ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
\ No newline at end of file
+CHILDREN-CHANGED:ADD index:2 CHILD:(role=ROLE_LIST_ITEM) role=ROLE_LIST ENABLED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-auralinux.txt b/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-auralinux.txt
index 9801cf5..a5ad72e6 100644
--- a/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-auralinux.txt
@@ -1,3 +1 @@
-CHILDREN-CHANGED:ADD index:2 CHILD:(role=ROLE_LIST_ITEM) role=ROLE_LIST ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
\ No newline at end of file
+CHILDREN-CHANGED:ADD index:2 CHILD:(role=ROLE_LIST_ITEM) role=ROLE_LIST ENABLED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-auralinux.txt b/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-auralinux.txt
index f18e7d67..d5ee6d2c 100644
--- a/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-auralinux.txt
@@ -9,10 +9,7 @@
 STATE-CHANGE:FOCUSED:TRUE role=ROLE_MENU_ITEM name='Open...' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
 === Start Continuation ===
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_PANEL) role=ROLE_MENU_BAR ENABLED,HORIZONTAL,SENSITIVE,SHOWING,VISIBLE
-CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_MENU_BAR ENABLED,HORIZONTAL,SENSITIVE,SHOWING,VISIBLE
-PARENT-CHANGED PARENT:(role=ROLE_PANEL name='(null)') role=ROLE_MENU_ITEM name='About' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
-PARENT-CHANGED PARENT:(role=ROLE_PANEL name='(null)') role=ROLE_MENU_ITEM name='File' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE,HAS-POPUP
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
+CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_PANEL) role=ROLE_MENU_BAR ENABLED,HORIZONTAL,SENSITIVE,SHOWING,VISIBLE
 === Start Continuation ===
 FOCUS-EVENT:FALSE role=ROLE_MENU_ITEM name='Open...' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
 FOCUS-EVENT:TRUE role=ROLE_MENU_ITEM name='Quit' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-win.txt b/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-win.txt
index 1018175..7ed90a5 100644
--- a/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-win.txt
+++ b/content/test/data/accessibility/event/reparent-element-with-active-descendant-expected-win.txt
@@ -4,11 +4,7 @@
 EVENT_OBJECT_FOCUS on <div#open> role=ROLE_SYSTEM_MENUITEM name="Open..." FOCUSED,FOCUSABLE PosInSet=2 SetSize=3
 IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <div#file-menu> role=ROLE_SYSTEM_MENUPOPUP name="File" FOCUSABLE IA2_STATE_VERTICAL SetSize=3
 === Start Continuation ===
-EVENT_OBJECT_HIDE on <div#extra> role=ROLE_SYSTEM_GROUPING
-EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_MENUBAR FOCUSED IA2_STATE_HORIZONTAL SetSize=2
-EVENT_OBJECT_SHOW on <div#extra> role=ROLE_SYSTEM_GROUPING
-IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_MENUBAR FOCUSED IA2_STATE_HORIZONTAL SetSize=2 new_text={'<obj>' start=0 end=1}
-IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_MENUBAR FOCUSED IA2_STATE_HORIZONTAL SetSize=2 old_text={'<obj>' start=0 end=1}
+IA2_EVENT_ROLE_CHANGED on <div#extra> role=ROLE_SYSTEM_GROUPING
 === Start Continuation ===
 EVENT_OBJECT_FOCUS on <div#quit> role=ROLE_SYSTEM_MENUITEM name="Quit" FOCUSED,FOCUSABLE PosInSet=3 SetSize=3
-IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <div#file-menu> role=ROLE_SYSTEM_MENUPOPUP name="File" FOCUSABLE IA2_STATE_VERTICAL SetSize=3
\ No newline at end of file
+IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <div#file-menu> role=ROLE_SYSTEM_MENUPOPUP name="File" FOCUSABLE IA2_STATE_VERTICAL SetSize=3
diff --git a/content/test/data/accessibility/event/role-changed-expected-auralinux.txt b/content/test/data/accessibility/event/role-changed-expected-auralinux.txt
index 797be32..a78cec1 100644
--- a/content/test/data/accessibility/event/role-changed-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/role-changed-expected-auralinux.txt
@@ -1,4 +1,3 @@
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_PANEL) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-PARENT-CHANGED PARENT:(role=ROLE_PUSH_BUTTON name='Role will change') role=ROLE_STATIC name='Role will change' ENABLED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
\ No newline at end of file
+CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_PUSH_BUTTON) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+NAME-CHANGED:Role will change role=ROLE_PUSH_BUTTON name='Role will change' ENABLED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/role-changed-expected-mac.txt b/content/test/data/accessibility/event/role-changed-expected-mac.txt
index e69de29..28576b0 100644
--- a/content/test/data/accessibility/event/role-changed-expected-mac.txt
+++ b/content/test/data/accessibility/event/role-changed-expected-mac.txt
@@ -0,0 +1 @@
+AXTitleChanged on AXButton AXTitle='Role will change'
diff --git a/content/test/data/accessibility/event/role-changed-expected-win.txt b/content/test/data/accessibility/event/role-changed-expected-win.txt
index 48fa7f5..5965124 100644
--- a/content/test/data/accessibility/event/role-changed-expected-win.txt
+++ b/content/test/data/accessibility/event/role-changed-expected-win.txt
@@ -1,5 +1 @@
-EVENT_OBJECT_HIDE on <div#a> role=ROLE_SYSTEM_GROUPING
-EVENT_OBJECT_REORDER on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSED,FOCUSABLE
-EVENT_OBJECT_SHOW on <div#a> role=ROLE_SYSTEM_PUSHBUTTON name="Role will change"
-IA2_EVENT_TEXT_INSERTED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSED,FOCUSABLE new_text={'<obj>' start=0 end=1}
-IA2_EVENT_TEXT_REMOVED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSED,FOCUSABLE old_text={'<obj>' start=0 end=1}
\ No newline at end of file
+IA2_EVENT_ROLE_CHANGED on <div#a> role=ROLE_SYSTEM_PUSHBUTTON name="Role will change"
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/text-selection-inside-hidden-element-expected-auralinux.txt b/content/test/data/accessibility/event/text-selection-inside-hidden-element-expected-auralinux.txt
index 2ad88deb..3657567 100644
--- a/content/test/data/accessibility/event/text-selection-inside-hidden-element-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/text-selection-inside-hidden-element-expected-auralinux.txt
@@ -1,3 +1,6 @@
-CHILDREN-CHANGED:REMOVE index:0 CHILD:(role=ROLE_SECTION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+PARENT-CHANGED PARENT:(role=ROLE_DOCUMENT_WEB name='(null)') role=ROLE_COMBO_BOX name='(null)' ENABLED,EXPANDABLE,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE,HAS-POPUP
+PARENT-CHANGED PARENT:(role=ROLE_DOCUMENT_WEB name='(null)') role=ROLE_SECTION name='(null)' ENABLED,FOCUSABLE,SENSITIVE
+TEXT-ATTRIBUTES-CHANGED role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+TEXT-ATTRIBUTES-CHANGED role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
 TEXT-CARET-MOVED role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-TEXT-SELECTION-CHANGED role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
\ No newline at end of file
+TEXT-SELECTION-CHANGED role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/mock_platform_notification_service.cc b/content/test/mock_platform_notification_service.cc
index a282b3c..b3ef5af 100644
--- a/content/test/mock_platform_notification_service.cc
+++ b/content/test/mock_platform_notification_service.cc
@@ -101,7 +101,7 @@
   if (timestamp > base::Time::Now())
     return;
 
-  context_->ForEachStoragePartition(
+  context_->ForEachLoadedStoragePartition(
       base::BindRepeating([](content::StoragePartition* partition) {
         partition->GetPlatformNotificationContext()->TriggerNotifications();
       }));
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc
index 69ebf7df..7dbf0a23 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc
@@ -7,9 +7,9 @@
 #include <iterator>
 #include <ostream>
 
-#include <base/callback_helpers.h>
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "dbus/property.h"
diff --git a/docs/callback.md b/docs/callback.md
index 64666f5..4193a85 100644
--- a/docs/callback.md
+++ b/docs/callback.md
@@ -6,8 +6,8 @@
 
 The templated `base::{Once, Repeating}Callback<>` classes are generalized
 function objects. Together with the `base::Bind{Once, Repeating}()` functions in
-base/bind.h, they provide a type-safe method for performing partial application
-of functions.
+base/functional/bind.h, they provide a type-safe method for performing partial
+application of functions.
 
 Partial application is the process of binding a subset of a function's arguments
 to produce another function that takes fewer arguments. This can be used to pass
@@ -916,7 +916,7 @@
 To change this behavior, we introduce a set of argument wrappers (e.g.,
 `base::Unretained()`).  These are simple container templates that are passed by
 value, and wrap a pointer to argument.  Each helper has a comment describing it
-in base/bind.h.
+in base/functional/bind.h.
 
 These types are passed to the `Unwrap()` functions to modify the behavior of
 `base::Bind{Once, Repeating}()`.  The `Unwrap()` functions change behavior by doing partial
@@ -940,5 +940,6 @@
 base::BindOnce(&Foo, _1, false); // _1 is a placeholder.
 ```
 
-If you are thinking of forward declaring `base::{Once, Repeating}Callback` in your own header
-file, please include "base/callback_forward.h" instead.
+If you are thinking of forward declaring `base::{Once, Repeating}Callback` in
+your own header file, please include "base/functional/callback_forward.h"
+instead.
diff --git a/docs/clangd.md b/docs/clangd.md
index 883ea757..f983da9 100644
--- a/docs/clangd.md
+++ b/docs/clangd.md
@@ -110,10 +110,11 @@
 5. Use clangd in your favourite editor, see detailed [instructions](
 https://clangd.llvm.org/installation.html#editor-plugins).
 
-    * Optional: You may want to add `-header-insertion=never` to the clangd flags,
-      so that your editor doesn't automatically add incorrect #include lines. The
-      feature doesn't correctly handle some common Chromium headers like
-      `base/strings/string_piece_forward.h` and `base/callback_forward.h`
+    * Optional: You may want to add `-header-insertion=never` to the clangd
+      flags, so that your editor doesn't automatically add incorrect #include
+      lines. The feature doesn't correctly handle some common Chromium headers
+      like `base/strings/string_piece_forward.h` and
+      `base/functional/callback_forward.h`
 
 ## Background Indexing
 
diff --git a/docs/patterns/inversion-of-control.md b/docs/patterns/inversion-of-control.md
index 755235e..756e930 100644
--- a/docs/patterns/inversion-of-control.md
+++ b/docs/patterns/inversion-of-control.md
@@ -388,16 +388,16 @@
 
 should be a property on the framework object instead of a delegate method.
 
-[Bind]: ../../base/bind.h
+[Bind]: ../../base/functional/bind.h
 [BrowserListObserver]: ../../chrome/browser/ui/browser_list_observer.h
 [CallbackList]: ../../base/callback_list.h
-[Callback]: ../../base/callback.h
+[Callback]: ../../base/functional/callback.h
 [CheckedObserver]: ../../base/observer_list_types.h
 [ObserverList]: ../../base/observer_list.h
 [base::ScopedObservation]: ../../base/scoped_observation.h
 [Subscription]: ../../base/callback_list.h
 [URLRequestJobFactory::ProtocolHandler]: ../../net/url_request/url_request_job_factory.h
-[Unretained]: ../../base/bind.h
+[Unretained]: ../../base/functional/bind.h
 [ViewObserver]: ../../ui/views/view_observer.h
 [WebContentsDelegate]: ../../content/public/browser/web_contents_delegate.h
 [WebContentsObserver]: ../../content/public/browser/web_contents_observer.h
diff --git a/docs/wmax_tokens.md b/docs/wmax_tokens.md
index f708b23..1b66494 100644
--- a/docs/wmax_tokens.md
+++ b/docs/wmax_tokens.md
@@ -46,7 +46,7 @@
    using techniques such as forward declarations to avoid increasing the header
    size. Even complex classes may have forward declarations available, see for
    example
-   [https://source.chromium.org/chromium/chromium/src/+/HEAD:base/callback_forward.h](callback_forward.h)
+   [https://source.chromium.org/chromium/chromium/src/+/HEAD:base/functional/callback_forward.h](callback_forward.h)
    and
    [https://source.chromium.org/chromium/chromium/src/+/HEAD:base/strings/string_piece_forward.h](string_piece_forward.h).
    Many types defined in .mojom.h files have forward declarations in a
diff --git a/extensions/browser/api/app_runtime/BUILD.gn b/extensions/browser/api/app_runtime/BUILD.gn
index 4c820cc..8173740 100644
--- a/extensions/browser/api/app_runtime/BUILD.gn
+++ b/extensions/browser/api/app_runtime/BUILD.gn
@@ -14,7 +14,6 @@
   ]
 
   deps = [
-    "//components/services/app_service/public/mojom",
     "//extensions/common",
     "//extensions/common/api",
   ]
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 09181e8..31ad56f 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -55,7 +55,6 @@
   public_deps = [
     "//base",
     "//build:chromeos_buildflags",
-    "//components/services/app_service/public/mojom",
     "//extensions/common:export_impl",
   ]
 
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index d55e230..f5b7935 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -52,7 +52,6 @@
     "//components/origin_trials:common",
     "//components/pref_registry",
     "//components/prefs",
-    "//components/services/app_service/public/mojom",
     "//components/sessions",
     "//components/storage_monitor",
     "//components/update_client",
diff --git a/fuchsia_web/webengine/browser/context_impl_browsertest.cc b/fuchsia_web/webengine/browser/context_impl_browsertest.cc
index 74bb4b90..a3a98b6 100644
--- a/fuchsia_web/webengine/browser/context_impl_browsertest.cc
+++ b/fuchsia_web/webengine/browser/context_impl_browsertest.cc
@@ -5,11 +5,11 @@
 #include <lib/fdio/namespace.h>
 #include <stdint.h>
 
-#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/fuchsia/file_utils.h"
 #include "base/fuchsia/fuchsia_logging.h"
+#include "base/functional/bind.h"
 #include "base/no_destructor.h"
 #include "base/system/sys_info.h"
 #include "base/threading/thread_restrictions.h"
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 7f7aa7a..428c92d 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -44,7 +44,7 @@
 #endif
 
 #if defined(HEADLESS_ENABLE_COMMANDS)
-#include "components/headless/command_handler/headless_command_handler.h"
+#include "components/headless/command_handler/headless_command_handler.h"  // nogncheck
 #endif
 
 namespace headless {
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 3feda14..70ffdd8 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -22200,7 +22200,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "free_space:standard"
-      dimensions: "os:Ubuntu-20.04"
+      dimensions: "os:Ubuntu-18.04"
       dimensions: "pool:luci.chromium.ci"
       dimensions: "ssd:0"
       exe {
@@ -79818,7 +79818,7 @@
       dimensions: "builderless:1"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-20.04"
+      dimensions: "os:Ubuntu-18.04"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:0"
       exe {
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star
index dbcdb9c..610f648b 100644
--- a/infra/config/subprojects/chromium/ci/chromium.memory.star
+++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -539,7 +539,6 @@
         category = "linux|webkit",
         short_name = "msn",
     ),
-    os = os.LINUX_FOCAL,
 )
 
 ci.builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index af10099..6d39cbb 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -312,7 +312,6 @@
     ],
     goma_backend = None,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
-    os = os.LINUX_FOCAL,
 )
 
 try_.builder(
diff --git a/ios/third_party/gtx/BUILD.gn b/ios/third_party/gtx/BUILD.gn
index a0840ca..1a54c94 100644
--- a/ios/third_party/gtx/BUILD.gn
+++ b/ios/third_party/gtx/BUILD.gn
@@ -21,7 +21,6 @@
 proto_library("proto") {
   sources = [ "src/OOPClasses/Protos/gtx.proto" ]
   cc_generator_options = "lite"
-  allow_optional = true
 }
 
 source_set("oop_classes") {
diff --git a/media/base/audio_codecs.cc b/media/base/audio_codecs.cc
index 5ce194a4..f28f7d2d 100644
--- a/media/base/audio_codecs.cc
+++ b/media/base/audio_codecs.cc
@@ -88,10 +88,6 @@
     return AudioCodec::kOpus;
   if (codec_id == "vorbis")
     return AudioCodec::kVorbis;
-  if (codec_id == "dtsc")
-    return AudioCodec::kDTS;
-  if (codec_id == "dtsx")
-    return AudioCodec::kDTSXP2;
   if (base::StartsWith(codec_id, "mp4a.40.", base::CompareCase::SENSITIVE))
     return AudioCodec::kAAC;
   return AudioCodec::kUnknown;
diff --git a/mojo/public/tools/mojom/mojom_parser.py b/mojo/public/tools/mojom/mojom_parser.py
index 00543b5b..9693090e 100755
--- a/mojo/public/tools/mojom/mojom_parser.py
+++ b/mojo/public/tools/mojom/mojom_parser.py
@@ -61,7 +61,7 @@
   raise ValueError('"%s" does not exist in any of %s' % (path, roots))
 
 
-def _RebaseAbsolutePath(path, roots):
+def RebaseAbsolutePath(path, roots):
   """Rewrites an absolute file path as relative to an absolute directory path in
   roots.
 
@@ -294,7 +294,7 @@
   loaded_modules = {}
   input_dependencies = defaultdict(set)
   mojom_files_to_parse = dict((os.path.normcase(abs_path),
-                               _RebaseAbsolutePath(abs_path, input_root_paths))
+                               RebaseAbsolutePath(abs_path, input_root_paths))
                               for abs_path in mojom_files)
   abs_paths = dict(
       (path, abs_path) for abs_path, path in mojom_files_to_parse.items())
diff --git a/net/BUILD.gn b/net/BUILD.gn
index d00ab54..42081e32 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1576,6 +1576,8 @@
       "websockets/websocket_handshake_stream_create_helper.h",
       "websockets/websocket_http2_handshake_stream.cc",
       "websockets/websocket_http2_handshake_stream.h",
+      "websockets/websocket_http3_handshake_stream.cc",
+      "websockets/websocket_http3_handshake_stream.h",
       "websockets/websocket_inflater.cc",
       "websockets/websocket_inflater.h",
       "websockets/websocket_quic_spdy_stream.cc",
diff --git a/net/disk_cache/blockfile/backend_impl.h b/net/disk_cache/blockfile/backend_impl.h
index bcb8f85..453949a 100644
--- a/net/disk_cache/blockfile/backend_impl.h
+++ b/net/disk_cache/blockfile/backend_impl.h
@@ -400,7 +400,11 @@
   InFlightBackendIO background_queue_;  // The controller of pending operations.
   scoped_refptr<MappedFile> index_;  // The main cache index.
   base::FilePath path_;  // Path to the folder used as backing storage.
-  raw_ptr<Index> data_;  // Pointer to the index data.
+
+  // Pointer to the index data.
+  // May point to a mapped file's unmapped memory at destruction time.
+  raw_ptr<Index, DisableDanglingPtrDetection> data_;
+
   BlockFiles block_files_;  // Set of files used to store all data.
   Rankings rankings_;  // Rankings to be able to trim the cache.
   uint32_t mask_ = 0;  // Binary mask to map a hash to the hash table.
diff --git a/net/disk_cache/blockfile/eviction.h b/net/disk_cache/blockfile/eviction.h
index f6f5f05..faef34f 100644
--- a/net/disk_cache/blockfile/eviction.h
+++ b/net/disk_cache/blockfile/eviction.h
@@ -75,7 +75,10 @@
 
   raw_ptr<BackendImpl> backend_ = nullptr;
   raw_ptr<Rankings> rankings_;
-  raw_ptr<IndexHeader> header_;
+
+  // May point to a mapped file's unmapped memory at destruction time.
+  raw_ptr<IndexHeader, DisableDanglingPtrDetection> header_;
+
   int max_size_;
   int trim_delays_;
   int index_size_;
diff --git a/net/disk_cache/blockfile/rankings.h b/net/disk_cache/blockfile/rankings.h
index 74148eb4..3e98029 100644
--- a/net/disk_cache/blockfile/rankings.h
+++ b/net/disk_cache/blockfile/rankings.h
@@ -211,7 +211,11 @@
   Addr heads_[LAST_ELEMENT];
   Addr tails_[LAST_ELEMENT];
   raw_ptr<BackendImpl> backend_;
-  raw_ptr<LruData> control_data_;  // Data related to the LRU lists.
+
+  // Data related to the LRU lists.
+  // May point to a mapped file's unmapped memory at destruction time.
+  raw_ptr<LruData, DisableDanglingPtrDetection> control_data_;
+
   IteratorList iterators_;
 };
 
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 961ded4..f85d002 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -713,6 +713,12 @@
     NOTREACHED();
     return nullptr;
   }
+  std::unique_ptr<WebSocketHandshakeStreamBase> CreateHttp3Stream(
+      std::unique_ptr<QuicChromiumClientSession::Handle> session,
+      std::set<std::string> dns_aliases) override {
+    NOTREACHED();
+    return nullptr;
+  }
 };
 
 // Returns true if |entry| is not one of the log types paid attention to in this
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index 25a682e..3a15a59 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -357,6 +357,12 @@
     NOTREACHED();
     return nullptr;
   }
+  std::unique_ptr<WebSocketHandshakeStreamBase> CreateHttp3Stream(
+      std::unique_ptr<QuicChromiumClientSession::Handle> session,
+      std::set<std::string> dns_aliases) override {
+    NOTREACHED();
+    return nullptr;
+  }
 };
 
 struct TestCase {
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index 24e52b8..195b7c8 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -4026,8 +4026,7 @@
       GetNextOutgoingBidirectionalStreamId(), this, quic::BIDIRECTIONAL);
 
   auto adapter = std::make_unique<WebSocketQuicStreamAdapter>(
-      websocket_quic_spdy_stream.get());
-
+      websocket_quic_spdy_stream.get(), delegate);
   ActivateStream(std::move(websocket_quic_spdy_stream));
 
   ++num_total_streams_;
diff --git a/net/websockets/websocket_basic_stream_adapters.cc b/net/websockets/websocket_basic_stream_adapters.cc
index 1fd9c2e..12c7e5c9 100644
--- a/net/websockets/websocket_basic_stream_adapters.cc
+++ b/net/websockets/websocket_basic_stream_adapters.cc
@@ -15,6 +15,7 @@
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/socket.h"
 #include "net/spdy/spdy_buffer.h"
+#include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
 #include "net/websockets/websocket_quic_spdy_stream.h"
 
 namespace net {
@@ -230,8 +231,10 @@
 }
 
 WebSocketQuicStreamAdapter::WebSocketQuicStreamAdapter(
-    WebSocketQuicSpdyStream* websocket_quic_spdy_stream)
-    : websocket_quic_spdy_stream_(websocket_quic_spdy_stream) {
+    WebSocketQuicSpdyStream* websocket_quic_spdy_stream,
+    Delegate* delegate)
+    : websocket_quic_spdy_stream_(websocket_quic_spdy_stream),
+      delegate_(delegate) {
   websocket_quic_spdy_stream_->set_delegate(this);
 }
 
@@ -241,6 +244,13 @@
   }
 }
 
+size_t WebSocketQuicStreamAdapter::WriteHeaders(
+    spdy::Http2HeaderBlock header_block,
+    bool fin) {
+  return websocket_quic_spdy_stream_->WriteHeaders(std::move(header_block), fin,
+                                                   nullptr);
+}
+
 // WebSocketBasicStream::Adapter methods.
 int WebSocketQuicStreamAdapter::Read(IOBuffer* buf,
                                      int buf_len,
@@ -269,14 +279,31 @@
 }
 
 // WebSocketQuicSpdyStream::Delegate methods.
-void WebSocketQuicStreamAdapter::ClearStream() {
-  if (websocket_quic_spdy_stream_) {
-    websocket_quic_spdy_stream_ = nullptr;
+
+void WebSocketQuicStreamAdapter::OnInitialHeadersComplete(
+    bool fin,
+    size_t frame_len,
+    const quic::QuicHeaderList& quic_header_list) {
+  spdy::Http2HeaderBlock response_headers;
+  if (!quic::SpdyUtils::CopyAndValidateHeaders(quic_header_list, nullptr,
+                                               &response_headers)) {
+    DLOG(ERROR) << "Failed to parse header list: "
+                << quic_header_list.DebugString();
+    websocket_quic_spdy_stream_->ConsumeHeaderList();
+    websocket_quic_spdy_stream_->Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD);
+    return;
   }
+  delegate_->OnHeadersReceived(response_headers);
 }
 
 void WebSocketQuicStreamAdapter::OnBodyAvailable() {
   // TODO(momoka): implement this.
 }
 
+void WebSocketQuicStreamAdapter::ClearStream() {
+  if (websocket_quic_spdy_stream_) {
+    websocket_quic_spdy_stream_ = nullptr;
+  }
+}
+
 }  // namespace net
diff --git a/net/websockets/websocket_basic_stream_adapters.h b/net/websockets/websocket_basic_stream_adapters.h
index f89a285..f644b9bf 100644
--- a/net/websockets/websocket_basic_stream_adapters.h
+++ b/net/websockets/websocket_basic_stream_adapters.h
@@ -158,8 +158,21 @@
     : public WebSocketBasicStream::Adapter,
       public WebSocketQuicSpdyStream::Delegate {
  public:
+  // The Delegate interface is implemented by WebSocketHttp3HandshakeStream the
+  // user of the WebSocketQuicStreamAdapter to receive events related to the
+  // lifecycle of the Adapter.
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+    virtual void OnHeadersSent() = 0;
+    virtual void OnHeadersReceived(
+        const spdy::Http2HeaderBlock& response_headers) = 0;
+    virtual void OnClose(int status) = 0;
+  };
+
   explicit WebSocketQuicStreamAdapter(
-      WebSocketQuicSpdyStream* websocket_quic_spdy_stream);
+      WebSocketQuicSpdyStream* websocket_quic_spdy_stream,
+      Delegate* delegate);
 
   WebSocketQuicStreamAdapter(const WebSocketQuicStreamAdapter&) = delete;
   WebSocketQuicStreamAdapter& operator=(const WebSocketQuicStreamAdapter&) =
@@ -167,6 +180,11 @@
 
   ~WebSocketQuicStreamAdapter() override;
 
+  // Called by WebSocketQuicStreamAdapter::Delegate before it is destroyed.
+  void clear_delegate() { delegate_ = nullptr; }
+
+  size_t WriteHeaders(spdy::Http2HeaderBlock header_block, bool fin);
+
   // WebSocketBasicStream::Adapter methods.
   // TODO(momoka): Add functions that are needed to implement
   // WebSocketHttp3HandshakeStream.
@@ -181,13 +199,19 @@
   bool is_initialized() const override;
 
   // WebSocketQuicSpdyStream::Delegate methods.
-  void ClearStream() override;
+  void OnInitialHeadersComplete(
+      bool fin,
+      size_t frame_len,
+      const quic::QuicHeaderList& header_list) override;
   void OnBodyAvailable() override;
+  void ClearStream() override;
 
  private:
   //  `websocket_quic_spdy_stream_` notifies this object of its destruction,
   //  because they may be destroyed in any order.
   raw_ptr<WebSocketQuicSpdyStream> websocket_quic_spdy_stream_;
+
+  raw_ptr<Delegate> delegate_;
 };
 
 }  // namespace net
diff --git a/net/websockets/websocket_basic_stream_adapters_test.cc b/net/websockets/websocket_basic_stream_adapters_test.cc
index 00fd848a..51ab64c 100644
--- a/net/websockets/websocket_basic_stream_adapters_test.cc
+++ b/net/websockets/websocket_basic_stream_adapters_test.cc
@@ -61,6 +61,7 @@
 
 using testing::_;
 using testing::AnyNumber;
+using testing::Invoke;
 using testing::Return;
 using testing::StrictMock;
 using testing::Test;
@@ -290,9 +291,12 @@
 class MockDelegate : public WebSocketSpdyStreamAdapter::Delegate {
  public:
   ~MockDelegate() override = default;
-  MOCK_METHOD0(OnHeadersSent, void());
-  MOCK_METHOD1(OnHeadersReceived, void(const spdy::Http2HeaderBlock&));
-  MOCK_METHOD1(OnClose, void(int));
+  MOCK_METHOD(void, OnHeadersSent, (), (override));
+  MOCK_METHOD(void,
+              OnHeadersReceived,
+              (const spdy::Http2HeaderBlock&),
+              (override));
+  MOCK_METHOD(void, OnClose, (int), (override));
 };
 
 class WebSocketSpdyStreamAdapterTest : public TestWithTaskEnvironment {
@@ -1075,15 +1079,22 @@
 class MockQuicDelegate : public WebSocketQuicStreamAdapter::Delegate {
  public:
   ~MockQuicDelegate() override = default;
-  MOCK_METHOD(void, OnBodyAvailable, (), (override));
-  MOCK_METHOD(void, Reset, ());
-  MOCK_METHOD(void, ClearStream, ());
+  MOCK_METHOD(void, OnHeadersSent, (), (override));
+  MOCK_METHOD(void,
+              OnHeadersReceived,
+              (const spdy::Http2HeaderBlock&),
+              (override));
+  MOCK_METHOD(void, OnClose, (int), (override));
 };
 
 class WebSocketQuicStreamAdapterTest
     : public TestWithTaskEnvironment,
       public ::testing::WithParamInterface<quic::ParsedQuicVersion> {
  protected:
+  static spdy::Http2HeaderBlock RequestHeaders() {
+    return WebSocketHttp2Request("/", "www.example.org:443",
+                                 "http://www.example.org", {});
+  }
   WebSocketQuicStreamAdapterTest()
       : version_(GetParam()),
         mock_quic_data_(version_),
@@ -1106,6 +1117,12 @@
                       "mail.example.org",
                       quic::Perspective::IS_CLIENT,
                       /*client_headers_include_h2_stream_dependency_=*/false),
+        server_maker_(version_,
+                      connection_id_,
+                      &clock_,
+                      "mail.example.org",
+                      quic::Perspective::IS_SERVER,
+                      /*client_headers_include_h2_stream_dependency_=*/false),
         peer_addr_(IPAddress(192, 0, 2, 23), 443),
         destination_endpoint_(url::kHttpsScheme, "mail.example.org", 80) {}
 
@@ -1141,6 +1158,17 @@
                                        /*include_stop_sending_if_v99=*/true);
   }
 
+  std::unique_ptr<quic::QuicReceivedPacket> ConstructAckAndRstPacket(
+      uint64_t packet_number,
+      quic::QuicRstStreamErrorCode error_code,
+      uint64_t largest_received,
+      uint64_t smallest_received) {
+    return client_maker_.MakeAckAndRstPacket(
+        packet_number, /*include_version=*/false, client_data_stream_id1_,
+        error_code, largest_received, smallest_received,
+        /*include_stop_sending_if_v99=*/true);
+  }
+
   void Initialize() {
     auto socket = std::make_unique<MockUDPClientSocket>(
         mock_quic_data_.InitializeAndGetSequencedSocketData(), NetLog::Get());
@@ -1222,16 +1250,21 @@
   const quic::ParsedQuicVersion version_;
   MockQuicData mock_quic_data_;
   StrictMock<MockQuicDelegate> mock_delegate_;
+  const quic::QuicStreamId client_data_stream_id1_;
 
  private:
-  const quic::QuicStreamId client_data_stream_id1_;
-  quic::MockClock clock_;
-  std::unique_ptr<QuicChromiumClientSession> session_;
-  std::unique_ptr<QuicChromiumClientSession::Handle> session_handle_;
-  scoped_refptr<TestTaskRunner> runner_;
   quic::QuicCryptoClientConfig crypto_config_;
   const quic::QuicConnectionId connection_id_;
+
+ protected:
   QuicTestPacketMaker client_maker_;
+  QuicTestPacketMaker server_maker_;
+  std::unique_ptr<QuicChromiumClientSession> session_;
+
+ private:
+  quic::MockClock clock_;
+  std::unique_ptr<QuicChromiumClientSession::Handle> session_handle_;
+  scoped_refptr<TestTaskRunner> runner_;
   ProofVerifyDetailsChromium verify_details_;
   MockCryptoClientStreamFactory crypto_client_stream_factory_;
   quic::test::MockConnectionIdGenerator connection_id_generator_;
@@ -1276,4 +1309,95 @@
   // TODO(momoka): Add tests to test both destruction orders.
 }
 
+TEST_P(WebSocketQuicStreamAdapterTest, SendRequestHeadersThenDisconnect) {
+  int packet_number = 1;
+  if (VersionUsesHttp3(version_.transport_version)) {
+    mock_quic_data_.AddWrite(SYNCHRONOUS,
+                             ConstructSettingsPacket(packet_number++));
+  }
+  SpdyTestUtil spdy_util;
+  spdy::Http2HeaderBlock request_header_block = WebSocketHttp2Request(
+      "/", "www.example.org:443", "http://www.example.org", {});
+  mock_quic_data_.AddWrite(
+      SYNCHRONOUS,
+      client_maker_.MakeRequestHeadersPacket(
+          packet_number++, client_data_stream_id1_,
+          /*should_include_version=*/true,
+          /*fin=*/false, ConvertRequestPriorityToQuicPriority(LOWEST),
+          std::move(request_header_block), 0, nullptr));
+
+  mock_quic_data_.AddWrite(
+      SYNCHRONOUS,
+      ConstructRstPacket(packet_number++, quic::QUIC_STREAM_CANCELLED));
+
+  Initialize();
+
+  net::QuicChromiumClientSession::Handle* session_handle =
+      GetQuicSessionHandle();
+  ASSERT_TRUE(session_handle);
+
+  std::unique_ptr<WebSocketQuicStreamAdapter> adapter =
+      session_handle->CreateWebSocketQuicStreamAdapter(&mock_delegate_);
+  ASSERT_TRUE(adapter);
+  EXPECT_TRUE(adapter->is_initialized());
+
+  adapter->WriteHeaders(RequestHeaders(), false);
+
+  adapter->Disconnect();
+}
+
+TEST_P(WebSocketQuicStreamAdapterTest, OnHeadersReceivedThenDisconnect) {
+  int packet_number = 1;
+  if (VersionUsesHttp3(version_.transport_version)) {
+    mock_quic_data_.AddWrite(SYNCHRONOUS,
+                             ConstructSettingsPacket(packet_number++));
+  }
+
+  SpdyTestUtil spdy_util;
+  spdy::Http2HeaderBlock request_header_block = WebSocketHttp2Request(
+      "/", "www.example.org:443", "http://www.example.org", {});
+  mock_quic_data_.AddWrite(
+      SYNCHRONOUS,
+      client_maker_.MakeRequestHeadersPacket(
+          packet_number++, client_data_stream_id1_,
+          /*should_include_version=*/true,
+          /*fin=*/false, ConvertRequestPriorityToQuicPriority(LOWEST),
+          std::move(request_header_block), 0, nullptr));
+
+  spdy::Http2HeaderBlock response_header_block = WebSocketHttp2Response({});
+  mock_quic_data_.AddRead(ASYNC,
+                          server_maker_.MakeResponseHeadersPacket(
+                              /*packet_number=*/1, client_data_stream_id1_,
+                              /*should_include_version=*/false, /*fin=*/false,
+                              std::move(response_header_block),
+                              /*spdy_headers_frame_length=*/nullptr));
+  mock_quic_data_.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+  mock_quic_data_.AddWrite(
+      SYNCHRONOUS, ConstructAckAndRstPacket(packet_number++,
+                                            quic::QUIC_STREAM_CANCELLED, 1, 0));
+  base::RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+  EXPECT_CALL(mock_delegate_, OnHeadersReceived(_)).WillOnce(Invoke([&]() {
+    std::move(quit_closure).Run();
+  }));
+
+  Initialize();
+
+  net::QuicChromiumClientSession::Handle* session_handle =
+      GetQuicSessionHandle();
+  ASSERT_TRUE(session_handle);
+
+  std::unique_ptr<WebSocketQuicStreamAdapter> adapter =
+      session_handle->CreateWebSocketQuicStreamAdapter(&mock_delegate_);
+  ASSERT_TRUE(adapter);
+  EXPECT_TRUE(adapter->is_initialized());
+
+  adapter->WriteHeaders(RequestHeaders(), false);
+
+  session_->StartReading();
+  run_loop.Run();
+
+  adapter->Disconnect();
+}
+
 }  // namespace net::test
diff --git a/net/websockets/websocket_handshake_stream_base.h b/net/websockets/websocket_handshake_stream_base.h
index b9409d57..c169757 100644
--- a/net/websockets/websocket_handshake_stream_base.h
+++ b/net/websockets/websocket_handshake_stream_base.h
@@ -18,6 +18,7 @@
 #include "base/supports_user_data.h"
 #include "net/base/net_export.h"
 #include "net/http/http_stream.h"
+#include "net/quic/quic_chromium_client_session.h"
 #include "net/websockets/websocket_deflate_parameters.h"
 #include "net/websockets/websocket_stream.h"
 
@@ -112,6 +113,13 @@
     virtual std::unique_ptr<WebSocketHandshakeStreamBase> CreateHttp2Stream(
         base::WeakPtr<SpdySession> session,
         std::set<std::string> dns_aliases) = 0;
+
+    // Create a WebSocketHttp3HandshakeStream. This is called after the
+    // underlying HTTP/3 connection has been established but before the stream
+    // has been opened.  This cannot be called more than once.
+    virtual std::unique_ptr<WebSocketHandshakeStreamBase> CreateHttp3Stream(
+        std::unique_ptr<QuicChromiumClientSession::Handle> session,
+        std::set<std::string> dns_aliases) = 0;
   };
 
   // After the handshake has completed, this method creates a WebSocketStream
diff --git a/net/websockets/websocket_handshake_stream_create_helper.cc b/net/websockets/websocket_handshake_stream_create_helper.cc
index 38606f99..4fd8f901 100644
--- a/net/websockets/websocket_handshake_stream_create_helper.cc
+++ b/net/websockets/websocket_handshake_stream_create_helper.cc
@@ -12,6 +12,7 @@
 #include "net/socket/client_socket_handle.h"
 #include "net/websockets/websocket_basic_handshake_stream.h"
 #include "net/websockets/websocket_http2_handshake_stream.h"
+#include "net/websockets/websocket_http3_handshake_stream.h"
 
 namespace net {
 
@@ -60,4 +61,18 @@
   return stream;
 }
 
+std::unique_ptr<WebSocketHandshakeStreamBase>
+WebSocketHandshakeStreamCreateHelper::CreateHttp3Stream(
+    std::unique_ptr<QuicChromiumClientSession::Handle> session,
+    std::set<std::string> dns_aliases) {
+  std::vector<std::string> extensions(
+      1, "permessage-deflate; client_max_window_bits");
+
+  auto stream = std::make_unique<WebSocketHttp3HandshakeStream>(
+      std::move(session), connect_delegate_, requested_subprotocols_,
+      extensions, request_, std::move(dns_aliases));
+  request_->OnHttp3HandshakeStreamCreated(stream.get());
+  return stream;
+}
+
 }  // namespace net
diff --git a/net/websockets/websocket_handshake_stream_create_helper.h b/net/websockets/websocket_handshake_stream_create_helper.h
index 1291a2c8..c67dacb6 100644
--- a/net/websockets/websocket_handshake_stream_create_helper.h
+++ b/net/websockets/websocket_handshake_stream_create_helper.h
@@ -57,6 +57,10 @@
       base::WeakPtr<SpdySession> session,
       std::set<std::string> dns_aliases) override;
 
+  std::unique_ptr<WebSocketHandshakeStreamBase> CreateHttp3Stream(
+      std::unique_ptr<QuicChromiumClientSession::Handle> session,
+      std::set<std::string> dns_aliases) override;
+
  private:
   const raw_ptr<WebSocketStream::ConnectDelegate, DanglingUntriaged>
       connect_delegate_;
diff --git a/net/websockets/websocket_handshake_stream_create_helper_test.cc b/net/websockets/websocket_handshake_stream_create_helper_test.cc
index 3982e7e..d66aa15 100644
--- a/net/websockets/websocket_handshake_stream_create_helper_test.cc
+++ b/net/websockets/websocket_handshake_stream_create_helper_test.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/memory/scoped_refptr.h"
+#include "base/task/single_thread_task_runner.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_endpoint.h"
@@ -23,6 +24,15 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/http_response_info.h"
 #include "net/log/net_log_with_source.h"
+#include "net/quic/address_utils.h"
+#include "net/quic/mock_crypto_client_stream_factory.h"
+#include "net/quic/mock_quic_data.h"
+#include "net/quic/quic_chromium_alarm_factory.h"
+#include "net/quic/quic_chromium_connection_helper.h"
+#include "net/quic/quic_server_info.h"
+#include "net/quic/quic_test_packet_maker.h"
+#include "net/quic/test_quic_crypto_client_config_handle.h"
+#include "net/quic/test_task_runner.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/connect_job.h"
 #include "net/socket/socket_tag.h"
@@ -38,6 +48,7 @@
 #include "net/test/gtest_util.h"
 #include "net/test/test_data_directory.h"
 #include "net/test/test_with_task_environment.h"
+#include "net/third_party/quiche/src/quiche/quic/test_tools/crypto_test_utils.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/websockets/websocket_basic_handshake_stream.h"
 #include "net/websockets/websocket_stream.h"
@@ -60,7 +71,11 @@
 namespace net {
 namespace {
 
-enum HandshakeStreamType { BASIC_HANDSHAKE_STREAM, HTTP2_HANDSHAKE_STREAM };
+enum HandshakeStreamType {
+  BASIC_HANDSHAKE_STREAM,
+  HTTP2_HANDSHAKE_STREAM,
+  HTTP3_HANDSHAKE_STREAM
+};
 
 // This class encapsulates the details of creating a mock ClientSocketHandle.
 class MockClientSocketHandleFactory {
@@ -150,6 +165,8 @@
                void(WebSocketBasicHandshakeStream* handshake_stream));
   MOCK_METHOD1(OnHttp2HandshakeStreamCreated,
                void(WebSocketHttp2HandshakeStream* handshake_stream));
+  MOCK_METHOD1(OnHttp3HandshakeStreamCreated,
+               void(WebSocketHttp3HandshakeStream* handshake_stream));
   MOCK_METHOD3(OnFailure,
                void(const std::string& message,
                     int net_error,
@@ -181,6 +198,10 @@
         EXPECT_CALL(stream_request_, OnHttp2HandshakeStreamCreated(_)).Times(1);
         break;
 
+      case HTTP3_HANDSHAKE_STREAM:
+        EXPECT_CALL(stream_request_, OnHttp3HandshakeStreamCreated(_)).Times(1);
+        break;
+
       default:
         NOTREACHED();
     }
@@ -359,5 +380,218 @@
       stream->GetExtensions());
 }
 
+// Temporary test class to test the creation of WebSocketHttp3HandshakeStream.
+// TODO(momoka): Move this function inside
+// HandshakeStreamCreateHelperTest::CreateAndInitializeStream() once
+// implementation of WebSocketHttp3HandshakeStream is done.
+class TemporaryHttp3WebSocketHandshakeStreamCreateHelperTest
+    : public TestWithTaskEnvironment {
+ protected:
+  void CreateAndInitializeStream(
+      const std::vector<std::string>& sub_protocols,
+      const WebSocketExtraHeaders& extra_request_headers,
+      const WebSocketExtraHeaders& extra_response_headers) {
+    const char kPath[] = "/";
+    const char kOrigin[] = "http://origin.example.org";
+    const GURL url("wss://www.example.org/");
+    NetLogWithSource net_log;
+
+    WebSocketHandshakeStreamCreateHelper create_helper(
+        &connect_delegate_, sub_protocols, &stream_request_);
+
+    EXPECT_CALL(stream_request_, OnHttp3HandshakeStreamCreated(_));
+
+    EXPECT_CALL(stream_request_, OnFailure(_, _, _)).Times(0);
+
+    HttpRequestInfo request_info;
+    request_info.url = url;
+    request_info.method = "GET";
+    request_info.load_flags = LOAD_DISABLE_CACHE;
+    request_info.traffic_annotation =
+        MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+
+    auto headers = WebSocketCommonTestHeaders();
+
+    quic::ParsedQuicVersion quic_version = quic::ParsedQuicVersion(
+        quic::HandshakeProtocol::PROTOCOL_TLS1_3,
+        quic::QuicTransportVersion::QUIC_VERSION_IETF_RFC_V1);
+    test::MockQuicData mock_quic_data(quic_version);
+    const quic::QuicStreamId client_data_stream_id1(
+        quic::QuicUtils::GetFirstBidirectionalStreamId(
+            quic_version.transport_version, quic::Perspective::IS_CLIENT));
+    quic::QuicCryptoClientConfig crypto_config(
+        quic::test::crypto_test_utils::ProofVerifierForTesting());
+
+    const quic::QuicConnectionId connection_id(quic::test::TestConnectionId(2));
+    test::QuicTestPacketMaker client_maker(
+        quic_version, connection_id, &clock_, "mail.example.org",
+        quic::Perspective::IS_CLIENT,
+        /*client_headers_include_h2_stream_dependency_=*/false);
+    test::QuicTestPacketMaker server_maker(
+        quic_version, connection_id, &clock_, "mail.example.org",
+        quic::Perspective::IS_SERVER,
+        /*client_headers_include_h2_stream_dependency_=*/false);
+    IPEndPoint peer_addr(IPAddress(192, 0, 2, 23), 443);
+    quic::test::MockConnectionIdGenerator connection_id_generator;
+
+    testing::StrictMock<quic::test::MockQuicConnectionVisitor> visitor;
+    ProofVerifyDetailsChromium verify_details;
+    MockCryptoClientStreamFactory crypto_client_stream_factory;
+    TransportSecurityState transport_security_state;
+    quic::test::NoopQpackStreamSenderDelegate noop_qpack_stream_sender_delegate;
+
+    FLAGS_quic_enable_http3_grease_randomness = false;
+    clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(20));
+    quic::QuicEnableVersion(quic_version);
+    quic::test::MockRandom random_generator{0};
+
+    spdy::Http2HeaderBlock request_header_block = WebSocketHttp2Request(
+        kPath, "www.example.org", kOrigin, extra_request_headers);
+
+    int packet_number = 1;
+    mock_quic_data.AddWrite(
+        SYNCHRONOUS, client_maker.MakeInitialSettingsPacket(packet_number++));
+
+    mock_quic_data.AddWrite(
+        ASYNC, client_maker.MakeRequestHeadersPacket(
+                   packet_number++, client_data_stream_id1,
+                   /*should_include_version=*/true,
+                   /*fin=*/false, ConvertRequestPriorityToQuicPriority(LOWEST),
+                   std::move(request_header_block), 0, nullptr));
+
+    spdy::Http2HeaderBlock response_header_block =
+        WebSocketHttp2Response(extra_response_headers);
+
+    mock_quic_data.AddRead(ASYNC,
+                           server_maker.MakeResponseHeadersPacket(
+                               /*packet_number=*/1, client_data_stream_id1,
+                               /*should_include_version=*/true, /*fin=*/false,
+                               std::move(response_header_block),
+                               /*spdy_headers_frame_length=*/nullptr));
+
+    mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+
+    mock_quic_data.AddWrite(
+        SYNCHRONOUS,
+        client_maker.MakeAckAndRstPacket(
+            packet_number++, /*include_version=*/false, client_data_stream_id1,
+            quic::QUIC_STREAM_CANCELLED, 1, 0,
+            /*include_stop_sending_if_v99=*/true));
+    auto socket = std::make_unique<MockUDPClientSocket>(
+        mock_quic_data.InitializeAndGetSequencedSocketData(), NetLog::Get());
+    socket->Connect(peer_addr);
+
+    scoped_refptr<test::TestTaskRunner> runner =
+        base::MakeRefCounted<test::TestTaskRunner>(&clock_);
+    auto helper = std::make_unique<QuicChromiumConnectionHelper>(
+        &clock_, &random_generator);
+    auto alarm_factory =
+        std::make_unique<QuicChromiumAlarmFactory>(runner.get(), &clock_);
+    // Ownership of 'writer' is passed to 'QuicConnection'.
+    QuicChromiumPacketWriter* writer = new QuicChromiumPacketWriter(
+        socket.get(), base::SingleThreadTaskRunner::GetCurrentDefault().get());
+    quic::QuicConnection* connection = new quic::QuicConnection(
+        connection_id, quic::QuicSocketAddress(),
+        net::ToQuicSocketAddress(peer_addr), helper.get(), alarm_factory.get(),
+        writer, true /* owns_writer */, quic::Perspective::IS_CLIENT,
+        quic::test::SupportedVersions(quic_version), connection_id_generator);
+    connection->set_visitor(&visitor);
+
+    // Load a certificate that is valid for *.example.org
+    scoped_refptr<X509Certificate> test_cert(
+        ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+    EXPECT_TRUE(test_cert.get());
+
+    verify_details.cert_verify_result.verified_cert = test_cert;
+    verify_details.cert_verify_result.is_issued_by_known_root = true;
+    crypto_client_stream_factory.AddProofVerifyDetails(&verify_details);
+
+    base::TimeTicks dns_end = base::TimeTicks::Now();
+    base::TimeTicks dns_start = dns_end - base::Milliseconds(1);
+
+    auto session = std::make_unique<QuicChromiumClientSession>(
+        connection, std::move(socket),
+        /*stream_factory=*/nullptr, &crypto_client_stream_factory, &clock_,
+        &transport_security_state, /*ssl_config_service=*/nullptr,
+        /*server_info=*/nullptr,
+        QuicSessionKey("mail.example.org", 80, PRIVACY_MODE_DISABLED,
+                       SocketTag(), NetworkAnonymizationKey(),
+                       SecureDnsPolicy::kAllow,
+                       /*require_dns_https_alpn=*/false),
+        /*require_confirmation=*/false,
+        /*migrate_session_early_v2=*/false,
+        /*migrate_session_on_network_change_v2=*/false,
+        /*default_network=*/handles::kInvalidNetworkHandle,
+        quic::QuicTime::Delta::FromMilliseconds(
+            kDefaultRetransmittableOnWireTimeout.InMilliseconds()),
+        /*migrate_idle_session=*/true, /*allow_port_migration=*/false,
+        kDefaultIdleSessionMigrationPeriod, kMaxTimeOnNonDefaultNetwork,
+        kMaxMigrationsToNonDefaultNetworkOnWriteError,
+        kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
+        kQuicYieldAfterPacketsRead,
+        quic::QuicTime::Delta::FromMilliseconds(
+            kQuicYieldAfterDurationMilliseconds),
+        /*client_headers_include_h2_stream_dependency_=*/false,
+        /*cert_verify_flags=*/0, quic::test::DefaultQuicConfig(),
+        std::make_unique<TestQuicCryptoClientConfigHandle>(&crypto_config),
+        "CONNECTION_UNKNOWN", dns_start, dns_end,
+        std::make_unique<quic::QuicClientPushPromiseIndex>(), nullptr,
+        base::DefaultTickClock::GetInstance(),
+        base::SingleThreadTaskRunner::GetCurrentDefault().get(),
+        /*socket_performance_watcher=*/nullptr, NetLog::Get());
+
+    session->Initialize();
+
+    // Blackhole QPACK decoder stream instead of constructing mock writes.
+    session->qpack_decoder()->set_qpack_stream_sender_delegate(
+        &noop_qpack_stream_sender_delegate);
+    TestCompletionCallback callback;
+    EXPECT_THAT(session->CryptoConnect(callback.callback()), IsOk());
+    EXPECT_TRUE(session->OneRttKeysAvailable());
+    std::unique_ptr<QuicChromiumClientSession::Handle> session_handle =
+        session->CreateHandle(
+            url::SchemeHostPort(url::kHttpsScheme, "mail.example.org", 80));
+
+    std::unique_ptr<WebSocketHandshakeStreamBase> handshake =
+        create_helper.CreateHttp3Stream(std::move(session_handle),
+                                        {} /* dns_aliases */);
+    ASSERT_TRUE(handshake);
+
+    handshake->RegisterRequest(&request_info);
+    int rv = handshake->InitializeStream(true, DEFAULT_PRIORITY, net_log,
+                                         CompletionOnceCallback());
+    EXPECT_THAT(rv, IsOk());
+
+    HttpResponseInfo response;
+    TestCompletionCallback request_callback;
+    rv =
+        handshake->SendRequest(headers, &response, request_callback.callback());
+    EXPECT_THAT(rv, IsOk());
+
+    session->StartReading();
+
+    TestCompletionCallback response_callback;
+    rv = handshake->ReadResponseHeaders(response_callback.callback());
+    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+    rv = response_callback.WaitForResult();
+    EXPECT_THAT(rv, IsOk());
+
+    EXPECT_EQ(200, response.headers->response_code());
+
+    handshake->Upgrade();
+  }
+
+ private:
+  quic::MockClock clock_;
+  MockClientSocketHandleFactory socket_handle_factory_;
+  TestConnectDelegate connect_delegate_;
+  StrictMock<MockWebSocketStreamRequestAPI> stream_request_;
+  WebSocketEndpointLockManager websocket_endpoint_lock_manager_;
+};
+
+TEST_F(TemporaryHttp3WebSocketHandshakeStreamCreateHelperTest, BasicStream) {
+  CreateAndInitializeStream({}, {}, {});
+}
+
 }  // namespace
 }  // namespace net
diff --git a/net/websockets/websocket_http3_handshake_stream.cc b/net/websockets/websocket_http3_handshake_stream.cc
new file mode 100644
index 0000000..3220126
--- /dev/null
+++ b/net/websockets/websocket_http3_handshake_stream.cc
@@ -0,0 +1,385 @@
+// 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 "net/websockets/websocket_http3_handshake_stream.h"
+
+#include <cstddef>
+#include <set>
+#include <utility>
+
+#include "base/check_op.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "net/base/ip_endpoint.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_request_info.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/spdy/spdy_http_utils.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/websockets/websocket_deflate_predictor_impl.h"
+#include "net/websockets/websocket_deflate_stream.h"
+#include "net/websockets/websocket_handshake_constants.h"
+
+namespace net {
+
+namespace {
+
+bool ValidateStatus(const HttpResponseHeaders* headers) {
+  return headers->GetStatusLine() == "HTTP/1.1 200";
+}
+
+}  // namespace
+
+WebSocketHttp3HandshakeStream::WebSocketHttp3HandshakeStream(
+    std::unique_ptr<QuicChromiumClientSession::Handle> session,
+    WebSocketStream::ConnectDelegate* connect_delegate,
+    std::vector<std::string> requested_sub_protocols,
+    std::vector<std::string> requested_extensions,
+    WebSocketStreamRequestAPI* request,
+    std::set<std::string> dns_aliases)
+    : session_(std::move(session)),
+      connect_delegate_(connect_delegate),
+      requested_sub_protocols_(std::move(requested_sub_protocols)),
+      requested_extensions_(std::move(requested_extensions)),
+      stream_request_(request),
+      dns_aliases_(std::move(dns_aliases)) {
+  DCHECK(connect_delegate);
+  DCHECK(request);
+}
+
+WebSocketHttp3HandshakeStream::~WebSocketHttp3HandshakeStream() {
+  quic_stream_request_.reset();
+  RecordHandshakeResult(result_);
+}
+
+void WebSocketHttp3HandshakeStream::RegisterRequest(
+    const HttpRequestInfo* request_info) {
+  DCHECK(request_info);
+  DCHECK(request_info->traffic_annotation.is_valid());
+  request_info_ = request_info;
+}
+
+int WebSocketHttp3HandshakeStream::InitializeStream(
+    bool can_send_early,
+    RequestPriority priority,
+    const NetLogWithSource& net_log,
+    CompletionOnceCallback callback) {
+  priority_ = priority;
+  net_log_ = net_log;
+  request_time_ = base::Time::Now();
+  return OK;
+}
+
+int WebSocketHttp3HandshakeStream::SendRequest(
+    const HttpRequestHeaders& request_headers,
+    HttpResponseInfo* response,
+    CompletionOnceCallback callback) {
+  DCHECK(!request_headers.HasHeader(websockets::kSecWebSocketKey));
+  DCHECK(!request_headers.HasHeader(websockets::kSecWebSocketProtocol));
+  DCHECK(!request_headers.HasHeader(websockets::kSecWebSocketExtensions));
+  DCHECK(request_headers.HasHeader(HttpRequestHeaders::kOrigin));
+  DCHECK(request_headers.HasHeader(websockets::kUpgrade));
+  DCHECK(request_headers.HasHeader(HttpRequestHeaders::kConnection));
+  DCHECK(request_headers.HasHeader(websockets::kSecWebSocketVersion));
+
+  if (!session_) {
+    constexpr int rv = ERR_CONNECTION_CLOSED;
+    OnFailure("Connection closed before sending request.", rv, absl::nullopt);
+    return rv;
+  }
+
+  http_response_info_ = response;
+
+  IPEndPoint address;
+  int result = session_->GetPeerAddress(&address);
+  if (result != OK) {
+    OnFailure("Error getting IP address.", result, absl::nullopt);
+    return result;
+  }
+  http_response_info_->remote_endpoint = address;
+
+  auto request = std::make_unique<WebSocketHandshakeRequestInfo>(
+      request_info_->url, base::Time::Now());
+  request->headers.CopyFrom(request_headers);
+
+  AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketExtensions,
+                            requested_extensions_, &request->headers);
+  AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketProtocol,
+                            requested_sub_protocols_, &request->headers);
+
+  CreateSpdyHeadersFromHttpRequestForWebSocket(
+      request_info_->url, request->headers, &http3_request_headers_);
+
+  connect_delegate_->OnStartOpeningHandshake(std::move(request));
+
+  callback_ = std::move(callback);
+
+  stream_adapter_ = session_->CreateWebSocketQuicStreamAdapter(this);
+  if (!stream_adapter_) {
+    // TODO(momoka): Add request to streamRequest and postpone the creation of
+    // stream. Also, add a boolean 'for_websocket' and a
+    // WebSocketHttp3HandshakeStream member to streamRequest to indicate if a
+    // particular request is for websockets. OnCanCreateNewOutgoingStream() will
+    // create a stream when we can create a new stream and call Start
+    // RequestCallback().
+    return ERR_IO_PENDING;
+  }
+  StartRequestCallback();
+  return OK;
+}
+
+int WebSocketHttp3HandshakeStream::ReadResponseHeaders(
+    CompletionOnceCallback callback) {
+  if (stream_closed_) {
+    return stream_error_;
+  }
+
+  if (response_headers_complete_) {
+    return ValidateResponse();
+  }
+
+  callback_ = std::move(callback);
+  return ERR_IO_PENDING;
+}
+
+// TODO(momoka): Implement this.
+int WebSocketHttp3HandshakeStream::ReadResponseBody(
+    IOBuffer* buf,
+    int buf_len,
+    CompletionOnceCallback callback) {
+  return OK;
+}
+
+void WebSocketHttp3HandshakeStream::Close(bool not_reusable) {
+  quic_stream_request_.reset();
+  if (stream_adapter_) {
+    stream_adapter_->Disconnect();
+    stream_closed_ = true;
+    stream_error_ = ERR_CONNECTION_CLOSED;
+  }
+}
+
+// TODO(momoka): Implement this.
+bool WebSocketHttp3HandshakeStream::IsResponseBodyComplete() const {
+  return false;
+}
+
+// TODO(momoka): Implement this.
+bool WebSocketHttp3HandshakeStream::IsConnectionReused() const {
+  return true;
+}
+
+// TODO(momoka): Implement this.
+void WebSocketHttp3HandshakeStream::SetConnectionReused() {}
+
+// TODO(momoka): Implement this.
+bool WebSocketHttp3HandshakeStream::CanReuseConnection() const {
+  return false;
+}
+
+// TODO(momoka): Implement this.
+int64_t WebSocketHttp3HandshakeStream::GetTotalReceivedBytes() const {
+  return 0;
+}
+
+// TODO(momoka): Implement this.
+int64_t WebSocketHttp3HandshakeStream::GetTotalSentBytes() const {
+  return 0;
+}
+
+// TODO(momoka): Implement this.
+bool WebSocketHttp3HandshakeStream::GetAlternativeService(
+    AlternativeService* alternative_service) const {
+  return false;
+}
+
+// TODO(momoka): Implement this.
+bool WebSocketHttp3HandshakeStream::GetLoadTimingInfo(
+    LoadTimingInfo* load_timing_info) const {
+  return false;
+}
+
+// TODO(momoka): Implement this.
+void WebSocketHttp3HandshakeStream::GetSSLInfo(SSLInfo* ssl_info) {}
+
+// TODO(momoka): Implement this.
+void WebSocketHttp3HandshakeStream::GetSSLCertRequestInfo(
+    SSLCertRequestInfo* cert_request_info) {}
+
+// TODO(momoka): Implement this.
+int WebSocketHttp3HandshakeStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
+  return 0;
+}
+
+// TODO(momoka): Implement this.
+void WebSocketHttp3HandshakeStream::Drain(HttpNetworkSession* session) {}
+
+// TODO(momoka): Implement this.
+void WebSocketHttp3HandshakeStream::SetPriority(RequestPriority priority) {}
+
+// TODO(momoka): Implement this.
+void WebSocketHttp3HandshakeStream::PopulateNetErrorDetails(
+    NetErrorDetails* details) {}
+
+// TODO(momoka): Implement this.
+std::unique_ptr<HttpStream>
+WebSocketHttp3HandshakeStream::RenewStreamForAuth() {
+  return nullptr;
+}
+
+// TODO(momoka): Implement this.
+const std::set<std::string>& WebSocketHttp3HandshakeStream::GetDnsAliases()
+    const {
+  return dns_aliases_;
+}
+
+// TODO(momoka): Implement this.
+base::StringPiece WebSocketHttp3HandshakeStream::GetAcceptChViaAlps() const {
+  return {};
+}
+
+// WebSocketHandshakeStreamBase methods.
+
+// TODO(momoka): Implement this.
+std::unique_ptr<WebSocketStream> WebSocketHttp3HandshakeStream::Upgrade() {
+  DCHECK(extension_params_.get());
+
+  stream_adapter_->clear_delegate();
+  std::unique_ptr<WebSocketStream> basic_stream =
+      std::make_unique<WebSocketBasicStream>(std::move(stream_adapter_),
+                                             nullptr, sub_protocol_,
+                                             extensions_, net_log_);
+
+  if (!extension_params_->deflate_enabled) {
+    return basic_stream;
+  }
+
+  return std::make_unique<WebSocketDeflateStream>(
+      std::move(basic_stream), extension_params_->deflate_parameters,
+      std::make_unique<WebSocketDeflatePredictorImpl>());
+}
+
+base::WeakPtr<WebSocketHandshakeStreamBase>
+WebSocketHttp3HandshakeStream::GetWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
+void WebSocketHttp3HandshakeStream::OnHeadersSent() {
+  std::move(callback_).Run(OK);
+}
+
+void WebSocketHttp3HandshakeStream::OnHeadersReceived(
+    const spdy::Http2HeaderBlock& response_headers) {
+  DCHECK(!response_headers_complete_);
+  DCHECK(http_response_info_);
+
+  response_headers_complete_ = true;
+
+  const int rv =
+      SpdyHeadersToHttpResponse(response_headers, http_response_info_);
+  DCHECK_NE(rv, ERR_INCOMPLETE_HTTP2_HEADERS);
+
+  // Do not store SSLInfo in the response here, HttpNetworkTransaction will take
+  // care of that part.
+  http_response_info_->was_alpn_negotiated = true;
+  http_response_info_->response_time = base::Time::Now();
+  http_response_info_->request_time = request_time_;
+  http_response_info_->connection_info =
+      HttpResponseInfo::CONNECTION_INFO_HTTP2;
+  http_response_info_->alpn_negotiated_protocol =
+      HttpResponseInfo::ConnectionInfoToString(
+          http_response_info_->connection_info);
+
+  if (callback_) {
+    std::move(callback_).Run(ValidateResponse());
+  }
+}
+
+void WebSocketHttp3HandshakeStream::OnClose(int status) {
+  DCHECK(stream_adapter_);
+  DCHECK_GT(ERR_IO_PENDING, status);
+
+  stream_closed_ = true;
+  stream_error_ = status;
+
+  stream_adapter_.reset();
+
+  // If response headers have already been received,
+  // then ValidateResponse() sets `result_`.
+  if (!response_headers_complete_) {
+    result_ = HandshakeResult::HTTP2_FAILED;
+  }
+
+  OnFailure(std::string("Stream closed with error: ") + ErrorToString(status),
+            status, absl::nullopt);
+
+  if (callback_) {
+    std::move(callback_).Run(status);
+  }
+}
+
+void WebSocketHttp3HandshakeStream::StartRequestCallback() {
+  // WriteHeaders returns synchronously.
+  stream_adapter_->WriteHeaders(std::move(http3_request_headers_), false);
+}
+
+int WebSocketHttp3HandshakeStream::ValidateResponse() {
+  DCHECK(http_response_info_);
+  const HttpResponseHeaders* headers = http_response_info_->headers.get();
+  const int response_code = headers->response_code();
+  switch (response_code) {
+    case HTTP_OK:
+      return ValidateUpgradeResponse(headers);
+
+    // We need to pass these through for authentication to work.
+    case HTTP_UNAUTHORIZED:
+    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
+      return OK;
+
+    // Other status codes are potentially risky (see the warnings in the
+    // WHATWG WebSocket API spec) and so are dropped by default.
+    default:
+      OnFailure(
+          base::StringPrintf(
+              "Error during WebSocket handshake: Unexpected response code: %d",
+              headers->response_code()),
+          ERR_FAILED, headers->response_code());
+      result_ = HandshakeResult::HTTP2_INVALID_STATUS;
+      return ERR_INVALID_RESPONSE;
+  }
+}
+
+int WebSocketHttp3HandshakeStream::ValidateUpgradeResponse(
+    const HttpResponseHeaders* headers) {
+  extension_params_ = std::make_unique<WebSocketExtensionParams>();
+  std::string failure_message;
+  if (!ValidateStatus(headers)) {
+    result_ = HandshakeResult::HTTP2_INVALID_STATUS;
+  } else if (!ValidateSubProtocol(headers, requested_sub_protocols_,
+                                  &sub_protocol_, &failure_message)) {
+    result_ = HandshakeResult::HTTP2_FAILED_SUBPROTO;
+  } else if (!ValidateExtensions(headers, &extensions_, &failure_message,
+                                 extension_params_.get())) {
+    result_ = HandshakeResult::HTTP2_FAILED_EXTENSIONS;
+  } else {
+    result_ = HandshakeResult::HTTP2_CONNECTED;
+    return OK;
+  }
+
+  const int rv = ERR_INVALID_RESPONSE;
+  OnFailure("Error during WebSocket handshake: " + failure_message, rv,
+            absl::nullopt);
+  return rv;
+}
+
+// TODO(momoka): Implement this.
+void WebSocketHttp3HandshakeStream::OnFailure(
+    const std::string& message,
+    int net_error,
+    absl::optional<int> response_code) {
+  stream_request_->OnFailure(message, net_error, response_code);
+}
+
+}  // namespace net
\ No newline at end of file
diff --git a/net/websockets/websocket_http3_handshake_stream.h b/net/websockets/websocket_http3_handshake_stream.h
new file mode 100644
index 0000000..9eccc99e
--- /dev/null
+++ b/net/websockets/websocket_http3_handshake_stream.h
@@ -0,0 +1,190 @@
+// 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 NET_WEBSOCKETS_WEBSOCKET_HTTP3_HANDSHAKE_STREAM_H_
+#define NET_WEBSOCKETS_WEBSOCKET_HTTP3_HANDSHAKE_STREAM_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/net_export.h"
+#include "net/base/request_priority.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/quic_stream_factory.h"
+#include "net/third_party/quiche/src/quiche/spdy/core/http2_header_block.h"
+#include "net/websockets/websocket_basic_stream_adapters.h"
+#include "net/websockets/websocket_handshake_stream_base.h"
+#include "net/websockets/websocket_stream.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace net {
+
+class HttpNetworkSession;
+class HttpResponseHeaders;
+class HttpResponseInfo;
+class HttpStream;
+class IOBuffer;
+class IPEndPoint;
+class SSLCertRequestInfo;
+class SSLInfo;
+struct HttpRequestInfo;
+struct LoadTimingInfo;
+struct NetErrorDetails;
+
+class NET_EXPORT_PRIVATE WebSocketHttp3HandshakeStream final
+    : public WebSocketHandshakeStreamBase,
+      public WebSocketQuicStreamAdapter::Delegate {
+ public:
+  WebSocketHttp3HandshakeStream(
+      std::unique_ptr<QuicChromiumClientSession::Handle> session,
+      WebSocketStream::ConnectDelegate* connect_delegate,
+      std::vector<std::string> requested_sub_protocols,
+      std::vector<std::string> requested_extensions,
+      WebSocketStreamRequestAPI* request,
+      std::set<std::string> dns_aliases);
+
+  WebSocketHttp3HandshakeStream(const WebSocketHttp3HandshakeStream&) = delete;
+  WebSocketHttp3HandshakeStream& operator=(
+      const WebSocketHttp3HandshakeStream&) = delete;
+
+  ~WebSocketHttp3HandshakeStream() override;
+
+  // HttpStream methods.
+  void RegisterRequest(const HttpRequestInfo* request_info) override;
+  int InitializeStream(bool can_send_early,
+                       RequestPriority priority,
+                       const NetLogWithSource& net_log,
+                       CompletionOnceCallback callback) override;
+  int SendRequest(const HttpRequestHeaders& request_headers,
+                  HttpResponseInfo* response,
+                  CompletionOnceCallback callback) override;
+  int ReadResponseHeaders(CompletionOnceCallback callback) override;
+  int ReadResponseBody(IOBuffer* buf,
+                       int buf_len,
+                       CompletionOnceCallback callback) override;
+  void Close(bool not_reusable) override;
+  bool IsResponseBodyComplete() const override;
+  bool IsConnectionReused() const override;
+  void SetConnectionReused() override;
+  bool CanReuseConnection() const override;
+  int64_t GetTotalReceivedBytes() const override;
+  int64_t GetTotalSentBytes() const override;
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override;
+  bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+  void GetSSLInfo(SSLInfo* ssl_info) override;
+  void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
+  int GetRemoteEndpoint(IPEndPoint* endpoint) override;
+  void Drain(HttpNetworkSession* session) override;
+  void SetPriority(RequestPriority priority) override;
+  void PopulateNetErrorDetails(NetErrorDetails* details) override;
+  std::unique_ptr<HttpStream> RenewStreamForAuth() override;
+  const std::set<std::string>& GetDnsAliases() const override;
+  base::StringPiece GetAcceptChViaAlps() const override;
+
+  // WebSocketHandshakeStreamBase methods.
+
+  // This is called from the top level once correct handshake response headers
+  // have been received. It creates an appropriate subclass of WebSocketStream
+  // depending on what extensions were negotiated. This object is unusable after
+  // Upgrade() has been called and should be disposed of as soon as possible.
+  std::unique_ptr<WebSocketStream> Upgrade() override;
+
+  base::WeakPtr<WebSocketHandshakeStreamBase> GetWeakPtr() override;
+
+  // WebSocketQuicStreamAdapter::Delegate methods.
+  void OnHeadersSent() override;
+  void OnHeadersReceived(
+      const spdy::Http2HeaderBlock& response_headers) override;
+  void OnClose(int status) override;
+
+  void StartRequestCallback();
+
+ private:
+  // Validates the response and sends the finished handshake event.
+  int ValidateResponse();
+
+  // Check that the headers are well-formed and have a 200 status code,
+  // in which case returns OK, otherwise returns ERR_INVALID_RESPONSE.
+  int ValidateUpgradeResponse(const HttpResponseHeaders* headers);
+
+  void OnFailure(const std::string& message,
+                 int net_error,
+                 absl::optional<int> response_code);
+
+  HandshakeResult result_ = HandshakeResult::HTTP2_INCOMPLETE;
+
+  std::unique_ptr<WebSocketSpdyStreamAdapter> adapter_;
+
+  // True if `stream_` has been created then closed.
+  bool stream_closed_ = false;
+
+  // The error code corresponding to the reason for closing the stream.
+  // Only meaningful if `stream_closed_` is true.
+  int stream_error_ = OK;
+
+  // True if complete response headers have been received.
+  bool response_headers_complete_ = false;
+
+  // Time the request was issued.
+  base::Time request_time_;
+
+  std::unique_ptr<QuicChromiumClientSession::Handle> session_;
+  // Owned by another object.
+  // `connect_delegate` will live during the lifetime of this object.
+  const raw_ptr<WebSocketStream::ConnectDelegate, DanglingUntriaged>
+      connect_delegate_;
+
+  raw_ptr<HttpResponseInfo> http_response_info_ = nullptr;
+
+  spdy::Http2HeaderBlock http3_request_headers_;
+
+  // The sub-protocols we requested.
+  std::vector<std::string> requested_sub_protocols_;
+
+  // The extensions we requested.
+  std::vector<std::string> requested_extensions_;
+
+  const raw_ptr<WebSocketStreamRequestAPI, DanglingUntriaged> stream_request_;
+
+  raw_ptr<const HttpRequestInfo, DanglingUntriaged> request_info_ = nullptr;
+
+  RequestPriority priority_;
+
+  NetLogWithSource net_log_;
+
+  std::unique_ptr<QuicStreamRequest> quic_stream_request_;
+
+  // WebSocketQuicStreamAdapter holding a WeakPtr to `stream_`.
+  // This can be passed on to WebSocketBasicStream when created.
+  std::unique_ptr<WebSocketQuicStreamAdapter> stream_adapter_;
+
+  CompletionOnceCallback callback_;
+
+  // The sub-protocol selected by the server.
+  std::string sub_protocol_;
+
+  // The extension(s) selected by the server.
+  std::string extensions_;
+
+  // The extension parameters. The class is defined in the implementation file
+  // to avoid including extension-related header files here.
+  std::unique_ptr<WebSocketExtensionParams> extension_params_;
+
+  std::set<std::string> dns_aliases_;
+
+  base::WeakPtrFactory<WebSocketHttp3HandshakeStream> weak_ptr_factory_{this};
+};
+
+}  // namespace net
+
+#endif  // NET_WEBSOCKETS_WEBSOCKET_HTTP3_HANDSHAKE_STREAM_H_
\ No newline at end of file
diff --git a/net/websockets/websocket_quic_spdy_stream.cc b/net/websockets/websocket_quic_spdy_stream.cc
index 82510275..305ed66 100644
--- a/net/websockets/websocket_quic_spdy_stream.cc
+++ b/net/websockets/websocket_quic_spdy_stream.cc
@@ -24,4 +24,14 @@
   }
 }
 
-}  // namespace net
\ No newline at end of file
+void WebSocketQuicSpdyStream::OnInitialHeadersComplete(
+    bool fin,
+    size_t frame_len,
+    const quic::QuicHeaderList& header_list) {
+  QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
+  if (delegate_) {
+    delegate_->OnInitialHeadersComplete(fin, frame_len, header_list);
+  }
+}
+
+}  // namespace net
diff --git a/net/websockets/websocket_quic_spdy_stream.h b/net/websockets/websocket_quic_spdy_stream.h
index 7fdd5009..30c14d12 100644
--- a/net/websockets/websocket_quic_spdy_stream.h
+++ b/net/websockets/websocket_quic_spdy_stream.h
@@ -7,7 +7,6 @@
 
 #include "net/quic/quic_chromium_client_stream.h"
 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_session_base.h"
-#include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_stream.h"
 
 namespace net {
 class NET_EXPORT_PRIVATE WebSocketQuicSpdyStream : public quic::QuicSpdyStream {
@@ -17,6 +16,10 @@
     Delegate() = default;
     Delegate(const Delegate&) = delete;
     Delegate& operator=(const Delegate&) = delete;
+    virtual void OnInitialHeadersComplete(
+        bool fin,
+        size_t frame_len,
+        const quic::QuicHeaderList& header_list) = 0;
     virtual void OnBodyAvailable() = 0;
     virtual void ClearStream() = 0;
 
@@ -33,6 +36,10 @@
 
   void set_delegate(Delegate* delegate) { delegate_ = delegate; }
 
+  void OnInitialHeadersComplete(
+      bool fin,
+      size_t frame_len,
+      const quic::QuicHeaderList& header_list) override;
   void OnBodyAvailable() override;
 
  private:
diff --git a/net/websockets/websocket_stream.cc b/net/websockets/websocket_stream.cc
index cc96c0e..150f8a1 100644
--- a/net/websockets/websocket_stream.cc
+++ b/net/websockets/websocket_stream.cc
@@ -33,6 +33,7 @@
 #include "net/websockets/websocket_handshake_stream_base.h"
 #include "net/websockets/websocket_handshake_stream_create_helper.h"
 #include "net/websockets/websocket_http2_handshake_stream.h"
+#include "net/websockets/websocket_http3_handshake_stream.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -150,6 +151,14 @@
     OnHandshakeStreamCreated(handshake_stream);
   }
 
+  void OnHttp3HandshakeStreamCreated(
+      WebSocketHttp3HandshakeStream* handshake_stream) override {
+    if (api_delegate_) {
+      api_delegate_->OnHttp3HandshakeStreamCreated(handshake_stream);
+    }
+    OnHandshakeStreamCreated(handshake_stream);
+  }
+
   void OnFailure(const std::string& message,
                  int net_error,
                  absl::optional<int> response_code) override {
@@ -271,10 +280,10 @@
 
   // This is owned by the caller of
   // WebsocketHandshakeStreamCreateHelper::CreateBasicStream() or
-  // CreateHttp2Stream().  Both the stream and this object will be destroyed
-  // during the destruction of the URLRequest object associated with the
-  // handshake. This is only guaranteed to be a valid pointer if the handshake
-  // succeeded.
+  // CreateHttp2Stream() or CreateHttp3Stream().  Both the stream and this
+  // object will be destroyed during the destruction of the URLRequest object
+  // associated with the handshake. This is only guaranteed to be a valid
+  // pointer if the handshake succeeded.
   base::WeakPtr<WebSocketHandshakeStreamBase> handshake_stream_;
 
   // The failure information supplied by WebSocketBasicHandshakeStream, if any.
diff --git a/net/websockets/websocket_stream.h b/net/websockets/websocket_stream.h
index c4e7f1d..a72f94c7 100644
--- a/net/websockets/websocket_stream.h
+++ b/net/websockets/websocket_stream.h
@@ -45,6 +45,7 @@
 struct WebSocketFrame;
 class WebSocketBasicHandshakeStream;
 class WebSocketHttp2HandshakeStream;
+class WebSocketHttp3HandshakeStream;
 struct NetworkTrafficAnnotationTag;
 
 // WebSocketStreamRequest is the caller's handle to the process of creation of a
@@ -66,6 +67,8 @@
       WebSocketBasicHandshakeStream* handshake_stream) = 0;
   virtual void OnHttp2HandshakeStreamCreated(
       WebSocketHttp2HandshakeStream* handshake_stream) = 0;
+  virtual void OnHttp3HandshakeStreamCreated(
+      WebSocketHttp3HandshakeStream* handshake_stream) = 0;
   virtual void OnFailure(const std::string& message,
                          int net_error,
                          absl::optional<int> response_code) = 0;
diff --git a/net/websockets/websocket_test_util.cc b/net/websockets/websocket_test_util.cc
index 3b4ae7a1..54f899d 100644
--- a/net/websockets/websocket_test_util.cc
+++ b/net/websockets/websocket_test_util.cc
@@ -291,4 +291,6 @@
 void TestWebSocketStreamRequestAPI::OnHttp2HandshakeStreamCreated(
     WebSocketHttp2HandshakeStream* handshake_stream) {}
 
+void TestWebSocketStreamRequestAPI::OnHttp3HandshakeStreamCreated(
+    WebSocketHttp3HandshakeStream* handshake_stream) {}
 }  // namespace net
diff --git a/net/websockets/websocket_test_util.h b/net/websockets/websocket_test_util.h
index 4363f9c..7edb9df 100644
--- a/net/websockets/websocket_test_util.h
+++ b/net/websockets/websocket_test_util.h
@@ -223,6 +223,8 @@
       WebSocketBasicHandshakeStream* handshake_stream) override;
   void OnHttp2HandshakeStreamCreated(
       WebSocketHttp2HandshakeStream* handshake_stream) override;
+  void OnHttp3HandshakeStreamCreated(
+      WebSocketHttp3HandshakeStream* handshake_stream) override;
   void OnFailure(const std::string& message,
                  int net_error,
                  absl::optional<int> response_code) override {}
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 8119e4e..0939018 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -50,6 +50,10 @@
 
   if (use_cups) {
     public_configs = [ ":cups" ]
+    sources += [
+      "print_job_constants_cups.cc",
+      "print_job_constants_cups.h",
+    ]
   }
 
   cflags = []
diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc
index e97abc1f..68676d8 100644
--- a/printing/backend/cups_helper.cc
+++ b/printing/backend/cups_helper.cc
@@ -22,7 +22,7 @@
 #include "printing/backend/print_backend.h"
 #include "printing/backend/print_backend_consts.h"
 #include "printing/mojom/print.mojom.h"
-#include "printing/print_job_constants.h"
+#include "printing/print_job_constants_cups.h"
 #include "printing/printing_utils.h"
 #include "printing/units.h"
 #include "url/gurl.h"
@@ -51,12 +51,6 @@
 constexpr char kCupsMaxCopies[] = "cupsMaxCopies";
 
 constexpr char kColorDevice[] = "ColorDevice";
-constexpr char kColorModel[] = "ColorModel";
-constexpr char kColorMode[] = "ColorMode";
-constexpr char kProcessColorModel[] = "ProcessColorModel";
-constexpr char kPrintoutMode[] = "PrintoutMode";
-constexpr char kDraftGray[] = "Draft.Gray";
-constexpr char kHighGray[] = "High.Gray";
 
 constexpr char kDuplex[] = "Duplex";
 constexpr char kDuplexNone[] = "None";
@@ -66,32 +60,6 @@
 
 // Brother printer specific options.
 constexpr char kBrotherDuplex[] = "BRDuplex";
-constexpr char kBrotherMonoColor[] = "BRMonoColor";
-constexpr char kBrotherPrintQuality[] = "BRPrintQuality";
-
-// Epson printer specific options.
-constexpr char kEpsonInk[] = "Ink";
-constexpr char kEpsonColor[] = "COLOR";
-constexpr char kEpsonMono[] = "MONO";
-
-// HP printer specific options.
-constexpr char kHpColorMode[] = "HPColorMode";
-constexpr char kHpColorPrint[] = "ColorPrint";
-constexpr char kHpGrayscalePrint[] = "GrayscalePrint";
-
-// Samsung printer specific options.
-constexpr char kSamsungColorTrue[] = "True";
-constexpr char kSamsungColorFalse[] = "False";
-
-// Sharp printer specific options.
-constexpr char kSharpARCMode[] = "ARCMode";
-constexpr char kSharpCMColor[] = "CMColor";
-constexpr char kSharpCMBW[] = "CMBW";
-
-// Xerox printer specific options.
-constexpr char kXeroxXRXColor[] = "XRXColor";
-constexpr char kXeroxAutomatic[] = "Automatic";
-constexpr char kXeroxBW[] = "BW";
 
 int32_t GetCopiesMax(ppd_file_t* ppd) {
   ppd_attr_t* attr = ppdFindAttr(ppd, kCupsMaxCopies, nullptr);
@@ -188,7 +156,7 @@
                                 mojom::ColorModel* color_model_for_black,
                                 mojom::ColorModel* color_model_for_color,
                                 bool* color_is_default) {
-  ppd_option_t* color_model = ppdFindOption(ppd, kColorModel);
+  ppd_option_t* color_model = ppdFindOption(ppd, kCUPSColorModel);
   if (!color_model)
     return false;
 
@@ -216,7 +184,7 @@
   else if (ppdFindChoice(color_model, kCMY_K))
     *color_model_for_color = mojom::ColorModel::kCMYPlusK;
 
-  ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel);
+  ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kCUPSColorModel);
   if (!marked_choice)
     marked_choice = ppdFindChoice(color_model, color_model->defchoice);
 
@@ -233,7 +201,7 @@
                                   mojom::ColorModel* color_model_for_black,
                                   mojom::ColorModel* color_model_for_color,
                                   bool* color_is_default) {
-  ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode);
+  ppd_option_t* printout_mode = ppdFindOption(ppd, kCUPSPrintoutMode);
   if (!printout_mode)
     return false;
 
@@ -249,7 +217,8 @@
 
   // Get the default marked choice to identify the default color setting
   // value.
-  ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode);
+  ppd_choice_t* printout_mode_choice =
+      ppdFindMarkedChoice(ppd, kCUPSPrintoutMode);
   if (!printout_mode_choice) {
     printout_mode_choice =
         ppdFindChoice(printout_mode, printout_mode->defchoice);
@@ -270,7 +239,7 @@
                           mojom::ColorModel* color_model_for_color,
                           bool* color_is_default) {
   // Samsung printers use "ColorMode" attribute in their PPDs.
-  ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode);
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSColorMode);
   if (!color_mode_option)
     return false;
 
@@ -284,7 +253,7 @@
     *color_model_for_black = mojom::ColorModel::kColorModeMonochrome;
   }
 
-  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kCUPSColorMode);
   if (!mode_choice) {
     mode_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
@@ -304,9 +273,9 @@
                              bool* color_is_default) {
   // Some Brother printers use "BRMonoColor" attribute in their PPDs.
   // Some Brother printers use "BRPrintQuality" attribute in their PPDs.
-  ppd_option_t* color_mode_option = ppdFindOption(ppd, kBrotherMonoColor);
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSBrotherMonoColor);
   if (!color_mode_option)
-    color_mode_option = ppdFindOption(ppd, kBrotherPrintQuality);
+    color_mode_option = ppdFindOption(ppd, kCUPSBrotherPrintQuality);
   if (!color_mode_option)
     return false;
 
@@ -320,7 +289,7 @@
   else if (ppdFindChoice(color_mode_option, kBlack))
     *color_model_for_black = mojom::ColorModel::kBrotherBRScript3Black;
 
-  ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorMode);
+  ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kCUPSColorMode);
   if (!marked_choice) {
     marked_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
@@ -347,7 +316,7 @@
   if (ppdFindChoice(color_mode_option, kBlack))
     *color_model_for_black = mojom::ColorModel::kHPColorBlack;
 
-  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kCUPSColorMode);
   if (!mode_choice) {
     mode_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
@@ -363,7 +332,7 @@
                             mojom::ColorModel* color_model_for_color,
                             bool* color_is_default) {
   // Some HP printers use "HPColorMode/Mode" attribute in their PPDs.
-  ppd_option_t* color_mode_option = ppdFindOption(ppd, kHpColorMode);
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSHpColorMode);
   if (!color_mode_option)
     return false;
 
@@ -372,7 +341,7 @@
   if (ppdFindChoice(color_mode_option, kHpGrayscalePrint))
     *color_model_for_black = mojom::ColorModel::kHPColorBlack;
 
-  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kHpColorMode);
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kCUPSHpColorMode);
   if (!mode_choice) {
     mode_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
@@ -389,7 +358,7 @@
                          mojom::ColorModel* color_model_for_color,
                          bool* color_is_default) {
   // Epson printers use "Ink" attribute in their PPDs.
-  ppd_option_t* color_mode_option = ppdFindOption(ppd, kEpsonInk);
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSEpsonInk);
   if (!color_mode_option)
     return false;
 
@@ -398,7 +367,7 @@
   if (ppdFindChoice(color_mode_option, kEpsonMono))
     *color_model_for_black = mojom::ColorModel::kEpsonInkMono;
 
-  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kEpsonInk);
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kCUPSEpsonInk);
   if (!mode_choice) {
     mode_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
@@ -415,7 +384,7 @@
                              mojom::ColorModel* color_model_for_color,
                              bool* color_is_default) {
   // Sharp printers use "ARCMode" attribute in their PPDs.
-  ppd_option_t* color_mode_option = ppdFindOption(ppd, kSharpARCMode);
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSSharpARCMode);
   if (!color_mode_option)
     return false;
 
@@ -424,7 +393,7 @@
   if (ppdFindChoice(color_mode_option, kSharpCMBW))
     *color_model_for_black = mojom::ColorModel::kSharpARCModeCMBW;
 
-  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kSharpARCMode);
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kCUPSSharpARCMode);
   if (!mode_choice) {
     mode_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
@@ -443,7 +412,7 @@
                            mojom::ColorModel* color_model_for_color,
                            bool* color_is_default) {
   // Some Xerox printers use "XRXColor" attribute in their PPDs.
-  ppd_option_t* color_mode_option = ppdFindOption(ppd, kXeroxXRXColor);
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSXeroxXRXColor);
   if (!color_mode_option)
     return false;
 
@@ -452,7 +421,7 @@
   if (ppdFindChoice(color_mode_option, kXeroxBW))
     *color_model_for_black = mojom::ColorModel::kXeroxXRXColorBW;
 
-  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kXeroxXRXColor);
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kCUPSXeroxXRXColor);
   if (!mode_choice) {
     mode_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
@@ -471,7 +440,7 @@
                                   mojom::ColorModel* color_model_for_color,
                                   bool* color_is_default) {
   // Canon printers use "ProcessColorModel" attribute in their PPDs.
-  ppd_option_t* color_mode_option = ppdFindOption(ppd, kProcessColorModel);
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSProcessColorModel);
   if (!color_mode_option)
     return false;
 
@@ -483,7 +452,7 @@
   if (ppdFindChoice(color_mode_option, kGreyscale))
     *color_model_for_black = mojom::ColorModel::kProcessColorModelGreyscale;
 
-  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel);
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kCUPSProcessColorModel);
   if (!mode_choice) {
     mode_choice =
         ppdFindChoice(color_mode_option, color_mode_option->defchoice);
diff --git a/printing/print_job_constants.cc b/printing/print_job_constants.cc
index 8011cff4..3237932 100644
--- a/printing/print_job_constants.cc
+++ b/printing/print_job_constants.cc
@@ -246,30 +246,4 @@
 const char kSettingIppClientVersion[] = "ipp-client-version";
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-#if BUILDFLAG(USE_CUPS)
-const char kBlack[] = "Black";
-const char kCMYK[] = "CMYK";
-const char kKCMY[] = "KCMY";
-const char kCMY_K[] = "CMY+K";
-const char kCMY[] = "CMY";
-const char kColor[] = "Color";
-const char kEpsonColor[] = "COLOR";
-const char kEpsonMono[] = "MONO";
-const char kFullColor[] = "FullColor";
-const char kGray[] = "Gray";
-const char kGrayscale[] = "Grayscale";
-const char kGreyscale[] = "Greyscale";
-const char kMono[] = "Mono";
-const char kMonochrome[] = "Monochrome";
-const char kNormal[] = "Normal";
-const char kNormalGray[] = "Normal.Gray";
-const char kRGB[] = "RGB";
-const char kRGBA[] = "RGBA";
-const char kRGB16[] = "RGB16";
-const char kSharpCMColor[] = "CMColor";
-const char kSharpCMBW[] = "CMBW";
-const char kXeroxAutomatic[] = "Automatic";
-const char kXeroxBW[] = "BW";
-#endif
-
 }  // namespace printing
diff --git a/printing/print_job_constants.h b/printing/print_job_constants.h
index a45758e..54b6d071 100644
--- a/printing/print_job_constants.h
+++ b/printing/print_job_constants.h
@@ -153,33 +153,6 @@
 extern const uint32_t kInvalidPageIndex;
 COMPONENT_EXPORT(PRINTING_BASE) extern const uint32_t kMaxPageCount;
 
-#if BUILDFLAG(USE_CUPS)
-// Printer color models
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kBlack[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kCMYK[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kKCMY[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kCMY_K[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kCMY[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kColor[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kEpsonColor[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kEpsonMono[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kFullColor[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kGray[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kGrayscale[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kGreyscale[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kMono[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kMonochrome[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kNormal[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kNormalGray[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kRGB[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kRGBA[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kRGB16[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kSharpCMColor[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kSharpCMBW[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kXeroxAutomatic[];
-COMPONENT_EXPORT(PRINTING_BASE) extern const char kXeroxBW[];
-#endif
-
 #if BUILDFLAG(IS_CHROMEOS)
 COMPONENT_EXPORT(PRINTING_BASE)
 extern const char kSettingChromeOSAccessOAuthToken[];
diff --git a/printing/print_job_constants_cups.cc b/printing/print_job_constants_cups.cc
new file mode 100644
index 0000000..c963047
--- /dev/null
+++ b/printing/print_job_constants_cups.cc
@@ -0,0 +1,52 @@
+// 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 "printing/print_job_constants_cups.h"
+
+namespace printing {
+
+// Variations of identifier used for specifying printer color model.
+const char kCUPSColorMode[] = "ColorMode";
+const char kCUPSColorModel[] = "ColorModel";
+const char kCUPSPrintoutMode[] = "PrintoutMode";
+const char kCUPSProcessColorModel[] = "ProcessColorModel";
+const char kCUPSBrotherMonoColor[] = "BRMonoColor";
+const char kCUPSBrotherPrintQuality[] = "BRPrintQuality";
+const char kCUPSEpsonInk[] = "Ink";
+const char kCUPSHpColorMode[] = "HPColorMode";
+const char kCUPSSharpARCMode[] = "ARCMode";
+const char kCUPSXeroxXRXColor[] = "XRXColor";
+
+// Variations of identifier used for specifying printer color model choice.
+const char kBlack[] = "Black";
+const char kCMYK[] = "CMYK";
+const char kKCMY[] = "KCMY";
+const char kCMY_K[] = "CMY+K";
+const char kCMY[] = "CMY";
+const char kColor[] = "Color";
+const char kDraftGray[] = "Draft.Gray";
+const char kEpsonColor[] = "COLOR";
+const char kEpsonMono[] = "MONO";
+const char kFullColor[] = "FullColor";
+const char kGray[] = "Gray";
+const char kGrayscale[] = "Grayscale";
+const char kGreyscale[] = "Greyscale";
+const char kHighGray[] = "High.Gray";
+const char kHpColorPrint[] = "ColorPrint";
+const char kHpGrayscalePrint[] = "GrayscalePrint";
+const char kMono[] = "Mono";
+const char kMonochrome[] = "Monochrome";
+const char kNormal[] = "Normal";
+const char kNormalGray[] = "Normal.Gray";
+const char kRGB[] = "RGB";
+const char kRGBA[] = "RGBA";
+const char kRGB16[] = "RGB16";
+const char kSamsungColorFalse[] = "False";
+const char kSamsungColorTrue[] = "True";
+const char kSharpCMColor[] = "CMColor";
+const char kSharpCMBW[] = "CMBW";
+const char kXeroxAutomatic[] = "Automatic";
+const char kXeroxBW[] = "BW";
+
+}  // namespace printing
diff --git a/printing/print_job_constants_cups.h b/printing/print_job_constants_cups.h
new file mode 100644
index 0000000..43ce34c
--- /dev/null
+++ b/printing/print_job_constants_cups.h
@@ -0,0 +1,63 @@
+// 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 PRINTING_PRINT_JOB_CONSTANTS_CUPS_H_
+#define PRINTING_PRINT_JOB_CONSTANTS_CUPS_H_
+
+#include "base/component_export.h"
+#include "build/build_config.h"
+#include "printing/buildflags/buildflags.h"
+
+#if !BUILDFLAG(USE_CUPS)
+#error "CUPS must be enabled."
+#endif
+
+namespace printing {
+
+// Variations of identifier used for specifying printer color model.
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSColorMode[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSColorModel[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSPrintoutMode[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSProcessColorModel[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSBrotherMonoColor[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSBrotherPrintQuality[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSEpsonInk[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSHpColorMode[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSSharpARCMode[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSXeroxXRXColor[];
+
+// Variations of identifier used for specifying printer color model choice.
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kBlack[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCMYK[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kKCMY[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCMY_K[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCMY[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kColor[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kDraftGray[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kEpsonColor[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kEpsonMono[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kFullColor[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kGray[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kGrayscale[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kGreyscale[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kHighGray[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kHpColorPrint[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kHpGrayscalePrint[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kMono[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kMonochrome[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kNormal[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kNormalGray[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kRGB[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kRGBA[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kRGB16[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kSamsungColorFalse[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kSamsungColorTrue[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kSharpCMColor[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kSharpCMBW[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kXeroxAutomatic[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kXeroxBW[];
+
+}  // namespace printing
+
+#endif  // PRINTING_PRINT_JOB_CONSTANTS_CUPS_H_
diff --git a/printing/print_settings.cc b/printing/print_settings.cc
index 882842c4c..fef065e9 100644
--- a/printing/print_settings.cc
+++ b/printing/print_settings.cc
@@ -10,10 +10,14 @@
 #include "printing/buildflags/buildflags.h"
 #include "printing/units.h"
 
-#if BUILDFLAG(USE_CUPS) && (BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(USE_CUPS)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
 #include <cups/cups.h>
 #endif
 
+#include "printing/print_job_constants_cups.h"
+#endif  // BUILDFLAG(USE_CUPS)
+
 #if BUILDFLAG(IS_WIN)
 #include "printing/mojom/print.mojom.h"
 #endif
@@ -31,16 +35,6 @@
 void GetColorModelForModel(mojom::ColorModel color_model,
                            std::string* color_setting_name,
                            std::string* color_value) {
-  constexpr char kCUPSColorMode[] = "ColorMode";
-  constexpr char kCUPSColorModel[] = "ColorModel";
-  constexpr char kCUPSPrintoutMode[] = "PrintoutMode";
-  constexpr char kCUPSProcessColorModel[] = "ProcessColorModel";
-  constexpr char kCUPSBrotherMonoColor[] = "BRMonoColor";
-  constexpr char kCUPSBrotherPrintQuality[] = "BRPrintQuality";
-  constexpr char kCUPSEpsonInk[] = "Ink";
-  constexpr char kCUPSSharpARCMode[] = "ARCMode";
-  constexpr char kCUPSXeroxXRXColor[] = "XRXColor";
-
   *color_setting_name = kCUPSColorModel;
 
   switch (color_model) {
diff --git a/services/network/attribution/attribution_attestation_mediator.cc b/services/network/attribution/attribution_attestation_mediator.cc
index 5bdd3b4..6332b8ff 100644
--- a/services/network/attribution/attribution_attestation_mediator.cc
+++ b/services/network/attribution/attribution_attestation_mediator.cc
@@ -6,8 +6,8 @@
 
 #include <utility>
 
-#include "base/bind.h"
 #include "base/check.h"
+#include "base/functional/bind.h"
 #include "base/task/thread_pool.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index a79a3d6..b55b7cc7 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1950,7 +1950,7 @@
       {
         "args": [],
         "cros_board": "eve",
-        "cros_img": "eve-release/R109-15236.35.0",
+        "cros_img": "eve-release/R110-15278.29.0",
         "name": "lacros_all_tast_tests EVE_RELEASE_BETA",
         "resultdb": {
           "enable": true,
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 06215aed..09f4438 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -12581,7 +12581,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-18.04"
             }
           ],
           "expiration": 36000,
@@ -12625,7 +12625,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-18.04"
             }
           ],
           "expiration": 36000,
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index ec5b4175..cb13ef2 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1165,7 +1165,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R109-15236.35.0",
+        "cros_img": "octopus-release/R110-15278.29.0",
         "name": "lacros_fyi_tast_tests OCTOPUS_RELEASE_BETA",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
@@ -1177,7 +1177,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R108-15183.78.0",
+        "cros_img": "octopus-release/R109-15236.66.0",
         "name": "lacros_fyi_tast_tests OCTOPUS_RELEASE_STABLE",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
@@ -1211,7 +1211,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R109-15236.35.0",
+        "cros_img": "octopus-release/R110-15278.29.0",
         "name": "ozone_unittests OCTOPUS_RELEASE_BETA",
         "swarming": {},
         "test": "ozone_unittests",
@@ -1222,7 +1222,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R108-15183.78.0",
+        "cros_img": "octopus-release/R109-15236.66.0",
         "name": "ozone_unittests OCTOPUS_RELEASE_STABLE",
         "swarming": {},
         "test": "ozone_unittests",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 602cc80..274576d 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -524,8 +524,8 @@
   'CROS_EVE_RELEASE_BETA': {
     'skylab': {
       'cros_board': 'eve',
-      'cros_chrome_version': '109.0.5414.41',
-      'cros_img': 'eve-release/R109-15236.35.0',
+      'cros_chrome_version': '110.0.5481.32',
+      'cros_img': 'eve-release/R110-15278.29.0',
     },
     'enabled': True,
     'identifier': 'EVE_RELEASE_BETA',
@@ -681,8 +681,8 @@
   'CROS_OCTOPUS_RELEASE_BETA': {
     'skylab': {
       'cros_board': 'octopus',
-      'cros_chrome_version': '109.0.5414.41',
-      'cros_img': 'octopus-release/R109-15236.35.0',
+      'cros_chrome_version': '110.0.5481.32',
+      'cros_img': 'octopus-release/R110-15278.29.0',
     },
     'enabled': True,
     'identifier': 'OCTOPUS_RELEASE_BETA',
@@ -690,8 +690,8 @@
   'CROS_OCTOPUS_RELEASE_STABLE': {
     'skylab': {
       'cros_board': 'octopus',
-      'cros_chrome_version': '108.0.5359.172',
-      'cros_img': 'octopus-release/R108-15183.78.0',
+      'cros_chrome_version': '109.0.5414.94',
+      'cros_img': 'octopus-release/R109-15236.66.0',
     },
     'enabled': True,
     'identifier': 'OCTOPUS_RELEASE_STABLE',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 15afaf7..be468ef 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5177,7 +5177,7 @@
       },
       'WebKit Linux MSAN': {
         'mixins': [
-          'linux-focal',
+          'linux-bionic',
         ],
         'test_suites': {
           'isolated_scripts': 'chromium_webkit_isolated_scripts',
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
index 101d0e9..c3176f4 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver.cc
@@ -139,9 +139,6 @@
 void ScriptPromiseResolver::ResolveOrRejectImmediately() {
   DCHECK(!GetExecutionContext()->IsContextDestroyed());
   DCHECK(!GetExecutionContext()->IsContextPaused());
-
-  probe::WillReactToScriptPromise(GetExecutionContext());
-
   {
     if (state_ == kResolving) {
       resolver_.Resolve(value_.Get(script_state_->GetIsolate()));
diff --git a/third_party/blink/renderer/core/accessibility/axid.h b/third_party/blink/renderer/core/accessibility/axid.h
index 4b805d8..e116ab0c 100644
--- a/third_party/blink/renderer/core/accessibility/axid.h
+++ b/third_party/blink/renderer/core/accessibility/axid.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_ACCESSIBILITY_AXID_H_
 
 namespace blink {
-using AXID = unsigned;
+using AXID = int;
 }
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ACCESSIBILITY_AXID_H_
diff --git a/third_party/blink/renderer/core/aom/computed_accessible_node.cc b/third_party/blink/renderer/core/aom/computed_accessible_node.cc
index 21ad0a7..42a2246 100644
--- a/third_party/blink/renderer/core/aom/computed_accessible_node.cc
+++ b/third_party/blink/renderer/core/aom/computed_accessible_node.cc
@@ -114,7 +114,7 @@
   ax_context_->GetDocument()->View()->UpdateAllLifecyclePhasesExceptPaint(
       DocumentUpdateReason::kAccessibility);
   AXObjectCache& cache = ax_context_->GetAXObjectCache();
-  AXID ax_id = ax_id_ ? ax_id_ : cache.GetAXID(element_);
+  AXID ax_id = ax_id_ ? ax_id_ : cache.GetExistingAXID(element_);
   if (!ax_id || !cache.ObjectFromAXID(ax_id)) {
     resolver_->Resolve();  // No AXObject exists for this element.
     return;
diff --git a/third_party/blink/renderer/core/frame/performance_monitor.cc b/third_party/blink/renderer/core/frame/performance_monitor.cc
index f0b57d5..4538562 100644
--- a/third_party/blink/renderer/core/frame/performance_monitor.cc
+++ b/third_party/blink/renderer/core/frame/performance_monitor.cc
@@ -154,10 +154,6 @@
   --script_depth_;
 }
 
-void PerformanceMonitor::WillReactToScriptPromise(ExecutionContext* context) {
-  UpdateTaskAttribution(context);
-}
-
 void PerformanceMonitor::UpdateTaskAttribution(ExecutionContext* context) {
   // If |context| is not a window, unable to attribute a frame context.
   auto* window = DynamicTo<LocalDOMWindow>(context);
diff --git a/third_party/blink/renderer/core/frame/performance_monitor.h b/third_party/blink/renderer/core/frame/performance_monitor.h
index b87047b8..eac33e0 100644
--- a/third_party/blink/renderer/core/frame/performance_monitor.h
+++ b/third_party/blink/renderer/core/frame/performance_monitor.h
@@ -99,8 +99,6 @@
 
   void DocumentWriteFetchScript(Document*);
 
-  void WillReactToScriptPromise(ExecutionContext*);
-
   // Direct API for core.
   void Subscribe(Violation, base::TimeDelta threshold, Client*);
   void UnsubscribeAll(Client*);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 0e549913..85dcaab6 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -8,6 +8,7 @@
 #include <numeric>
 
 #include "base/containers/adapters.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/ranges/algorithm.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -1038,7 +1039,7 @@
     // TODO(kojii): This shouldn't happen, but is not easy to fix all cases.
     // Return nullptr so that callers can chose to fail gracefully, or
     // null-deref. crbug.com/946004
-    NOTREACHED();
+    base::debug::DumpWithoutCrashing();
     return nullptr;
   }
 
diff --git a/third_party/blink/renderer/core/probe/core_probes.json5 b/third_party/blink/renderer/core/probe/core_probes.json5
index 56210b2..1eb4590 100644
--- a/third_party/blink/renderer/core/probe/core_probes.json5
+++ b/third_party/blink/renderer/core/probe/core_probes.json5
@@ -223,7 +223,6 @@
         "UserCallback",
         "V8Compile",
         "DocumentWriteFetchScript",
-        "WillReactToScriptPromise",
       ]
     },
     InspectorPerformanceAgent: {
diff --git a/third_party/blink/renderer/core/probe/core_probes.pidl b/third_party/blink/renderer/core/probe/core_probes.pidl
index e541426..df454194 100644
--- a/third_party/blink/renderer/core/probe/core_probes.pidl
+++ b/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -163,7 +163,6 @@
   UserCallback([Keep] ExecutionContext* context, const char* name, const AtomicString& atomic_name, bool recurring, EventTarget* event_target = nullptr);
   V8Compile([Keep] ExecutionContext* context, const String& file_name, int line, int column);
   ParseHTML(Document* document, HTMLDocumentParser* parser);
-  void WillReactToScriptPromise([Keep] ExecutionContext* context);
   void ForcePseudoState([Keep] Element* element, CSSSelector::PseudoType pseudo_state, bool* result);
   void ShouldForceCorsPreflight(ExecutionContext*, bool* result);
   void ShouldBlockRequest(CoreProbeSink*, const KURL&, bool* result);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 599b92c..4acc14a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -852,13 +852,13 @@
 
   auto it_id = layout_object_mapping_.find(layout_object);
   AXID ax_id = it_id != layout_object_mapping_.end() ? it_id->value : 0;
-  DCHECK(!WTF::IsHashTraitsDeletedValue<HashTraits<AXID>>(ax_id));
 
   Node* node = layout_object->GetNode();
 
   if (!ax_id)
     return node ? Get(node) : nullptr;
 
+  DCHECK(!WTF::IsHashTraitsEmptyOrDeletedValue<HashTraits<AXID>>(ax_id));
   if (IsDisplayLocked(layout_object) ||
       !IsLayoutObjectRelevantForAccessibility(*layout_object)) {
     // Change from AXLayoutObject -> AXNodeObject.
@@ -914,12 +914,15 @@
   }
 #endif
 
-  auto iter = node_object_mapping_.find(node);
-  if (iter == node_object_mapping_.end()) {
+  AXID node_id =
+      static_cast<AXID>(DOMNodeIds::ExistingIdForNode(const_cast<Node*>(node)));
+  if (!node_id) {
+    // An ID hasn't yet been generated for this DOM node, but ::CreateAndInit()
+    // will ensure a DOMNodeID is generated. Therefore if an id doesn't exist
+    // for a DOM node, it means that it can't have an associated AXObject.
     return nullptr;
   }
 
-  AXID node_id = iter->value;
   auto it_result = objects_.find(node_id);
   if (it_result == objects_.end()) {
     return nullptr;
@@ -976,9 +979,9 @@
   auto it_ax = inline_text_box_object_mapping_.find(inline_text_box);
   AXID ax_id =
       it_ax != inline_text_box_object_mapping_.end() ? it_ax->value : 0;
-  DCHECK(!WTF::IsHashTraitsDeletedValue<HashTraits<AXID>>(ax_id));
   if (!ax_id)
     return nullptr;
+  DCHECK(!WTF::IsHashTraitsEmptyOrDeletedValue<HashTraits<AXID>>(ax_id));
 
   auto it_result = objects_.find(ax_id);
   AXObject* result = it_result != objects_.end() ? it_result->value : nullptr;
@@ -998,6 +1001,8 @@
     ScheduleAXUpdate();
 }
 
+// TODO(accessibility) Combine this with GetExistingAXID() now that we can
+// determine what AXID would be if it exists via DOMNodeIDs::IdForNode(node).
 AXID AXObjectCacheImpl::GetAXID(Node* node) {
   AXObject* ax_object = GetOrCreate(node);
   if (!ax_object)
@@ -1028,9 +1033,9 @@
 
   auto it_ax = accessible_node_mapping_.find(accessible_node);
   AXID ax_id = it_ax != accessible_node_mapping_.end() ? it_ax->value : 0;
-  DCHECK(!WTF::IsHashTraitsDeletedValue<HashTraits<AXID>>(ax_id));
   if (!ax_id)
     return nullptr;
+  DCHECK(!WTF::IsHashTraitsEmptyOrDeletedValue<HashTraits<AXID>>(ax_id));
 
   auto it_result = objects_.find(ax_id);
   AXObject* result = it_result != objects_.end() ? it_result->value : nullptr;
@@ -1337,8 +1342,7 @@
 // Caller must provide a node, a layout object, or both (where they match).
 AXObject* AXObjectCacheImpl::CreateAndInit(Node* node,
                                            LayoutObject* layout_object,
-                                           AXObject* parent_if_known,
-                                           AXID use_axid) {
+                                           AXObject* parent_if_known) {
 #if DCHECK_IS_ON()
   DCHECK(node || layout_object);
   DCHECK(!node || !layout_object || layout_object->GetNode() == node);
@@ -1395,22 +1399,22 @@
     }
   }
 
-  AXID axid = GenerateAXID();
+  // If there is a DOM node, use its dom_node_id, otherwise, generate an AXID.
+  // The dom_node_id can be used even if there is also a layout object.
+  AXID axid =
+      node ? static_cast<AXID>(DOMNodeIds::IdForNode(node)) : GenerateAXID();
   DCHECK(objects_.find(axid) == objects_.end());
 
-  if (node) {
-    node_object_mapping_.Set(node, axid);
-  } else {
-    DCHECK(!layout_object_mapping_.Contains(layout_object))
-        << "Already have an AXObject for " << layout_object;
-    layout_object_mapping_.Set(layout_object, axid);
-  }
-
   // Create the new AXObject.
   AXObject* new_obj = nullptr;
   if (ax_type == kAXLayoutObject) {
     // Prefer to create from renderer if there is a layout object because
     // AXLayoutObjects can provide information about bounding boxes.
+    if (!node) {
+      DCHECK(!layout_object_mapping_.Contains(layout_object))
+          << "Already have an AXObject for " << layout_object;
+      layout_object_mapping_.Set(layout_object, axid);
+    }
     new_obj = CreateFromRenderer(layout_object);
   } else {
     new_obj = CreateFromNode(node);
@@ -1483,7 +1487,7 @@
 
   AXObject* new_obj = CreateFromInlineTextBox(inline_text_box);
 
-  const AXID axid = AssociateAXID(new_obj);
+  AXID axid = AssociateAXID(new_obj);
 
   inline_text_box_object_mapping_.Set(inline_text_box, axid);
   new_obj->Init(parent);
@@ -1571,7 +1575,9 @@
   // Finally, remove the object.
   // TODO(accessibility) We don't use the return value, can we use .erase()
   // and it will still make sure that the object is cleaned up?
-  objects_.Take(ax_id);
+  if (!objects_.Take(ax_id)) {
+    return;
+  }
 }
 
 // This is safe to call even if there isn't a current mapping.
@@ -1626,26 +1632,15 @@
 
   layout_object_mapping_.erase(iter);
   Remove(ax_id);
-
-  return;
 }
 
 // This is safe to call even if there isn't a current mapping.
 void AXObjectCacheImpl::Remove(Node* node) {
-  if (!node)
-    return;
-
-  LayoutObject* layout_object = node->GetLayoutObject();
-
-  auto iter = node_object_mapping_.find(node);
-  if (iter != node_object_mapping_.end()) {
-    DCHECK(!layout_object || layout_object_mapping_.find(layout_object) ==
-                                 layout_object_mapping_.end())
-        << "AXObject cannot be backed by both a layout object and node.";
-    AXID ax_id = iter->value;
-    DCHECK(ax_id);
-    node_object_mapping_.erase(iter);
-    Remove(ax_id);
+  DCHECK(node);
+  AXID axid = static_cast<AXID>(DOMNodeIds::ExistingIdForNode(node));
+  if (axid) {
+    DCHECK_GE(axid, 1);
+    Remove(axid);
   }
 }
 
@@ -1675,15 +1670,32 @@
   Remove(ax_id);
 }
 
+// All generated AXIDs are negative, ranging from kFirstGeneratedId to INT_MIN,
+// in order to avoid conflict with the ids reused from dom_node_ids, which are
+// positive, and generated IDs on the browser side, which are negative, starting
+// at -1.
 AXID AXObjectCacheImpl::GenerateAXID() const {
-  static AXID last_used_id = 0;
+  // The first id is close to INT_MIN/2, leaving plenty of room for negative
+  // generated IDs both her and on the browser side, but starting at an even
+  // number makes it easier to read when debugging.
+  constexpr int kFirstGeneratedId = -1000000000;
+  static AXID last_used_id = kFirstGeneratedId;
+
+  // This is very unlikely to happen, but if we find that it happens often, we
+  // could gracefully turn off a11y instead of crashing the renderer.
+  CHECK(objects_.size() < kFirstGeneratedId - INT_MIN - 1)
+      << "Not enough room in map for more accessibility objects.";
 
   // Generate a new ID.
   AXID obj_id = last_used_id;
   do {
-    ++obj_id;
-  } while (!obj_id || WTF::IsHashTraitsDeletedValue<HashTraits<AXID>>(obj_id) ||
-           objects_.Contains(obj_id));
+    if (--obj_id == INT_MIN) {
+      has_axid_generator_looped_ = true;
+      obj_id = kFirstGeneratedId;
+    }
+  } while (has_axid_generator_looped_ && objects_.Contains(obj_id));
+
+  DCHECK(!WTF::IsHashTraitsEmptyOrDeletedValue<HashTraits<AXID>>(obj_id));
 
   last_used_id = obj_id;
 
@@ -1708,7 +1720,10 @@
   // Check for already-assigned ID.
   DCHECK(!obj->AXObjectID()) << "Object should not already have an AXID";
 
-  const AXID new_axid = use_axid ? use_axid : GenerateAXID();
+  AXID new_axid = use_axid ? use_axid : GenerateAXID();
+
+  DCHECK_EQ(obj->GetNode() && !obj->IsAXInlineTextBox(), IsDOMNodeID(new_axid))
+      << "AXObjects with a DOM node must use a dom_node_id for the AXID.";
 
   obj->SetAXObjectID(new_axid);
   objects_.Set(new_axid, obj);
@@ -1726,7 +1741,7 @@
   AXID obj_id = object->AXObjectID();
   if (!obj_id)
     return;
-  DCHECK(!WTF::IsHashTraitsDeletedValue<HashTraits<AXID>>(obj_id));
+  DCHECK(!WTF::IsHashTraitsEmptyOrDeletedValue<HashTraits<AXID>>(obj_id));
   object->SetAXObjectID(0);
   // Clear AXIDs from maps. Note: do not need to erase id from
   // changed_bounds_ids_, a set which is cleared each time
@@ -1734,11 +1749,21 @@
   // invalidated_ids_main_ or invalidated_ids_popup_, which are cleared each
   // time ProcessInvalidatedObjects() finishes, and having extra ids in those
   // sets is not harmful.
-  autofill_state_map_.erase(obj_id);
-  fixed_or_sticky_node_ids_.erase(obj_id);
   cached_bounding_boxes_.erase(obj_id);
-  // Clear id from relation cache.
-  relation_cache_->RemoveAXID(obj_id);
+
+  if (IsDOMNodeID(obj_id)) {
+    // Optimization: these maps only contain ids for AXObjects with a DOM node.
+    autofill_state_map_.erase(obj_id);
+    fixed_or_sticky_node_ids_.erase(obj_id);
+    // Only objects with a DOM node can be in the relation cache.
+    relation_cache_->RemoveAXID(obj_id);
+    // Allow the new AXObject for the same node to be serialized correctly.
+    nodes_with_pending_children_changed_.erase(obj_id);
+  } else {
+    // Non-DOM ids should never find their way into these maps.
+    DCHECK(!autofill_state_map_.Contains(obj_id));
+    DCHECK(!fixed_or_sticky_node_ids_.Contains(obj_id));
+  }
 }
 
 AXObject* AXObjectCacheImpl::NearestExistingAncestor(Node* node) {
@@ -1939,9 +1964,11 @@
     return;
 
   // A text changed event is redundant with children changed on the same node.
-  if (nodes_with_pending_children_changed_.find(node) !=
-      nodes_with_pending_children_changed_.end()) {
-    return;
+  if (AXID node_id = static_cast<AXID>(DOMNodeIds::ExistingIdForNode(node))) {
+    if (nodes_with_pending_children_changed_.find(node_id) !=
+        nodes_with_pending_children_changed_.end()) {
+      return;
+    }
   }
 
   DeferTreeUpdate(&AXObjectCacheImpl::TextChangedWithCleanLayout, node);
@@ -1956,10 +1983,13 @@
   // when it has a block sibling.
   Node* node = GetClosestNodeForLayoutObject(layout_object);
   if (node) {
-    // A text changed event is redundant with children changed on the same node.
-    if (nodes_with_pending_children_changed_.find(node) !=
-        nodes_with_pending_children_changed_.end()) {
-      return;
+    if (AXID node_id = static_cast<AXID>(DOMNodeIds::ExistingIdForNode(node))) {
+      // A text changed event is redundant with children changed on the same
+      // node.
+      if (nodes_with_pending_children_changed_.find(node_id) !=
+          nodes_with_pending_children_changed_.end()) {
+        return;
+      }
     }
 
     DeferTreeUpdate(&AXObjectCacheImpl::TextChangedWithCleanLayout, node);
@@ -2080,21 +2110,26 @@
       << "Unclean document at lifecycle " << document->Lifecycle().ToString();
 #endif  // DCHECK_IS_ON()
 
-  // Process any relation attributes that can affect ax objects already created.
-
   // Force computation of aria-owns, so that original parents that already
   // computed their children get the aria-owned children removed.
   if (AXObject::HasARIAOwns(element))
     HandleAttributeChangedWithCleanLayout(html_names::kAriaOwnsAttr, element);
 
-  MaybeNewRelationTarget(*node, Get(node));
+  // If there is a previous AXObject, it is being reattached with a new
+  // LayoutObject, in which case we should ensure its invalidation.
+  AXObject* previous_ax_object = Get(node);
+  ChildrenChangedWithCleanLayout(node, previous_ax_object);
+  // MarkAXObjectDirtyWithCleanLayout(previous_ax_object);
+
+  // Process any relation attributes that can affect ax objects already created.
+  MaybeNewRelationTarget(*node, previous_ax_object);
 
   // Even if the node or parent are ignored, an ancestor may need to include
   // descendants of the attached node, thus ChildrenChangedWithCleanLayout()
   // must be called. It handles ignored logic, ensuring that the first ancestor
   // that should have this as a child will be updated.
   ChildrenChangedWithCleanLayout(
-      Get(LayoutTreeBuilderTraversal::Parent(*node)));
+      GetOrCreate(LayoutTreeBuilderTraversal::Parent(*node)));
 
   // If an image map area is added, we need to update children on the image.
   if (IsA<HTMLAreaElement>(node))
@@ -2201,7 +2236,8 @@
     return nullptr;
   // Don't enqueue a deferred event on the same node more than once.
   if (ancestor->GetNode() &&
-      !nodes_with_pending_children_changed_.insert(ancestor->GetNode())
+      !nodes_with_pending_children_changed_
+           .insert(DOMNodeIds::ExistingIdForNode(ancestor->GetNode()))
            .is_new_entry) {
     return nullptr;
   }
@@ -2499,17 +2535,7 @@
     }
 
     AXID retained_axid = current->AXObjectID();
-    // Remove from relevant maps, but not from relation cache, as the relations
-    // between AXIDs will still be the same.
-    node_object_mapping_.erase(node);
-    if (is_ax_layout_object) {
-      layout_object_mapping_.erase(current->GetLayoutObject());
-    } else {
-      DCHECK(will_be_ax_layout_object);
-      DCHECK(node->GetLayoutObject());
-      DCHECK(!layout_object_mapping_.Contains(node->GetLayoutObject()))
-          << node << " " << node->GetLayoutObject();
-    }
+    DCHECK_EQ(retained_axid, DOMNodeIds::ExistingIdForNode(node));
 
     ChildrenChangedOnAncestorOf(current);
     current->Detach();
@@ -2522,9 +2548,9 @@
     // TODO(accessibility) That may be the only example of this, in which case
     // it could be handled in RoleChangedWithCleanLayout(), and the cached
     // parent could be used.
-    AXObject* new_object = CreateAndInit(
-        node, node->GetLayoutObject(),
-        AXObject::ComputeNonARIAParent(*this, node), retained_axid);
+    AXObject* new_object =
+        CreateAndInit(node, node->GetLayoutObject(),
+                      AXObject::ComputeNonARIAParent(*this, node));
     if (new_object) {
       // Any owned objects need to reset their parent_ to point to the
       // new object.
@@ -2532,6 +2558,7 @@
           AXRelationCache::IsValidOwner(new_object)) {
         relation_cache_->UpdateAriaOwnsWithCleanLayout(new_object, true);
       }
+      DCHECK_EQ(new_object->AXObjectID(), retained_axid);
     } else {
       // Failed to create, so remove object completely.
       RemoveAXID(current);
@@ -3086,8 +3113,13 @@
     // because some roles allow aria-owns and others don't.
     // In addition, any owned objects need to reset their parent_ to point
     // to the new object.
-    if (AXObject* new_object = GetOrCreate(node))
+    if (AXObject* new_object = GetOrCreate(node)) {
       relation_cache_->UpdateAriaOwnsWithCleanLayout(new_object, true);
+      // Need to mark dirty because the dom_node_id-based ID remains the same,
+      // and therefore the serializer may not automatically serialize this node
+      // from the children changed on the parent.
+      MarkAXObjectDirtyWithCleanLayout(new_object);
+    }
   }
 }
 
@@ -3427,7 +3459,6 @@
 
   auto it = layout_object_mapping_.find(layout_object);
   AXID ax_id = it != layout_object_mapping_.end() ? it->value : 0;
-  DCHECK(!WTF::IsHashTraitsDeletedValue<HashTraits<AXID>>(ax_id));
 
   // Only update if the accessibility object already exists and it's
   // not already marked as dirty.
@@ -3436,6 +3467,7 @@
   // which uses the NGInlineCursor. However, the NGInlineCursor cannot be used
   // while inline boxes are being updated.
   if (ax_id) {
+    DCHECK(!WTF::IsHashTraitsEmptyOrDeletedValue<HashTraits<AXID>>(ax_id));
     AXObject* obj = objects_.at(ax_id);
     DCHECK(obj);
     DCHECK(obj->IsAXLayoutObject());
@@ -4078,10 +4110,14 @@
       !marker_controller.MarkersFor(*text_node, spelling_and_grammar_markers)
            .empty();
   if (has_spelling_or_grammar_markers) {
-    if (nodes_with_spelling_or_grammar_markers_.insert(node).is_new_entry)
+    if (nodes_with_spelling_or_grammar_markers_
+            .insert(DOMNodeIds::IdForNode(node))
+            .is_new_entry) {
       ChildrenChangedWithCleanLayout(node);
+    }
   } else {
-    const auto& iter = nodes_with_spelling_or_grammar_markers_.find(node);
+    const auto& iter = nodes_with_spelling_or_grammar_markers_.find(
+        DOMNodeIds::IdForNode(node));
     if (iter != nodes_with_spelling_or_grammar_markers_.end()) {
       nodes_with_spelling_or_grammar_markers_.erase(iter);
       ChildrenChangedWithCleanLayout(node);
@@ -4376,7 +4412,6 @@
   visitor->Trace(last_selected_from_active_descendant_);
   visitor->Trace(accessible_node_mapping_);
   visitor->Trace(layout_object_mapping_);
-  visitor->Trace(node_object_mapping_);
   visitor->Trace(active_aria_modal_dialog_);
 
   visitor->Trace(objects_);
@@ -4386,8 +4421,6 @@
   visitor->Trace(permission_observer_receiver_);
   visitor->Trace(tree_update_callback_queue_main_);
   visitor->Trace(tree_update_callback_queue_popup_);
-  visitor->Trace(nodes_with_pending_children_changed_);
-  visitor->Trace(nodes_with_spelling_or_grammar_markers_);
   visitor->Trace(ax_tree_source_);
   visitor->Trace(dirty_objects_);
   visitor->Trace(aria_notifications_);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index 5639fe7..27d6b7f9 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -72,15 +72,10 @@
 class LocalFrameView;
 class WebLocalFrameClient;
 
-// Describes a decicion on whether to create an AXNodeObject, an AXLayoutObject,
+// Describes a decision on whether to create an AXNodeObject, an AXLayoutObject,
 // or nothing (which will cause the AX subtree to be pruned at that point).
-// Currently this also mirrors the decision on whether to back the object by a
-// node or a layout object. When the AXObject is backed by a node, it's
-// AXID can be looked up in node_object_mapping_, and when the AXObject is
-// backed by layout, it's AXID can be looked up in layout_object_mapping_.
-// TODO(accessibility) Split the decision of what to use for backing from what
-// type of object to create, and use a node whenever possible, in order to
-// enable more stable IDs for most objects.
+// Not that AXLayoutObjects may be backed by a node, if it has one, and most do.
+// Only pseudo element descendants are missing DOM nodes.
 enum AXObjectType { kPruneSubtree = 0, kAXNodeObject, kAXLayoutObject };
 
 // This class should only be used from inside the accessibility directory.
@@ -247,7 +242,7 @@
   AXObject* ObjectFromAXID(AXID id) const override;
   AXObject* Root();
 
-  // Used for objects without backing DOM nodes, layout objects, etc.
+  // Used for objects without a backing DOM nodes, layout or inline text box.
   AXObject* CreateAndInit(ax::mojom::blink::Role, AXObject* parent);
 
   AXObject* GetOrCreate(AccessibleNode*, AXObject* parent);
@@ -560,14 +555,10 @@
 
   // Create an AXObject, and do not check if a previous one exists.
   // Also, initialize the object and add it to maps for later retrieval.
-  AXObject* CreateAndInit(Node*,
-                          LayoutObject*,
-                          AXObject* parent_if_known,
-                          AXID use_axid = 0);
+  AXObject* CreateAndInit(Node*, LayoutObject*, AXObject* parent_if_known);
   // Helpers for CreateAndInitIfRelevant() methods..
   AXObject* CreateFromRenderer(LayoutObject*);
   AXObject* CreateFromNode(Node*);
-
   AXObject* CreateFromInlineTextBox(AbstractInlineTextBox*);
 
   mojo::Remote<mojom::blink::RenderAccessibilityHost>&
@@ -579,6 +570,10 @@
   bool IsMainDocumentDirty() const;
   bool IsPopupDocumentDirty() const;
 
+  // Returns true if the AXID is for a DOM node.
+  // All other AXIDs are generated.
+  bool IsDOMNodeID(AXID axid) { return axid > 0; }
+
   HeapHashSet<WeakMember<InspectorAccessibilityAgent>> agents_;
 
   struct AXEventParams final : public GarbageCollected<AXEventParams> {
@@ -657,12 +652,16 @@
   Member<Document> popup_document_;
 
   ui::AXMode ax_mode_;
+  // AXIDs for AXNodeObjects reuse the int ids in dom_node_id, all other AXIDs
+  // are negative in order to avoid a conflict.
   HeapHashMap<AXID, Member<AXObject>> objects_;
   // LayoutObject and AbstractInlineTextBox are not on the Oilpan heap so we
   // do not use HeapHashMap for those mappings.
   HeapHashMap<Member<AccessibleNode>, AXID> accessible_node_mapping_;
+  // When the AXObject is backed by layout, its AXID can be looked up in
+  // layout_object_mapping_. When the AXObject is backed by a node, its
+  // AXID can be looked up via DOMNodeIDs::ExistingIdForNode(node).
   HeapHashMap<Member<const LayoutObject>, AXID> layout_object_mapping_;
-  HeapHashMap<Member<const Node>, AXID> node_object_mapping_;
   HashMap<AbstractInlineTextBox*, AXID> inline_text_box_object_mapping_;
   int modification_count_;
 
@@ -847,11 +846,11 @@
   TreeUpdateCallbackQueue tree_update_callback_queue_popup_;
 
   // Help de-dupe processing of repetitive events.
-  HeapHashSet<WeakMember<Node>> nodes_with_pending_children_changed_;
+  HashSet<AXID> nodes_with_pending_children_changed_;
   HashSet<AXID> nodes_with_pending_location_changed_;
 
   // Nodes with document markers that have received accessibility updates.
-  HeapHashSet<WeakMember<Node>> nodes_with_spelling_or_grammar_markers_;
+  HashSet<AXID> nodes_with_spelling_or_grammar_markers_;
 
   // True when layout has changed, and changed locations must be serialized.
   bool need_to_send_location_changes_ = false;
@@ -914,6 +913,8 @@
 
   Deque<ui::AXEvent> pending_events_;
 
+  mutable bool has_axid_generator_looped_ = false;
+
   FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, PauseUpdatesAfterMaxNumberQueued);
   FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, RemoveAXID);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/DEPS b/third_party/blink/renderer/platform/scheduler/DEPS
index 208d0f2b..71a0712 100644
--- a/third_party/blink/renderer/platform/scheduler/DEPS
+++ b/third_party/blink/renderer/platform/scheduler/DEPS
@@ -9,13 +9,13 @@
   "+base/atomic_sequence_num.h",
   "+base/atomicops.h",
   "+base/barrier_closure.h",
-  "+base/callback_helpers.h",
   "+base/cancelable_callback.h",
   "+base/command_line.h",
   "+base/compiler_specific.h",
   "+base/containers/circular_deque.h",
   "+base/feature_list.h",
   "+base/format_macros.h",
+  "+base/functional/callback_helpers.h",
   "+base/gtest_prod_util.h",
   "+base/logging.h",
   "+base/message_loop/message_loop.h",
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 7873c8a..1d77544 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -149,7 +149,7 @@
             'base::expected',
             'base::unexpected',
 
-            # //base/bind.h
+            # //base/functional/bind.h
             'base::IgnoreResult',
 
             # //base/bits.h
@@ -159,12 +159,12 @@
             'base::ObserverList',
             'base::CheckedObserver',
 
-            # //base/callback_helpers.h.
+            # //base/functional/callback_helpers.h.
             'base::DoNothing',
             'base::SplitOnceCallback',
 
-            # //base/callback.h is allowed, but you need to use WTF::Bind or
-            # WTF::BindRepeating to create callbacks in Blink.
+            # //base/functional/callback.h is allowed, but you need to use
+            # WTF::Bind or WTF::BindRepeating to create callbacks in Blink.
             'base::BarrierClosure',
             'base::NullCallback',
             'base::OnceCallback',
diff --git a/third_party/blink/web_tests/accessibility/aom-computed-accessible-node.html b/third_party/blink/web_tests/accessibility/aom-computed-accessible-node.html
index e7f937e..dfa6c57 100644
--- a/third_party/blink/web_tests/accessibility/aom-computed-accessible-node.html
+++ b/third_party/blink/web_tests/accessibility/aom-computed-accessible-node.html
@@ -51,13 +51,12 @@
     assert_equals(button2CAXNode.name, "axButton");
     assert_equals(button2CAXNode.role, "button");
 
-    // As button1 has no node in the accessibility tree anymore, assert that the
-    // its previously retrieved computed accessible node has had its attributes
-    // nullified.
+    // As button1 still has a node in the accessibility tree, but its layout has
+    // been removed,and therefore the name is now null.
     assert_equals(button1CAXNode.name, null);
-    assert_equals(button1CAXNode.role, null);
+    assert_equals(button1CAXNode.role, "button");
 
-}, "Deleting nodes from the accessibility tree will not cause a crash, and properties on any references to a deleted computed accessible node have been nullified.");
+}, "Deleting layout from the accessibility tree will not cause a crash.");
 
 </script>
 
diff --git a/third_party/blink/web_tests/external/wpt/longtask-timing/longtask-promise.html b/third_party/blink/web_tests/external/wpt/longtask-timing/longtask-promise.html
deleted file mode 100644
index 1709304..0000000
--- a/third_party/blink/web_tests/external/wpt/longtask-timing/longtask-promise.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE HTML>
-<meta charset=utf-8>
-<title>LongTask Timing: long task in rAF</title>
-<body>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/utils.js"></script>
-
-<h1>Long Task: promises</h1>
-<script>
-  function test_promise_long_task(name, promise) {
-    promise_test(async t => {
-      assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.');
-      const longTaskPromise = new Promise(resolve => {
-        const observer = new PerformanceObserver(t.step_func(entryList => resolve(entryList.getEntries())));
-        observer.observe({entryTypes: ['longtask']});
-      });
-
-      await promise().catch(() => {});
-      busyWait();
-      const entries = await longTaskPromise;
-      assert_greater_than_equal(entries.length, 1);
-    }, `Performance longtask entries after a promise: ${name}`);
-  }
-
-  test_promise_long_task("successful fetch", () => fetch("/common/dummy.xml"));
-  test_promise_long_task("Response.text()", () => fetch("/common/dummy.xml").then(r => r.text()));
-  test_promise_long_task("rejected fetch", () => fetch("/common/non-existent.xml"));
-  test_promise_long_task("JSON error", () => fetch("/common/dummy.xml").then(r => r.json()));
-  test_promise_long_task("image.decode", async () => {
-    const img = document.createElement("img");
-    img.src = "/images/blue.png";
-    return img.decode();
-  })
-</script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/longtask-timing/resources/utils.js b/third_party/blink/web_tests/external/wpt/longtask-timing/resources/utils.js
index 482b2b3..36bd6c7b 100644
--- a/third_party/blink/web_tests/external/wpt/longtask-timing/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/longtask-timing/resources/utils.js
@@ -11,8 +11,3 @@
 function hasUnrelatedTaskName(taskName, expectedTaskName) {
   return (taskName !== expectedTaskName);
 }
-
-function busyWait(millis = 60) {
-  const start = performance.now()
-  while (performance.now() < (start + millis)) {}
-}
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_size_different_with_back_buffer_size.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_size_different_with_back_buffer_size.https.html
deleted file mode 100644
index 36ae83b..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_size_different_with_back_buffer_size.https.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html class="reftest-wait">
-  <base href="/gen/third_party/webgpu-cts/src/webgpu/web_platform/reftests/" />
-  <title>WebGPU canvas_back_buffer_different_size</title>
-  <meta charset="utf-8" />
-  <link rel="help" href="https://gpuweb.github.io/gpuweb/" />
-  <meta
-    name="assert"
-    content="WebGPU canvas should present correctly with different size of back buffer"
-  />
-  <meta name=fuzzy content="maxDifference=1;totalPixels=0-2000">
-  <link rel="match"
-        href="./ref/canvas_size_different_with_back_buffer_size-ref.html" />
-
-  <canvas id="cvs_larger_than_back_buffer" width="6" height="8"></canvas>
-  <canvas id="cvs_same_as_back_buffer" width="3" height="4"></canvas>
-  <canvas id="cvs_smaller_than_back_buffer" width="3" height="4"></canvas>
-  <canvas id="cvs_change_size_after_configure" width="3" height="4"></canvas>
-  <canvas id="cvs_change_size_and_reconfigure" width="3" height="4"></canvas>
-  <canvas id="back_buffer_smaller_than_cvs_and_css" width="6" height="8" style="width: 12px; height: 16px;"></canvas>
-  <canvas id="cvs_smaller_than_back_buffer_and_css" width="3" height="4" style="width: 12px; height: 16px;"></canvas>
-  <script type="module">
-    import { run } from './canvas_size_different_with_back_buffer_size.html.js';
-    run();
-  </script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/ref/canvas_size_different_with_back_buffer_size-ref.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/ref/canvas_size_different_with_back_buffer_size-ref.html
deleted file mode 100644
index 5b0ef5e4..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/ref/canvas_size_different_with_back_buffer_size-ref.html
+++ /dev/null
@@ -1,100 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <base href="/gen/third_party/webgpu-cts/src/webgpu/web_platform/reftests/ref/" />
-  <title>WebGPU canvas_back_buffer_different_size (ref)</title>
-  <meta charset="utf-8" />
-  <link rel="help" href="https://gpuweb.github.io/gpuweb/" />
-  <canvas id="cvs_larger_than_back_buffer_ref" width="3" height="4" style="width: 6px; height: 8px;"></canvas>
-  <canvas id="cvs_same_as_back_buffer_ref" width="3" height="4"></canvas>
-  <canvas id="cvs_smaller_than_back_buffer_ref" width="6" height="8" style="width: 3px; height: 4px;"></canvas>
-  <canvas id="cvs_change_size_after_configure_ref" width="3" height="4" style="width: 6px; height: 8px;"></canvas>
-  <canvas id="cvs_change_size_and_reconfigure_ref" width="6" height="8"></canvas>
-  <canvas id="back_buffer_smaller_than_cvs_and_css_ref" width="3" height="4" style="width: 12px; height: 16px;"></canvas>
-  <canvas id="cvs_smaller_than_back_buffer_and_css" width="6" height="8" style="width: 12px; height: 16px;"></canvas>
-  <script>
-  {
-    const context = cvs_larger_than_back_buffer_ref.getContext('2d');
-    context.fillStyle = "#FF0000";
-    context.fillRect(0, 0, 2, 2);
-    context.fillStyle = "#00FF00";
-    context.fillRect(2, 0, 1, 2);
-    context.fillStyle = "#0000FF";
-    context.fillRect(0, 2, 2, 2);
-    context.fillStyle = "#FFFF00";
-    context.fillRect(2, 2, 1, 2);
-    }
-
-    {
-    const context = cvs_same_as_back_buffer_ref.getContext('2d');
-    context.fillStyle = "#FF0000";
-    context.fillRect(0, 0, 2, 2);
-    context.fillStyle = "#00FF00";
-    context.fillRect(2, 0, 1, 2);
-    context.fillStyle = "#0000FF";
-    context.fillRect(0, 2, 2, 2);
-    context.fillStyle = "#FFFF00";
-    context.fillRect(2, 2, 1, 2);
-    }
-
-    {
-    const context = cvs_smaller_than_back_buffer_ref.getContext('2d');
-    context.fillStyle = "#FF0000";
-    context.fillRect(0, 0, 4, 4);
-    context.fillStyle = "#00FF00";
-    context.fillRect(4, 0, 2, 4);
-    context.fillStyle = "#0000FF";
-    context.fillRect(0, 4, 4, 4);
-    context.fillStyle = "#FFFF00";
-    context.fillRect(4, 4, 2, 4);
-    }
-
-    {
-    const context = cvs_change_size_after_configure_ref.getContext('2d');
-    context.fillStyle = "#FF0000";
-    context.fillRect(0, 0, 2, 2);
-    context.fillStyle = "#00FF00";
-    context.fillRect(2, 0, 1, 2);
-    context.fillStyle = "#0000FF";
-    context.fillRect(0, 2, 2, 2);
-    context.fillStyle = "#FFFF00";
-    context.fillRect(2, 2, 1, 2);
-    }
-
-    {
-    const context = cvs_change_size_and_reconfigure_ref.getContext('2d');
-    context.fillStyle = "#FF0000";
-    context.fillRect(0, 0, 4, 4);
-    context.fillStyle = "#00FF00";
-    context.fillRect(4, 0, 2, 4);
-    context.fillStyle = "#0000FF";
-    context.fillRect(0, 4, 4, 4);
-    context.fillStyle = "#FFFF00";
-    context.fillRect(4, 4, 2, 4);
-    }
-
-    {
-    const context = back_buffer_smaller_than_cvs_and_css_ref.getContext('2d');
-    context.fillStyle = "#FF0000";
-    context.fillRect(0, 0, 2, 2);
-    context.fillStyle = "#00FF00";
-    context.fillRect(2, 0, 1, 2);
-    context.fillStyle = "#0000FF";
-    context.fillRect(0, 2, 2, 2);
-    context.fillStyle = "#FFFF00";
-    context.fillRect(2, 2, 1, 2);
-    }
-
-    {
-    const context = cvs_smaller_than_back_buffer_and_css.getContext('2d');
-    context.fillStyle = "#FF0000";
-    context.fillRect(0, 0, 4, 4);
-    context.fillStyle = "#00FF00";
-    context.fillRect(4, 0, 2, 4);
-    context.fillRect(2, 1, 1, 1);
-    context.fillStyle = "#0000FF";
-    context.fillRect(0, 4, 4, 4);
-    context.fillStyle = "#FFFF00";
-    context.fillRect(4, 4, 2, 4);
-    }
-  </script>
-</html>
diff --git a/third_party/libwebp/BUILD.gn b/third_party/libwebp/BUILD.gn
index 84c56558..f70a986 100644
--- a/third_party/libwebp/BUILD.gn
+++ b/third_party/libwebp/BUILD.gn
@@ -365,10 +365,16 @@
   public = [ "src/sharpyuv/sharpyuv_dsp.h" ]
 }
 
+source_set("libwebp_dsp_cpu_c") {
+  public = [ "src/src/dsp/cpu.c" ]
+}
+
 static_library("libwebp_sharpyuv") {
   sources = [
     "src/sharpyuv/sharpyuv.c",
     "src/sharpyuv/sharpyuv.h",
+    "src/sharpyuv/sharpyuv_cpu.c",
+    "src/sharpyuv/sharpyuv_cpu.h",
     "src/sharpyuv/sharpyuv_csp.c",
     "src/sharpyuv/sharpyuv_csp.h",
     "src/sharpyuv/sharpyuv_gamma.c",
@@ -385,6 +391,7 @@
   all_dependent_configs = [ ":libwebp_config" ]
 
   deps = [
+    ":libwebp_dsp_cpu_c",
     ":libwebp_dsp_headers",
     ":libwebp_sharpyuv_dsp",
     ":libwebp_webp",
@@ -393,6 +400,8 @@
 
 static_library("libwebp_sharpyuv_dsp") {
   sources = [
+    "src/sharpyuv/sharpyuv.h",
+    "src/sharpyuv/sharpyuv_cpu.h",
     "src/sharpyuv/sharpyuv_dsp.c",
     "src/sharpyuv/sharpyuv_dsp.h",
   ]
@@ -644,6 +653,7 @@
       ":imagedec",
       ":imageio_util",
       ":libwebp",
+      ":libwebp_sharpyuv",
       ":libwebp_webp",
       "//base",
       "//build/win:default_exe_manifest",
diff --git a/third_party/libwebp/README.chromium b/third_party/libwebp/README.chromium
index c5445919..9032efdf 100644
--- a/third_party/libwebp/README.chromium
+++ b/third_party/libwebp/README.chromium
@@ -1,9 +1,9 @@
 Name: WebP image encoder/decoder
 Short Name: libwebp
 URL: https://chromium.googlesource.com/webm/libwebp
-Version: v1.2.3
-Revision: 7366f7f394af26de814296152c50e673ed0a832f
-CPEPrefix: cpe:/a:webmproject:libwebp:1.2.3
+Version: v1.3.0
+Revision: 603e8d7adb0ccc35237419c2938194623b60e9be
+CPEPrefix: cpe:/a:webmproject:libwebp:1.3.0
 License: BSD
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni
index 1f4da29..50915417 100644
--- a/third_party/protobuf/proto_library.gni
+++ b/third_party/protobuf/proto_library.gni
@@ -35,10 +35,6 @@
 #       Generates a "_py_runtime"-suffixed target for test targets that need the
 #       Python stubs available at runtime.
 #
-#   TODO(crbug.com/1237958): Remove allow_optional when proto rolls to 3.15.
-#   allow_optional (optional, default false)
-#       Enables experimental_allow_proto3_optional.
-#
 #   cc_generator_options (optional)
 #       List of extra flags passed to the protocol compiler.  If you need to
 #       add an EXPORT macro to a protobuf's C++ header, set the
@@ -387,9 +383,6 @@
           invoker.cc_generator_options,
         ]
       }
-      if (defined(invoker.allow_optional) && invoker.allow_optional == true) {
-        args += [ "--allow-optional" ]
-      }
       if (defined(invoker.cc_include)) {
         args += [
           "--include",
diff --git a/third_party/webgpu-cts/BUILD.gn b/third_party/webgpu-cts/BUILD.gn
index e88b3390..dfb0fdee 100644
--- a/third_party/webgpu-cts/BUILD.gn
+++ b/third_party/webgpu-cts/BUILD.gn
@@ -40,6 +40,7 @@
   inputs = [
              "//third_party/node/node_modules/typescript/lib/tsc.js",
              "//third_party/node/node.py",
+             "//third_party/node/node_modules.tar.gz.sha1",
              "scripts/tsc_ignore_errors.py",
 
              # If the only change is that a file is deleted, we still need to
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index dabcba3d..6c2e89b 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -302,6 +302,8 @@
 src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts
 src/webgpu/shader/execution/expression/binary/f32_arithmetic.spec.ts
 src/webgpu/shader/execution/expression/binary/f32_logical.spec.ts
+src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts
+src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts
 src/webgpu/shader/execution/expression/call/builtin/builtin.ts
 src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts
 src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts
@@ -463,7 +465,6 @@
 src/webgpu/web_platform/reftests/canvas_complex.html.ts
 src/webgpu/web_platform/reftests/canvas_composite_alpha.html.ts
 src/webgpu/web_platform/reftests/canvas_image_rendering.html.ts
-src/webgpu/web_platform/reftests/canvas_size_different_with_back_buffer_size.html.ts
 src/webgpu/web_platform/reftests/create-pattern-data-url.ts
 src/webgpu/web_platform/reftests/resize_observer.html.ts
 src/webgpu/web_platform/worker/worker.spec.ts
diff --git a/tools/binary_size/supersize.pydeps b/tools/binary_size/supersize.pydeps
index ae1b981..daa26f5 100644
--- a/tools/binary_size/supersize.pydeps
+++ b/tools/binary_size/supersize.pydeps
@@ -1,6 +1,5 @@
 # Generated by running:
 #   build/print_python_deps.py --root tools/binary_size --output tools/binary_size/supersize.pydeps tools/binary_size/libsupersize/main.py
-../../third_party/six/src/six.py
 ../grit/grit/__init__.py
 ../grit/grit/clique.py
 ../grit/grit/constants.py
diff --git a/tools/grit/BUILD.gn b/tools/grit/BUILD.gn
index dfcfbe8..49cdbd99f 100644
--- a/tools/grit/BUILD.gn
+++ b/tools/grit/BUILD.gn
@@ -35,7 +35,6 @@
     "//tools/grit/",
     "//third_party/catapult/third_party/typ/",
     "//third_party/node/",
-    "//third_party/six/src/six.py",
   ]
 }
 
diff --git a/tools/grit/grit/__init__.py b/tools/grit/grit/__init__.py
index fa82d3a..38e9891 100644
--- a/tools/grit/grit/__init__.py
+++ b/tools/grit/grit/__init__.py
@@ -4,12 +4,3 @@
 
 '''Package 'grit'
 '''
-
-
-import os
-import sys
-
-
-_HERE_PATH = os.path.dirname(__file__)
-_SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..', '..'))
-sys.path.insert(0, os.path.join(_SRC_PATH, 'third_party', 'six', 'src'))
diff --git a/tools/grit/grit/clique.py b/tools/grit/grit/clique.py
index 01560f6..714b9e7 100644
--- a/tools/grit/grit/clique.py
+++ b/tools/grit/grit/clique.py
@@ -9,8 +9,6 @@
 
 import re
 
-import six
-
 from grit import constants
 from grit import exception
 from grit import lazy_re
diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py
index 5cc3702d..99ed30f1 100755
--- a/tools/grit/grit/grd_reader.py
+++ b/tools/grit/grit/grd_reader.py
@@ -12,8 +12,6 @@
 import xml.sax
 import xml.sax.handler
 
-import six
-
 from grit import exception
 from grit import util
 from grit.node import mapping
diff --git a/tools/grit/grit/tclib.py b/tools/grit/grit/tclib.py
index cb23764..b14f5ec 100644
--- a/tools/grit/grit/tclib.py
+++ b/tools/grit/grit/tclib.py
@@ -9,8 +9,6 @@
 import functools
 import re
 
-import six
-
 from grit import exception
 from grit import lazy_re
 import grit.extern.tclib
diff --git a/tools/grit/grit/tool/android2grd.py b/tools/grit/grit/tool/android2grd.py
index 8526a7ef..908ae69 100644
--- a/tools/grit/grit/tool/android2grd.py
+++ b/tools/grit/grit/tool/android2grd.py
@@ -11,7 +11,6 @@
 from xml.dom import Node
 import xml.dom.minidom
 
-import six
 from io import StringIO
 
 import grit.node.empty
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py
index 664b9f6..f3f61c4 100644
--- a/tools/grit/grit/tool/build.py
+++ b/tools/grit/grit/tool/build.py
@@ -15,8 +15,6 @@
 import shutil
 import sys
 
-import six
-
 from grit import grd_reader
 from grit import shortcuts
 from grit import util
diff --git a/tools/grit/grit/tool/menu_from_parts.py b/tools/grit/grit/tool/menu_from_parts.py
index 7e0466a..075edc8 100644
--- a/tools/grit/grit/tool/menu_from_parts.py
+++ b/tools/grit/grit/tool/menu_from_parts.py
@@ -5,8 +5,6 @@
 '''The 'grit menufromparts' tool.'''
 
 
-import six
-
 from grit import grd_reader
 from grit import util
 from grit import xtb_reader
diff --git a/tools/grit/grit/tool/rc2grd.py b/tools/grit/grit/tool/rc2grd.py
index 291f2e71..e0282d9 100644
--- a/tools/grit/grit/tool/rc2grd.py
+++ b/tools/grit/grit/tool/rc2grd.py
@@ -10,7 +10,6 @@
 import re
 import sys
 
-import six
 from io import StringIO
 
 import grit.node.empty
diff --git a/tools/grit/grit/tool/xmb.py b/tools/grit/grit/tool/xmb.py
index 1c27d8a..646bdd9 100644
--- a/tools/grit/grit/tool/xmb.py
+++ b/tools/grit/grit/tool/xmb.py
@@ -12,8 +12,6 @@
 
 from xml.sax import saxutils
 
-import six
-
 from grit import grd_reader
 from grit import lazy_re
 from grit import tclib
diff --git a/tools/grit/grit/util_unittest.py b/tools/grit/grit/util_unittest.py
index 342d7c2..71640df 100755
--- a/tools/grit/grit/util_unittest.py
+++ b/tools/grit/grit/util_unittest.py
@@ -14,8 +14,6 @@
 
 import unittest
 
-import six
-
 from grit import util
 
 
diff --git a/tools/grit/pak_util.py b/tools/grit/pak_util.py
index 4a0b5dc..49f16220 100755
--- a/tools/grit/pak_util.py
+++ b/tools/grit/pak_util.py
@@ -19,12 +19,6 @@
 import sys
 import tempfile
 
-_HERE_PATH = os.path.dirname(__file__)
-_SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..'))
-sys.path.insert(0, os.path.join(_SRC_PATH, 'third_party', 'six', 'src'))
-
-import six
-
 from grit import constants
 from grit.format import data_pack
 
diff --git a/tools/grit/setup.py b/tools/grit/setup.py
index cc2d80a..3784add 100755
--- a/tools/grit/setup.py
+++ b/tools/grit/setup.py
@@ -16,9 +16,6 @@
         'console_scripts': ['grit = grit.grit_runner:Main'],
     },
     packages=setuptools.find_packages(),
-    install_requires=[
-        'six >= 1.10',
-    ],
     author='The Chromium Authors',
     author_email='chromium-dev@chromium.org',
     description=('Google Resource and Internationalization Tool for managing '
@@ -34,7 +31,6 @@
         'Operating System :: Microsoft :: Windows',
         'Operating System :: POSIX :: Linux',
         'Programming Language :: Python',
-        'Programming Language :: Python :: 2.7',
         'Programming Language :: Python :: 3',
         'Programming Language :: Python :: 3.6',
         'Programming Language :: Python :: 3.7',
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 6e99c37..7de4bdb 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -3161,7 +3161,7 @@
     ],
 
     'msan_release_bot_blink_reclient': [
-      'msan_focal', 'release_bot_blink_reclient',
+      'msan', 'release_bot_blink_reclient',
     ],
 
     'msan_release_bot_reclient': [
@@ -4530,7 +4530,7 @@
 
     # experiment windows cross. crbug.com/1213717
     'reclient_win_cross': {
-      'gn_args': 'use_remoteexec=true rbe_cfg_dir="../../buildtools/reclient_cfgs/win-cross-experiments"',
+      'gn_args': 'use_remoteexec=true rbe_cfg_dir="../../buildtools/reclient_cfgs/win-cross"',
     },
 
     # Historically, a 'release' bot had DCHECKs turned off. DCHECKs are now
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index cea65515..45d4a00f 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -549,7 +549,7 @@
       "is_component_build": false,
       "is_debug": false,
       "proprietary_codecs": true,
-      "rbe_cfg_dir": "../../buildtools/reclient_cfgs/win-cross-experiments",
+      "rbe_cfg_dir": "../../buildtools/reclient_cfgs/win-cross",
       "symbol_level": 1,
       "use_remoteexec": true
     }
@@ -561,7 +561,7 @@
       "is_component_build": false,
       "is_debug": false,
       "proprietary_codecs": true,
-      "rbe_cfg_dir": "../../buildtools/reclient_cfgs/win-cross-experiments",
+      "rbe_cfg_dir": "../../buildtools/reclient_cfgs/win-cross",
       "symbol_level": 1,
       "use_remoteexec": true
     }
diff --git a/tools/mb/mb_config_expectations/chromium.memory.json b/tools/mb/mb_config_expectations/chromium.memory.json
index 0d1affa..2f33792c 100644
--- a/tools/mb/mb_config_expectations/chromium.memory.json
+++ b/tools/mb/mb_config_expectations/chromium.memory.json
@@ -105,7 +105,7 @@
     "gn_args": {
       "dcheck_always_on": false,
       "ffmpeg_branding": "Chrome",
-      "instrumented_libraries_release": "focal",
+      "instrumented_libraries_release": "xenial",
       "is_component_build": false,
       "is_debug": false,
       "is_msan": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a1257dec..3d3a023 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -90281,6 +90281,7 @@
   <int value="400" label="DIAGCFG"/>
   <int value="401" label="DIAGPKG"/>
   <int value="402" label="PSM1"/>
+  <int value="403" label="BGI"/>
 </enum>
 
 <enum name="SBClientDownloadIsSignedBinary">
@@ -108897,6 +108898,11 @@
   <int value="8" label="Reject leaving ESS"/>
 </enum>
 
+<enum name="WiFiCiscoAdaptiveFTSupport">
+  <int value="0" label="Does not support Adaptive FT"/>
+  <int value="1" label="Supports Adaptive FT"/>
+</enum>
+
 <enum name="WiFiConnectionStatusAfterWake">
   <int value="0" label="Connected (Wake On WiFi enabled)"/>
   <int value="1" label="Not connected (Wake On WiFi enabled)"/>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index a6a671d..c128af9 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -559,7 +559,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.GameProvider.UpdateStatus" enum="DiscoveryError"
-    expires_after="2023-02-28">
+    expires_after="2023-08-28">
   <owner>wrong@chromium.org</owner>
   <owner>amandadeacon@chromium.org</owner>
   <summary>
@@ -569,7 +569,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.GameResult.IconLoadStatus" enum="DiscoveryError"
-    expires_after="2023-02-28">
+    expires_after="2023-08-28">
   <owner>wrong@chromium.org</owner>
   <owner>amandadeacon@chromium.org</owner>
   <owner>chenjih@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index bc68c1d..f511174 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -3560,9 +3560,9 @@
   <owner>cros-lurs@google.com</owner>
   <summary>
     The number of incorrect passwords entered in Chrome OS
-    {AuthenticationSurface} screen until a successful/failed attempt. For
-    previous data (grouped for login and lock screen together) see
-    &quot;Ash.Login.Lock.NbPasswordAttempts.{AuthenticationOutcome}&quot;.
+    {AuthenticationSurface} screen until the &quot;{AuthenticationOutcome}&quot;
+    outcome. For previous data (grouped for login and lock screen together) see
+    &quot;Ash.Login.Lock.NbPasswordAttempts.*&quot;.
   </summary>
   <token key="AuthenticationSurface">
     <variant name="Lock"/>
@@ -3570,6 +3570,7 @@
   </token>
   <token key="AuthenticationOutcome">
     <variant name="UntilFailure"/>
+    <variant name="UntilRecovery"/>
     <variant name="UntilSuccess"/>
   </token>
 </histogram>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index 1f290725..8771eb3 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -644,7 +644,7 @@
 
 <histogram
     name="ContentSettings.{RegularProfileFiltered}DefaultRequestDesktopSiteSetting"
-    enum="ContentSetting" expires_after="2023-02-26">
+    enum="ContentSetting" expires_after="2023-06-26">
   <owner>shuyng@google.com</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index d5bce87..8e1cb9d4 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -2689,6 +2689,17 @@
   </summary>
 </histogram>
 
+<histogram name="Network.Shill.WiFi.CiscoAdaptiveFTSupport"
+    enum="WiFiCiscoAdaptiveFTSupport" expires_after="2023-12-01">
+  <owner>matthewmwang@chromium.org</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    Chrome OS network metric sampling the number of Wireless Access Points that
+    support Cisco's Adaptive FT feature, sampled on successful connections to an
+    AP.
+  </summary>
+</histogram>
+
 <histogram name="Network.Shill.WiFi.ClientDisconnectReason"
     enum="WiFiReasonCode" expires_after="2023-06-18">
   <owner>norvez@chromium.org</owner>
@@ -3163,7 +3174,7 @@
 </histogram>
 
 <histogram name="Network.Shill.Wifi.TimeResumeToReady" units="ms"
-    expires_after="2023-02-12">
+    expires_after="2023-12-01">
   <owner>norvez@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
diff --git a/tools/polymer/PRESUBMIT.py b/tools/polymer/PRESUBMIT.py
index f158c906..d5ecd013 100644
--- a/tools/polymer/PRESUBMIT.py
+++ b/tools/polymer/PRESUBMIT.py
@@ -14,7 +14,7 @@
 def RunPolymerTests(input_api, output_api):
   presubmit_path = input_api.PresubmitLocalPath()
   sources = [
-      'polymer_test.py', 'html_to_wrapper_test.py', 'css_to_wrapper_test.py'
+      'html_to_js_test.py', 'html_to_wrapper_test.py', 'css_to_wrapper_test.py'
   ]
   tests = [input_api.os_path.join(presubmit_path, s) for s in sources]
   return input_api.canned_checks.RunUnitTests(input_api,
@@ -27,7 +27,8 @@
   results = []
   affected = input_api.AffectedFiles()
 
-  webui_sources = set(['polymer.py', 'html_to_wrapper.py', 'css_to_wrapper.py'])
+  webui_sources = set(
+      ['html_to_js.py', 'html_to_wrapper.py', 'css_to_wrapper.py'])
   affected_files = [input_api.os_path.basename(f.LocalPath()) for f in affected]
   if webui_sources.intersection(set(affected_files)):
     results += RunPolymerTests(input_api, output_api)
diff --git a/tools/polymer/html_to_js.gni b/tools/polymer/html_to_js.gni
index 7acf430..cc79ba3e2 100644
--- a/tools/polymer/html_to_js.gni
+++ b/tools/polymer/html_to_js.gni
@@ -12,10 +12,7 @@
     script = "//tools/polymer/html_to_js.py"
     forward_variables_from(invoker, [ "visibility" ])
 
-    inputs = [
-      # Declare dependencies of html_to_js.py as well.
-      "//tools/polymer/polymer.py",
-    ]
+    inputs = []
     outputs = []
 
     foreach(js_file, invoker.js_files) {
diff --git a/tools/polymer/html_to_js.py b/tools/polymer/html_to_js.py
index 40ef4d96..94a32cb 100644
--- a/tools/polymer/html_to_js.py
+++ b/tools/polymer/html_to_js.py
@@ -10,11 +10,48 @@
 import sys
 import io
 from os import path, getcwd, makedirs
-from polymer import process_v3_ready
 
 _CWD = getcwd()
 
 
+def _add_template_markers(html_template):
+  return '<!--_html_template_start_-->%s<!--_html_template_end_-->' % \
+      html_template
+
+
+def _extract_template(html_file):
+  with io.open(html_file, encoding='utf-8', mode='r') as f:
+    template = f.read()
+    return _add_template_markers('\n' + template)
+
+
+def process_v3_ready(js_file, html_file):
+  # Extract HTML template and place in JS file.
+  html_template = _extract_template(html_file)
+
+  with io.open(js_file, encoding='utf-8') as f:
+    lines = f.readlines()
+
+  HTML_TEMPLATE_REGEX = '{__html_template__}'
+  found = 0
+  for i, line in enumerate(lines):
+    if HTML_TEMPLATE_REGEX in line:
+      found += 1
+      line = line.replace(HTML_TEMPLATE_REGEX, html_template)
+      lines[i] = line
+
+  if found == 0:
+    raise AssertionError('No HTML placeholder ' + HTML_TEMPLATE_REGEX +
+                         ' found in ' + js_file)
+
+  if found > 1:
+    raise AssertionError('Multiple HTML placeholders ' + HTML_TEMPLATE_REGEX +
+                         ' found in ' + js_file)
+
+  out_filename = path.basename(js_file)
+  return lines, out_filename
+
+
 def main(argv):
   parser = argparse.ArgumentParser()
   parser.add_argument('--in_folder', required=True)
diff --git a/tools/polymer/html_to_js_test.py b/tools/polymer/html_to_js_test.py
index f27e0490..1689ea6 100755
--- a/tools/polymer/html_to_js_test.py
+++ b/tools/polymer/html_to_js_test.py
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
-# Copyright 2020 The Chromium Authors
+#!/usr/bin/env python3
+# Copyright 2023 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -9,12 +9,14 @@
 import tempfile
 import unittest
 
+
 _HERE_DIR = os.path.dirname(__file__)
 
 
 class HtmlToJsTest(unittest.TestCase):
   def setUp(self):
     self._out_folder = None
+    self.maxDiff = None
 
   def tearDown(self):
     if self._out_folder:
@@ -22,37 +24,31 @@
 
   def _read_out_file(self, file_name):
     assert self._out_folder
-    with open(os.path.join(self._out_folder, file_name), 'rb') as f:
+    with open(os.path.join(self._out_folder, file_name), 'r') as f:
       return f.read()
 
-  def _run_test(self, js_file, js_out_file, js_out_file_expected):
+  def _run_test(self, js_file, js_file_expected):
     assert not self._out_folder
     self._out_folder = tempfile.mkdtemp(dir=_HERE_DIR)
     html_to_js.main([
         '--in_folder',
-        os.path.join(_HERE_DIR, 'tests'), '--out_folder', self._out_folder,
-        '--js_files', js_file
+        os.path.join(_HERE_DIR, 'tests'),
+        '--out_folder',
+        self._out_folder,
+        '--js_files',
+        js_file,
     ])
 
-    actual_js = self._read_out_file(js_out_file)
-    with open(os.path.join(_HERE_DIR, 'tests', js_out_file_expected),
-              'rb') as f:
+    actual_js = self._read_out_file(js_file)
+    with open(os.path.join(_HERE_DIR, 'tests', js_file_expected), 'r') as f:
       expected_js = f.read()
-    self.assertEqual(expected_js, actual_js)
+    self.assertMultiLineEqual(str(expected_js), str(actual_js))
 
-  def testHtmlToJs(self):
-    self._run_test('v3_ready.js', 'v3_ready.js', 'v3_ready_expected.js')
+  def testHtmlToJs_Js(self):
+    self._run_test('html_to_js/foo.js', 'html_to_js/foo_expected.js')
 
-  def testHtmlToTs(self):
-    self._run_test('v3_ready.ts', 'v3_ready.ts', 'v3_ready_expected.ts')
-
-  def testHtmlToJsWithSubfolder(self):
-    self._run_test('subfolder/v3_ready.js', 'subfolder/v3_ready.js',
-                   'subfolder/v3_ready_expected.js')
-
-  def testHtmlToTsWithSubfolder(self):
-    self._run_test('subfolder/v3_ready.ts', 'subfolder/v3_ready.ts',
-                   'subfolder/v3_ready_expected.ts')
+  def testHtmlToJs_Ts(self):
+    self._run_test('html_to_js/foo.ts', 'html_to_js/foo_expected.ts')
 
 
 if __name__ == '__main__':
diff --git a/tools/polymer/polymer.gni b/tools/polymer/polymer.gni
deleted file mode 100644
index aea2ff326..0000000
--- a/tools/polymer/polymer.gni
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 2019 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/chromeos/ui_mode.gni")
-import("//ui/webui/resources/tools/js_modulizer.gni")
-
-assert(is_chromeos_ash)
-
-common_auto_imports = [
-  "third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/iron-a11y-announcer.html|IronA11yAnnouncer",
-  "third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-ripple-behavior.html|PaperRippleBehavior",
-  "ash/webui/common/resources/i18n_behavior.html|I18nBehavior",
-  "ash/webui/common/resources/cr_policy_pref_behavior.html|CrPolicyPrefBehavior",
-  "ash/webui/common/resources/web_ui_listener_behavior.html|WebUIListenerBehavior",
-  "ui/webui/resources/html/load_time_data.html|loadTimeData",
-  "ash/webui/common/resources/parse_html_subset.html|parseHtmlSubset",
-  "ui/webui/resources/html/polymer.html|Polymer,html",
-
-  # TODO(dpapad): Add more auto-imports here, as needed.
-]
-
-template("polymer_modulizer") {
-  action(target_name + "_module") {
-    script = "//tools/polymer/polymer.py"
-
-    inputs = [ invoker.html_file ]
-
-    if (invoker.html_type == "dom-module" || invoker.html_type == "v3-ready") {
-      inputs += [ invoker.js_file ]
-    }
-
-    output_js_file = invoker.js_file
-    if (invoker.html_type == "dom-module") {
-      output_js_file = get_path_info(invoker.js_file, "name") + ".m.js"
-    }
-    outputs = [ "$target_gen_dir/" + output_js_file ]
-
-    args = [
-      "--js_file",
-      invoker.js_file,
-      "--html_file",
-      invoker.html_file,
-      "--html_type",
-      invoker.html_type,
-      "--in_folder",
-      rebase_path(".", root_build_dir),
-      "--out_folder",
-      rebase_path(target_gen_dir, root_build_dir),
-    ]
-
-    args += [ "--namespace_rewrites" ] + common_namespace_rewrites
-    if (defined(invoker.namespace_rewrites)) {
-      args += invoker.namespace_rewrites
-    }
-
-    args += [ "--auto_imports" ] + common_auto_imports
-    if (defined(invoker.auto_imports)) {
-      args += invoker.auto_imports
-    }
-
-    if (defined(invoker.ignore_imports)) {
-      args += [ "--ignore_imports" ] + invoker.ignore_imports
-    }
-
-    if (defined(invoker.migrated_imports)) {
-      args += [ "--migrated_imports" ] + invoker.migrated_imports
-    }
-
-    if (defined(invoker.preserve_url_scheme) && invoker.preserve_url_scheme) {
-      args += [ "--preserve_url_scheme" ]
-    }
-  }
-}
diff --git a/tools/polymer/polymer.py b/tools/polymer/polymer.py
deleted file mode 100644
index b1ace8f..0000000
--- a/tools/polymer/polymer.py
+++ /dev/null
@@ -1,659 +0,0 @@
-# Copyright 2019 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Generates Polymer3 UI elements (using JS modules) from existing Polymer2
-# elements (using HTML imports). This is useful for avoiding code duplication
-# while Polymer2 to Polymer3 migration is in progress.
-#
-# Variables:
-#   html_file:
-#     The input Polymer2 HTML file to be processed.
-#
-#   js_file:
-#     The input Polymer2 JS file to be processed, or the name of the output JS
-#     file when no input JS file exists (see |html_type| below).
-#
-#   in_folder:
-#     The folder where |html_file| and |js_file| (when it exists) reside.
-#
-#   out_folder:
-#     The output folder for the generated Polymer JS file.
-#
-#   html_type:
-#     Specifies the type of the |html_file| such that the script knows how to
-#     process the |html_file|. Available values are:
-#       dom-module: A file holding a <dom-module> for a UI element (this is
-#                   the majority case). Note: having multiple <dom-module>s
-#                   within a single HTML file is not currently supported
-#       style-module: A file holding a shared style <dom-module>
-#                     (no corresponding Polymer2 JS file exists)
-#       custom-style: A file holding a <custom-style> (usually a *_vars_css.html
-#                     file, no corresponding Polymer2 JS file exists)
-#       iron-iconset: A file holding one or more <iron-iconset-svg> instances
-#                     (no corresponding Polymer2 JS file exists)
-#       v3-ready: A file holding HTML that is already written for Polymer3. A
-#                 Polymer3 JS file already exists for such cases. In this mode
-#                 HTML content is simply pasted within the JS file. This mode
-#                 will be the only supported mode after migration finishes.
-#
-#   namespace_rewrites:
-#     A list of string replacements for replacing global namespaced references
-#     with explicitly imported dependencies in the generated JS module.
-#     For example "cr.foo.Bar|Bar" will replace all occurrences of "cr.foo.Bar"
-#     with "Bar".
-#
-#   auto_imports:
-#     A list of of auto-imports, to inform the script on which variables to
-#     import from a JS module. For example "ui/webui/foo/bar/baz.html|Foo,Bar"
-#     will result in something like "import {Foo, Bar} from ...;" when
-#     encountering any dependency to that file.
-
-import argparse
-import io
-import os
-import re
-import sys
-from collections import OrderedDict
-
-_CWD = os.getcwd()
-_HERE_PATH = os.path.dirname(__file__)
-_ROOT = os.path.normpath(os.path.join(_HERE_PATH, '..', '..'))
-
-POLYMER_V1_DIR = 'third_party/polymer/v1_0/components-chromium/'
-POLYMER_V3_DIR = 'third_party/polymer/v3_0/components-chromium/'
-
-# Rewrite rules for replacing global namespace references like "cr.ui.Foo", to
-# "Foo" within a generated JS module. Populated from command line arguments.
-_namespace_rewrites = {}
-
-# Auto-imports map, populated from command line arguments. Specifies which
-# variables to import from a given dependency. For example this is used to
-# import |FocusOutlineManager| whenever a dependency to
-# ui/webui/resources/html/cr/ui/focus_outline_manager.html is encountered.
-_auto_imports = {}
-
-# Populated from command line arguments. Specifies a list of HTML imports to
-# ignore when converting HTML imports to JS modules.
-_ignore_imports = []
-
-_migrated_imports = []
-
-# Populated from command line arguments. Specifies whether "chrome://" URLs
-# should be preserved, or whether they should be converted to scheme-relative
-# URLs "//" (default behavior).
-_preserve_url_scheme = False
-
-# Use an OrderedDict, since the order these redirects are applied matters.
-_chrome_redirects = OrderedDict([
-    ('//resources/polymer/v1_0/', POLYMER_V1_DIR),
-    ('//resources/ash/common/', 'ash/webui/common/resources/'),
-    ('//resources/', 'ui/webui/resources/'),
-])
-
-_chrome_reverse_redirects = {
-    POLYMER_V3_DIR: '//resources/polymer/v3_0/',
-    'ui/webui/resources/': '//resources/',
-    'ash/webui/common/resources/': '//resources/ash/common/',
-}
-
-
-# Helper class for converting dependencies expressed in HTML imports, to JS
-# imports. |to_js_import()| is the only public method exposed by this class.
-# Internally an HTML import path is
-#
-# 1) normalized, meaning converted from a chrome or scheme-relative or relative
-#    URL to to an absolute path starting at the repo's root
-# 2) converted to an equivalent JS normalized path
-# 3) de-normalized, meaning converted back to a scheme or scheme-relative or
-#    relative URL
-# 4) converted to a JS import statement
-class Dependency:
-  def __init__(self, src, dst):
-    self.html_file = src
-    self.html_path = dst
-
-    if self.html_path.startswith('chrome://'):
-      self.input_format = 'scheme'
-      self.input_scheme = 'chrome'
-    elif self.html_path.startswith('chrome-extension://'):
-      self.input_format = 'scheme'
-      self.input_scheme = 'chrome-extension'
-    elif self.html_path.startswith('//'):
-      self.input_format = 'scheme-relative'
-    else:
-      self.input_format = 'relative'
-    self.output_format = self.input_format
-
-    self.html_path_normalized = self._to_html_normalized()
-    self.js_path_normalized = self._to_js_normalized()
-    self.js_path = self._to_js()
-
-  def _to_html_normalized(self):
-    if self.input_format == 'scheme' or self.input_format == 'scheme-relative':
-      self.html_path_normalized = self.html_path
-
-      if self.input_format == 'scheme':
-        # Strip the URL scheme.
-        colon_index = self.html_path_normalized.find(':')
-        self.html_path_normalized = self.html_path_normalized[colon_index + 1:]
-
-      for r in _chrome_redirects:
-        if self.html_path_normalized.startswith(r):
-          self.html_path_normalized = (self.html_path_normalized.replace(
-              r, _chrome_redirects[r]))
-          break
-      return self.html_path_normalized
-
-    input_dir = os.path.relpath(os.path.dirname(self.html_file), _ROOT)
-    return os.path.normpath(
-        os.path.join(input_dir, self.html_path)).replace("\\", "/")
-
-  def _to_js_normalized(self):
-    if re.match(POLYMER_V1_DIR, self.html_path_normalized):
-      return (self.html_path_normalized
-          .replace(POLYMER_V1_DIR, POLYMER_V3_DIR)
-          .replace(r'.html', '.js'))
-
-    if self.html_path_normalized == 'ui/webui/resources/html/polymer.html':
-      if self.output_format == 'relative':
-        self.output_format = 'scheme'
-        self.input_scheme = 'chrome'
-      return POLYMER_V3_DIR + 'polymer/polymer_bundled.min.js'
-
-    extension = ('.js'
-                 if self.html_path_normalized in _migrated_imports else '.m.js')
-
-    if re.match(r'ui/webui/resources/html/', self.html_path_normalized):
-      return (self.html_path_normalized
-          .replace(r'ui/webui/resources/html/', 'ui/webui/resources/js/')
-          .replace(r'.html', extension))
-
-    # TODO(crbug.com/1184053): Remove when remaining OOBE files have been
-    # checked in as Polymer3.
-    if self.html_path_normalized == 'ui/webui/resources/cr_elements/icons.html':
-      return 'ui/webui/resources/cr_elements/icons.html.js'
-
-    return self.html_path_normalized.replace(r'.html', extension)
-
-  def _to_js(self):
-    js_path = self.js_path_normalized
-
-    if self.output_format == 'scheme' or self.output_format == 'scheme-relative':
-      for r in _chrome_reverse_redirects:
-        if self.js_path_normalized.startswith(r):
-          js_path = self.js_path_normalized.replace(
-              r, _chrome_reverse_redirects[r])
-          break
-
-      # Restore the original scheme if |preserve_url_scheme| is enabled.
-      if _preserve_url_scheme and self.output_format == 'scheme':
-        js_path = self.input_scheme + ":" + js_path
-      return js_path
-
-    assert self.output_format == 'relative'
-    input_dir = os.path.relpath(os.path.dirname(self.html_file), _ROOT)
-    relpath = os.path.relpath(
-        self.js_path_normalized, input_dir).replace("\\", "/")
-    # Prepend "./" if |relpath| refers to a relative subpath, that is not "../".
-    # This prefix is required for JS Modules paths.
-    if not relpath.startswith('.'):
-      relpath = './' + relpath
-
-    return relpath
-
-  def to_js_import(self, auto_imports):
-    if self.html_path_normalized in auto_imports:
-      imports = auto_imports[self.html_path_normalized]
-      return 'import {%s} from \'%s\';' % (', '.join(imports), self.js_path)
-
-    return 'import \'%s\';' % self.js_path
-
-
-def _generate_js_imports(html_file, html_type):
-  output = []
-  imports_start_offset = -1
-  imports_end_index = -1
-  imports_found = False
-  with io.open(html_file, encoding='utf-8', mode='r') as f:
-    lines = f.readlines()
-    for i, line in enumerate(lines):
-      match = re.search(r'\s*<link rel="import" href="(.*)"', line)
-      if match:
-        if not imports_found:
-          imports_found = True
-          imports_start_offset = i
-          # Include the previous line if it is an opening <if> tag.
-          if (i > 0):
-            previous_line = lines[i - 1]
-            if re.search(r'^\s*<if', previous_line):
-              imports_start_offset -= 1
-              previous_line = '// ' + previous_line
-              output.append(previous_line.rstrip('\n'))
-
-        imports_end_index = i - imports_start_offset
-
-        # Convert HTML import URL to equivalent JS import URL.
-        dep = Dependency(html_file, match.group(1))
-
-        auto_imports = _auto_imports
-
-        # Override default polymer.html auto import for non dom-module cases.
-        if html_type == 'iron-iconset':
-          auto_imports = _auto_imports.copy()
-          auto_imports["ui/webui/resources/html/polymer.html"] = ["html"]
-        elif html_type == 'custom-style' or html_type == 'style-module':
-          auto_imports = _auto_imports.copy()
-          del auto_imports["ui/webui/resources/html/polymer.html"]
-
-        js_import = dep.to_js_import(auto_imports)
-
-        if dep.html_path_normalized in _ignore_imports:
-          output.append('// ' + js_import)
-        else:
-          output.append(js_import)
-
-      elif imports_found:
-        if re.search(r'^\s*</?if', line):
-          line = '// ' + line
-        output.append(line.rstrip('\n'))
-
-  if len(output) == 0:
-    return output
-
-  # Include the next line if it is a closing </if> tag.
-  if re.search(r'^// \s*</if>', output[imports_end_index + 1]):
-    imports_end_index += 1
-
-  return output[0:imports_end_index + 1]
-
-
-def _extract_dom_module_id(html_file):
-  with io.open(html_file, encoding='utf-8', mode='r') as f:
-    contents = f.read()
-    match = re.search(r'\s*<dom-module id="(.*)"', contents)
-    assert match
-    return match.group(1)
-
-
-def _add_template_markers(html_template):
-  return '<!--_html_template_start_-->%s<!--_html_template_end_-->' % \
-      html_template;
-
-
-def _extract_template(html_file, html_type):
-  if html_type == 'v3-ready':
-    with io.open(html_file, encoding='utf-8', mode='r') as f:
-      template = f.read()
-      return _add_template_markers('\n' + template)
-
-  if html_type == 'dom-module':
-    with io.open(html_file, encoding='utf-8', mode='r') as f:
-      lines = f.readlines()
-      start_line = -1
-      end_line = -1
-      for i, line in enumerate(lines):
-        if re.match(r'\s*<dom-module ', line):
-          assert start_line == -1
-          assert end_line == -1
-          assert re.match(r'\s*<template', lines[i + 1])
-          start_line = i + 2;
-        if re.match(r'\s*</dom-module>', line):
-          assert start_line != -1
-          assert end_line == -1
-          assert re.match(r'\s*</template>', lines[i - 2])
-          assert re.match(r'\s*<script ', lines[i - 1])
-          end_line = i - 3;
-        # Should not have an iron-iconset-svg in a dom-module file.
-        assert not re.match(r'\s*<iron-iconset-svg ', line)
-
-    # If an opening <dom-module> tag was found, check that a closing one was
-    # found as well.
-    if start_line != - 1:
-      assert end_line != -1
-
-    return _add_template_markers('\n' + ''.join(lines[start_line:end_line + 1]))
-
-  if html_type == 'style-module':
-    with io.open(html_file, encoding='utf-8', mode='r') as f:
-      lines = f.readlines()
-      start_line = -1
-      end_line = -1
-      for i, line in enumerate(lines):
-        if re.match(r'\s*<dom-module ', line):
-          assert start_line == -1
-          assert end_line == -1
-          assert re.match(r'\s*<template', lines[i + 1])
-          start_line = i + 1;
-        if re.match(r'\s*</dom-module>', line):
-          assert start_line != -1
-          assert end_line == -1
-          assert re.match(r'\s*</template>', lines[i - 1])
-          end_line = i - 1;
-    return '\n' + ''.join(lines[start_line:end_line + 1])
-
-
-  if html_type == 'iron-iconset':
-    templates = []
-    with io.open(html_file, encoding='utf-8', mode='r') as f:
-      lines = f.readlines()
-      start_line = -1
-      end_line = -1
-      for i, line in enumerate(lines):
-        if re.match(r'\s*<iron-iconset-svg ', line):
-          assert start_line == -1
-          assert end_line == -1
-          start_line = i;
-        if re.match(r'\s*</iron-iconset-svg>', line):
-          assert start_line != -1
-          assert end_line == -1
-          end_line = i
-          templates.append(''.join(lines[start_line:end_line + 1]))
-          # Reset indices.
-          start_line = -1
-          end_line = -1
-    return '\n' + ''.join(templates)
-
-
-  assert html_type == 'custom-style'
-  with io.open(html_file, encoding='utf-8', mode='r') as f:
-    lines = f.readlines()
-    start_line = -1
-    end_line = -1
-    for i, line in enumerate(lines):
-      if re.match(r'\s*<custom-style>', line):
-        assert start_line == -1
-        assert end_line == -1
-        start_line = i;
-      if re.match(r'\s*</custom-style>', line):
-        assert start_line != -1
-        assert end_line == -1
-        end_line = i;
-
-  return '\n' + ''.join(lines[start_line:end_line + 1])
-
-
-# Replace various global references with their non-namespaced version, for
-# example "cr.ui.Foo" becomes "Foo".
-def _rewrite_namespaces(string):
-  for rewrite in _namespace_rewrites:
-    string = string.replace(rewrite, _namespace_rewrites[rewrite])
-  return string
-
-
-def process_v3_ready(js_file, html_file):
-  # Extract HTML template and place in JS file.
-  html_template = _extract_template(html_file, 'v3-ready')
-
-  with io.open(js_file, encoding='utf-8') as f:
-    lines = f.readlines()
-
-  HTML_TEMPLATE_REGEX = '{__html_template__}'
-  found = 0
-  for i, line in enumerate(lines):
-    if HTML_TEMPLATE_REGEX in line:
-      found += 1
-      line = line.replace(HTML_TEMPLATE_REGEX, html_template)
-      lines[i] = line
-
-  if found == 0:
-    raise AssertionError('No HTML placeholder ' + HTML_TEMPLATE_REGEX +
-                         ' found in ' + js_file)
-
-  if found > 1:
-    raise AssertionError('Multiple HTML placeholders ' + HTML_TEMPLATE_REGEX +
-                         ' found in ' + js_file)
-
-  out_filename = os.path.basename(js_file)
-  return lines, out_filename
-
-def _process_dom_module(js_file, html_file):
-  html_template = _extract_template(html_file, 'dom-module')
-  js_imports = _generate_js_imports(html_file, 'dom-module')
-
-  # Remove IFFE opening/closing lines.
-  IIFE_OPENING = '(function() {\n'
-  IIFE_OPENING_ARROW = '(() => {\n'
-  IIFE_CLOSING = '})();'
-
-  # Remove this line.
-  CR_DEFINE_START_REGEX = r'cr.define\('
-  # Ignore all lines after this comment, including the line it appears on.
-  CR_DEFINE_END_REGEX = r'\s*// #cr_define_end'
-
-  # Replace export annotations with 'export'.
-  EXPORT_LINE_REGEX = '/* #export */'
-
-  # Ignore lines with an ignore annotation.
-  IGNORE_LINE_REGEX = '\s*/\* #ignore \*/(\S|\s)*'
-
-  # Special syntax used for files using ES class syntax. (OOBE screens)
-  JS_IMPORTS_PLACEHOLDER_REGEX = '/* #js_imports_placeholder */';
-  HTML_TEMPLATE_PLACEHOLDER_REGEX = '/* #html_template_placeholder */';
-
-  with io.open(js_file, encoding='utf-8') as f:
-    lines = f.readlines()
-
-  imports_added = False
-  html_content_added = False
-  iife_found = False
-  cr_define_found = False
-  cr_define_end_line = -1
-
-  for i, line in enumerate(lines):
-    if not imports_added:
-      if line.startswith(IIFE_OPENING) or line.startswith(IIFE_OPENING_ARROW):
-        assert not cr_define_found, 'cr.define() and IFFE in the same file'
-        # Replace the IIFE opening line with the JS imports.
-        line = '\n'.join(js_imports) + '\n\n'
-        imports_added = True
-        iife_found = True
-      elif re.match(CR_DEFINE_START_REGEX, line):
-        assert not cr_define_found, 'Multiple cr.define()s are not supported'
-        assert not iife_found, 'cr.define() and IFFE in the same file'
-        line = '\n'.join(js_imports) + '\n\n'
-        cr_define_found = True
-        imports_added = True
-      elif JS_IMPORTS_PLACEHOLDER_REGEX in line:
-        line = line.replace(JS_IMPORTS_PLACEHOLDER_REGEX,
-                            '\n'.join(js_imports) + '\n')
-        imports_added = True
-      elif 'Polymer({\n' in line:
-        # Place the JS imports right before the opening "Polymer({" line.
-        line = '\n'.join(js_imports) + '\n\n' + line
-        imports_added = True
-
-    # Place the HTML content right after the opening "Polymer({" line if using
-    # the Polymer() factory method, or replace HTML_TEMPLATE_PLACEHOLDER_REGEX
-    # with the HTML content if the files is using ES6 class syntax.
-    # Note: There is currently an assumption that only one Polymer() declaration,
-    # or one class declaration exists per file.
-    error_message = """Multiple Polymer() declarations found, or mixed ES6 class
-                       syntax with Polymer() declarations in the same file"""
-    if 'Polymer({' in line:
-      assert not html_content_added, error_message
-      line = line.replace(
-          r'Polymer({',
-          'Polymer({\n  _template: html`%s`,' % html_template)
-      html_content_added = True
-    elif HTML_TEMPLATE_PLACEHOLDER_REGEX in line:
-      assert not html_content_added, error_message
-      line = line.replace(HTML_TEMPLATE_PLACEHOLDER_REGEX,
-        'static get template() {\n    return html`%s`;\n  }' % html_template)
-      html_content_added = True
-
-    line = line.replace(EXPORT_LINE_REGEX, 'export')
-
-    if re.match(CR_DEFINE_END_REGEX, line):
-      assert cr_define_found, 'Found cr_define_end without cr.define()'
-      cr_define_end_line = i
-      break
-
-    if re.match(IGNORE_LINE_REGEX, line):
-      line = ''
-
-    line = _rewrite_namespaces(line)
-    lines[i] = line
-
-  if cr_define_found:
-    assert cr_define_end_line != -1, 'No cr_define_end found'
-    lines = lines[0:cr_define_end_line]
-
-  if iife_found:
-    last_line = lines[-1]
-    assert last_line.startswith(IIFE_CLOSING), 'Could not detect IIFE closing'
-    lines[-1] = ''
-
-  # Use .m.js extension for the generated JS file, since both files need to be
-  # served by a chrome:// URL side-by-side.
-  out_filename = os.path.basename(js_file).replace('.js', '.m.js')
-  return lines, out_filename
-
-def _process_style_module(js_file, html_file):
-  html_template = _extract_template(html_file, 'style-module')
-  js_imports = _generate_js_imports(html_file, 'style-module')
-
-  style_id = _extract_dom_module_id(html_file)
-
-  # Add |assetpath| attribute so that relative CSS url()s are resolved
-  # correctly. Without this they are resolved with respect to the main HTML
-  # documents location (unlike Polymer2). Note: This is assuming that only style
-  # modules under ui/webui/resources/ are processed by polymer_modulizer(), for
-  # example cr_icons.css.html.
-  js_template = \
-"""%(js_imports)s
-const template = document.createElement('template');
-template.innerHTML = `
-<dom-module id="%(style_id)s" assetpath="chrome://resources/">%(html_template)s</dom-module>
-`;
-document.body.appendChild(template.content.cloneNode(true));""" % {
-      'html_template': html_template,
-      'js_imports': '\n'.join(js_imports),
-      'style_id': style_id,
-  }
-
-  out_filename = os.path.basename(js_file)
-  return js_template, out_filename
-
-
-def _process_custom_style(js_file, html_file):
-  html_template = _extract_template(html_file, 'custom-style')
-  js_imports = _generate_js_imports(html_file, 'custom-style')
-
-  js_template = \
-"""%(js_imports)s
-const $_documentContainer = document.createElement('template');
-$_documentContainer.innerHTML = `%(html_template)s`;
-document.head.appendChild($_documentContainer.content);""" % {
-      'js_imports': '\n'.join(js_imports),
-      'html_template': html_template,
-  }
-
-  out_filename = os.path.basename(js_file)
-  return js_template, out_filename
-
-def _process_iron_iconset(js_file, html_file):
-  html_template = _extract_template(html_file, 'iron-iconset')
-  js_imports = _generate_js_imports(html_file, 'iron-iconset')
-
-  js_template = \
-"""%(js_imports)s
-const template = html`%(html_template)s`;
-document.head.appendChild(template.content);
-""" % {
-      'js_imports': '\n'.join(js_imports),
-      'html_template': html_template,
-  }
-
-  out_filename = os.path.basename(js_file)
-  return js_template, out_filename
-
-def _resetGlobals():
-  global _namespace_rewrites
-  _namespace_rewrites = {}
-  global _auto_imports
-  _auto_imports = {}
-  global _ignore_imports
-  _ignore_imports = []
-  global _migrated_imports
-  _migrated_imports = []
-
-def main(argv):
-  parser = argparse.ArgumentParser()
-  parser.add_argument('--in_folder', required=True)
-  parser.add_argument('--out_folder', required=True)
-  parser.add_argument('--js_file', required=True)
-  parser.add_argument('--html_file', required=True)
-  parser.add_argument('--namespace_rewrites', required=False, nargs="*")
-  parser.add_argument('--ignore_imports', required=False, nargs="*")
-  parser.add_argument('--auto_imports', required=False, nargs="*")
-  parser.add_argument('--migrated_imports', required=False, nargs="*")
-  parser.add_argument('--preserve_url_scheme', action="store_true")
-  parser.add_argument(
-      '--html_type', choices=['dom-module', 'style-module', 'custom-style',
-      'iron-iconset', 'v3-ready'],
-      required=True)
-  args = parser.parse_args(argv)
-
-  # Extract namespace rewrites from arguments.
-  if args.namespace_rewrites:
-    for r in args.namespace_rewrites:
-      before, after = r.split('|')
-      _namespace_rewrites[before] = after
-
-  # Extract automatic imports from arguments.
-  if args.auto_imports:
-    global _auto_imports
-    for entry in args.auto_imports:
-      path, imports = entry.split('|')
-      _auto_imports[path] = imports.split(',')
-
-  # Extract ignored imports from arguments.
-  if args.ignore_imports:
-    assert args.html_type != 'v3-ready'
-    global _ignore_imports
-    _ignore_imports = args.ignore_imports
-
-  # Extract migrated imports from arguments.
-  if args.migrated_imports:
-    assert args.html_type != 'v3-ready'
-    global _migrated_imports
-    _migrated_imports = args.migrated_imports
-
-  # Extract |preserve_url_scheme| from arguments.
-  global _preserve_url_scheme
-  _preserve_url_scheme = args.preserve_url_scheme
-
-  in_folder = os.path.normpath(os.path.join(_CWD, args.in_folder))
-  out_folder = os.path.normpath(os.path.join(_CWD, args.out_folder))
-
-  js_file = os.path.join(in_folder, args.js_file)
-  html_file = os.path.join(in_folder, args.html_file)
-
-  result = ()
-  if args.html_type == 'dom-module':
-    result = _process_dom_module(js_file, html_file)
-  if args.html_type == 'style-module':
-    result = _process_style_module(js_file, html_file)
-  elif args.html_type == 'custom-style':
-    result = _process_custom_style(js_file, html_file)
-  elif args.html_type == 'iron-iconset':
-    result = _process_iron_iconset(js_file, html_file)
-  elif args.html_type == 'v3-ready':
-    result = process_v3_ready(js_file, html_file)
-
-  # Reconstruct file.
-  # Specify the newline character so that the exact same file is generated
-  # across platforms.
-  with io.open(os.path.join(out_folder, result[1]), mode='wb') as f:
-    for l in result[0]:
-      f.write(l.encode('utf-8'))
-
-  # Reset global variables so that main() can be invoked multiple times during
-  # testing without leaking state from one test to the next.
-  _resetGlobals()
-  return
-
-
-if __name__ == '__main__':
-  main(sys.argv[1:])
diff --git a/tools/polymer/polymer_test.py b/tools/polymer/polymer_test.py
deleted file mode 100755
index 546bfa50..0000000
--- a/tools/polymer/polymer_test.py
+++ /dev/null
@@ -1,278 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2019 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import polymer
-import os
-import shutil
-import tempfile
-import unittest
-
-
-_HERE_DIR = os.path.dirname(__file__)
-
-
-class PolymerModulizerTest(unittest.TestCase):
-  def setUp(self):
-    self._out_folder = None
-    self._additional_flags = []
-
-  def tearDown(self):
-    if self._out_folder:
-      shutil.rmtree(self._out_folder)
-
-  def _read_out_file(self, file_name):
-    assert self._out_folder
-    return open(os.path.join(self._out_folder, file_name), 'rb').read()
-
-  def _run_test(self, html_type, html_file, js_file,
-      js_out_file, js_file_expected):
-    assert not self._out_folder
-    self._out_folder = tempfile.mkdtemp(dir=_HERE_DIR)
-    polymer.main([
-      '--in_folder', os.path.join(_HERE_DIR, 'tests'),
-      '--out_folder', self._out_folder,
-      '--js_file',  js_file,
-      '--html_file',  html_file,
-      '--html_type',  html_type,
-      '--namespace_rewrites',
-      'Polymer.PaperRippleBehavior|PaperRippleBehavior',
-      '--auto_imports',
-      'ui/webui/resources/html/polymer.html|Polymer,html',
-      'third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-ripple-behavior.html|PaperRippleBehavior',
-    ] + self._additional_flags)
-
-    actual_js = self._read_out_file(js_out_file)
-    expected_js = open(os.path.join(
-        _HERE_DIR, 'tests', js_file_expected), 'rb').read()
-    self.assertEqual(expected_js.split(b'\n'), actual_js.split(b'\n'))
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module>.
-  def testDomModule(self):
-    self._run_test(
-        'dom-module', 'dom_module.html', 'dom_module.js',
-        'dom_module.m.js', 'dom_module_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module> that is
-  # using ES6 class syntax.
-  def testDomModuleWithClassSyntax(self):
-    self._run_test(
-        'dom-module', 'dom_module.html', 'dom_module_with_class_syntax.js',
-        'dom_module_with_class_syntax.m.js', 'dom_module_with_class_syntax_expected.js')
-
-  # Test case where a commented out HTML import exists in the original HTML
-  # file. It is purposefully picked up and converted to a JS module, to address
-  # a unique use case of the FilesApp where an HTML import does not actually
-  # exist in the Polymer2 code.
-  # TODO(crbug.com/1133186): Remove after FilesApp Polymer3 migration is
-  # completed.
-  def testDomModuleWithCommentedOutImport(self):
-    self._run_test('dom-module', 'dom_module_with_commented_out_import.html',
-                   'dom_module.js', 'dom_module.m.js',
-                   'dom_module_with_commented_out_import_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module> that is
-  # wrapped in an IIFE function.
-  def testDomModuleIife(self):
-    self._run_test(
-        'dom-module', 'dom_module.html', 'dom_module_iife.js',
-        'dom_module_iife.m.js', 'dom_module_iife_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module> that is
-  # wrapped in an arrow IIFE function.
-  def testDomModuleIifeArrow(self):
-    self._run_test(
-        'dom-module', 'dom_module.html', 'dom_module_iife_arrow.js',
-        'dom_module_iife_arrow.m.js', 'dom_module_iife_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module> that is
-  # assigned to a variable.
-  def testDomModuleIifeAndAssigned(self):
-    self._run_test(
-        'dom-module', 'dom_module.html', 'dom_module_with_assignment.js',
-        'dom_module_with_assignment.m.js',
-        'dom_module_with_assignment_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module> that also
-  # has a 'cr.define()' in its JS file.
-  def testDomModuleWithDefine(self):
-    self._run_test(
-        'dom-module', 'dom_module.html', 'dom_module_with_define.js',
-        'dom_module_with_define.m.js', 'dom_module_with_define_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module> that has
-  # ignore annotations.
-  def testDomModuleWithIgnore(self):
-    self._run_test('dom-module', 'dom_module.html', 'dom_module_with_ignore.js',
-                   'dom_module_with_ignore.m.js',
-                   'dom_module_with_ignore_expected.js')
-
-  # Test case where some HTML imports should be ignored.
-  def testDomModuleWithIgnoreImports(self):
-    self._additional_flags = [
-      '--ignore_imports',
-      'ui/webui/resources/html/ignore_me.html',
-    ]
-    self._run_test('dom-module', 'dom_module.html', 'dom_module.js',
-                   'dom_module.m.js',
-                   'dom_module_with_ignore_imports_expected.js')
-
-  # Test case where some HTML imports have already been fully migrated to
-  # Polymer3.
-  def testDomModuleWithMigratedImports(self):
-    self._additional_flags = [
-      '--migrated_imports',
-      'tools/polymer/tests/foo.html',
-      'ui/webui/resources/html/ignore_me.html',
-    ]
-    self._run_test('dom-module', 'dom_module.html', 'dom_module.js',
-                   'dom_module.m.js',
-                   'dom_module_with_migrated_imports_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 <dom-module> that also
-  # uses <if expr> for imports.
-  def testDomModuleWithConditionalImport(self):
-    self._run_test('dom-module', 'dom_module_with_if_expr.html',
-                   'dom_module.js', 'dom_module.m.js',
-                   'dom_module_with_if_expr_expected.js')
-
-  # Test case where HTML has some comment before the first <link rel="import"> \
-  # and also uses <if expr> for imports.
-  def testDomModuleImportsWithCopyrightPrefix(self):
-    self._run_test('dom-module', 'dom_module_with_copyright.html',
-                   'dom_module.js', 'dom_module.m.js',
-                   'dom_module_with_if_expr_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 style module.
-  def testStyleModule(self):
-    self._run_test(
-        'style-module', 'style_module.html', 'style_module.m.js',
-        'style_module.m.js', 'style_module_expected.js')
-    return
-
-  # Test case where HTML is extracted from a Polymer2 <custom-style>.
-  def testCustomStyle(self):
-    self._run_test(
-        'custom-style', 'custom_style.html', 'custom_style.m.js',
-        'custom_style.m.js', 'custom_style_expected.js')
-
-  # Test case where HTML is extracted from a Polymer2 iron-iconset-svg file.
-  def testIronIconset(self):
-    self._run_test(
-        'iron-iconset', 'iron_iconset.html', 'iron_iconset.m.js',
-        'iron_iconset.m.js', 'iron_iconset_expected.js')
-
-  # Test case where the provided HTML is already in the form needed by Polymer3.
-  def testV3Ready(self):
-    self._run_test(
-        'v3-ready', 'v3_ready.html', 'v3_ready.js',
-        'v3_ready.js', 'v3_ready_expected.js')
-
-
-  # Test the |Dependency| class directly, which is responsible for converting
-  # HTML imports to JS imports.
-  def testImportsHtmlToJs(self):
-    _HERE = os.path.abspath(os.path.dirname(__file__))
-    _ROOT = os.path.normpath(os.path.join(_HERE, '..', '..'))
-
-    src = os.path.join(_ROOT, 'ui/webui/resources/foo/bar/baz.html')
-
-    auto_imports = {
-      'ui/webui/resources/html/polymer.html': ['Polymer', 'html'],
-      'ui/webui/resources/html/foo.html': ['Foo'],
-    }
-
-    def assert_html_to_js(html, expected_js):
-      actual_js = polymer.Dependency(src, html).to_js_import(auto_imports)
-      self.assertEqual(expected_js, actual_js)
-
-    cases = [
-        # Relative paths cases.
-        # Case where relative path to polymer.html is used.
-        [
-            '../../html/polymer.html',
-            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
-            'import {Polymer, html} from \'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
-        ],
-        # Case where relative path to file in the same folder is used.
-        [
-            'foo.html',
-            'import \'./foo.m.js\';',
-            'import \'./foo.m.js\';',
-        ],
-        # Case where relative path to file in the same subtree is used.
-        [
-            'path/to/subfolder/foo.html',
-            'import \'./path/to/subfolder/foo.m.js\';',
-            'import \'./path/to/subfolder/foo.m.js\';',
-        ],
-        # Case where relative path to file in ui/webui/resources/html/ is used.
-        [
-            '../../html/foo.html',
-            'import {Foo} from \'../../js/foo.m.js\';',
-            'import {Foo} from \'../../js/foo.m.js\';',
-        ],
-
-        # chrome:// paths cases.
-        # Case where absolute path to a Polymer UI element is used.
-        [
-            'chrome://resources/polymer/v1_0/path/to/folder/foo.html',
-            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';',
-            'import \'chrome://resources/polymer/v3_0/path/to/folder/foo.js\';',
-        ],
-        # Case where chrome:// path to polymer.html is used.
-        [
-            'chrome://resources/html/polymer.html',
-            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
-            'import {Polymer, html} from \'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
-        ],
-        # Case where chrome://resources/html/ path to something other than
-        # polymer.html is used.
-        [
-            'chrome://resources/html/bar.html',
-            'import \'//resources/js/bar.m.js\';',
-            'import \'chrome://resources/js/bar.m.js\';',
-        ],
-
-        # chrome-extension:// paths cases.
-        [
-            'chrome-extension://path/to/folder/foo.html',
-            'import \'//path/to/folder/foo.m.js\';',
-            'import \'chrome-extension://path/to/folder/foo.m.js\';',
-        ],
-
-        # Scheme-relative paths cases.
-        # Case where absolute path to a Polymer UI element is used.
-        [
-            '//resources/polymer/v1_0/path/to/folder/foo.html',
-            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';',
-            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';',
-        ],
-        # Case where path to polymer.html is used.
-        [
-            '//resources/html/polymer.html',
-            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
-            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
-        ],
-        # Case where //resources/html/ path to something other than
-        # polymer.html is used.
-        [
-            '//resources/html/bar.html',
-            'import \'//resources/js/bar.m.js\';',
-            'import \'//resources/js/bar.m.js\';',
-        ],
-    ]
-
-    for [html, js_expected1, js_expected2] in cases:
-      # Test case where |preserve_url_scheme| is False
-      polymer._preserve_url_scheme = False
-      assert_html_to_js(html, js_expected1)
-
-      # Test case where |preserve_url_scheme| is True
-      polymer._preserve_url_scheme = True
-      assert_html_to_js(html, js_expected2)
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/tools/polymer/tests/custom_style.html b/tools/polymer/tests/custom_style.html
deleted file mode 100644
index d1093bae..0000000
--- a/tools/polymer/tests/custom_style.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<link rel="import" href="../../../ui/webui/resources/html/polymer.html">
-
-<link rel="import" href="foo.html">
-
-<custom-style>
-  <style>
-    html {
-      --foo-bar: 2rem;
-    }
-  </style>
-</custom-style>
diff --git a/tools/polymer/tests/custom_style_expected.js b/tools/polymer/tests/custom_style_expected.js
deleted file mode 100644
index 5de0d6fb..0000000
--- a/tools/polymer/tests/custom_style_expected.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import './foo.m.js';
-const $_documentContainer = document.createElement('template');
-$_documentContainer.innerHTML = `
-<custom-style>
-  <style>
-    html {
-      --foo-bar: 2rem;
-    }
-  </style>
-</custom-style>
-`;
-document.head.appendChild($_documentContainer.content);
\ No newline at end of file
diff --git a/tools/polymer/tests/dom_module.html b/tools/polymer/tests/dom_module.html
deleted file mode 100644
index 4242cca..0000000
--- a/tools/polymer/tests/dom_module.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<link rel="import" href="../../../ui/webui/resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
-<link rel="import" href="chrome://resources/html/ignore_me.html">
-<link rel="import" href="../shared_vars_css.html">
-<link rel="import" href="foo.html">
-
-<dom-module id="cr-test-foo">
-  <template>
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-  </template>
-  <script src="dom_module.js"></script>
-</dom-module>
diff --git a/tools/polymer/tests/dom_module.js b/tools/polymer/tests/dom_module.js
deleted file mode 100644
index 782b0d5..0000000
--- a/tools/polymer/tests/dom_module.js
+++ /dev/null
@@ -1,4 +0,0 @@
-Polymer({
-  is: 'cr-test-foo',
-  behaviors: [Polymer.PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_expected.js b/tools/polymer/tests/dom_module_expected.js
deleted file mode 100644
index 32781d3d..0000000
--- a/tools/polymer/tests/dom_module_expected.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-
-Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_iife.js b/tools/polymer/tests/dom_module_iife.js
deleted file mode 100644
index 34375f1..0000000
--- a/tools/polymer/tests/dom_module_iife.js
+++ /dev/null
@@ -1,8 +0,0 @@
-(function() {
-const foo = 'foo';
-
-Polymer({
-  is: 'cr-test-foo',
-  behaviors: [Polymer.PaperRippleBehavior],
-});
-})();
diff --git a/tools/polymer/tests/dom_module_iife_arrow.js b/tools/polymer/tests/dom_module_iife_arrow.js
deleted file mode 100644
index 6c6f901..0000000
--- a/tools/polymer/tests/dom_module_iife_arrow.js
+++ /dev/null
@@ -1,8 +0,0 @@
-(() => {
-const foo = 'foo';
-
-Polymer({
-  is: 'cr-test-foo',
-  behaviors: [Polymer.PaperRippleBehavior],
-});
-})();
diff --git a/tools/polymer/tests/dom_module_iife_expected.js b/tools/polymer/tests/dom_module_iife_expected.js
deleted file mode 100644
index 8acfa744..0000000
--- a/tools/polymer/tests/dom_module_iife_expected.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-
-const foo = 'foo';
-
-Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_with_assignment.js b/tools/polymer/tests/dom_module_with_assignment.js
deleted file mode 100644
index a05cf3c..0000000
--- a/tools/polymer/tests/dom_module_with_assignment.js
+++ /dev/null
@@ -1,6 +0,0 @@
-const foo = 'foo';
-
-const CrTestFoo = Polymer({
-  is: 'cr-test-foo',
-  behaviors: [Polymer.PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_with_assignment_expected.js b/tools/polymer/tests/dom_module_with_assignment_expected.js
deleted file mode 100644
index c892147c..0000000
--- a/tools/polymer/tests/dom_module_with_assignment_expected.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const foo = 'foo';
-
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-
-const CrTestFoo = Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_with_class_syntax.js b/tools/polymer/tests/dom_module_with_class_syntax.js
deleted file mode 100644
index f9959ad..0000000
--- a/tools/polymer/tests/dom_module_with_class_syntax.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/* #js_imports_placeholder */
-
-class CrTestFoo extends PolymerElement {
-  static get is() { return 'cr-test-foo'; }
-
-  /* #html_template_placeholder */
-
-}
\ No newline at end of file
diff --git a/tools/polymer/tests/dom_module_with_class_syntax_expected.js b/tools/polymer/tests/dom_module_with_class_syntax_expected.js
deleted file mode 100644
index 6e14a8ca..0000000
--- a/tools/polymer/tests/dom_module_with_class_syntax_expected.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-
-
-class CrTestFoo extends PolymerElement {
-  static get is() { return 'cr-test-foo'; }
-
-  static get template() {
-    return html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`;
-  }
-
-}
\ No newline at end of file
diff --git a/tools/polymer/tests/dom_module_with_commented_out_import.html b/tools/polymer/tests/dom_module_with_commented_out_import.html
deleted file mode 100644
index 5989e5b..0000000
--- a/tools/polymer/tests/dom_module_with_commented_out_import.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<link rel="import" href="../../../ui/webui/resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
-<link rel="import" href="chrome://resources/html/ignore_me.html">
-<link rel="import" href="../shared_vars_css.html">
-<link rel="import" href="foo.html">
-<!-- <link rel="import" href="bar.html"> -->
-
-<dom-module id="cr-test-foo">
-  <template>
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-  </template>
-  <script src="dom_module.js"></script>
-</dom-module>
diff --git a/tools/polymer/tests/dom_module_with_commented_out_import_expected.js b/tools/polymer/tests/dom_module_with_commented_out_import_expected.js
deleted file mode 100644
index f25489e1..0000000
--- a/tools/polymer/tests/dom_module_with_commented_out_import_expected.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-import './bar.m.js';
-
-Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_with_copyright.html b/tools/polymer/tests/dom_module_with_copyright.html
deleted file mode 100644
index ddd7328..0000000
--- a/tools/polymer/tests/dom_module_with_copyright.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- Copyright 2020 The Chromium Authors
-  -- Use of this source code is governed by a BSD-style license that can be
-  -- found in the LICENSE file.
--->
-
-<if expr="chromeos_ash">
-<link rel="import" href="../shared_vars_chromeos_css.html">
-</if>
-<link rel="import" href="../../../ui/webui/resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
-<link rel="import" href="../shared_vars_css.html">
-<link rel="import" href="foo.html">
-<if expr="chromeos_ash">
-<link rel="import" href="bar.html">
-</if>
-
-<dom-module id="cr-test-foo">
-  <template>
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-  </template>
-  <script src="dom_module.js"></script>
-</dom-module>
diff --git a/tools/polymer/tests/dom_module_with_define.js b/tools/polymer/tests/dom_module_with_define.js
deleted file mode 100644
index 8e2cfe0e..0000000
--- a/tools/polymer/tests/dom_module_with_define.js
+++ /dev/null
@@ -1,32 +0,0 @@
-cr.define('cr.testFoo', () => {
-  let instance_ = null;
-
-  let bar_ = 1;
-
-  /* #export */ const someExport = true;
-
-  /* #export */ function getInstance() {
-    return assert(instance_);
-  }
-
-  function getBarInternal_() {
-    return bar_;
-  }
-
-  /* #export */ function getBar(isTest) {
-    return isTest ? 0 : getBarInternal_();
-  }
-
-  /* #export */ let CrTestFooElement = Polymer({
-    is: 'cr-test-foo',
-    behaviors: [Polymer.PaperRippleBehavior],
-  });
-
-  // #cr_define_end
-  return {
-    CrTestFooElement: CrTestFooElement,
-    someExport: someExport,
-    getInstance: getInstance,
-    getBar: getBar,
-  };
-});
diff --git a/tools/polymer/tests/dom_module_with_define_expected.js b/tools/polymer/tests/dom_module_with_define_expected.js
deleted file mode 100644
index caff6e7..0000000
--- a/tools/polymer/tests/dom_module_with_define_expected.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-
-  let instance_ = null;
-
-  let bar_ = 1;
-
-  export const someExport = true;
-
-  export function getInstance() {
-    return assert(instance_);
-  }
-
-  function getBarInternal_() {
-    return bar_;
-  }
-
-  export function getBar(isTest) {
-    return isTest ? 0 : getBarInternal_();
-  }
-
-  export let CrTestFooElement = Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-    is: 'cr-test-foo',
-    behaviors: [PaperRippleBehavior],
-  });
-
diff --git a/tools/polymer/tests/dom_module_with_if_expr.html b/tools/polymer/tests/dom_module_with_if_expr.html
deleted file mode 100644
index c415d0b..0000000
--- a/tools/polymer/tests/dom_module_with_if_expr.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<if expr="chromeos_ash">
-<link rel="import" href="../shared_vars_chromeos_css.html">
-</if>
-<link rel="import" href="../../../ui/webui/resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
-<link rel="import" href="../shared_vars_css.html">
-<link rel="import" href="foo.html">
-<if expr="chromeos_ash">
-<link rel="import" href="bar.html">
-</if>
-
-<dom-module id="cr-test-foo">
-  <template>
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-  </template>
-  <script src="dom_module.js"></script>
-</dom-module>
diff --git a/tools/polymer/tests/dom_module_with_if_expr_expected.js b/tools/polymer/tests/dom_module_with_if_expr_expected.js
deleted file mode 100644
index 8a51b42..0000000
--- a/tools/polymer/tests/dom_module_with_if_expr_expected.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// <if expr="chromeos_ash">
-import '../shared_vars_chromeos_css.m.js';
-// </if>
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-// <if expr="chromeos_ash">
-import './bar.m.js';
-// </if>
-
-Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_with_ignore.js b/tools/polymer/tests/dom_module_with_ignore.js
deleted file mode 100644
index e59c8d2..0000000
--- a/tools/polymer/tests/dom_module_with_ignore.js
+++ /dev/null
@@ -1,8 +0,0 @@
-Polymer({
-  is: 'cr-test-foo',
-  behaviors: [Polymer.PaperRippleBehavior],
-  /** @override */
-  ready() {
-    /* #ignore */ this.importHref('./foo.html');
-  },
-});
diff --git a/tools/polymer/tests/dom_module_with_ignore_expected.js b/tools/polymer/tests/dom_module_with_ignore_expected.js
deleted file mode 100644
index b82ead94..0000000
--- a/tools/polymer/tests/dom_module_with_ignore_expected.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-
-Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-  /** @override */
-  ready() {
-  },
-});
diff --git a/tools/polymer/tests/dom_module_with_ignore_imports_expected.js b/tools/polymer/tests/dom_module_with_ignore_imports_expected.js
deleted file mode 100644
index 0876b6b5..0000000
--- a/tools/polymer/tests/dom_module_with_ignore_imports_expected.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-// import '//resources/js/ignore_me.m.js';
-import '../shared_vars_css.m.js';
-import './foo.m.js';
-
-Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/dom_module_with_migrated_imports_expected.js b/tools/polymer/tests/dom_module_with_migrated_imports_expected.js
deleted file mode 100644
index 580e391..0000000
--- a/tools/polymer/tests/dom_module_with_migrated_imports_expected.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import '//resources/js/ignore_me.js';
-import '../shared_vars_css.m.js';
-import './foo.js';
-
-Polymer({
-  _template: html`<!--_html_template_start_-->
-    <style>
-      div {
-        font-size: 2rem;
-      }
-    </style>
-    <div>Hello world</div>
-<!--_html_template_end_-->`,
-  is: 'cr-test-foo',
-  behaviors: [PaperRippleBehavior],
-});
diff --git a/tools/polymer/tests/v3_ready.html b/tools/polymer/tests/html_to_js/foo.html
similarity index 100%
rename from tools/polymer/tests/v3_ready.html
rename to tools/polymer/tests/html_to_js/foo.html
diff --git a/tools/polymer/tests/html_to_js/foo.js b/tools/polymer/tests/html_to_js/foo.js
new file mode 100644
index 0000000..95df368
--- /dev/null
+++ b/tools/polymer/tests/html_to_js/foo.js
@@ -0,0 +1,11 @@
+// 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.
+
+Polymer({
+  is: 'cr-foo',
+
+  _template: html`
+{__html_template__}
+  `,
+});
diff --git a/tools/polymer/tests/html_to_js/foo.ts b/tools/polymer/tests/html_to_js/foo.ts
new file mode 100644
index 0000000..95df368
--- /dev/null
+++ b/tools/polymer/tests/html_to_js/foo.ts
@@ -0,0 +1,11 @@
+// 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.
+
+Polymer({
+  is: 'cr-foo',
+
+  _template: html`
+{__html_template__}
+  `,
+});
diff --git a/tools/polymer/tests/html_to_js/foo_expected.js b/tools/polymer/tests/html_to_js/foo_expected.js
new file mode 100644
index 0000000..76e2d3f
--- /dev/null
+++ b/tools/polymer/tests/html_to_js/foo_expected.js
@@ -0,0 +1,18 @@
+// 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.
+
+Polymer({
+  is: 'cr-foo',
+
+  _template: html`
+<!--_html_template_start_-->
+<style>
+  div {
+    font-size: 2rem;
+  }
+</style>
+<div>Hello world</div>
+<!--_html_template_end_-->
+  `,
+});
diff --git a/tools/polymer/tests/html_to_js/foo_expected.ts b/tools/polymer/tests/html_to_js/foo_expected.ts
new file mode 100644
index 0000000..76e2d3f
--- /dev/null
+++ b/tools/polymer/tests/html_to_js/foo_expected.ts
@@ -0,0 +1,18 @@
+// 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.
+
+Polymer({
+  is: 'cr-foo',
+
+  _template: html`
+<!--_html_template_start_-->
+<style>
+  div {
+    font-size: 2rem;
+  }
+</style>
+<div>Hello world</div>
+<!--_html_template_end_-->
+  `,
+});
diff --git a/tools/polymer/tests/iron_iconset.html b/tools/polymer/tests/iron_iconset.html
deleted file mode 100644
index 70ca3e9..0000000
--- a/tools/polymer/tests/iron_iconset.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<link rel="import" href="../../../ui/webui/resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
-
-<iron-iconset-svg name="cr_foo_20" size="20">
-  <svg>
-    <defs>
-      <g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></g>
-    </defs>
-  </svg>
-</iron-iconset-svg>
-<iron-iconset-svg name="cr_foo_24" size="24">
-  <svg>
-    <defs>
-      <g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></g>
-    </defs>
-  </svg>
-</iron-iconset-svg>
diff --git a/tools/polymer/tests/iron_iconset_expected.js b/tools/polymer/tests/iron_iconset_expected.js
deleted file mode 100644
index a88bbebe..0000000
--- a/tools/polymer/tests/iron_iconset_expected.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import {html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import '//resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
-const template = html`
-<iron-iconset-svg name="cr_foo_20" size="20">
-  <svg>
-    <defs>
-      <g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></g>
-    </defs>
-  </svg>
-</iron-iconset-svg>
-<iron-iconset-svg name="cr_foo_24" size="24">
-  <svg>
-    <defs>
-      <g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></g>
-    </defs>
-  </svg>
-</iron-iconset-svg>
-`;
-document.head.appendChild(template.content);
diff --git a/tools/polymer/tests/style_module.html b/tools/polymer/tests/style_module.html
deleted file mode 100644
index 37d2dbe6..0000000
--- a/tools/polymer/tests/style_module.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<link rel="import" href="../../../ui/webui/resources/html/polymer.html">
-
-<link rel="import" href="some_other_style.html">
-
-<dom-module id="cr-foo-style">
-  <template>
-    <style include="some-other-style">
-      :host {
-        margin: 0;
-      }
-    </style>
-  </template>
-</dom-module>
diff --git a/tools/polymer/tests/style_module_expected.js b/tools/polymer/tests/style_module_expected.js
deleted file mode 100644
index b4fbee9..0000000
--- a/tools/polymer/tests/style_module_expected.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import './some_other_style.m.js';
-const template = document.createElement('template');
-template.innerHTML = `
-<dom-module id="cr-foo-style" assetpath="chrome://resources/">
-  <template>
-    <style include="some-other-style">
-      :host {
-        margin: 0;
-      }
-    </style>
-  </template>
-</dom-module>
-`;
-document.body.appendChild(template.content.cloneNode(true));
\ No newline at end of file
diff --git a/tools/polymer/tests/v3_ready.js b/tools/polymer/tests/v3_ready.js
deleted file mode 100644
index b5eea54..0000000
--- a/tools/polymer/tests/v3_ready.js
+++ /dev/null
@@ -1,7 +0,0 @@
-Polymer({
-  is: 'cr-foo',
-
-  _template: html`
-{__html_template__}
-  `,
-});
diff --git a/tools/polymer/tests/v3_ready.ts b/tools/polymer/tests/v3_ready.ts
deleted file mode 100644
index b5eea54..0000000
--- a/tools/polymer/tests/v3_ready.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-Polymer({
-  is: 'cr-foo',
-
-  _template: html`
-{__html_template__}
-  `,
-});
diff --git a/tools/polymer/tests/v3_ready_expected.js b/tools/polymer/tests/v3_ready_expected.js
deleted file mode 100644
index 8d0685e..0000000
--- a/tools/polymer/tests/v3_ready_expected.js
+++ /dev/null
@@ -1,14 +0,0 @@
-Polymer({
-  is: 'cr-foo',
-
-  _template: html`
-<!--_html_template_start_-->
-<style>
-  div {
-    font-size: 2rem;
-  }
-</style>
-<div>Hello world</div>
-<!--_html_template_end_-->
-  `,
-});
diff --git a/tools/polymer/tests/v3_ready_expected.ts b/tools/polymer/tests/v3_ready_expected.ts
deleted file mode 100644
index 8d0685e..0000000
--- a/tools/polymer/tests/v3_ready_expected.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-Polymer({
-  is: 'cr-foo',
-
-  _template: html`
-<!--_html_template_start_-->
-<style>
-  div {
-    font-size: 2rem;
-  }
-</style>
-<div>Hello world</div>
-<!--_html_template_end_-->
-  `,
-});
diff --git a/tools/protoc_wrapper/protoc_wrapper.py b/tools/protoc_wrapper/protoc_wrapper.py
index 5ee68c4..d53fd5e 100755
--- a/tools/protoc_wrapper/protoc_wrapper.py
+++ b/tools/protoc_wrapper/protoc_wrapper.py
@@ -94,10 +94,6 @@
                       'codesearch.')
   parser.add_argument("--plugin",
                       help="Relative path to custom generator plugin.")
-  #   TODO(crbug.com/1237958): Remove allow_optional when proto rolls to 3.15.
-  parser.add_argument("--allow-optional",
-                      action='store_true',
-                      help="Enables experimental_allow_proto3_optional.")
   parser.add_argument("--plugin-options",
                       help="Custom generator plugin options.")
   parser.add_argument("--cc-options",
@@ -155,9 +151,6 @@
     if options.cc_options:
       cc_options_list.append(options.cc_options)
 
-    if options.allow_optional:
-      protoc_cmd += ["--experimental_allow_proto3_optional"]
-
     cc_options = FormatGeneratorOptions(','.join(cc_options_list))
     protoc_cmd += ["--cpp_out", cc_options + cc_out_dir]
     for filename in protos:
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index d21206d..92c46b5 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -324,7 +324,8 @@
                                      ax::mojom::Role old_role,
                                      ax::mojom::Role new_role) {
   DCHECK_EQ(tree_, tree);
-  AddEvent(node, Event::ROLE_CHANGED);
+  AddEvent(node, new_role == ax::mojom::Role::kAlert ? Event::ALERT
+                                                     : Event::ROLE_CHANGED);
 }
 
 void AXEventGenerator::OnIgnoredChanged(AXTree* tree,
@@ -756,6 +757,7 @@
       new_tree_data.sel_focus_object_id != old_tree_data.sel_focus_object_id ||
       new_tree_data.sel_focus_offset != old_tree_data.sel_focus_offset ||
       new_tree_data.sel_focus_affinity != old_tree_data.sel_focus_affinity) {
+    LOG(ERROR) << "********** Document selection changed: " << tree->root();
     AddEvent(tree->root(), Event::DOCUMENT_SELECTION_CHANGED);
 
     // A special event is also fired internally for selection changes in text
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index a91865f..d64b65f 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -1917,7 +1917,8 @@
   for (AXTreeObserver& observer : observers_)
     observer.OnNodeDataChanged(this, old_data, new_data);
 
-  if (old_data.role != new_data.role) {
+  if (old_data.role != new_data.role && !old_data.IsInvisibleOrIgnored() &&
+      !new_data.IsInvisibleOrIgnored()) {
     for (AXTreeObserver& observer : observers_)
       observer.OnRoleChanged(this, node, old_data.role, new_data.role);
   }
diff --git a/ui/accessibility/platform/ax_platform_node.cc b/ui/accessibility/platform/ax_platform_node.cc
index b8d4462..cb57ee5 100644
--- a/ui/accessibility/platform/ax_platform_node.cc
+++ b/ui/accessibility/platform/ax_platform_node.cc
@@ -59,7 +59,7 @@
 
 int32_t AXPlatformNode::GetUniqueId() const {
   DCHECK(GetDelegate()) << "|GetUniqueId| must be called after |Init|.";
-  return GetDelegate() ? GetDelegate()->GetUniqueId().Get() : -1;
+  return GetDelegate()->GetUniqueId().Get();
 }
 
 void AXPlatformNode::SetIsPrimaryWebContentsForWindow(bool is_primary) {
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index d24956b..0b28a2a0 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -2465,6 +2465,12 @@
   if (!GetDelegate()->IsWebContent())
     return;
 
+  // If there is a parent, then this is not the root document.
+  if (GetDelegate()->node()->GetUnignoredParent()) {
+    return;
+  }
+
+  // Get the ATK parent, which will cross over into the UI hierarchy.
   AtkObject* parent_atk_object = GetParent();
   AXPlatformNodeAuraLinux* parent =
       AXPlatformNodeAuraLinux::FromAtkObject(parent_atk_object);
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index ca2443a6..bb56f298 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1979,6 +1979,7 @@
   // convention here and when we fire events via
   // ::NotifyWinEvent().
   *id = -GetUniqueId();
+  DCHECK(*id < 0);
   return S_OK;
 }
 
diff --git a/ui/accessibility/platform/ax_unique_id.h b/ui/accessibility/platform/ax_unique_id.h
index a53d8b1..c80e30b 100644
--- a/ui/accessibility/platform/ax_unique_id.h
+++ b/ui/accessibility/platform/ax_unique_id.h
@@ -21,6 +21,8 @@
 //
 // These ids must not be conflated with the int id, that comes with web node
 // data, which are only unique within their source frame.
+// TODO(accessibility) We should be able to get rid of this, because node IDs
+// are actually unique within their own OS-level window.
 class COMPONENT_EXPORT(AX_PLATFORM) AXUniqueId {
  public:
   AXUniqueId();
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 2db965c..37ba3be 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -504,20 +504,17 @@
 
 std::unique_ptr<WindowTreeHost::VideoCaptureLock>
 WindowTreeHost::CreateVideoCaptureLock() {
-  if (!NativeWindowOcclusionTracker::
-          IsNativeWindowOcclusionTrackingAlwaysEnabled(this)) {
-    return nullptr;
-  }
-  // Throtting doesn't actually change the visibility, so no need for the lock.
-  if (ShouldThrottleWhenOccluded())
-    return nullptr;
-
   ++video_capture_count_;
   MaybeUpdateComposibleVisibilityForVideoLockCountChange();
+  OnVideoCaptureLockChanged();
   // WrapUnique() is used as constructor is private.
   return base::WrapUnique(new VideoCaptureLock(this));
 }
 
+bool WindowTreeHost::HasVideoCaptureLocks() const {
+  return video_capture_count_ > 0;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WindowTreeHost, protected:
 
@@ -754,9 +751,18 @@
   DCHECK_GT(video_capture_count_, 0);
   --video_capture_count_;
   MaybeUpdateComposibleVisibilityForVideoLockCountChange();
+  OnVideoCaptureLockChanged();
 }
 
 void WindowTreeHost::MaybeUpdateComposibleVisibilityForVideoLockCountChange() {
+  // Throttling doesn't actually change the visibility, so no need for the
+  // lock.
+  if (!NativeWindowOcclusionTracker::
+          IsNativeWindowOcclusionTrackingAlwaysEnabled(this) ||
+      ShouldThrottleWhenOccluded()) {
+    return;
+  }
+
   // Should only be called if the occlusion is applied to the compositor.
   DCHECK(!ShouldThrottleWhenOccluded());
 
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index c85e519e..16c9296 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -296,8 +296,9 @@
   virtual std::string GetUniqueId() const = 0;
 #endif
 
-  // See VideoCaptureLock for details. This may return null.
+  // See VideoCaptureLock for details.
   std::unique_ptr<VideoCaptureLock> CreateVideoCaptureLock();
+  bool HasVideoCaptureLocks() const;
 
 #if BUILDFLAG(IS_WIN)
   // Returns whether a host's window is on the current workspace or not,
@@ -353,6 +354,11 @@
   void OnHostCloseRequested();
   void OnHostLostWindowCapture();
 
+  // Called when the video capture count has changed. This can happen when locks
+  // are created or destroyed. Users might need this signal to decide whether
+  //  to change their states depending on whether there is capture.
+  virtual void OnVideoCaptureLockChanged() {}
+
   // Sets the currently displayed cursor.
   virtual void SetCursorNative(gfx::NativeCursor cursor) = 0;
 
diff --git a/ui/aura/window_tree_host_unittest.cc b/ui/aura/window_tree_host_unittest.cc
index cbdee35..54187b3 100644
--- a/ui/aura/window_tree_host_unittest.cc
+++ b/ui/aura/window_tree_host_unittest.cc
@@ -323,6 +323,10 @@
 
   TestWindowTreeHost(const TestWindowTreeHost&) = delete;
   TestWindowTreeHost& operator=(const TestWindowTreeHost&) = delete;
+
+  void OnVideoCaptureLockChanged() override { ++num_capture_lock_changes; }
+
+  int num_capture_lock_changes = 0;
 };
 
 TEST_F(WindowTreeHostTest, LostCaptureDuringTearDown) {
@@ -334,6 +338,20 @@
   TestWindowTreeHost host;
 }
 
+TEST_F(WindowTreeHostTest, VideoCaptureLockRecorded) {
+  TestWindowTreeHost host;
+  ASSERT_FALSE(host.HasVideoCaptureLocks());
+  ASSERT_EQ(host.num_capture_lock_changes, 0);
+
+  auto lock = host.CreateVideoCaptureLock();
+  EXPECT_TRUE(host.HasVideoCaptureLocks());
+  EXPECT_EQ(host.num_capture_lock_changes, 1);
+
+  lock.reset();
+  EXPECT_FALSE(host.HasVideoCaptureLocks());
+  EXPECT_EQ(host.num_capture_lock_changes, 2);
+}
+
 #if BUILDFLAG(IS_WIN)
 class WindowTreeHostWithReleaseTest : public test::AuraTestBase {
  public:
diff --git a/ui/file_manager/.eslintrc.js b/ui/file_manager/.eslintrc.js
index c8e2043..986293b 100644
--- a/ui/file_manager/.eslintrc.js
+++ b/ui/file_manager/.eslintrc.js
@@ -6,4 +6,17 @@
   'rules' : {
     'no-console' : 'off',
   },
+
+  'overrides': [{
+    'files': ['**/*.ts'],
+    'parser': '../../third_party/node/node_modules/@typescript-eslint/parser',
+    'plugins': [
+      '@typescript-eslint',
+    ],
+    'rules': {
+      // TODO(b/265863256): Re-enable when TypeScript annotations complication
+      // has been fixed.
+      '@typescript-eslint/no-unused-vars': 'off',
+    },
+  }],
 };
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index a2678f62..40751d2f 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1434,11 +1434,6 @@
   return /** @type {!HTMLDialogElement} */ (dialogElement);
 };
 
-util.isDriveDssPinEnabled = () => {
-  return loadTimeData.valueExists('DRIVE_DSS_PIN_ENABLED') &&
-      loadTimeData.getBoolean('DRIVE_DSS_PIN_ENABLED');
-};
-
 /**
  *
  * @param {!chrome.fileManagerPrivate.FileTaskDescriptor} left
diff --git a/ui/file_manager/file_manager/containers/search_container.ts b/ui/file_manager/file_manager/containers/search_container.ts
index 274330c5..d2bfa2d7 100644
--- a/ui/file_manager/file_manager/containers/search_container.ts
+++ b/ui/file_manager/file_manager/containers/search_container.ts
@@ -10,8 +10,8 @@
 import {VolumeManager} from '../externs/volume_manager.js';
 import {PathComponent} from '../foreground/js/path_component.js';
 import {SearchAutocompleteList} from '../foreground/js/ui/search_autocomplete_list.js';
-import {updateSearch} from '../state/actions.js';
-import {getStore, Store} from '../state/store.js';
+import {clearSearch, updateSearch} from '../state/actions.js';
+import {getDefaultSearchOptions, getStore, Store} from '../state/store.js';
 import {XfPathDisplayElement} from '../widgets/xf_path_display.js';
 import {OptionKind, SEARCH_OPTIONS_CHANGED, SearchOptionsChangedEvent, XfSearchOptionsElement} from '../widgets/xf_search_options.js';
 
@@ -57,11 +57,7 @@
   // far.
   private autocompleteList_: SearchAutocompleteList;
   // The current value of search options, initialized to some sensible default.
-  private currentOptions_: SearchOptions = {
-    location: SearchLocation.THIS_FOLDER,
-    recency: SearchRecency.ANYTIME,
-    type: SearchFileType.ALL_TYPES,
-  };
+  private currentOptions_: SearchOptions = getDefaultSearchOptions();
   // The store which updates us about state changes.
   private store_: Store;
   // The cached state of the store; store may post events if other parts of the
@@ -152,7 +148,15 @@
     const value = this.inputElement_.value;
     if (value !== '') {
       this.inputElement_.value = '';
-      this.onQueryChanged_();
+      if (!util.isSearchV2Enabled()) {
+        // Force query change flow only if V2 search is not enabled. This
+        // is due to the fact that in the legacy search we listen to input
+        // events from the text field, which are not posted when the value
+        // is directly assigned a value. In the V2 search we listen to store
+        // change events that cause the code path that handles clearing of
+        // search to be executed.
+        this.onQueryChanged_();
+      }
       requestAnimationFrame(() => {
         this.closeSearch();
       });
@@ -433,7 +437,7 @@
         const location = value as unknown as SearchLocation;
         if (location !== this.currentOptions_.location) {
           this.currentOptions_.location = location;
-          this.updateState_();
+          this.updateSearchOptions_();
         }
         break;
       }
@@ -441,7 +445,7 @@
         const recency = value as unknown as SearchRecency;
         if (recency !== this.currentOptions_.recency) {
           this.currentOptions_.recency = recency;
-          this.updateState_();
+          this.updateSearchOptions_();
         }
         break;
       }
@@ -449,7 +453,7 @@
         const type = value as unknown as SearchFileType;
         if (type !== this.currentOptions_.type) {
           this.currentOptions_.type = type;
-          this.updateState_();
+          this.updateSearchOptions_();
         }
         break;
       }
@@ -460,9 +464,9 @@
   }
 
   /**
-   * Updates the store state.
+   * Updates search options in the store.
    */
-  private updateState_() {
+  private updateSearchOptions_() {
     if (util.isSearchV2Enabled()) {
       this.store_.dispatch(updateSearch({
         query: undefined,   // do not change
@@ -564,6 +568,7 @@
     if (this.inputState_ === SearchInputState.OPEN) {
       this.hideOptions_();
       this.hidePathDisplay_();
+      this.store_.dispatch(clearSearch());
       this.inputState_ = SearchInputState.CLOSING;
       this.inputElement_.tabIndex = -1;
       this.inputElement_.disabled = true;
diff --git a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html
index 61b8399..4e74c656 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html
@@ -16,14 +16,9 @@
 
   #box {
     display: block;
-    margin: 0;
     overflow: auto;
-    padding: 0;
-    width: 320px;
-  }
-
-  :host([files-ng]) #box {
     padding-top: 16px;
+    width: 320px;
   }
 
   .category {
diff --git a/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html b/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html
index 671145d..86e75de0 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html
@@ -10,14 +10,10 @@
 
   #box {
     display: flex;
-    margin: 12px 0;
-    min-height: 14px;
-    width: 320px;
-  }
-
-  :host([files-ng]) #box {
     line-height: 20px;
     margin: 10px 0;
+    min-height: 14px;
+    width: 320px;
   }
 
   #box[hidden] {
diff --git a/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.js b/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.js
index dcff4eb..3c21e16 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.js
@@ -35,14 +35,6 @@
   },
 
   /**
-   * On element creation, set the files-ng attribute to enable files-ng
-   * specific CSS styling.
-   */
-  created: function() {
-    this.setAttribute('files-ng', '');
-  },
-
-  /**
    * When value is changed, it is displayed in the #valueContainer element.
    * How the value is represented depends on [[isPath]] value.
    * @param {string} newValue
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 569839d..4327f8c 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -9,12 +9,16 @@
 import {mountGuest} from '../../common/js/api.js';
 import {AsyncQueue, ConcurrentQueue} from '../../common/js/async_util.js';
 import {createDOMError} from '../../common/js/dom_utils.js';
+import {FileType} from '../../common/js/file_type.js';
 import {metrics} from '../../common/js/metrics.js';
 import {createTrashReaders} from '../../common/js/trash.js';
 import {util} from '../../common/js/util.js';
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
+import {EntryLocation} from '../../externs/entry_location.js';
 import {FakeEntry, FilesAppDirEntry} from '../../externs/files_app_entry_interfaces.js';
+import {SearchFileType, SearchLocation, SearchOptions, SearchRecency} from '../../externs/ts/state.js';
 import {VolumeManager} from '../../externs/volume_manager.js';
+import {getDefaultSearchOptions} from '../../state/store.js';
 
 import {constants} from './constants.js';
 import {FileListModel} from './file_list_model.js';
@@ -218,6 +222,188 @@
 }
 
 /**
+ * A content scanner capable of scanning both the local file system and Google
+ * Drive. When created you need to specify the root type, current entry
+ * in the directory tree, the search query and options. The `rootType` together
+ * with `options` is then used to determine if the search is conducted on the
+ * local folder, root folder, or on the local file system and Google Drive.
+ *
+ * NOTE: This class is a stop-gap solution when transitioning to a content
+ * scanner that talks to a browser level service. The service ultimately should
+ * be the one that determines what is being searched, and aggregates the results
+ * for the frontend client.
+ */
+export class SearchV2ContentScanner extends ContentScanner {
+  /**
+   * @param {!VolumeManagerCommon.RootType|null} rootType The root type of the
+   *    location in the directory tree, if known.
+   * @param {!DirectoryEntry} entry The current directory.
+   * @param {!string} query The query of the search.
+   * @param {SearchOptions=} options The options for the search.
+   */
+  constructor(rootType, entry, query, options = undefined) {
+    super();
+    this.rootType_ = rootType;
+    this.entry_ = entry;
+    this.query_ = query.toLowerCase();
+    this.options_ = options || getDefaultSearchOptions();
+  }
+
+  /**
+   * @returns {function(Entry): boolean} A function to filter by file type.
+   * @private
+   */
+  getTypeFilter_() {
+    switch (this.options_.type) {
+      case SearchFileType.AUDIO:
+        return FileType.isAudio;
+      case SearchFileType.DOCUMENTS:
+        return FileType.isDocument;
+      case SearchFileType.IMAGES:
+        return FileType.isImage;
+      case SearchFileType.VIDEOS:
+        return FileType.isVideo;
+      default:
+        return (entry) => true;
+    }
+  }
+
+  /**
+   * @returns Whether or not the local (MY_FILES) search should be performed.
+   * @private
+   */
+  isSearchingLocal_() {
+    if (this.options_.location === SearchLocation.EVERYWHERE ||
+        this.options_.location === SearchLocation.THIS_CHROMEBOOK) {
+      return true;
+    }
+    if (this.options_.location === SearchLocation.THIS_FOLDER) {
+      return this.rootType_ === VolumeManagerCommon.RootType.MY_FILES ||
+          this.rootType_ == VolumeManagerCommon.RootType.DOWNLOADS;
+    }
+    return false;
+  }
+
+  /**
+   * Computes the timestamp based on options. If the options ask for today's
+   * results, it uses the time in ms from midnight. For yesterday, it goes back
+   * by one day from midnight. For week, it goes back by 6 days from midnight.
+   * For a month, it goes back by 30 days since midnight, regardless of how
+   * many days are in the current month. For a year, it goes back by 365 days
+   * since midnight, regardless if the current year is a leap year or not.
+   * @private
+   */
+  getEarliestTimestamp_() {
+    const now = new Date();
+    const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+    const midnightMs = midnight.getTime();
+    const dayMs = 24 * 60 * 60 * 1000;
+
+    switch (this.options_.recency) {
+      case SearchRecency.TODAY:
+        return midnightMs;
+      case SearchRecency.YESTERDAY:
+        return midnightMs - 1 * dayMs;
+      case SearchRecency.LAST_WEEK:
+        return midnightMs - 6 * dayMs;
+      case SearchRecency.LAST_MONTH:
+        return midnightMs - 30 * dayMs;
+      case SearchRecency.LAST_YEAR:
+        return midnightMs - 365 * dayMs;
+      default:
+        return 0;
+    }
+  }
+
+  /**
+   * @returns Whether or not the Google Drive search should be performed.
+   * @private
+   */
+  isSearchingDrive_() {
+    if (this.options_.location === SearchLocation.EVERYWHERE) {
+      return true;
+    }
+    if (this.options_.location === SearchLocation.THIS_FOLDER) {
+      return (this.rootType_ === VolumeManagerCommon.RootType.DRIVE);
+    }
+    return false;
+  }
+
+  /**
+   * Starts the file name search.
+   * @override
+   */
+  async scan(
+      entriesCallback, successCallback, errorCallback,
+      invalidateCache = false) {
+    const searchPromises = [];
+    if (this.isSearchingLocal_()) {
+      searchPromises.push(new Promise((resolve, reject) => {
+        const rootDir = this.options_.location === SearchLocation.THIS_FOLDER ?
+            this.entry_ :
+            undefined;
+        const timestamp = this.getEarliestTimestamp_();
+        chrome.fileManagerPrivate.searchFiles(
+            {
+              rootDir: rootDir,
+              query: this.query_,
+              types: chrome.fileManagerPrivate.SearchType.ALL,
+              maxResults: 100,
+              timestamp: timestamp,
+            },
+            /**
+             * @param {!Array<!Entry>} entries
+             */
+            (entries) => {
+              if (this.cancelled_) {
+                reject(createDOMError(util.FileError.ABORT_ERR));
+              } else if (chrome.runtime.lastError) {
+                reject(createDOMError(
+                    util.FileError.NOT_READABLE_ERR,
+                    chrome.runtime.lastError.message));
+              } else {
+                resolve(entries.filter(this.getTypeFilter_()));
+              }
+            });
+      }));
+    }
+    if (this.isSearchingDrive_()) {
+      searchPromises.push(new Promise((resolve, reject) => {
+        chrome.fileManagerPrivate.searchDrive(
+            {query: this.query_, nextFeed: ''}, (entries, nextFeed) => {
+              if (chrome.runtime.lastError) {
+                reject(createDOMError(
+                    util.FileError.NOT_READABLE_ERR,
+                    chrome.runtime.lastError.message));
+              } else if (this.cancelled_) {
+                reject(createDOMError(util.FileError.ABORT_ERR));
+              } else if (!entries) {
+                reject(createDOMError(util.FileError.INVALID_MODIFICATION_ERR));
+              } else {
+                resolve(entries.filter(this.getTypeFilter_()));
+              }
+            });
+      }));
+    }
+    if (!searchPromises) {
+      console.warn(
+          `No search promises for options ${JSON.stringify(this.options_)}`);
+      successCallback();
+    }
+    Promise.allSettled(searchPromises).then((results) => {
+      for (const result of results) {
+        if (result.status === 'rejected') {
+          errorCallback(/** @type {DOMError} */ (result.reason));
+        } else if (result.status === 'fulfilled') {
+          entriesCallback(result.value);
+        }
+      }
+      successCallback();
+    });
+  }
+}
+
+/**
  * Scanner of the entries for the metadata search on Drive File System.
  */
 export class DriveMetadataSearchContentScanner extends ContentScanner {
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index 30ec139c..9baf62e8 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {dispatchSimpleEvent} from 'chrome://resources/ash/common/cr_deprecated.js';
 import {assert} from 'chrome://resources/ash/common/assert.js';
+import {dispatchSimpleEvent} from 'chrome://resources/ash/common/cr_deprecated.js';
 import {NativeEventTarget as EventTarget} from 'chrome://resources/ash/common/event_target.js';
 
 import {Aggregator, AsyncQueue} from '../../common/js/async_util.js';
@@ -14,16 +14,16 @@
 import {FileOperationManager} from '../../externs/background/file_operation_manager.js';
 import {EntriesChangedEvent} from '../../externs/entries_changed_event.js';
 import {FakeEntry, FilesAppDirEntry, FilesAppEntry} from '../../externs/files_app_entry_interfaces.js';
-import {PropStatus, State} from '../../externs/ts/state.js';
+import {PropStatus, SearchOptions, State} from '../../externs/ts/state.js';
 import {Store} from '../../externs/ts/store.js';
 import {VolumeInfo} from '../../externs/volume_info.js';
 import {VolumeManager} from '../../externs/volume_manager.js';
-import {clearSearch, updateSearch} from '../../state/actions.js';
+import {updateSearch} from '../../state/actions.js';
 import {changeDirectory} from '../../state/actions/current_directory.js';
 import {getStore} from '../../state/store.js';
 
 import {constants} from './constants.js';
-import {ContentScanner, CrostiniMounter, DirectoryContents, DirectoryContentScanner, DriveMetadataSearchContentScanner, DriveSearchContentScanner, FileFilter, FileListContext, GuestOsMounter, LocalSearchContentScanner, MediaViewContentScanner, RecentContentScanner, TrashContentScanner} from './directory_contents.js';
+import {ContentScanner, CrostiniMounter, DirectoryContents, DirectoryContentScanner, DriveMetadataSearchContentScanner, DriveSearchContentScanner, FileFilter, FileListContext, GuestOsMounter, LocalSearchContentScanner, MediaViewContentScanner, RecentContentScanner, SearchV2ContentScanner, TrashContentScanner} from './directory_contents.js';
 import {FileListModel} from './file_list_model.js';
 import {FileWatcher} from './file_watcher.js';
 import {MetadataModel} from './metadata/metadata_model.js';
@@ -1445,11 +1445,12 @@
    *
    * @param {!DirectoryEntry|!FilesAppEntry} entry Directory entry.
    * @param {string=} opt_query Search query string.
+   * @param {SearchOptions=} opt_options search options.
    * @return {function():ContentScanner} The factory to create ContentScanner
    *     instance.
    */
-  createScannerFactory(entry, opt_query) {
-    const query = (opt_query || '').trimLeft();
+  createScannerFactory(entry, opt_query, opt_options) {
+    const query = (opt_query || '').trimStart();
     const locationInfo = this.volumeManager_.getLocationInfo(entry);
     const canUseDriveSearch =
         this.volumeManager_.getDriveConnectionState().type !==
@@ -1495,6 +1496,15 @@
         return new TrashContentScanner(this.volumeManager_);
       };
     }
+    if (util.isSearchV2Enabled()) {
+      if (query) {
+        return () => {
+          return new SearchV2ContentScanner(
+              locationInfo ? locationInfo.rootType : null,
+              /** @type {!DirectoryEntry} */ (entry), query, opt_options);
+        };
+      }
+    }
     if (query && canUseDriveSearch) {
       // Drive search.
       return () => {
@@ -1550,12 +1560,14 @@
    * @param {FileListContext} context File list context.
    * @param {!DirectoryEntry|!FilesAppDirEntry} entry Current directory.
    * @param {string=} opt_query Search query string.
+   * @param {SearchOptions=} opt_options Search options.
    * @return {DirectoryContents} Directory contents.
    * @private
    */
-  createDirectoryContents_(context, entry, opt_query) {
+  createDirectoryContents_(context, entry, opt_query, opt_options) {
     const isSearch = this.isSearchDirectory(entry, opt_query);
-    const scannerFactory = this.createScannerFactory(entry, opt_query);
+    const scannerFactory =
+        this.createScannerFactory(entry, opt_query, opt_options);
     return new DirectoryContents(context, isSearch, entry, scannerFactory);
   }
 
@@ -1581,10 +1593,12 @@
    * name search over current directory will be performed.
    *
    * @param {string} query Query that will be searched for.
+   * @param {SearchOptions|undefined} options Search options, such as file
+   *     type, etc.
    * @param {function(Event)} onSearchRescan Function that will be called when
    *     the search directory is rescanned (i.e. search results are displayed).
    */
-  search(query, onSearchRescan) {
+  search(query, options, onSearchRescan) {
     this.lastSearchQuery_ = query;
     this.stopActiveSearch_();
     const currentDirEntry = this.getCurrentDirEntry();
@@ -1600,7 +1614,7 @@
         return;
       }
 
-      if (!(query || '').trimLeft()) {
+      if (!(query || '').trimStart()) {
         if (this.isSearching()) {
           const newDirContents = this.createDirectoryContents_(
               this.currentFileListContext_, assert(currentDirEntry));
@@ -1612,7 +1626,8 @@
       }
 
       const newDirContents = this.createDirectoryContents_(
-          this.currentFileListContext_, assert(currentDirEntry), query);
+          this.currentFileListContext_, assert(currentDirEntry), query,
+          options);
       if (!newDirContents) {
         callback();
         return;
@@ -1647,10 +1662,6 @@
       this.removeEventListener('scan-completed', this.onSearchCompleted_);
       this.onSearchCompleted_ = null;
     }
-
-    if (this.store_.getState()?.search?.query) {
-      this.store_.dispatch(clearSearch());
-    }
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/search_controller.js b/ui/file_manager/file_manager/foreground/js/search_controller.js
index 31ec508..e636e02 100644
--- a/ui/file_manager/file_manager/foreground/js/search_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/search_controller.js
@@ -6,7 +6,10 @@
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
 import {SEARCH_ITEM_CHANGED, SEARCH_QUERY_CHANGED, SearchContainer} from '../../containers/search_container.js';
 import {EntryLocation} from '../../externs/entry_location.js';
+import {SearchOptions, State} from '../../externs/ts/state.js';
+import {Store} from '../../externs/ts/store.js';
 import {VolumeManager} from '../../externs/volume_manager.js';
+import {getStore} from '../../state/store.js';
 
 import {DirectoryModel} from './directory_model.js';
 import {TaskController} from './task_controller.js';
@@ -50,12 +53,37 @@
     /** @const @private {!FileManagerUI} */
     this.a11y_ = a11y;
 
-    searchContainer.addEventListener(SEARCH_QUERY_CHANGED, (event) => {
-      this.onTextChange_(event.detail.query);
-    });
-    searchContainer.addEventListener(
-        SEARCH_ITEM_CHANGED, this.onItemSelect_.bind(this));
     directoryModel.addEventListener('directory-changed', this.clear.bind(this));
+
+    if (util.isSearchV2Enabled()) {
+      this.cachedSearchState_ = {};
+      this.store_ = getStore();
+      this.store_.subscribe(this);
+    } else {
+      searchContainer.addEventListener(SEARCH_QUERY_CHANGED, (event) => {
+        this.onSearchChange_(event.detail.query, event.detail.options);
+      });
+      searchContainer.addEventListener(
+          SEARCH_ITEM_CHANGED, this.onItemSelect_.bind(this));
+    }
+  }
+
+  /**
+   * Reacts to state change in the store. This method checks if the search
+   * component of the search state changed. If so, it triggers a new search.
+   * @param {State} state
+   */
+  onStateChanged(state) {
+    const searchState = state.search;
+    if (!searchState) {
+      return;
+    }
+    if (searchState.query === this.cachedSearchState_.query &&
+        searchState.options === this.cachedSearchState_.options) {
+      return;
+    }
+    this.cachedSearchState_ = searchState;
+    this.onSearchChange_(searchState.query || '', searchState.options);
   }
 
   /**
@@ -108,7 +136,7 @@
    */
   setSearchQuery(searchQuery) {
     this.searchContainer_.setQuery(searchQuery);
-    this.onTextChange_(searchQuery);
+    this.onSearchChange_(searchQuery, undefined);
     if (this.isOnDrive_) {
       this.onItemSelect_();
     }
@@ -117,15 +145,17 @@
   /**
    * Handles text change event.
    * @param {string} query
+   * @param {SearchOptions|undefined} options Search options, such as type,
+   *    location, etc.
    * @private
    */
-  onTextChange_(query) {
+  onSearchChange_(query, options) {
     const searchString = query;
 
     // On drive, incremental search is not invoked since we have an auto-
     // complete suggestion instead.
-    if (!this.isOnDrive_) {
-      this.search_(searchString);
+    if (!this.isOnDrive_ || util.isSearchV2Enabled()) {
+      this.search_(searchString, options);
       return;
     }
 
@@ -134,7 +164,7 @@
     // {@code DirectoryModel.search()}.
     if (this.directoryModel_.isSearching() &&
         this.directoryModel_.getLastSearchQuery() != searchString) {
-      this.directoryModel_.search('', () => {});
+      this.directoryModel_.search('', undefined, () => {});
     }
 
     this.requestAutocompleteSuggestions_();
@@ -207,7 +237,7 @@
     if (!selectedItem || selectedItem.isHeaderItem) {
       const query = selectedItem ? selectedItem.searchQuery :
                                    this.searchContainer_.getQuery();
-      this.search_(query);
+      this.search_(query, undefined);
       return;
     }
 
@@ -252,11 +282,13 @@
 
   /**
    * Search files and update the list with the search result.
-   * @param {string} searchString String to be searched with.
+   * @param {string} query String to be searched with.
+   * @param {SearchOptions|undefined} options Search options, such as file
+   *     type, etc.
    * @private
    */
-  search_(searchString) {
-    if (!searchString) {
+  search_(query, options) {
+    if (!query) {
       const msg = str('SEARCH_A11Y_CLEAR_SEARCH');
       this.a11y_.speakA11yMessage(msg);
     }
@@ -265,10 +297,10 @@
       const count = fileList.getFileCount() + fileList.getFolderCount();
       const msgId =
           count === 0 ? 'SEARCH_A11Y_NO_RESULT' : 'SEARCH_A11Y_RESULT';
-      const msg = strf(msgId, searchString);
+      const msg = strf(msgId, query);
       this.a11y_.speakA11yMessage(msg);
     };
 
-    this.directoryModel_.search(searchString, onSearchRescan.bind(this));
+    this.directoryModel_.search(query, options, onSearchRescan.bind(this));
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.js b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.js
index f47bdc5e..b205ac9 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.js
@@ -49,13 +49,10 @@
    * @returns {!Array<!Banner.AllowedVolume>}
    */
   allowedVolumes() {
-    if (util.isDriveDssPinEnabled()) {
-      return [{
-        type: VolumeManagerCommon.VolumeType.DRIVE,
-        root: VolumeManagerCommon.RootType.DRIVE,
-      }];
-    }
-    return [];
+    return [{
+      type: VolumeManagerCommon.VolumeType.DRIVE,
+      root: VolumeManagerCommon.RootType.DRIVE,
+    }];
   }
 }
 
diff --git a/ui/file_manager/file_manager/state/reducers/search.ts b/ui/file_manager/file_manager/state/reducers/search.ts
index 2cdd8a2..99284d2 100644
--- a/ui/file_manager/file_manager/state/reducers/search.ts
+++ b/ui/file_manager/file_manager/state/reducers/search.ts
@@ -32,7 +32,7 @@
     search.status = payload.status;
   }
   if (payload.options !== undefined) {
-    search.options = payload.options;
+    search.options = {...payload.options};
   }
   return {...state, search};
 }
diff --git a/ui/file_manager/file_manager/state/store.ts b/ui/file_manager/file_manager/state/store.ts
index 0bbe6798..8a33263 100644
--- a/ui/file_manager/file_manager/state/store.ts
+++ b/ui/file_manager/file_manager/state/store.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {FileData, FileKey, State} from '../externs/ts/state.js';
+import {FileData, FileKey, SearchFileType, SearchLocation, SearchOptions, SearchRecency, State} from '../externs/ts/state.js';
 import {BaseStore} from '../lib/base_store.js';
 
 import {Action} from './actions.js';
@@ -50,6 +50,17 @@
 }
 
 /**
+ * Search options to be used if the user did not specify their own.
+ */
+export function getDefaultSearchOptions(): SearchOptions {
+  return {
+    location: SearchLocation.THIS_FOLDER,
+    recency: SearchRecency.ANYTIME,
+    type: SearchFileType.ALL_TYPES,
+  } as SearchOptions;
+}
+
+/**
  * Promise resolved when the store's state in an desired condition.
  *
  * For each Store update the `checker` function is called, when it returns True
diff --git a/ui/file_manager/integration_tests/file_manager/drive_specific.js b/ui/file_manager/integration_tests/file_manager/drive_specific.js
index e25795c..c0ab04f 100644
--- a/ui/file_manager/integration_tests/file_manager/drive_specific.js
+++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -873,23 +873,6 @@
 };
 
 /**
- * Tests that the Drive offline info banner does not show when the
- * DriveFsBidirectionalNativeMessaging flag is disabled.
- */
-testcase.driveOfflineInfoBannerWithoutFlag = async () => {
-  // Open Files app on Drive.
-  const appId = await setupAndWaitUntilReady(RootPath.DRIVE, []);
-
-  await remoteCall.isolateBannerForTesting(
-      appId, 'drive-offline-pinning-banner');
-  const driveOfflineInfoBannerHiddenQuery =
-      '#banners > drive-offline-pinning-banner';
-
-  // Check: the Drive Offline info banner should not appear.
-  await remoteCall.waitForElementLost(appId, driveOfflineInfoBannerHiddenQuery);
-};
-
-/**
  * Tests that the inline file sync "in progress" icon is displayed in Drive as
  * the file starts syncing then disappears as it finishes syncing.
  */
diff --git a/ui/file_manager/integration_tests/file_manager/search.js b/ui/file_manager/integration_tests/file_manager/search.js
index 5883ab3..d8ebe2a0 100644
--- a/ui/file_manager/integration_tests/file_manager/search.js
+++ b/ui/file_manager/integration_tests/file_manager/search.js
@@ -3,11 +3,11 @@
 // found in the LICENSE file.
 
 import {FilesAppState} from '../files_app_state.js';
-import {addEntries, ENTRIES, getCaller, pending, repeatUntil, RootPath, sendTestMessage, TestEntryInfo} from '../test_util.js';
+import {addEntries, ENTRIES, EntryType, getCaller, pending, repeatUntil, RootPath, sendTestMessage, TestEntryInfo} from '../test_util.js';
 import {testcase} from '../testcase.js';
 
-import {remoteCall, setupAndWaitUntilReady} from './background.js';
-import {BASIC_DRIVE_ENTRY_SET, BASIC_LOCAL_ENTRY_SET} from './test_data.js';
+import {navigateWithDirectoryTree, remoteCall, setupAndWaitUntilReady} from './background.js';
+import {BASIC_DRIVE_ENTRY_SET, BASIC_LOCAL_ENTRY_SET, NESTED_ENTRY_SET} from './test_data.js';
 
 /**
  * Expected files shown in the search results for 'hello'
@@ -100,7 +100,9 @@
   // Check that a11y message for clearing the search term has been issued.
   const a11yMessages =
       await remoteCall.callRemoteTestUtil('getA11yAnnounces', appId, []);
-  chrome.test.assertEq(2, a11yMessages.length, 'Missing a11y message');
+  chrome.test.assertEq(
+      2, a11yMessages.length,
+      `Want 2 messages got ${JSON.stringify(a11yMessages)}`);
   chrome.test.assertEq(
       'Search text cleared, showing all files and folders.', a11yMessages[1]);
 };
@@ -312,15 +314,133 @@
 };
 
 /**
- * Checks that the search options are shown as expected.
+ * Checks that changing location options correctly filters search results.
  */
-testcase.searchOptions = async () => {
+testcase.searchWithLocationOptions = async () => {
   // Open Files app on Downloads.
   const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
 
-  // Enter some text in the search box. Minimum one character is needed.
-  await remoteCall.typeSearchText(appId, 'x');
+  // Modify the basic entry set by adding nested directories and
+  // a copy of the hello entry.
+  const nestedHello = ENTRIES.hello.cloneWith({
+    targetPath: 'A/hello.txt',
+  });
+  addEntries(['local'], [ENTRIES.directoryA, nestedHello]);
+
+  // Start in the nested directory, as the default search location
+  // is THIS_FOLDER. Expect to find one hello file. Then search on
+  // THIS_CHROMEBOOK and expect to find two.
+  await navigateWithDirectoryTree(appId, '/My files/Downloads/A');
+
+  // Search for all files with "hello" in their name.
+  await remoteCall.typeSearchText(appId, 'hello');
 
   // Verify that the search options are visible.
   await remoteCall.waitForElement(appId, 'xf-search-options:not([hidden])');
+
+  // Expect only the nested hello to be found.
+  await remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows([
+    nestedHello,
+  ]));
+
+  // Click the second button, which is This Chromebook.
+  chrome.test.assertTrue(
+      !!await remoteCall.callRemoteTestUtil(
+          'fakeMouseClick', appId,
+          [
+            [
+              'xf-search-options',
+              'xf-select#location-selector',
+              'cr-action-menu cr-button:nth-of-type(2)',
+            ],
+          ]),
+      'Failed to click "This Chromebook" location selector');
+
+  // Expect all hello files to be found.
+  await remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows([
+    ENTRIES.hello,
+    nestedHello,
+  ]));
+};
+
+/**
+ * Checks that changing recency options correctly filters search results.
+ */
+testcase.searchWithRecencyOptions = async () => {
+  // Open Files app on Downloads.
+  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
+
+  // Modify the basic entry set by adding another hello file with
+  // a recent date. We cannot make it today's date as those dates
+  // are rendered with 'Today' string rather than actual date string.
+  const recentHello = ENTRIES.hello.cloneWith({
+    nameText: 'hello-recent.txt',
+    lastModifiedTime: new Date().toDateString(),
+    targetPath: 'hello-recent.txt',
+  });
+  await addEntries(['local'], [recentHello]);
+  // Unfortunately, today's files use custom date string. Make it so.
+  const todayHello = recentHello.cloneWith({
+    lastModifiedTime: 'Today 12:00 AM',
+  });
+
+  // Search for all files with "hello" in their name.
+  await remoteCall.typeSearchText(appId, 'hello');
+
+  // Expect two files, with no recency restrictions.
+  await remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows([
+    ENTRIES.hello,
+    todayHello,
+  ]));
+
+  // Click the fourth button, which is "Last week" option.
+  chrome.test.assertTrue(
+      !!await remoteCall.callRemoteTestUtil(
+          'fakeMouseClick', appId,
+          [
+            [
+              'xf-search-options',
+              'xf-select#recency-selector',
+              'cr-action-menu cr-button:nth-of-type(4)',
+            ],
+          ]),
+      'Failed to click "Last week" recency selector');
+
+  // Expect only the recent hello file to be found.
+  await remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows([
+    todayHello,
+  ]));
+};
+
+/**
+ * Checks that changing file types options correctly filters search results.
+ */
+testcase.searchWithTypeOptions = async () => {
+  // Open Files app on Downloads.
+  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
+
+  // Search for all files with "hello" in their name.
+  await remoteCall.typeSearchText(appId, 'o');
+
+  // Expect all basic files, with no type restrictions.
+  await remoteCall.waitForFiles(
+      appId, TestEntryInfo.getExpectedRows(BASIC_LOCAL_ENTRY_SET));
+
+  // Click the fifth button, which is "Video" option.
+  chrome.test.assertTrue(
+      !!await remoteCall.callRemoteTestUtil(
+          'fakeMouseClick', appId,
+          [
+            [
+              'xf-search-options',
+              'xf-select#type-selector',
+              'cr-action-menu cr-button:nth-of-type(5)',
+            ],
+          ]),
+      'Failed to click "Videos" type selector');
+
+  // Expect only world, which is a video file.
+  await remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows([
+    ENTRIES.world,
+  ]));
 };
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index a0002c1..852ae2e 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -443,6 +443,17 @@
   }
 
   /**
+   * Returns a new entry with modified attributes specified in the
+   * `newOptions` object.
+   * @param {!Object} newOptions  The options to be modified.
+   * @returns {!TestEntryInfo}
+   */
+  cloneWith(newOptions) {
+    return new TestEntryInfo(/** @type {TestEntryInfoOptions} */ (
+        Object.assign({}, this, newOptions)));
+  }
+
+  /**
    * Clone the existing TestEntryInfo object to a new TestEntryInfo object but
    * with modified lastModifiedTime field. This is especially useful for
    * constructing TestEntryInfo for Recents view.
@@ -451,11 +462,7 @@
    * @return {!TestEntryInfo}
    */
   cloneWithModifiedDate(newDate) {
-    const updatedOptions =
-        /** @type {TestEntryInfoOptions} */ (Object.assign({}, this, {
-          lastModifiedTime: newDate,
-        }));
-    return new TestEntryInfo(updatedOptions);
+    return this.cloneWith({lastModifiedTime: newDate});
   }
 
   /**
@@ -467,12 +474,10 @@
    * @return {!TestEntryInfo}
    */
   cloneWithNewName(newName) {
-    const updatedOptions =
-        /** @type {TestEntryInfoOptions} */ (Object.assign({}, this, {
-          targetPath: newName,
-          nameText: newName,
-        }));
-    return new TestEntryInfo(updatedOptions);
+    return this.cloneWith({
+      targetPath: newName,
+      nameText: newName,
+    });
   }
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 1421864..113fcb9 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -348,6 +348,7 @@
   if (close_widget_factory_.HasWeakPtrs() || !platform_window())
     return;
 
+  is_closing_ = true;
   GetContentWindow()->Hide();
 
   // Hide while waiting for the close.
@@ -841,13 +842,16 @@
   bool was_minimized = old_state == ui::PlatformWindowState::kMinimized;
   bool is_minimized = new_state == ui::PlatformWindowState::kMinimized;
 
-  // Propagate minimization/restore to compositor to avoid drawing 'blank'
-  // frames that could be treated as previews, which show content even if a
-  // window is minimized.
   if (is_minimized != was_minimized) {
     if (is_minimized) {
-      SetVisible(false);
-      GetContentWindow()->Hide();
+      if (!HasVideoCaptureLocks()) {
+        // Hide the content window and pause the compositor to prevent drawing
+        // a blank frame which will show up in the window preview. Hiding the
+        // content window is intended to prevent rendering frames when the
+        // window is not visible.
+        SetVisible(false);
+        GetContentWindow()->Hide();
+      }
     } else {
       GetContentWindow()->Show();
       SetVisible(true);
@@ -860,6 +864,24 @@
   ScheduleRelayout();
 }
 
+void DesktopWindowTreeHostPlatform::OnVideoCaptureLockChanged() {
+  // This does not account for the case when the lock is destroyed while the
+  // window is minimized. In that case, the content should be hidden and the
+  // compositor paused. However, that does require more state tracking. Because
+  // the difference is not observable to users, a more simple approach is
+  // taken.
+  // We need to ensure that we do not show the content when the window is
+  // closing.
+  if (HasVideoCaptureLocks() && !GetContentWindow()->IsVisible() &&
+      !is_closing_) {
+    // If a video capture lock has been created, this implies that there is a
+    // consumer for the content window's content. Therefore, we must show it and
+    // start rendering it if it is currently hidden.
+    GetContentWindow()->Show();
+    SetVisible(true);
+  }
+}
+
 void DesktopWindowTreeHostPlatform::OnCloseRequest() {
   GetWidget()->Close();
 }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 5cecf15..872d73e 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -143,6 +143,7 @@
   void HideImpl() override;
   gfx::Rect CalculateRootWindowBounds() const override;
   gfx::Rect GetBoundsInDIP() const override;
+  void OnVideoCaptureLockChanged() override;
 
   // PlatformWindowDelegate:
   void OnClosed() override;
@@ -224,6 +225,11 @@
 
   bool is_active_ = false;
 
+  // Tracks whether a close has been requested. The content is first hidden
+  // followed by a delayed delete. This variable should be used to ensure that
+  // we do not attempt to show the content during that delay window.
+  bool is_closing_ = false;
+
   std::u16string window_title_;
 
   // We can optionally have a parent which can order us to close, or own
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
index 8d82bf0..6491f6b 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -191,6 +191,67 @@
   EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
 }
 
+// Tests that the minimization information is propagated to the content window.
+TEST_F(DesktopWindowTreeHostPlatformTest,
+       ToggleMinimizePropogateToContentWindowDoesNotHideWithVideoCaptureLock) {
+  std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+  widget->Show();
+
+  auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+      widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+  ASSERT_TRUE(host_platform);
+
+  EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
+
+  auto capture_lock =
+      widget->GetNativeWindow()->GetHost()->CreateVideoCaptureLock();
+
+  // Pretend a PlatformWindow enters the minimized state.
+  host_platform->OnWindowStateChanged(ui::PlatformWindowState::kUnknown,
+                                      ui::PlatformWindowState::kMinimized);
+
+  // Should remain visible, because a video capture lock currently exists.
+  EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
+}
+
+// Tests that content will show the content and restart the compositor if the
+// capture count changes.
+TEST_F(DesktopWindowTreeHostPlatformTest,
+       OnVideoCaptureLocksShowsContentWhenNeeded) {
+  std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+  widget->Show();
+
+  auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+      widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+  ASSERT_TRUE(host_platform);
+
+  EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
+
+  // Pretend a PlatformWindow enters the minimized state.
+  host_platform->OnWindowStateChanged(ui::PlatformWindowState::kUnknown,
+                                      ui::PlatformWindowState::kMinimized);
+
+  // Widget should now be not visible.
+  EXPECT_FALSE(widget->GetNativeWindow()->IsVisible());
+
+  // Creating a capture should now make the widget visible.
+  widget->GetNativeWindow()->GetHost()->CreateVideoCaptureLock();
+  EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
+}
+
+TEST_F(DesktopWindowTreeHostPlatformTest,
+       OnVideoCaptureLocksDoesNotShowContentWhenClosing) {
+  std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+  widget->Show();
+  EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
+
+  widget->Close();
+
+  // Creating a video lock should not show the content if the widget is closing.
+  widget->GetNativeWindow()->GetHost()->CreateVideoCaptureLock();
+  EXPECT_FALSE(widget->GetNativeWindow()->IsVisible());
+}
+
 // Tests that the window shape is updated from the
 // |NonClientView::GetWindowMask|.
 TEST_F(DesktopWindowTreeHostPlatformTest, UpdateWindowShapeFromWindowMask) {
diff --git a/weblayer/browser/profile_impl.cc b/weblayer/browser/profile_impl.cc
index f17b74ebc..a2c70ad3 100644
--- a/weblayer/browser/profile_impl.cc
+++ b/weblayer/browser/profile_impl.cc
@@ -396,7 +396,7 @@
 }
 
 void ProfileImpl::OnLocaleChanged() {
-  GetBrowserContext()->ForEachStoragePartition(base::BindRepeating(
+  GetBrowserContext()->ForEachLoadedStoragePartition(base::BindRepeating(
       [](const std::string& accept_language,
          content::StoragePartition* storage_partition) {
         storage_partition->GetNetworkContext()->SetAcceptLanguage(