diff --git a/AUTHORS b/AUTHORS
index 2244e67..9cc81a4 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1012,6 +1012,7 @@
 Prashant Hiremath <prashhir@cisco.com>
 Prashant Nevase <prashant.n@samsung.com>
 Prashant Patil <prashant.patil@imgtec.com>
+Pratham <prathamIN@proton.me>
 Praveen Akkiraju <praveen.anp@samsung.com>
 Preeti Nayak <preeti.nayak@samsung.com>
 Pritam Nikam <pritam.nikam@samsung.com>
diff --git a/DEPS b/DEPS
index f588a66..73435d6 100644
--- a/DEPS
+++ b/DEPS
@@ -300,15 +300,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '79088c6b7a33d69358e79bbd8bb90db71ecd6564',
+  'skia_revision': 'ef226c5a7930c04e78f987ff7bfb14f487baf79f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '0f44e4c2a6fe21c4ef4cf1f1fba2aa145209d91d',
+  'v8_revision': 'aa5ec7646265bd97a4ecd51d2bdcfeae116253d8',
   # 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': 'c04ad8e025ee06b64b52ff7009a19fb7c1e720a4',
+  'angle_revision': 'ae0f0f47e1b4cb3ac7e8919a2930ca174a7f5a5d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -387,7 +387,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': 'cc55777c34d501ad6be16c52e17f318b0822a1c3',
+  'devtools_frontend_revision': '70475a9b48dddc74a07cd67b2be714b98e8458a8',
   # 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.
@@ -427,7 +427,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '30dc1b5abb1f90cf32a16008688ebba4476e0e55',
+  'dawn_revision': '55e57b362bc99bcd9db4bea8781906daf2d37e31',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -463,7 +463,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'cros_components_revision': '29226ca637ca0a5cd8348994c0798c7416b78244',
+  'cros_components_revision': '0c2d6bae878ffcdd629744501166852beb64384e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -803,7 +803,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '26ebce4f7765b4b6881b238930863e750e134a60',
+    'dac084598c86c1719fce71aedab9fcdbcecf54bb',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1233,7 +1233,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '20ada862d00f9533e867112b95b36ac2e2ec3ada',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '7b4ebf8878d739aa9fad8fe292301d0613f32a5e',
     'condition': 'checkout_src_internal',
   },
 
@@ -1700,7 +1700,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '87d4934194957d4d3073209cd450c197843fe25a',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f7a6f0099ec3287ef9496bac0a27d0405b9fb4c3',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1845,7 +1845,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@2968842d10ac82d571ba996e0a81bd5eb11816cf',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@dc49e5c6de1eb6410fb92ab591891ed951eee02e',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1885,7 +1885,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'b033a4f1ae4a0e19ae4d5563fae023001bbf570f',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0483755f4e4b362fdd8aeb35e86df3f6f5ceef9e',
+    Var('webrtc_git') + '/src.git' + '@' + '15feded162a254474a3aa7c573724b5ed460a57b',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -2038,7 +2038,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'MqvBJn3bTBo7m4NpvMicINE2i_MCX3Rxupza4aKSUMkC',
+        'version': 'D8-w6E8xqGQGNB8P70FyWLHOXBlmZcoAKid5nL8JbHUC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4174,7 +4174,7 @@
 
   'src/ios_internal':  {
       'url': '{chrome_git}/chrome/ios_internal.git' + '@' +
-        'eaf3983e83a2fc7122f713828677293ee0dbbe93',
+        '8450392c60de3eddbc68e3d0d51fe794451f312b',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 7fe85b1..3c56044 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -626,8 +626,6 @@
     ":common_platform_services_java",
     ":common_variations_java",
     ":resources",
-    "//android_webview:common_platform_services_java",
-    "//android_webview/proto:aw_variations_seed_proto_java",
     "//android_webview/proto:metrics_bridge_records_proto_java",
     "//base:base_java",
     "//base:jni_java",
diff --git a/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java b/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java
index 81cb368..c70d296 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java
@@ -4,12 +4,14 @@
 
 package org.chromium.android_webview;
 
+import org.chromium.android_webview.common.Lifetime;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 
 /**
  * Controller for Remote Web Debugging (Developer Tools).
  */
+@Lifetime.Singleton
 @JNINamespace("android_webview")
 public class AwDevToolsServer {
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwDisplayCutoutController.java b/android_webview/java/src/org/chromium/android_webview/AwDisplayCutoutController.java
index f3922a7..f386ff4 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwDisplayCutoutController.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwDisplayCutoutController.java
@@ -13,6 +13,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.android_webview.common.Lifetime;
 import org.chromium.base.Log;
 
 /**
@@ -21,6 +22,7 @@
  * This object should be constructed in WebView's constructor to support set listener logic for
  * Android P and above.
  */
+@Lifetime.WebView
 @RequiresApi(Build.VERSION_CODES.P)
 public class AwDisplayCutoutController {
     private static final boolean DEBUG = false;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwDisplayModeController.java b/android_webview/java/src/org/chromium/android_webview/AwDisplayModeController.java
index 29b26f7f..8ee5028 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwDisplayModeController.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwDisplayModeController.java
@@ -9,6 +9,7 @@
 import android.graphics.Rect;
 import android.view.View;
 
+import org.chromium.android_webview.common.Lifetime;
 import org.chromium.base.Log;
 import org.chromium.blink.mojom.DisplayMode;
 
@@ -18,6 +19,7 @@
  * Display mode will be used for display cutout controller's internal implementation since we only
  * apply display cutout to fullscreen mode. Also, display mode will be reported as CSS property.
  */
+@Lifetime.WebView
 public class AwDisplayModeController {
     private static final boolean DEBUG = false;
     private static final String TAG = "DisplayMode";
diff --git a/android_webview/nonembedded/BUILD.gn b/android_webview/nonembedded/BUILD.gn
index 06c44fd4..1f5cd97 100644
--- a/android_webview/nonembedded/BUILD.gn
+++ b/android_webview/nonembedded/BUILD.gn
@@ -130,7 +130,6 @@
     "//android_webview:common_java",
     "//android_webview:common_platform_services_java",
     "//android_webview:common_variations_java",
-    "//android_webview/proto:aw_variations_seed_proto_java",
     "//android_webview/proto:metrics_bridge_records_proto_java",
     "//base:base_java",
     "//base:jni_java",
diff --git a/ash/app_list/app_list_presenter_unittest.cc b/ash/app_list/app_list_presenter_unittest.cc
index abde981..57cd0b45 100644
--- a/ash/app_list/app_list_presenter_unittest.cc
+++ b/ash/app_list/app_list_presenter_unittest.cc
@@ -3792,7 +3792,8 @@
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
 }
 
-TEST_F(AppListPresenterTest, ClickingShelfArrowDoesNotHideAppList) {
+// TODO(b/283753290): Deflake and re-enable the test.
+TEST_F(AppListPresenterTest, DISABLED_ClickingShelfArrowDoesNotHideAppList) {
   // Add enough shelf items for the shelf to enter overflow.
   Shelf* const shelf = GetPrimaryShelf();
   ScrollableShelfView* const scrollable_shelf_view =
diff --git a/ash/booting/booting_animation_controller.cc b/ash/booting/booting_animation_controller.cc
index efbc8f9a..e3deba73 100644
--- a/ash/booting/booting_animation_controller.cc
+++ b/ash/booting/booting_animation_controller.cc
@@ -11,9 +11,11 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/system/sys_info.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
+#include "base/time/time.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -52,6 +54,12 @@
 BootingAnimationController::~BootingAnimationController() = default;
 
 void BootingAnimationController::Show() {
+  // If data fetch failed, notify caller immediately without showing the widget.
+  if (data_fetch_failed_.has_value() && data_fetch_failed_.value()) {
+    std::move(animation_played_callback_).Run();
+    return;
+  }
+
   widget_ = std::make_unique<views::Widget>();
   views::Widget::InitParams params;
   params.delegate = new views::WidgetDelegate;  // Takes ownership.
@@ -73,7 +81,7 @@
   params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
   widget_->Init(std::move(params));
 
-  if (animation_data_.empty()) {
+  if (!data_fetch_failed_.has_value()) {
     LOG(ERROR) << "Booting animation isn't ready yet.";
     start_once_ready_ = true;
     return;
@@ -87,13 +95,21 @@
 
   // Don't wait for GPU to be ready in non-ChromeOS environment.
   if (!base::SysInfo::IsRunningOnChromeOS()) {
-    is_gpu_ready_ = true;
-    scoped_display_configurator_observer_.Reset();
+    IgnoreGpuReadiness();
+    return;
   }
 
-  if (!scoped_display_configurator_observer_.IsObserving()) {
-    Show();
+  // If we are still waiting for the signal from DisplayConfigurator wait for
+  // not more than a second and play the animation anyway.
+  if (scoped_display_configurator_observer_.IsObserving()) {
+    base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&BootingAnimationController::IgnoreGpuReadiness,
+                       weak_factory_.GetWeakPtr()),
+        base::TimeDelta(base::Seconds(1)));
+    return;
   }
+  Show();
 }
 
 void BootingAnimationController::Finish() {
@@ -138,9 +154,15 @@
 void BootingAnimationController::OnAnimationDataFetched(std::string data) {
   if (data.empty()) {
     LOG(ERROR) << "No booting animation file available.";
+    data_fetch_failed_ = true;
+    // Notify caller immediately that there is no animation file.
+    if (!animation_played_callback_.is_null()) {
+      std::move(animation_played_callback_).Run();
+    }
     return;
   }
 
+  data_fetch_failed_ = false;
   animation_data_ = std::move(data);
 
   if (start_once_ready_) {
@@ -164,4 +186,18 @@
   view->Play();
 }
 
+void BootingAnimationController::IgnoreGpuReadiness() {
+  // Don't do anything if we already stopped observing DisplayConfigurator.
+  if (!scoped_display_configurator_observer_.IsObserving()) {
+    return;
+  }
+  LOG(ERROR) << "Ignore the readinees of the GPU and play the animation.";
+
+  is_gpu_ready_ = true;
+  scoped_display_configurator_observer_.Reset();
+  if (!animation_played_callback_.is_null()) {
+    Show();
+  }
+}
+
 }  // namespace ash
diff --git a/ash/booting/booting_animation_controller.h b/ash/booting/booting_animation_controller.h
index b387ded40..8bcbbe1 100644
--- a/ash/booting/booting_animation_controller.h
+++ b/ash/booting/booting_animation_controller.h
@@ -49,9 +49,11 @@
   void Show();
   void OnAnimationDataFetched(std::string data);
   void StartAnimation();
+  void IgnoreGpuReadiness();
 
   std::string animation_data_;
   std::unique_ptr<views::Widget> widget_;
+  absl::optional<bool> data_fetch_failed_;
   bool start_once_ready_ = false;
   bool was_shown_ = false;
   bool is_gpu_ready_ = false;
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 8639534a..026bfc9 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -40,6 +40,7 @@
 #include "ash/system/time/time_of_day.h"
 #include "base/functional/bind.h"
 #include "base/i18n/time_formatting.h"
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_util.h"
@@ -794,6 +795,11 @@
   DCHECK(callbacks.on_easy_unlock_icon_hovered);
   DCHECK(callbacks.on_auth_factor_is_hiding_password_changed);
   DCHECK_NE(user.basic_user_info.type, user_manager::USER_TYPE_PUBLIC_ACCOUNT);
+  if (Shell::Get()->login_screen_controller()->IsAuthenticating()) {
+    // TODO(b/276246832): We should avoid re-layouting during Authentication.
+    LOG(WARNING)
+        << "LoginAuthUserView::LoginAuthUserView called during Authentication.";
+  }
 
   // Build child views.
   auto user_view = std::make_unique<LoginUserView>(
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index 7d307c8..e804c05 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -6,6 +6,7 @@
 
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/constants/ash_features.h"
+#include "ash/login/login_screen_controller.h"
 #include "ash/login/ui/arrow_button_view.h"
 #include "ash/login/ui/horizontal_image_sequence_animation_decoder.h"
 #include "ash/login/ui/hover_notifier.h"
@@ -20,6 +21,7 @@
 #include "ash/style/ash_color_provider.h"
 #include "ash/style/color_util.h"
 #include "base/functional/bind.h"
+#include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -767,6 +769,13 @@
 }
 
 void LoginPasswordView::SetReadOnly(bool read_only) {
+  if (!read_only &&
+      Shell::Get()->login_screen_controller()->IsAuthenticating()) {
+    // TODO(b/276246832): We shouldn't enable the LoginPasswordView during
+    // Authentication.
+    LOG(WARNING) << "LoginPasswordView::SetReadOnly called with false during "
+                    "Authentication.";
+  }
   textfield_->SetReadOnly(read_only);
   textfield_->SetCursorEnabled(!read_only);
   UpdateUiState();
diff --git a/ash/login/ui/login_pin_input_view.cc b/ash/login/ui/login_pin_input_view.cc
index d3d1ff08..33458a4 100644
--- a/ash/login/ui/login_pin_input_view.cc
+++ b/ash/login/ui/login_pin_input_view.cc
@@ -5,11 +5,14 @@
 #include "ash/login/ui/login_pin_input_view.h"
 
 #include "ash/constants/ash_features.h"
+#include "ash/login/login_screen_controller.h"
 #include "ash/login/ui/access_code_input.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_id.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/accessibility/ax_enums.mojom-shared.h"
@@ -243,6 +246,13 @@
 }
 
 void LoginPinInputView::SetReadOnly(bool read_only) {
+  if (!read_only &&
+      Shell::Get()->login_screen_controller()->IsAuthenticating()) {
+    // TODO(b/276246832): We shouldn't enable the LoginPinInputView during
+    // Authentication.
+    LOG(WARNING) << "LoginPinInputView::SetReadOnly called with false during "
+                    "Authentication.";
+  }
   is_read_only_ = read_only;
   code_input_->SetReadOnly(read_only);
 }
diff --git a/ash/system/unified/date_tray_unittest.cc b/ash/system/unified/date_tray_unittest.cc
index 56fc3bb..590a30f 100644
--- a/ash/system/unified/date_tray_unittest.cc
+++ b/ash/system/unified/date_tray_unittest.cc
@@ -188,7 +188,7 @@
   EXPECT_FALSE(AreContentsViewShown());
 }
 
-TEST_P(DateTrayTest, ShowTasksComboModel) {
+TEST_P(DateTrayTest, DISABLED_ShowTasksComboModel) {
   LeftClickOn(GetDateTray());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsBubbleShown());
diff --git a/ash/webui/camera_app_ui/resources/js/main.ts b/ash/webui/camera_app_ui/resources/js/main.ts
index 6b0f3d2..eb9f2d6 100644
--- a/ash/webui/camera_app_ui/resources/js/main.ts
+++ b/ash/webui/camera_app_ui/resources/js/main.ts
@@ -121,6 +121,7 @@
     windowController.addListener(() => nav.layoutShownViews());
 
     util.setupI18nElements(document.body);
+    this.setupTooltip();
     this.setupToggles();
     localStorage.cleanup();
     this.setupEffect();
@@ -137,6 +138,47 @@
   }
 
   /**
+   * Sets up tooltips for elements having `i18n-label` attribute. This method
+   * also setup tooltips for the elements:
+   * * Added to the DOM and have a `i18n-label` attribute.
+   * * Newly set with a `i18n-label` attribute.
+   *
+   * Note `i18n-label` attribute should not be removed from elements.
+   */
+  private setupTooltip() {
+    const tooltipAttribute = 'i18n-label';
+    const elements =
+        Array.from(dom.getAll(`[${tooltipAttribute}]`, HTMLElement));
+    tooltip.setup(elements);
+    const observer = new MutationObserver((mutations) => {
+      const elements: HTMLElement[] = [];
+      for (const mutation of mutations) {
+        if (mutation.type === 'childList') {
+          for (const node of mutation.addedNodes) {
+            if (node instanceof HTMLElement &&
+                node.hasAttribute(tooltipAttribute)) {
+              elements.push(node);
+            }
+          }
+        } else if (mutation.type === 'attributes') {
+          const {target: node, attributeName, oldValue} = mutation;
+          if (node instanceof HTMLElement &&
+              attributeName === tooltipAttribute && oldValue === null) {
+            elements.push(node);
+          }
+        }
+      }
+      tooltip.setup(elements);
+    });
+    observer.observe(document.body, {
+      subtree: true,
+      childList: true,
+      attributes: true,
+      attributeOldValue: true,
+    });
+  }
+
+  /**
    * Sets up toggles (checkbox and radio) by data attributes.
    */
   private setupToggles() {
diff --git a/ash/webui/camera_app_ui/resources/js/tooltip.ts b/ash/webui/camera_app_ui/resources/js/tooltip.ts
index a994a01..e0651f6 100644
--- a/ash/webui/camera_app_ui/resources/js/tooltip.ts
+++ b/ash/webui/camera_app_ui/resources/js/tooltip.ts
@@ -89,9 +89,8 @@
  * Sets up tooltips for elements.
  *
  * @param elements Elements whose tooltips to be shown.
- * @return Elements whose tooltips have been set up.
  */
-export function setup(elements: HTMLElement[]): HTMLElement[] {
+export function setup(elements: HTMLElement[]): void {
   wrapper = dom.get('#tooltip', HTMLElement);
   for (const el of elements) {
     function handler() {
@@ -100,9 +99,10 @@
         hide();
       }
     }
-    el.addEventListener('mouseout', handler);
+    el.addEventListener('mouseleave', handler);
     el.addEventListener('click', handler);
-    el.addEventListener('mouseover', () => show(el));
+    el.addEventListener('blur', handler);
+    el.addEventListener('mouseenter', () => show(el));
+    el.addEventListener('focus', () => show(el));
   }
-  return elements;
 }
diff --git a/ash/webui/camera_app_ui/resources/js/util.ts b/ash/webui/camera_app_ui/resources/js/util.ts
index 39bd420b..7edeb7f 100644
--- a/ash/webui/camera_app_ui/resources/js/util.ts
+++ b/ash/webui/camera_app_ui/resources/js/util.ts
@@ -8,7 +8,6 @@
 import {I18nString} from './i18n_string.js';
 import * as loadTimeData from './models/load_time_data.js';
 import * as state from './state.js';
-import * as tooltip from './tooltip.js';
 import {AspectRatioSet, Facing, FpsRange, Resolution} from './type.js';
 
 /**
@@ -188,11 +187,10 @@
     element.setAttribute(
         'tooltip-false', getMessage(element, 'i18n-tooltip-false'));
   }
-  for (const element of getElements('i18n-aria')) {
-    setAriaLabel(element, 'i18n-aria');
-  }
-  for (const element of tooltip.setup(getElements('i18n-label'))) {
-    setAriaLabel(element, 'i18n-label');
+  for (const attribute of ['i18n-aria', 'i18n-label']) {
+    for (const element of getElements(attribute)) {
+      setAriaLabel(element, attribute);
+    }
   }
 }
 
diff --git a/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts b/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts
index 194e636..0c756c0b 100644
--- a/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts
@@ -556,7 +556,7 @@
       const cornerIndex =
           (this.getRotationIndex(this.rotation) + index) % this.corners.length;
       const cornElement = this.corners[cornerIndex].el;
-      cornElement.setAttribute('i18n-aria', label);
+      cornElement.setAttribute('i18n-label', label);
     }
     util.setupI18nElements(this.root);
   }
diff --git a/base/allocator/partition_allocator/address_pool_manager.cc b/base/allocator/partition_allocator/address_pool_manager.cc
index 3604507..63a9c467 100644
--- a/base/allocator/partition_allocator/address_pool_manager.cc
+++ b/base/allocator/partition_allocator/address_pool_manager.cc
@@ -51,7 +51,7 @@
 void AddressPoolManager::Add(pool_handle handle, uintptr_t ptr, size_t length) {
   PA_DCHECK(!(ptr & kSuperPageOffsetMask));
   PA_DCHECK(!((ptr + length) & kSuperPageOffsetMask));
-  PA_CHECK(handle > 0 && handle <= std::size(aligned_pools_.pools_));
+  PA_CHECK(handle > 0 && handle <= std::size(pools_));
 
   Pool* pool = GetPool(handle);
   PA_CHECK(!pool->IsInitialized());
@@ -79,8 +79,8 @@
 }
 
 void AddressPoolManager::ResetForTesting() {
-  for (size_t i = 0; i < std::size(aligned_pools_.pools_); ++i) {
-    aligned_pools_.pools_[i].Reset();
+  for (size_t i = 0; i < std::size(pools_); ++i) {
+    pools_[i].Reset();
   }
 }
 
@@ -554,11 +554,11 @@
 // in Pool.
 void AddressPoolManager::AssertThreadIsolatedLayout() {
   constexpr size_t last_pool_offset =
-      offsetof(AlignedPools, pools_) + sizeof(Pool) * (kNumPools - 1);
+      offsetof(AddressPoolManager, pools_) + sizeof(Pool) * (kNumPools - 1);
   constexpr size_t alloc_bitset_offset =
       last_pool_offset + offsetof(Pool, alloc_bitset_);
   static_assert(alloc_bitset_offset % PA_THREAD_ISOLATED_ALIGN_SZ == 0);
-  static_assert(sizeof(AlignedPools) % PA_THREAD_ISOLATED_ALIGN_SZ == 0);
+  static_assert(sizeof(AddressPoolManager) % PA_THREAD_ISOLATED_ALIGN_SZ == 0);
 }
 #endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
 
diff --git a/base/allocator/partition_allocator/address_pool_manager.h b/base/allocator/partition_allocator/address_pool_manager.h
index 9791158..b7105883 100644
--- a/base/allocator/partition_allocator/address_pool_manager.h
+++ b/base/allocator/partition_allocator/address_pool_manager.h
@@ -51,7 +51,8 @@
 // to judge whether a given address is in a pool that supports BackupRefPtr or
 // in a pool that doesn't. All PartitionAlloc allocations must be in either of
 // the pools.
-class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManager {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+    PA_THREAD_ISOLATED_ALIGN AddressPoolManager {
  public:
   static AddressPoolManager& GetInstance();
 
@@ -118,7 +119,6 @@
 
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
 
-  struct AlignedPools;
   class Pool {
    public:
     constexpr Pool() = default;
@@ -147,7 +147,7 @@
     // lock can be used without acquiring write-permission first (via
     // DumpStats()). So instead of protecting the whole variable, we only
     // protect the memory after the lock.
-    // See the alignment of `aligned_pools_` below.
+    // See the alignment of ` below.
     Lock lock_;
 
     // The bitset stores the allocation state of the address pool. 1 bit per
@@ -167,14 +167,13 @@
 #endif
 
 #if BUILDFLAG(ENABLE_THREAD_ISOLATION)
-    friend void AddressPoolManager::AssertThreadIsolatedLayout();
-    friend struct AlignedPools;
+    friend class AddressPoolManager;
 #endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
   };
 
   PA_ALWAYS_INLINE Pool* GetPool(pool_handle handle) {
     PA_DCHECK(kNullPoolHandle < handle && handle <= kNumPools);
-    return &aligned_pools_.pools_[handle - 1];
+    return &pools_[handle - 1];
   }
 
   // Gets the stats for the pool identified by `handle`, if
@@ -186,15 +185,11 @@
   // front of the pools so that the isolated one starts on a page boundary.
   // We also skip the Lock at the beginning of the pool since it needs to be
   // used in contexts where we didn't enable write access to the pool memory.
-  struct AlignedPools {
-    char pad_[PA_THREAD_ISOLATED_ARRAY_PAD_SZ_WITH_OFFSET(
-        Pool,
-        kNumPools,
-        offsetof(Pool, alloc_bitset_))] = {};
-    Pool pools_[kNumPools];
-    char pad_after_[PA_THREAD_ISOLATED_FILL_PAGE_SZ(
-        sizeof(Pool) - offsetof(Pool, alloc_bitset_))] = {};
-  } aligned_pools_ PA_THREAD_ISOLATED_ALIGN;
+  char pad_[PA_THREAD_ISOLATED_ARRAY_PAD_SZ_WITH_OFFSET(
+      Pool,
+      kNumPools,
+      offsetof(Pool, alloc_bitset_))] = {};
+  Pool pools_[kNumPools];
 
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
 
diff --git a/base/allocator/partition_allocator/reservation_offset_table.cc b/base/allocator/partition_allocator/reservation_offset_table.cc
index 6b0a421c..2d53cd2 100644
--- a/base/allocator/partition_allocator/reservation_offset_table.cc
+++ b/base/allocator/partition_allocator/reservation_offset_table.cc
@@ -9,9 +9,7 @@
 namespace partition_alloc::internal {
 
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
-ReservationOffsetTable::_PaddedReservationOffsetTables
-    ReservationOffsetTable::padded_reservation_offset_tables_
-        PA_THREAD_ISOLATED_ALIGN;
+ReservationOffsetTable ReservationOffsetTable::singleton_;
 #else
 ReservationOffsetTable::_ReservationOffsetTable
     ReservationOffsetTable::reservation_offset_table_;
diff --git a/base/allocator/partition_allocator/reservation_offset_table.h b/base/allocator/partition_allocator/reservation_offset_table.h
index 98f94912..73ea576 100644
--- a/base/allocator/partition_allocator/reservation_offset_table.h
+++ b/base/allocator/partition_allocator/reservation_offset_table.h
@@ -64,7 +64,8 @@
 //    to further determine which part of the super page is used by
 //    PartitionAlloc. This isn't a problem in 64-bit mode, where allocation
 //    granularity is kSuperPageSize.
-class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ReservationOffsetTable {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+    PA_THREAD_ISOLATED_ALIGN ReservationOffsetTable {
  public:
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
   // There is one reservation offset table per Pool in 64-bit mode.
@@ -99,15 +100,10 @@
   // If thread isolation support is enabled, we need to write-protect the tables
   // of the thread isolated pool. For this, we need to pad the tables so that
   // the thread isolated ones start on a page boundary.
-  struct _PaddedReservationOffsetTables {
-    char pad_[PA_THREAD_ISOLATED_ARRAY_PAD_SZ(_ReservationOffsetTable,
-                                              kNumPools)] = {};
-    struct _ReservationOffsetTable tables[kNumPools];
-    char pad_after_[PA_THREAD_ISOLATED_FILL_PAGE_SZ(
-        sizeof(_ReservationOffsetTable))] = {};
-  };
-  static PA_CONSTINIT _PaddedReservationOffsetTables
-      padded_reservation_offset_tables_ PA_THREAD_ISOLATED_ALIGN;
+  char pad_[PA_THREAD_ISOLATED_ARRAY_PAD_SZ(_ReservationOffsetTable,
+                                            kNumPools)] = {};
+  struct _ReservationOffsetTable tables[kNumPools];
+  static PA_CONSTINIT ReservationOffsetTable singleton_;
 #else
   // A single table for the entire 32-bit address space.
   static PA_CONSTINIT struct _ReservationOffsetTable reservation_offset_table_;
@@ -117,9 +113,7 @@
 #if BUILDFLAG(HAS_64_BIT_POINTERS)
 PA_ALWAYS_INLINE uint16_t* GetReservationOffsetTable(pool_handle handle) {
   PA_DCHECK(kNullPoolHandle < handle && handle <= kNumPools);
-  return ReservationOffsetTable::padded_reservation_offset_tables_
-      .tables[handle - 1]
-      .offsets;
+  return ReservationOffsetTable::singleton_.tables[handle - 1].offsets;
 }
 
 PA_ALWAYS_INLINE const uint16_t* GetReservationOffsetTableEnd(
diff --git a/base/allocator/partition_allocator/thread_isolation/pkey_unittest.cc b/base/allocator/partition_allocator/thread_isolation/pkey_unittest.cc
index 3e695bf5..1fb4d7c0e 100644
--- a/base/allocator/partition_allocator/thread_isolation/pkey_unittest.cc
+++ b/base/allocator/partition_allocator/thread_isolation/pkey_unittest.cc
@@ -30,14 +30,13 @@
 
 namespace partition_alloc::internal {
 
-struct IsolatedGlobals {
+struct PA_THREAD_ISOLATED_ALIGN IsolatedGlobals {
   int pkey = kInvalidPkey;
-  void* isolatedStack;
+  void* stack;
   partition_alloc::internal::base::NoDestructor<
       partition_alloc::PartitionAllocator>
       allocator{};
-  partition_alloc::ThreadSafePartitionRoot* allocatorRoot;
-} isolatedGlobals PA_THREAD_ISOLATED_ALIGN;
+} isolated_globals;
 
 int ProtFromSegmentFlags(ElfW(Word) flags) {
   int prot = 0;
@@ -67,12 +66,12 @@
     }
     uintptr_t start = info->dlpi_addr + phdr->p_vaddr;
     uintptr_t end = start + phdr->p_memsz;
-    uintptr_t startPage = RoundDownToSystemPage(start);
-    uintptr_t endPage = RoundUpToSystemPage(end);
-    uintptr_t size = endPage - startPage;
-    PA_PCHECK(PkeyMprotect(reinterpret_cast<void*>(startPage), size,
+    uintptr_t start_page = RoundDownToSystemPage(start);
+    uintptr_t end_page = RoundUpToSystemPage(end);
+    uintptr_t size = end_page - start_page;
+    PA_PCHECK(PkeyMprotect(reinterpret_cast<void*>(start_page), size,
                            ProtFromSegmentFlags(phdr->p_flags),
-                           isolatedGlobals.pkey) == 0);
+                           isolated_globals.pkey) == 0);
   }
   return 0;
 }
@@ -82,19 +81,18 @@
   static void PkeyProtectMemory() {
     PA_PCHECK(dl_iterate_phdr(ProtectROSegments, nullptr) == 0);
 
-    PA_PCHECK(PkeyMprotect(&isolatedGlobals, sizeof(isolatedGlobals),
-                           PROT_READ | PROT_WRITE, isolatedGlobals.pkey) == 0);
+    PA_PCHECK(PkeyMprotect(&isolated_globals, sizeof(isolated_globals),
+                           PROT_READ | PROT_WRITE, isolated_globals.pkey) == 0);
 
-    PA_PCHECK(PkeyMprotect(isolatedGlobals.isolatedStack,
-                           kIsolatedThreadStackSize, PROT_READ | PROT_WRITE,
-                           isolatedGlobals.pkey) == 0);
+    PA_PCHECK(PkeyMprotect(isolated_globals.stack, kIsolatedThreadStackSize,
+                           PROT_READ | PROT_WRITE, isolated_globals.pkey) == 0);
   }
 
   static void InitializeIsolatedThread() {
-    isolatedGlobals.isolatedStack =
+    isolated_globals.stack =
         mmap(nullptr, kIsolatedThreadStackSize, PROT_READ | PROT_WRITE,
              MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK, -1, 0);
-    PA_PCHECK(isolatedGlobals.isolatedStack != MAP_FAILED);
+    PA_PCHECK(isolated_globals.stack != MAP_FAILED);
 
     PkeyProtectMemory();
   }
@@ -102,7 +100,7 @@
   void SetUp() override {
     // SetUp only once, but we can't do it in SetUpTestSuite since that runs
     // before other PartitionAlloc initialization happened.
-    if (isolatedGlobals.pkey != kInvalidPkey) {
+    if (isolated_globals.pkey != kInvalidPkey) {
       return;
     }
 
@@ -110,14 +108,13 @@
     if (pkey == -1) {
       return;
     }
-    isolatedGlobals.pkey = pkey;
+    isolated_globals.pkey = pkey;
 
-    isolatedGlobals.allocator->init(PartitionOptions{
+    isolated_globals.allocator->init(PartitionOptions{
         .aligned_alloc = PartitionOptions::AlignedAlloc::kAllowed,
         .cookie = PartitionOptions::Cookie::kAllowed,
-        .thread_isolation = ThreadIsolationOption(isolatedGlobals.pkey),
+        .thread_isolation = ThreadIsolationOption(isolated_globals.pkey),
     });
-    isolatedGlobals.allocatorRoot = isolatedGlobals.allocator->root();
 
     InitializeIsolatedThread();
 
@@ -125,14 +122,14 @@
   }
 
   static void TearDownTestSuite() {
-    if (isolatedGlobals.pkey == kInvalidPkey) {
+    if (isolated_globals.pkey == kInvalidPkey) {
       return;
     }
-    PA_PCHECK(PkeyMprotect(&isolatedGlobals, sizeof(isolatedGlobals),
+    PA_PCHECK(PkeyMprotect(&isolated_globals, sizeof(isolated_globals),
                            PROT_READ | PROT_WRITE, kDefaultPkey) == 0);
-    isolatedGlobals.pkey = kDefaultPkey;
+    isolated_globals.pkey = kDefaultPkey;
     InitializeIsolatedThread();
-    PkeyFree(isolatedGlobals.pkey);
+    PkeyFree(isolated_globals.pkey);
   }
 };
 
@@ -141,12 +138,12 @@
 // In the final use, we'll likely allow at least read access to the default
 // pkey.
 ISOLATED_FUNCTION uint64_t IsolatedAllocFree(void* arg) {
-  char* buf = (char*)isolatedGlobals.allocatorRoot->AllocWithFlagsNoHooks(
+  char* buf = (char*)isolated_globals.allocator->root()->AllocWithFlagsNoHooks(
       0, 1024, partition_alloc::PartitionPageSize());
   if (!buf) {
     return 0xffffffffffffffffllu;
   }
-  isolatedGlobals.allocatorRoot->FreeNoHooks(buf);
+  isolated_globals.allocator->root()->FreeNoHooks(buf);
 
   return kTestReturnValue;
 }
@@ -159,14 +156,14 @@
 // order to do this, we need to tag all global read-only memory with our pkey as
 // well as switch to a pkey-tagged stack.
 TEST_F(PkeyTest, AllocWithoutDefaultPkey) {
-  if (isolatedGlobals.pkey == kInvalidPkey) {
+  if (isolated_globals.pkey == kInvalidPkey) {
     return;
   }
 
   uint64_t ret;
   uint32_t pkru_value = 0;
   for (int pkey = 0; pkey < kNumPkey; pkey++) {
-    if (pkey != isolatedGlobals.pkey) {
+    if (pkey != isolated_globals.pkey) {
       pkru_value |= (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE) << (2 * pkey);
     }
   }
@@ -245,7 +242,7 @@
 
       : "=r"(ret)
       : "a"(pkru_value), "c"(0), "d"(0),
-        "r"(reinterpret_cast<uintptr_t>(isolatedGlobals.isolatedStack) +
+        "r"(reinterpret_cast<uintptr_t>(isolated_globals.stack) +
             kIsolatedThreadStackSize - 8)
       : "memory", "cc", "r8", "r9", "r10", "r11", "xmm0", "xmm1", "xmm2",
         "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10",
@@ -262,7 +259,7 @@
 };
 
 TEST_F(PkeyTest, DumpPkeyPoolStats) {
-  if (isolatedGlobals.pkey == kInvalidPkey) {
+  if (isolated_globals.pkey == kInvalidPkey) {
     return;
   }
 
diff --git a/base/allocator/partition_allocator/thread_isolation/thread_isolation.cc b/base/allocator/partition_allocator/thread_isolation/thread_isolation.cc
index 3df0ade..dfb836e 100644
--- a/base/allocator/partition_allocator/thread_isolation/thread_isolation.cc
+++ b/base/allocator/partition_allocator/thread_isolation/thread_isolation.cc
@@ -18,8 +18,7 @@
 namespace partition_alloc::internal {
 
 #if BUILDFLAG(PA_DCHECK_IS_ON)
-ThreadIsolationSettings ThreadIsolationSettings::settings
-    PA_THREAD_ISOLATED_ALIGN;
+ThreadIsolationSettings ThreadIsolationSettings::settings;
 #endif
 
 void WriteProtectThreadIsolatedMemory(ThreadIsolationOption thread_isolation,
diff --git a/base/allocator/partition_allocator/thread_isolation/thread_isolation.h b/base/allocator/partition_allocator/thread_isolation/thread_isolation.h
index 79c575c..7c74e0a 100644
--- a/base/allocator/partition_allocator/thread_isolation/thread_isolation.h
+++ b/base/allocator/partition_allocator/thread_isolation/thread_isolation.h
@@ -54,10 +54,9 @@
 
 #if BUILDFLAG(PA_DCHECK_IS_ON)
 
-struct ThreadIsolationSettings {
+struct PA_THREAD_ISOLATED_ALIGN ThreadIsolationSettings {
   bool enabled = false;
-  char pad_[PA_THREAD_ISOLATED_FILL_PAGE_SZ(sizeof(enabled))] = {};
-  static ThreadIsolationSettings settings PA_THREAD_ISOLATED_ALIGN PA_CONSTINIT;
+  static ThreadIsolationSettings settings PA_CONSTINIT;
 };
 
 #if BUILDFLAG(ENABLE_PKEYS)
diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc
index f2dca14..fca4b535 100644
--- a/base/message_loop/message_pump_glib.cc
+++ b/base/message_loop/message_pump_glib.cc
@@ -252,7 +252,7 @@
 //        this case.
 
 struct WorkSource : public GSource {
-  raw_ptr<MessagePumpGlib, DanglingUntriaged> pump;
+  raw_ptr<MessagePumpGlib> pump;
 };
 
 gboolean WorkSourcePrepare(GSource* source, gint* timeout_ms) {
@@ -276,12 +276,20 @@
   return TRUE;
 }
 
+void WorkSourceFinalize(GSource* source) {
+  // Since the WorkSource object memory is managed by glib, WorkSource implicit
+  // destructor is never called, and thus WorkSource's raw_ptr never release
+  // its internal reference on the pump pointer. This leads to adding pressure
+  // to the BRP quarantine.
+  static_cast<WorkSource*>(source)->pump = nullptr;
+}
+
 // I wish these could be const, but g_source_new wants non-const.
 GSourceFuncs g_work_source_funcs = {WorkSourcePrepare, WorkSourceCheck,
-                                    WorkSourceDispatch, nullptr};
+                                    WorkSourceDispatch, WorkSourceFinalize};
 
 struct ObserverSource : public GSource {
-  raw_ptr<MessagePumpGlib, DanglingUntriaged> pump;
+  raw_ptr<MessagePumpGlib> pump;
 };
 
 gboolean ObserverPrepare(GSource* gsource, gint* timeout_ms) {
@@ -297,8 +305,13 @@
   return source->pump->HandleObserverCheck();
 }
 
+void ObserverFinalize(GSource* source) {
+  // Read the comment in `WorkSourceFinalize`, the issue is exactly the same.
+  static_cast<ObserverSource*>(source)->pump = nullptr;
+}
+
 GSourceFuncs g_observer_funcs = {ObserverPrepare, ObserverCheck, nullptr,
-                                 nullptr};
+                                 ObserverFinalize};
 
 struct FdWatchSource : public GSource {
   raw_ptr<MessagePumpGlib> pump;
@@ -323,8 +336,16 @@
   return TRUE;
 }
 
+void FdWatchSourcFinalize(GSource* gsource) {
+  // Read the comment in `WorkSourceFinalize`, the issue is exactly the same.
+  auto* source = static_cast<FdWatchSource*>(gsource);
+  source->pump = nullptr;
+  source->controller = nullptr;
+}
+
 GSourceFuncs g_fd_watch_source_funcs = {
-    FdWatchSourcePrepare, FdWatchSourceCheck, FdWatchSourceDispatch, nullptr};
+    FdWatchSourcePrepare, FdWatchSourceCheck, FdWatchSourceDispatch,
+    FdWatchSourcFinalize};
 
 }  // namespace
 
diff --git a/build/config/rust.gni b/build/config/rust.gni
index a36e1fd8..0629d96 100644
--- a/build/config/rust.gni
+++ b/build/config/rust.gni
@@ -19,9 +19,9 @@
   # should not be removed.
   # TODO(crbug.com/1386212): Mac
   # TODO(crbug.com/1271215): Windows
-  # TODO(crbug.com/1229419): is_official_build
   enable_rust =
-      !is_mac && !is_ios && !is_win && !is_official_build && build_with_chromium
+      !is_mac && !is_ios && !is_win &&
+      (!is_official_build || is_linux || is_android) && build_with_chromium
 
   # As we incrementally enable Rust on mainstream builders, we want to enable
   # the toolchain (by switching 'enable_rust' to true) while still disabling
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index f4bec63..4f75391 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -1359,49 +1359,41 @@
   float total_predicted_delta = 0;
   bool had_gesture_scrolls = false;
 
+  // This handles cases when we have multiple scroll events. Events for dropped
+  // frames are reported by the reporter for next presented frame which could
+  // lead to having multiple scroll events.
   base::TimeTicks input_generation_ts = base::TimeTicks::Max();
   base::TimeTicks last_coalesced_ts = base::TimeTicks::Min();
   for (const auto& event : events_metrics_) {
     TRACE_EVENT("input", "GestureType", "gesture", event->type());
+    const auto* scroll_update = event->AsScrollUpdate();
+    if (!scroll_update) {
+      continue;
+    }
+
+    total_predicted_delta += scroll_update->predicted_delta();
+    had_gesture_scrolls = true;
+    input_generation_ts = std::min(
+        input_generation_ts, event->GetDispatchStageTimestamp(
+                                 EventMetrics::DispatchStage::kGenerated));
+    last_coalesced_ts =
+        std::max(last_coalesced_ts, scroll_update->last_timestamp());
+
     switch (event->type()) {
-      // TODO(kartarsingh): Clean up common logic here. Related discussion:
-      // https://crrev.com/c/4430615/19/cc/metrics/compositor_frame_reporter.cc#1393
-      case EventMetrics::EventType::kGestureScrollUpdate:
-        normal_input_count += event->AsScrollUpdate()->coalesced_event_count();
-        total_predicted_delta += event->AsScrollUpdate()->predicted_delta();
-        had_gesture_scrolls = true;
-        input_generation_ts = std::min(
-            input_generation_ts, event->GetDispatchStageTimestamp(
-                                     EventMetrics::DispatchStage::kGenerated));
-        last_coalesced_ts = std::max(last_coalesced_ts,
-                                     event->AsScrollUpdate()->last_timestamp());
-        break;
       case EventMetrics::EventType::kFirstGestureScrollUpdate:
-        normal_input_count += event->AsScrollUpdate()->coalesced_event_count();
-        total_predicted_delta += event->AsScrollUpdate()->predicted_delta();
         if (global_trackers_.predictor_jank_tracker) {
           global_trackers_.predictor_jank_tracker
               ->ResetCurrentScrollReporting();
         }
-        had_gesture_scrolls = true;
-        input_generation_ts = std::min(
-            input_generation_ts, event->GetDispatchStageTimestamp(
-                                     EventMetrics::DispatchStage::kGenerated));
-        last_coalesced_ts = std::max(last_coalesced_ts,
-                                     event->AsScrollUpdate()->last_timestamp());
+        ABSL_FALLTHROUGH_INTENDED;
+      case EventMetrics::EventType::kGestureScrollUpdate:
+        normal_input_count += scroll_update->coalesced_event_count();
         break;
       case EventMetrics::EventType::kInertialGestureScrollUpdate:
-        fling_input_count += event->AsScrollUpdate()->coalesced_event_count();
-        total_predicted_delta += event->AsScrollUpdate()->predicted_delta();
-        had_gesture_scrolls = true;
-        input_generation_ts = std::min(
-            input_generation_ts, event->GetDispatchStageTimestamp(
-                                     EventMetrics::DispatchStage::kGenerated));
-        last_coalesced_ts = std::max(last_coalesced_ts,
-                                     event->AsScrollUpdate()->last_timestamp());
+        fling_input_count += scroll_update->coalesced_event_count();
         break;
       default:
-        continue;
+        NOTREACHED();
     }
   }
   // To handle web test failures which causes an event to be coalesced with an
diff --git a/cc/metrics/event_metrics.h b/cc/metrics/event_metrics.h
index 480fe35..36afa6e 100644
--- a/cc/metrics/event_metrics.h
+++ b/cc/metrics/event_metrics.h
@@ -405,9 +405,9 @@
 
   float predicted_delta() const { return predicted_delta_; }
 
-  int32_t coalesced_event_count() { return coalesced_event_count_; }
+  int32_t coalesced_event_count() const { return coalesced_event_count_; }
 
-  absl::optional<TraceId> trace_id() { return trace_id_; }
+  absl::optional<TraceId> trace_id() const { return trace_id_; }
 
   void set_predicted_delta(float predicted_delta) {
     predicted_delta_ = predicted_delta;
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index d0c8e8f..b2d4650 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -38,7 +38,6 @@
   "java/res/drawable-hdpi/ic_dialer_not_found_red_40dp.png",
   "java/res/drawable-hdpi/ic_download_pause.png",
   "java/res/drawable-hdpi/ic_download_pending.png",
-  "java/res/drawable-hdpi/ic_drive_site_white_24dp.png",
   "java/res/drawable-hdpi/ic_email_googblue_36dp.png",
   "java/res/drawable-hdpi/ic_error_grey800_24dp_filled.png",
   "java/res/drawable-hdpi/ic_error_outline_red_24dp.png",
@@ -108,7 +107,6 @@
   "java/res/drawable-mdpi/ic_dialer_not_found_red_40dp.png",
   "java/res/drawable-mdpi/ic_download_pause.png",
   "java/res/drawable-mdpi/ic_download_pending.png",
-  "java/res/drawable-mdpi/ic_drive_site_white_24dp.png",
   "java/res/drawable-mdpi/ic_email_googblue_36dp.png",
   "java/res/drawable-mdpi/ic_error_grey800_24dp_filled.png",
   "java/res/drawable-mdpi/ic_error_outline_red_24dp.png",
@@ -178,7 +176,6 @@
   "java/res/drawable-xhdpi/ic_dialer_not_found_red_40dp.png",
   "java/res/drawable-xhdpi/ic_download_pause.png",
   "java/res/drawable-xhdpi/ic_download_pending.png",
-  "java/res/drawable-xhdpi/ic_drive_site_white_24dp.png",
   "java/res/drawable-xhdpi/ic_email_googblue_36dp.png",
   "java/res/drawable-xhdpi/ic_error_grey800_24dp_filled.png",
   "java/res/drawable-xhdpi/ic_error_outline_red_24dp.png",
@@ -242,7 +239,6 @@
   "java/res/drawable-xxhdpi/ic_dialer_not_found_red_40dp.png",
   "java/res/drawable-xxhdpi/ic_download_pause.png",
   "java/res/drawable-xxhdpi/ic_download_pending.png",
-  "java/res/drawable-xxhdpi/ic_drive_site_white_24dp.png",
   "java/res/drawable-xxhdpi/ic_email_googblue_36dp.png",
   "java/res/drawable-xxhdpi/ic_error_grey800_24dp_filled.png",
   "java/res/drawable-xxhdpi/ic_error_outline_red_24dp.png",
@@ -304,7 +300,6 @@
   "java/res/drawable-xxxhdpi/ic_devices_16dp.png",
   "java/res/drawable-xxxhdpi/ic_dialer_icon_blue_40dp.png",
   "java/res/drawable-xxxhdpi/ic_dialer_not_found_red_40dp.png",
-  "java/res/drawable-xxxhdpi/ic_drive_site_white_24dp.png",
   "java/res/drawable-xxxhdpi/ic_email_googblue_36dp.png",
   "java/res/drawable-xxxhdpi/ic_error_grey800_24dp_filled.png",
   "java/res/drawable-xxxhdpi/ic_error_outline_red_24dp.png",
@@ -650,7 +645,6 @@
   "java/res/values/values.xml",
   "java/res/xml/about_chrome_preferences.xml",
   "java/res/xml/account_management_preferences.xml",
-  "java/res/xml/account_management_preferences_legacy.xml",
   "java/res/xml/ad_services_config.xml",
   "java/res/xml/bookmark_widget_info.xml",
   "java/res/xml/clear_browsing_data_preferences_tab.xml",
diff --git a/chrome/android/java/res/drawable-hdpi/ic_drive_site_white_24dp.png b/chrome/android/java/res/drawable-hdpi/ic_drive_site_white_24dp.png
deleted file mode 100644
index c5aea62..0000000
--- a/chrome/android/java/res/drawable-hdpi/ic_drive_site_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/ic_drive_site_white_24dp.png b/chrome/android/java/res/drawable-mdpi/ic_drive_site_white_24dp.png
deleted file mode 100644
index f877c7c..0000000
--- a/chrome/android/java/res/drawable-mdpi/ic_drive_site_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/ic_drive_site_white_24dp.png b/chrome/android/java/res/drawable-xhdpi/ic_drive_site_white_24dp.png
deleted file mode 100644
index 1da6d397..0000000
--- a/chrome/android/java/res/drawable-xhdpi/ic_drive_site_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/ic_drive_site_white_24dp.png b/chrome/android/java/res/drawable-xxhdpi/ic_drive_site_white_24dp.png
deleted file mode 100644
index 06e345df9..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/ic_drive_site_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/ic_drive_site_white_24dp.png b/chrome/android/java/res/drawable-xxxhdpi/ic_drive_site_white_24dp.png
deleted file mode 100644
index 0cb4f82e..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/ic_drive_site_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/xml/account_management_preferences.xml b/chrome/android/java/res/xml/account_management_preferences.xml
index 1d1d334..74049ef 100644
--- a/chrome/android/java/res/xml/account_management_preferences.xml
+++ b/chrome/android/java/res/xml/account_management_preferences.xml
@@ -5,14 +5,13 @@
 found in the LICENSE file.
 -->
 
-<!--Used only when ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS is enabled-->
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
 
   <org.chromium.components.browser_ui.settings.TextMessagePreference
       android:key="parent_account_category"
-      tools:summary="@string/account_management_two_parent_names"/>
+      tools:summary="@string/account_management_header_two_parent_names"/>
 
   <PreferenceCategory
       android:key="accounts_category"
diff --git a/chrome/android/java/res/xml/account_management_preferences_legacy.xml b/chrome/android/java/res/xml/account_management_preferences_legacy.xml
deleted file mode 100644
index 5c55904..0000000
--- a/chrome/android/java/res/xml/account_management_preferences_legacy.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2015 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<PreferenceScreen
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <PreferenceCategory
-        android:key="accounts_category"
-        android:title="@string/account_management_title"/>
-
-    <PreferenceCategory
-        android:key="parental_settings"
-        android:title="@string/account_management_parental_settings"/>
-
-    <org.chromium.components.browser_ui.settings.TextMessagePreference
-        android:key="parent_accounts"
-        tools:summary="@string/account_management_two_parent_names"/>
-
-    <Preference
-        android:key="child_content"
-        android:selectable="false"
-        android:title="@string/account_management_child_content_title"/>
-
-    <Preference
-        android:layout="@layout/divider_preference"/>
-
-    <Preference
-        android:key="sign_out"
-        android:title="@string/account_management_sign_out"/>
-
-    <Preference
-        android:key="sign_out_divider"
-        android:layout="@layout/divider_preference"/>
-
-</PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA
index 8dc897c..b597ffd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA
@@ -1,3 +1,3 @@
 monorail {
-  component: "UI>Browser>Autofill>UI"
+  component: "UI>Browser>Autofill"
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
index 296c458..8b303a8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
@@ -7,8 +7,6 @@
 import android.accounts.Account;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.UserManager;
 
@@ -20,9 +18,7 @@
 import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceScreen;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileAccountManagementMetrics;
@@ -34,7 +30,6 @@
 import org.chromium.chrome.browser.signin.services.SigninManager;
 import org.chromium.chrome.browser.signin.services.SigninManager.SignInStateObserver;
 import org.chromium.chrome.browser.signin.services.SigninMetricsUtils;
-import org.chromium.chrome.browser.superviseduser.FilteringBehavior;
 import org.chromium.chrome.browser.sync.SyncService;
 import org.chromium.chrome.browser.ui.signin.SignOutDialogCoordinator;
 import org.chromium.chrome.browser.ui.signin.SignOutDialogCoordinator.Listener;
@@ -42,7 +37,6 @@
 import org.chromium.components.browser_ui.settings.ChromeBasePreference;
 import org.chromium.components.browser_ui.settings.CustomDividerFragment;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
-import org.chromium.components.browser_ui.styles.SemanticColorUtils;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
@@ -173,18 +167,9 @@
                 mProfileDataCache.getProfileDataOrDefault(mSignedInAccountName);
         getActivity().setTitle(SyncSettingsUtils.getDisplayableFullNameOrEmailWithPreference(
                 profileData, getContext(), SyncSettingsUtils.TitlePreference.FULL_NAME));
-
-        if (ChromeFeatureList.isEnabled(
-                    ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS)) {
-            addPreferencesFromResource(R.xml.account_management_preferences);
-            configureSignOutSwitch();
-            configureChildAccountPreferences();
-        } else {
-            addPreferencesFromResource(R.xml.account_management_preferences_legacy);
-            configureSignOutSwitch();
-            configureChildAccountPreferencesLegacy();
-        }
-
+        addPreferencesFromResource(R.xml.account_management_preferences);
+        configureSignOutSwitch();
+        configureChildAccountPreferences();
         AccountManagerFacadeProvider.getInstance().getAccounts().then(this::updateAccountsList);
     }
 
@@ -266,52 +251,6 @@
         }
     }
 
-    private void configureChildAccountPreferencesLegacy() {
-        Preference parentAccounts = findPreference(PREF_PARENT_ACCOUNTS);
-        Preference childContent = findPreference(PREF_CHILD_CONTENT);
-        if (mProfile.isChild()) {
-            PrefService prefService = UserPrefs.get(mProfile);
-
-            String firstParent = prefService.getString(Pref.SUPERVISED_USER_CUSTODIAN_EMAIL);
-            String secondParent =
-                    prefService.getString(Pref.SUPERVISED_USER_SECOND_CUSTODIAN_EMAIL);
-            String parentText;
-
-            if (!secondParent.isEmpty()) {
-                parentText = getString(
-                        R.string.account_management_two_parent_names, firstParent, secondParent);
-            } else if (!firstParent.isEmpty()) {
-                parentText = getString(R.string.account_management_one_parent_name, firstParent);
-            } else {
-                parentText = getString(R.string.account_management_no_parental_data);
-            }
-            parentAccounts.setSummary(parentText);
-
-            final int childContentSummary;
-            int defaultBehavior =
-                    prefService.getInteger(Pref.DEFAULT_SUPERVISED_USER_FILTERING_BEHAVIOR);
-            if (defaultBehavior == FilteringBehavior.BLOCK) {
-                childContentSummary = R.string.account_management_child_content_approved;
-            } else if (prefService.getBoolean(Pref.SUPERVISED_USER_SAFE_SITES)) {
-                childContentSummary = R.string.account_management_child_content_filter_mature;
-            } else {
-                childContentSummary = R.string.account_management_child_content_all;
-            }
-            childContent.setSummary(childContentSummary);
-
-            Drawable newIcon = ApiCompatibilityUtils.getDrawable(
-                    getResources(), R.drawable.ic_drive_site_white_24dp);
-            newIcon.mutate().setColorFilter(
-                    SemanticColorUtils.getDefaultIconColor(getContext()), PorterDuff.Mode.SRC_IN);
-            childContent.setIcon(newIcon);
-        } else {
-            PreferenceScreen prefScreen = getPreferenceScreen();
-            prefScreen.removePreference(findPreference(PREF_PARENTAL_SETTINGS));
-            prefScreen.removePreference(parentAccounts);
-            prefScreen.removePreference(childContent);
-        }
-    }
-
     private void updateAccountsList(List<Account> accounts) {
         // This method is called asynchronously on accounts fetched from AccountManagerFacade.
         // Make sure the fragment is alive before updating preferences.
@@ -339,13 +278,7 @@
                 accountsCategory.addPreference(createAccountPreference(account));
             }
         }
-
-        if (!mProfile.isChild()
-                || ChromeFeatureList.isEnabled(
-                        ChromeFeatureList
-                                .ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS)) {
-            accountsCategory.addPreference(createAddAccountPreference());
-        }
+        accountsCategory.addPreference(createAddAccountPreference());
     }
 
     private Preference createAccountPreference(Account account) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java
index 97ae09b..205616bf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java
@@ -29,6 +29,7 @@
 import org.chromium.base.CollectionUtil;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
@@ -195,6 +196,7 @@
     @Test
     @LargeTest
     @Feature({"RenderTest"})
+    @DisabledTest(message = "crbug.com/1407312")
     public void testRenderSearchHistoryLinkSignedInUnknownNonGoogleDSE() throws IOException {
         mSigninTestRule.addTestAccountThenSigninAndEnableSync();
         setSyncable(false);
@@ -207,8 +209,6 @@
         View view = mSettingsActivityTestRule.getActivity()
                             .findViewById(android.R.id.content)
                             .getRootView();
-        // Looking for "Frees up less than 1 MB" but could conceivably free up more space.
-        // See crbug.com/1407312
         waitForView(withText("Frees up"));
         mRenderTestRule.render(view, "clear_browsing_data_basic_shl_unknown_signed_in");
     }
@@ -216,6 +216,7 @@
     @Test
     @LargeTest
     @Feature({"RenderTest"})
+    @DisabledTest(message = "crbug.com/1407312")
     public void testRenderSearchHistoryLinkSignedOutKnownNonGoogleDSE() throws IOException {
         configureMockSearchEngine();
         Mockito.doReturn(false).when(mMockTemplateUrlService).isDefaultSearchEngineGoogle();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java
index 89584aa..dd48e375 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java
@@ -103,6 +103,7 @@
         ChromeSurveyController.resetMessageShownForTesting();
     }
 
+    @DisabledTest(message = "https:://crbug.com/1447519")
     @Test
     @MediumTest
     public void testMessagePrimaryButtonClicked() throws TimeoutException, ExecutionException {
@@ -120,7 +121,7 @@
                 mTestSurveyController.showSurveyCallbackHelper.getCallCount());
     }
 
-    @DisabledTest(message = "https:://crbug.com/1447085")
+    @DisabledTest(message = "https:://crbug.com/1447519")
     @Test
     @MediumTest
     public void testMessageDismissed() throws TimeoutException, ExecutionException {
@@ -130,7 +131,7 @@
                 () -> mMessageDispatcher.dismissMessage(message, DismissReason.GESTURE));
     }
 
-    @DisabledTest(message = "https:://crbug.com/1447085")
+    @DisabledTest(message = "https:://crbug.com/1447519")
     @Test
     @MediumTest
     public void testNoMessageInNewTab() throws InterruptedException, ExecutionException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
index 969a1fd0..f772a95 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
@@ -90,10 +90,8 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @DisableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS,
-            ChromeFeatureList.HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL})
-    public void
-    testAccountManagementFragmentView() throws Exception {
+    @DisableFeatures(ChromeFeatureList.HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL)
+    public void testAccountManagementFragmentView() throws Exception {
         mSigninTestRule.addTestAccountThenSigninAndEnableSync();
         mSettingsActivityTestRule.startSettingsActivity();
         View view = mSettingsActivityTestRule.getFragment().getView();
@@ -104,19 +102,6 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @EnableFeatures(ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS)
-    public void testAccountManagementFragmentViewWithAddEduAccountEnabled() throws Exception {
-        mSigninTestRule.addTestAccountThenSigninAndEnableSync();
-        mSettingsActivityTestRule.startSettingsActivity();
-        View view = mSettingsActivityTestRule.getFragment().getView();
-        onViewWaiting(allOf(is(view), isDisplayed()));
-        mRenderTestRule.render(
-                view, "account_management_fragment_view_with_add_account_for_supervised_users");
-    }
-
-    @Test
-    @MediumTest
-    @Feature("RenderTest")
     @EnableFeatures(ChromeFeatureList.HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL)
     public void testAccountManagementFragmentViewWithHideNonDisplayableAccountEmailEnabled()
             throws Exception {
@@ -142,26 +127,6 @@
 
     @Test
     @MediumTest
-    @Feature("RenderTest")
-    @DisableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS})
-    public void testAccountManagementViewForChildAccount() throws Exception {
-        mSigninTestRule.addAccountAndWaitForSeeding(CHILD_ACCOUNT_NAME);
-        final Profile profile = TestThreadUtils.runOnUiThreadBlockingNoException(
-                Profile::getLastUsedRegularProfile);
-        CriteriaHelper.pollUiThread(profile::isChild);
-        mSettingsActivityTestRule.startSettingsActivity();
-        CriteriaHelper.pollUiThread(() -> {
-            return mSettingsActivityTestRule.getFragment()
-                    .getProfileDataCacheForTesting()
-                    .hasProfileDataForTesting(CHILD_ACCOUNT_NAME);
-        });
-        View view = mSettingsActivityTestRule.getFragment().getView();
-        onViewWaiting(allOf(is(view), isDisplayed()));
-        mRenderTestRule.render(view, "account_management_fragment_for_child_account");
-    }
-
-    @Test
-    @MediumTest
     @EnableFeatures({ChromeFeatureList.HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL})
     public void testAccountManagementViewForChildAccountWithNonDisplayableAccountEmail()
             throws Exception {
@@ -215,9 +180,7 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @EnableFeatures(ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS)
-    public void testAccountManagementViewForChildAccountWithAddEduAccountEnabled()
-            throws Exception {
+    public void testAccountManagementViewForChildAccount() throws Exception {
         mSigninTestRule.addAccountAndWaitForSeeding(CHILD_ACCOUNT_NAME);
         final Profile profile = TestThreadUtils.runOnUiThreadBlockingNoException(
                 Profile::getLastUsedRegularProfile);
@@ -237,35 +200,8 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @DisableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS})
     public void testAccountManagementViewForChildAccountWithSecondaryEduAccount() throws Exception {
         mSigninTestRule.addAccount(CHILD_ACCOUNT_NAME);
-        // The code under test doesn't care what account type this is, though in practice only
-        // EDU accounts are supported on devices where the primary account is a child account.
-        mSigninTestRule.addAccount("account@school.com");
-        mSigninTestRule.waitForSeeding();
-        final Profile profile = TestThreadUtils.runOnUiThreadBlockingNoException(
-                Profile::getLastUsedRegularProfile);
-        CriteriaHelper.pollUiThread(profile::isChild);
-        mSettingsActivityTestRule.startSettingsActivity();
-        CriteriaHelper.pollUiThread(() -> {
-            return mSettingsActivityTestRule.getFragment()
-                    .getProfileDataCacheForTesting()
-                    .hasProfileDataForTesting(CHILD_ACCOUNT_NAME);
-        });
-        View view = mSettingsActivityTestRule.getFragment().getView();
-        onViewWaiting(allOf(is(view), isDisplayed()));
-        mRenderTestRule.render(view, "account_management_fragment_for_child_and_edu_accounts");
-    }
-
-    @Test
-    @MediumTest
-    @Feature("RenderTest")
-    @EnableFeatures(ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS)
-    public void
-    testAccountManagementViewForChildAccountWithSecondaryEduAccountAndAddEduAccountEnabled()
-            throws Exception {
-        mSigninTestRule.addAccount(CHILD_ACCOUNT_NAME);
         mSigninTestRule.addAccount("account@school.com");
         mSigninTestRule.waitForSeeding();
         final Profile profile = TestThreadUtils.runOnUiThreadBlockingNoException(
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 3d87f9f1..743161e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4598,13 +4598,6 @@
     {"cormorant", flag_descriptions::kCormorantName,
      flag_descriptions::kCormorantDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(feed::kCormorant)},
-    {"add-edu-account-for-supervised-users",
-     flag_descriptions::kAddEduAccountFromAccountSettingsForSupervisedUsersName,
-     flag_descriptions::
-         kAddEduAccountFromAccountSettingsForSupervisedUsersDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(
-         chrome::android::kAddEduAccountFromAccountSettingsForSupervisedUsers)},
     {"hide-non-displayable-account-email",
      flag_descriptions::kHideNonDisplayableAccountEmailName,
      flag_descriptions::kHideNonDisplayableAccountEmailDescription, kOsAndroid,
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 27cf6b3..b20e2e2 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -738,6 +738,8 @@
     "browser_accelerator_configuration.h",
     "browser_context_keyed_service_factories.cc",
     "browser_context_keyed_service_factories.h",
+    "bruschetta/bruschetta_download.cc",
+    "bruschetta/bruschetta_download.h",
     "bruschetta/bruschetta_download_client.cc",
     "bruschetta/bruschetta_download_client.h",
     "bruschetta/bruschetta_features.cc",
@@ -1194,6 +1196,8 @@
     "file_system_provider/notification_manager.h",
     "file_system_provider/notification_manager_interface.h",
     "file_system_provider/observer.h",
+    "file_system_provider/odfs_metrics.cc",
+    "file_system_provider/odfs_metrics.h",
     "file_system_provider/operation_request_manager.cc",
     "file_system_provider/operation_request_manager.h",
     "file_system_provider/operations/abort.cc",
@@ -5038,6 +5042,7 @@
     "borealis/infra/described_unittest.cc",
     "borealis/infra/transition_unittest.cc",
     "browser_accelerator_configuration_unittest.cc",
+    "bruschetta/bruschetta_download_unittest.cc",
     "bruschetta/bruschetta_installer_impl_unittest.cc",
     "bruschetta/bruschetta_launcher_unittest.cc",
     "bruschetta/bruschetta_mount_provider_unittest.cc",
diff --git a/chrome/browser/ash/bruschetta/bruschetta_download.cc b/chrome/browser/ash/bruschetta/bruschetta_download.cc
new file mode 100644
index 0000000..0ff5050
--- /dev/null
+++ b/chrome/browser/ash/bruschetta/bruschetta_download.cc
@@ -0,0 +1,153 @@
+// 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/bruschetta/bruschetta_download.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "chrome/browser/extensions/cws_info_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/storage_partition.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace bruschetta {
+
+const net::NetworkTrafficAnnotationTag kBruschettaTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("bruschetta_installer_download",
+                                        R"(
+      semantics {
+        sender: "Bruschetta VM Installer",
+        description: "Request sent to download firmware and VM image for "
+          "a Bruschetta VM, which allows the user to run the VM."
+        trigger: "User installing a Bruschetta VM"
+        internal {
+          contacts {
+            email: "clumptini+oncall@google.com"
+          }
+        }
+        user_data: {
+          type: ACCESS_TOKEN
+        }
+        data: "Request to download Bruschetta firmware and VM image. "
+          "Sends cookies associated with the source to authenticate the user."
+        destination: WEBSITE
+        last_reviewed: "2023-01-09"
+      }
+      policy {
+        cookies_allowed: YES
+        cookies_store: "user"
+        chrome_policy {
+          BruschettaVMConfiguration {
+            BruschettaVMConfiguration: "{}"
+          }
+        }
+      }
+    )");
+
+namespace {
+
+std::unique_ptr<base::ScopedTempDir> MakeTempDir() {
+  auto dir = std::make_unique<base::ScopedTempDir>();
+  CHECK(dir->CreateUniqueTempDir());
+  return dir;
+}
+
+// Calculates the sha256 hash of the file at `path` incrementally i.e. without
+// loading the entire thing into memory at once. Blocking.
+std::string Sha256File(const base::FilePath& path) {
+  base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+  if (!file.IsValid()) {
+    return "";
+  }
+
+  std::unique_ptr<crypto::SecureHash> ctx(
+      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+  const size_t kReadBufferSize = 4096;
+  char buffer[kReadBufferSize];
+  while (true) {
+    int count = file.ReadAtCurrentPos(buffer, kReadBufferSize);
+
+    // Treat EOF the same as any other error, stop reading and return the hash
+    // of what we read. If there was a disk error or something we'll end up with
+    // an invalid hash, same as if the file were truncated.
+    if (count <= 0) {
+      break;
+    }
+    ctx->Update(buffer, count);
+  }
+
+  char digest_bytes[crypto::kSHA256Length];
+  ctx->Finish(digest_bytes, crypto::kSHA256Length);
+
+  return base::HexEncode(digest_bytes, crypto::kSHA256Length);
+}
+
+}  // namespace
+
+std::string Sha256FileForTesting(const base::FilePath& path) {
+  return Sha256File(path);
+}
+
+std::unique_ptr<SimpleURLLoaderDownload> SimpleURLLoaderDownload::StartDownload(
+    Profile* profile,
+    GURL url,
+    base::OnceCallback<void(base::FilePath path, std::string sha256)>
+        callback) {
+  return base::WrapUnique(new SimpleURLLoaderDownload(profile, std::move(url),
+                                                      std::move(callback)));
+}
+
+SimpleURLLoaderDownload::SimpleURLLoaderDownload(
+    Profile* profile,
+    GURL url,
+    base::OnceCallback<void(base::FilePath path, std::string sha256)> callback)
+    : profile_(profile), url_(std::move(url)), callback_(std::move(callback)) {
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()}, base::BindOnce(&MakeTempDir),
+      base::BindOnce(&SimpleURLLoaderDownload::Download,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+SimpleURLLoaderDownload::~SimpleURLLoaderDownload() {
+  auto seq = base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
+  seq->DeleteSoon(FROM_HERE, std::move(scoped_temp_dir_));
+  if (post_deletion_closure_for_testing_) {
+    seq->PostTask(FROM_HERE, std::move(post_deletion_closure_for_testing_));
+  }
+}
+
+void SimpleURLLoaderDownload::Download(
+    std::unique_ptr<base::ScopedTempDir> dir) {
+  scoped_temp_dir_ = std::move(dir);
+  auto path = scoped_temp_dir_->GetPath().Append("download");
+  auto req = std::make_unique<network::ResourceRequest>();
+  req->url = url_;
+  loader_ = network::SimpleURLLoader::Create(std::move(req),
+                                             kBruschettaTrafficAnnotation);
+  auto factory = profile_->GetDefaultStoragePartition()
+                     ->GetURLLoaderFactoryForBrowserProcess();
+  loader_->DownloadToFile(factory.get(),
+                          base::BindOnce(&SimpleURLLoaderDownload::Finished,
+                                         weak_ptr_factory_.GetWeakPtr()),
+                          std::move(path));
+}
+
+void SimpleURLLoaderDownload::Finished(base::FilePath path) {
+  if (path.empty()) {
+    LOG(ERROR) << "Download failed";
+    std::move(callback_).Run(path, "");
+    return;
+  }
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()}, base::BindOnce(&Sha256File, path),
+      base::BindOnce(std::move(callback_), path));
+}
+
+}  // namespace bruschetta
diff --git a/chrome/browser/ash/bruschetta/bruschetta_download.h b/chrome/browser/ash/bruschetta/bruschetta_download.h
new file mode 100644
index 0000000..1cd562e
--- /dev/null
+++ b/chrome/browser/ash/bruschetta/bruschetta_download.h
@@ -0,0 +1,69 @@
+// 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_BRUSCHETTA_BRUSCHETTA_DOWNLOAD_H_
+#define CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_DOWNLOAD_H_
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/functional/callback_forward.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+
+class Profile;
+namespace network {
+class SimpleURLLoader;
+}  // namespace network
+
+namespace bruschetta {
+
+extern const net::NetworkTrafficAnnotationTag kBruschettaTrafficAnnotation;
+
+// Only exposed so unit tests can test it.
+std::string Sha256FileForTesting(const base::FilePath& path);
+
+// Wraps SimpleURLLoader to make it even simpler for Bruschetta to use it for
+// downloading files.
+class SimpleURLLoaderDownload {
+ public:
+  // Starts downloading the file at `url`, will invoke `callback` upon
+  // completion. Either with the path to the downloaded file and a sha256 hash
+  // of its contents, or in case of error will run `callback` with an empty
+  // path. Destroying the returned download instance will cancel any active
+  // downloads and delete any downloaded files.
+  static std::unique_ptr<SimpleURLLoaderDownload> StartDownload(
+      Profile* profile,
+      GURL url,
+      base::OnceCallback<void(base::FilePath path, std::string sha256)>
+          callback);
+
+  void SetPostDeletionCallbackForTesting(base::OnceClosure closure) {
+    post_deletion_closure_for_testing_ = std::move(closure);
+  }
+
+  ~SimpleURLLoaderDownload();
+
+ private:
+  SimpleURLLoaderDownload(
+      Profile* profile,
+      GURL url,
+      base::OnceCallback<void(base::FilePath path, std::string sha256)>
+          callback);
+  void Download(std::unique_ptr<base::ScopedTempDir> dir);
+  void Finished(base::FilePath path);
+
+  base::raw_ptr<Profile> profile_;
+  GURL url_;
+  std::unique_ptr<base::ScopedTempDir> scoped_temp_dir_;
+  base::OnceCallback<void(base::FilePath path, std::string sha256)> callback_;
+  std::unique_ptr<network::SimpleURLLoader> loader_;
+  base::OnceClosure post_deletion_closure_for_testing_;
+
+  base::WeakPtrFactory<SimpleURLLoaderDownload> weak_ptr_factory_{this};
+};
+
+}  // namespace bruschetta
+
+#endif  // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_DOWNLOAD_H_
diff --git a/chrome/browser/ash/bruschetta/bruschetta_download_browsertest.cc b/chrome/browser/ash/bruschetta/bruschetta_download_browsertest.cc
new file mode 100644
index 0000000..a06982b8
--- /dev/null
+++ b/chrome/browser/ash/bruschetta/bruschetta_download_browsertest.cc
@@ -0,0 +1,84 @@
+// 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/bruschetta/bruschetta_download.h"
+
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "base/test/test_future.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace bruschetta {
+namespace {
+
+class BruschettaDownloadBrowserTest : public InProcessBrowserTest {
+ public:
+  BruschettaDownloadBrowserTest() = default;
+  ~BruschettaDownloadBrowserTest() override = default;
+
+  BruschettaDownloadBrowserTest(const BruschettaDownloadBrowserTest&) = delete;
+  BruschettaDownloadBrowserTest& operator=(
+      const BruschettaDownloadBrowserTest&) = delete;
+
+ protected:
+  void SetUpInProcessBrowserTestFixture() override {
+    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+  }
+};
+
+bool PathExistsBlockingAllowed(const base::FilePath& path) {
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  return base::PathExists(path);
+}
+
+IN_PROC_BROWSER_TEST_F(BruschettaDownloadBrowserTest, TestHappyPath) {
+  auto expected_hash = base::ToUpperASCII(
+      "f54d00e6d24844ee3b1d0d8c2b9d2ed80b967e94eb1055bb1fd43eb9522908cc");
+
+  net::EmbeddedTestServer server(net::EmbeddedTestServer::TYPE_HTTPS);
+  server.ServeFilesFromSourceDirectory("chrome/test/data/bruschetta");
+  auto server_handle = server.StartAndReturnHandle();
+  ASSERT_TRUE(server_handle);
+  GURL url = server.GetURL("/download_file.img");
+
+  base::test::TestFuture<base::FilePath, std::string> future;
+  base::FilePath path;
+  auto download = SimpleURLLoaderDownload::StartDownload(
+      browser()->profile(), url, future.GetCallback());
+
+  path = future.Get<base::FilePath>();
+  auto hash = future.Get<std::string>();
+
+  ASSERT_FALSE(path.empty());
+  EXPECT_EQ(hash, expected_hash);
+
+  // Deleting the download should clean up downloaded files. I found
+  // RunUntilIdle to be flaky hence we have an explicit callback for after
+  // deletion completes.
+  base::RunLoop run_loop;
+  download->SetPostDeletionCallbackForTesting(run_loop.QuitClosure());
+  download.reset();
+  run_loop.Run();
+  EXPECT_FALSE(PathExistsBlockingAllowed(path));
+}
+
+IN_PROC_BROWSER_TEST_F(BruschettaDownloadBrowserTest, TestDownloadFailed) {
+  base::test::TestFuture<base::FilePath, std::string> future;
+  auto download = SimpleURLLoaderDownload::StartDownload(
+      browser()->profile(), GURL("bad url"), future.GetCallback());
+
+  auto path = future.Get<base::FilePath>();
+  auto hash = future.Get<std::string>();
+
+  ASSERT_TRUE(path.empty());
+  EXPECT_EQ(hash, "");
+}
+
+}  // namespace
+}  // namespace bruschetta
diff --git a/chrome/browser/ash/bruschetta/bruschetta_download_client.h b/chrome/browser/ash/bruschetta/bruschetta_download_client.h
index b0c22790..32dd84e 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_download_client.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_download_client.h
@@ -52,4 +52,4 @@
 
 }  // namespace bruschetta
 
-#endif
+#endif  // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_DOWNLOAD_CLIENT_H_
diff --git a/chrome/browser/ash/bruschetta/bruschetta_download_unittest.cc b/chrome/browser/ash/bruschetta/bruschetta_download_unittest.cc
new file mode 100644
index 0000000..b68ed0b
--- /dev/null
+++ b/chrome/browser/ash/bruschetta/bruschetta_download_unittest.cc
@@ -0,0 +1,36 @@
+// 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/bruschetta/bruschetta_download.h"
+
+#include <cstring>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace bruschetta {
+namespace {
+
+class BruschettaDownloadTest : public testing::Test {};
+
+TEST_F(BruschettaDownloadTest, TestSha256File) {
+  base::ScopedTempDir dir;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+  const int kBufSize =
+      4096 * 2 + 1;  // Sha256File uses 4k block size, so make sure the file is
+                     // multiple blocks and not a complete block.
+  char buff[kBufSize];
+  memset(buff, 'd', kBufSize);
+  auto path = dir.GetPath().Append("file");
+  const char* expected =
+      "B1AAAD3DBE85816D70C94C35B873D45F0C68F9D3B3DB6F6AB858A1560540E4DF";
+  ASSERT_TRUE(base::WriteFile(path, buff, kBufSize));
+  auto hash = Sha256FileForTesting(path);
+
+  ASSERT_EQ(hash, expected);
+}
+
+}  // namespace
+}  // namespace bruschetta
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
index 8f41a7f..669fda9 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc
@@ -7,11 +7,14 @@
 #include <memory>
 
 #include "base/check.h"
+#include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/files/file_util.h"
+#include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
+#include "base/functional/callback_helpers.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/task/thread_pool.h"
+#include "chrome/browser/ash/bruschetta/bruschetta_download.h"
 #include "chrome/browser/ash/bruschetta/bruschetta_download_client.h"
 #include "chrome/browser/ash/bruschetta/bruschetta_installer.h"
 #include "chrome/browser/ash/bruschetta/bruschetta_pref_names.h"
@@ -39,38 +42,6 @@
 
 namespace {
 
-const net::NetworkTrafficAnnotationTag kBruschettaTrafficAnnotation =
-    net::DefineNetworkTrafficAnnotation("bruschetta_installer_download",
-                                        R"(
-      semantics {
-        sender: "Bruschetta VM Installer",
-        description: "Request sent to download firmware and VM image for "
-          "a Bruschetta VM, which allows the user to run the VM."
-        trigger: "User installing a Bruschetta VM"
-        internal {
-          contacts {
-            email: "clumptini+oncall@google.com"
-          }
-        }
-        user_data: {
-          type: ACCESS_TOKEN
-        }
-        data: "Request to download Bruschetta firmware and VM image. "
-          "Sends cookies associated with the source to authenticate the user."
-        destination: WEBSITE
-        last_reviewed: "2023-01-09"
-      }
-      policy {
-        cookies_allowed: YES
-        cookies_store: "user"
-        chrome_policy {
-          BruschettaVMConfiguration {
-            BruschettaVMConfiguration: "{}"
-          }
-        }
-      }
-    )");
-
 std::unique_ptr<BruschettaInstallerImpl::Fds> OpenFdsBlocking(
     base::FilePath boot_disk_path,
     base::FilePath pflash_path,
@@ -195,7 +166,17 @@
     return;
   }
 
-  DownloadBootDisk();
+  std::string strategy;
+  auto* cmdline = base::CommandLine::ForCurrentProcess();
+  if (cmdline->HasSwitch(kBruschettaInstallerDownloadStrategyFlag)) {
+    strategy =
+        cmdline->GetSwitchValueASCII(kBruschettaInstallerDownloadStrategyFlag);
+  }
+  if (strategy == kBruschettaInstallerDownloadStrategySimpleURLLoader) {
+    DownloadBootDiskURLLoader();
+  } else {
+    DownloadBootDiskDownloadService();
+  }
 }
 
 void BruschettaInstallerImpl::StartDownload(GURL url,
@@ -264,7 +245,7 @@
   std::move(download_callback_).Run(completion_info);
 }
 
-void BruschettaInstallerImpl::DownloadBootDisk() {
+void BruschettaInstallerImpl::DownloadBootDiskDownloadService() {
   VLOG(2) << "Downloading boot disk";
   // We need to generate the download UUID before notifying because the tests
   // need it to set the response.
@@ -273,12 +254,14 @@
 
   const std::string* url = config_.FindDict(prefs::kPolicyImageKey)
                                ->FindString(prefs::kPolicyURLKey);
-  StartDownload(GURL(*url),
-                base::BindOnce(&BruschettaInstallerImpl::OnBootDiskDownloaded,
-                               weak_ptr_factory_.GetWeakPtr()));
+  StartDownload(
+      GURL(*url),
+      base::BindOnce(
+          &BruschettaInstallerImpl::OnBootDiskDownloadedDownloadService,
+          weak_ptr_factory_.GetWeakPtr()));
 }
 
-void BruschettaInstallerImpl::OnBootDiskDownloaded(
+void BruschettaInstallerImpl::OnBootDiskDownloadedDownloadService(
     const download::CompletionInfo& completion_info) {
   if (MaybeClose()) {
     return;
@@ -298,10 +281,10 @@
 
   boot_disk_path_ = completion_info.path;
 
-  DownloadPflash();
+  DownloadPflashDownloadService();
 }
 
-void BruschettaInstallerImpl::DownloadPflash() {
+void BruschettaInstallerImpl::DownloadPflashDownloadService() {
   VLOG(2) << "Downloading pflash";
   // We need to generate the download UUID before notifying because the tests
   // need it to set the response.
@@ -318,11 +301,12 @@
 
   const std::string* url = pflash->FindString(prefs::kPolicyURLKey);
   StartDownload(GURL(*url),
-                base::BindOnce(&BruschettaInstallerImpl::OnPflashDownloaded,
-                               weak_ptr_factory_.GetWeakPtr()));
+                base::BindOnce(
+                    &BruschettaInstallerImpl::OnPflashDownloadedDownloadService,
+                    weak_ptr_factory_.GetWeakPtr()));
 }
 
-void BruschettaInstallerImpl::OnPflashDownloaded(
+void BruschettaInstallerImpl::OnPflashDownloadedDownloadService(
     const download::CompletionInfo& completion_info) {
   if (MaybeClose()) {
     return;
@@ -345,6 +329,86 @@
   OpenFds();
 }
 
+void BruschettaInstallerImpl::DownloadBootDiskURLLoader() {
+  VLOG(2) << "Downloading boot disk";
+  NotifyObserver(State::kBootDiskDownload);
+
+  const std::string* url = config_.FindDict(prefs::kPolicyImageKey)
+                               ->FindString(prefs::kPolicyURLKey);
+  boot_disk_download_ = SimpleURLLoaderDownload::StartDownload(
+      profile_, GURL(*url),
+      base::BindOnce(
+          &bruschetta::BruschettaInstallerImpl::OnBootDiskDownloadedURLLoader,
+          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BruschettaInstallerImpl::OnBootDiskDownloadedURLLoader(base::FilePath path,
+                                                            std::string hash) {
+  if (MaybeClose()) {
+    return;
+  }
+  if (path.empty()) {
+    install_running_ = false;
+    Error(BruschettaInstallResult::kDownloadError);
+    return;
+  }
+  const std::string* expected = config_.FindDict(prefs::kPolicyImageKey)
+                                    ->FindString(prefs::kPolicyHashKey);
+
+  if (!base::EqualsCaseInsensitiveASCII(hash, *expected)) {
+    install_running_ = false;
+    Error(BruschettaInstallResult::kInvalidBootDisk);
+    LOG(ERROR) << "Downloaded boot disk has incorrect hash";
+    LOG(ERROR) << "Actual   " << hash;
+    LOG(ERROR) << "Expected " << expected;
+    return;
+  }
+
+  boot_disk_path_ = path;
+
+  DownloadPflashURLLoader();
+}
+
+void BruschettaInstallerImpl::DownloadPflashURLLoader() {
+  VLOG(2) << "Downloading pflash";
+  NotifyObserver(State::kPflashDownload);
+
+  const std::string* url = config_.FindDict(prefs::kPolicyPflashKey)
+                               ->FindString(prefs::kPolicyURLKey);
+  pflash_download_ = SimpleURLLoaderDownload::StartDownload(
+      profile_, GURL(*url),
+      base::BindOnce(
+          &bruschetta::BruschettaInstallerImpl::OnPflashDownloadedURLLoader,
+          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BruschettaInstallerImpl::OnPflashDownloadedURLLoader(base::FilePath path,
+                                                          std::string hash) {
+  if (MaybeClose()) {
+    return;
+  }
+  if (path.empty()) {
+    install_running_ = false;
+    Error(BruschettaInstallResult::kDownloadError);
+    return;
+  }
+  const std::string* expected = config_.FindDict(prefs::kPolicyPflashKey)
+                                    ->FindString(prefs::kPolicyHashKey);
+
+  if (!base::EqualsCaseInsensitiveASCII(hash, *expected)) {
+    install_running_ = false;
+    Error(BruschettaInstallResult::kInvalidPflash);
+    LOG(ERROR) << "Downloaded pflash has incorrect hash";
+    LOG(ERROR) << "Actual   " << hash;
+    LOG(ERROR) << "Expected " << expected;
+    return;
+  }
+
+  pflash_path_ = path;
+
+  OpenFds();
+}
+
 void BruschettaInstallerImpl::OpenFds() {
   VLOG(2) << "Opening fds";
   NotifyObserver(State::kOpenFiles);
diff --git a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h
index e6142a6e..387b4bc 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h
+++ b/chrome/browser/ash/bruschetta/bruschetta_installer_impl.h
@@ -21,6 +21,7 @@
 class Profile;
 
 namespace bruschetta {
+class SimpleURLLoaderDownload;
 
 class BruschettaInstallerImpl : public BruschettaInstaller {
  public:
@@ -61,10 +62,18 @@
   void InstallFirmwareDlc();
   void OnFirmwareDlcInstalled(
       guest_os::GuestOsDlcInstallation::Result install_result);
-  void DownloadBootDisk();
-  void OnBootDiskDownloaded(const download::CompletionInfo& completion_info);
-  void DownloadPflash();
-  void OnPflashDownloaded(const download::CompletionInfo& completion_info);
+  // TODO(b/270656010): Pick the winner between the two strategies. Loser gets
+  // deleted, winner gets renamed back to "DownloadBootDisk" and etc.
+  void DownloadBootDiskDownloadService();
+  void OnBootDiskDownloadedDownloadService(
+      const download::CompletionInfo& completion_info);
+  void DownloadPflashDownloadService();
+  void OnPflashDownloadedDownloadService(
+      const download::CompletionInfo& completion_info);
+  void DownloadBootDiskURLLoader();
+  void OnBootDiskDownloadedURLLoader(base::FilePath path, std::string hash);
+  void DownloadPflashURLLoader();
+  void OnPflashDownloadedURLLoader(base::FilePath path, std::string hash);
   void OpenFds();
   void OnOpenFds(std::unique_ptr<Fds> fds);
   void CreateVmDisk();
@@ -99,6 +108,10 @@
 
   const raw_ptr<Profile> profile_;
 
+  // The downloaded files get deleted once these go out of scope.
+  std::unique_ptr<SimpleURLLoaderDownload> boot_disk_download_;
+  std::unique_ptr<SimpleURLLoaderDownload> pflash_download_;
+
   base::OnceClosure close_closure_;
 
   raw_ptr<Observer> observer_ = nullptr;
diff --git a/chrome/browser/ash/crosapi/browser_loader.cc b/chrome/browser/ash/crosapi/browser_loader.cc
index 8a527d1..efc5022 100644
--- a/chrome/browser/ash/crosapi/browser_loader.cc
+++ b/chrome/browser/ash/crosapi/browser_loader.cc
@@ -76,16 +76,12 @@
   return true;
 }
 
-void BrowserLoader::SelectRootfsLacros(LoadCompletionCallback callback,
-                                       bool load_stateful_lacros) {
+void BrowserLoader::SelectRootfsLacros(LoadCompletionCallback callback) {
   LOG(WARNING) << "rootfs lacros is selected";
 
   rootfs_lacros_loader_->Load(
       base::BindOnce(&BrowserLoader::OnLoadComplete, weak_factory_.GetWeakPtr(),
                      std::move(callback), LacrosSelection::kRootfs));
-  if (load_stateful_lacros) {
-    stateful_lacros_loader_->Load({});
-  }
 }
 
 void BrowserLoader::SelectStatefulLacros(LoadCompletionCallback callback) {
@@ -132,8 +128,7 @@
     // too.
     switch (lacros_selection.value()) {
       case browser_util::LacrosSelection::kRootfs:
-        SelectRootfsLacros(std::move(callback),
-                           /*load_stateful_lacros=*/false);
+        SelectRootfsLacros(std::move(callback));
         return;
       case browser_util::LacrosSelection::kStateful:
         SelectStatefulLacros(std::move(callback));
@@ -219,7 +214,7 @@
 
   switch (selected->selection) {
     case LacrosSelection::kRootfs: {
-      SelectRootfsLacros(std::move(callback), /*load_stateful_lacros=*/true);
+      SelectRootfsLacros(std::move(callback));
       break;
     }
     case LacrosSelection::kStateful: {
diff --git a/chrome/browser/ash/crosapi/browser_loader.h b/chrome/browser/ash/crosapi/browser_loader.h
index df0f095d..0b5df89 100644
--- a/chrome/browser/ash/crosapi/browser_loader.h
+++ b/chrome/browser/ash/crosapi/browser_loader.h
@@ -99,10 +99,7 @@
       OnLoadSelectionPolicyIsUserChoiceAndCommandLineIsStateful);
   FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest, OnLoadLacrosSpecifiedBySwitch);
 
-  // `load_stateful_lacros` specifies whether we should start the installation
-  // of stateful lacros in the background.
-  void SelectRootfsLacros(LoadCompletionCallback callback,
-                          bool load_stateful_lacros);
+  void SelectRootfsLacros(LoadCompletionCallback callback);
   void SelectStatefulLacros(LoadCompletionCallback callback);
 
   // Called on GetVersion for each rootfs and stateful lacros loader.
diff --git a/chrome/browser/ash/crosapi/move_migrator.cc b/chrome/browser/ash/crosapi/move_migrator.cc
index 99a72a2..6c96ab9 100644
--- a/chrome/browser/ash/crosapi/move_migrator.cc
+++ b/chrome/browser/ash/crosapi/move_migrator.cc
@@ -266,14 +266,14 @@
     }
   }
 
-  const int64_t extra_bytes_created =
+  const int64_t estimated_extra_bytes_created =
       browser_data_migrator_util::EstimatedExtraBytesCreated(
           original_profile_dir);
   // Now check if there is enough disk space for the migration to be carried
   // out.
   const int64_t extra_bytes_required_to_be_freed =
       browser_data_migrator_util::ExtraBytesRequiredToBeFreed(
-          extra_bytes_created, original_profile_dir);
+          estimated_extra_bytes_created, original_profile_dir);
 
   UMA_HISTOGRAM_MEDIUM_TIMES(kMoveMigratorPreMigrationCleanUpTimeUMA,
                              timer.Elapsed());
@@ -289,7 +289,8 @@
             extra_bytes_required_to_be_freed};
   }
 
-  return {TaskStatus::kSucceeded};
+  return {TaskStatus::kSucceeded, absl::nullopt, absl::nullopt,
+          estimated_extra_bytes_created};
 }
 
 void MoveMigrator::OnPreMigrationCleanUp(MoveMigrator::TaskResult result) {
@@ -299,6 +300,8 @@
     return;
   }
 
+  estimated_extra_bytes_created_ = *result.estimated_extra_bytes_created;
+
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE,
       {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
@@ -374,18 +377,22 @@
     return;
   }
 
+  DCHECK(estimated_extra_bytes_created_.has_value());
+
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE,
       {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
        base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
-      base::BindOnce(&MoveMigrator::SetupAshSplitDir, original_profile_dir_),
+      base::BindOnce(&MoveMigrator::SetupAshSplitDir, original_profile_dir_,
+                     *estimated_extra_bytes_created_),
       base::BindOnce(&MoveMigrator::OnSetupAshSplitDir,
                      weak_factory_.GetWeakPtr()));
 }
 
 // static
 MoveMigrator::TaskResult MoveMigrator::SetupAshSplitDir(
-    const base::FilePath& original_profile_dir) {
+    const base::FilePath& original_profile_dir,
+    const int64_t estimated_extra_bytes_created) {
   LOG(WARNING) << "Running SetupAshSplitDir()";
 
   const base::FilePath tmp_user_dir =
@@ -499,6 +506,26 @@
     }
   }
 
+  // Collect UMAs on sizes of artifacts created by migration.
+  const int64_t tmp_profile_dir_size =
+      base::ComputeDirectorySize(tmp_profile_dir);
+  const int64_t tmp_split_dir_size = base::ComputeDirectorySize(tmp_split_dir);
+  const int64_t extra_bytes_created = tmp_profile_dir_size + tmp_split_dir_size;
+  const int64_t extra_bytes_over_estimate =
+      extra_bytes_created - estimated_extra_bytes_created;
+  base::UmaHistogramCustomCounts(kMoveMigratorTmpProfileDirSize,
+                                 tmp_profile_dir_size / 1024 / 1024, 1, 10000,
+                                 100);
+  base::UmaHistogramCustomCounts(kMoveMigratorTmpSplitDirSize,
+                                 tmp_split_dir_size / 1024 / 1024, 1, 10000,
+                                 100);
+  base::UmaHistogramCustomCounts(kMoveMigratorExtraDiskSpaceOccupied,
+                                 extra_bytes_created / 1024 / 1024, 1, 10000,
+                                 100);
+  base::UmaHistogramCustomCounts(kMoveMigratorExtraDiskSpaceOccupiedDiffWithEst,
+                                 extra_bytes_over_estimate / 1024 / 1024,
+                                 -10000, 10000, 100);
+
   return {TaskStatus::kSucceeded};
 }
 
diff --git a/chrome/browser/ash/crosapi/move_migrator.h b/chrome/browser/ash/crosapi/move_migrator.h
index 19e7b39..2fa79e9 100644
--- a/chrome/browser/ash/crosapi/move_migrator.h
+++ b/chrome/browser/ash/crosapi/move_migrator.h
@@ -63,6 +63,15 @@
     "Ash.BrowserDataMigrator.MoveMigrator.MoveLacrosItemsTimeMS";
 constexpr char kMoveMigratorPosixErrnoUMA[] =
     "Ash.BrowserDataMigrator.MoveMigrator.PosixErrno.";
+constexpr char kMoveMigratorTmpProfileDirSize[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.TmpProfileDirSize";
+constexpr char kMoveMigratorTmpSplitDirSize[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.TmpSplitDirSize";
+constexpr char kMoveMigratorExtraDiskSpaceOccupied[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.ExtraDiskSpaceOccupied";
+constexpr char kMoveMigratorExtraDiskSpaceOccupiedDiffWithEst[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.ExtraDiskSpaceOccupied."
+    "DiffWithEstimate";
 
 // This class "moves" Lacros data from Ash to Lacros. It migrates user data from
 // `original_profile_dir` (/home/user/<hash>/), denoted as <Ash PDD> from here
@@ -190,6 +199,11 @@
     // be carried out. Only set if `status` is
     // `kPreMigrationCleanUpNotEnoughSpace`.
     absl::optional<uint64_t> extra_bytes_required_to_be_freed;
+
+    // Extra bytes that are estimated to be created due to the migration. It
+    // will later be used to calculate the diff between this estimate and the
+    // actual value.
+    absl::optional<int64_t> estimated_extra_bytes_created;
   };
 
   // Called to determine where to start the migration. Returns
@@ -243,7 +257,8 @@
   // Set up a temporary directory to hold items that need to be split between
   // ash and lacros. This folder will hold ash's version of the items.
   static TaskResult SetupAshSplitDir(
-      const base::FilePath& original_profile_dir);
+      const base::FilePath& original_profile_dir,
+      const int64_t estimated_extra_bytes_created);
 
   // Called as a reply to `SetupAshSplitDir()`. Posts `MoveLacrosItemsToNewDir`
   // as the next step.
@@ -334,6 +349,9 @@
   // data on how long the migration takes.
   const base::ElapsedTimer timer_;
 
+  // Extra bytes that are estimated to be created due to the migration.
+  absl::optional<int64_t> estimated_extra_bytes_created_;
+
   base::WeakPtrFactory<MoveMigrator> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ash/crosapi/move_migrator_unittest.cc b/chrome/browser/ash/crosapi/move_migrator_unittest.cc
index ebe603b..022b15a 100644
--- a/chrome/browser/ash/crosapi/move_migrator_unittest.cc
+++ b/chrome/browser/ash/crosapi/move_migrator_unittest.cc
@@ -551,7 +551,7 @@
   ASSERT_TRUE(base::CreateDirectory(tmp_user_dir));
   ASSERT_TRUE(base::CreateDirectory(tmp_profile_dir));
 
-  EXPECT_EQ(MoveMigrator::SetupAshSplitDir(original_profile_dir).status,
+  EXPECT_EQ(MoveMigrator::SetupAshSplitDir(original_profile_dir, 0).status,
             MoveMigrator::TaskStatus::kSucceeded);
 
   const base::FilePath tmp_split_dir =
diff --git a/chrome/browser/ash/crosapi/stateful_lacros_loader.cc b/chrome/browser/ash/crosapi/stateful_lacros_loader.cc
index 354b0d6e..06cdb4e 100644
--- a/chrome/browser/ash/crosapi/stateful_lacros_loader.cc
+++ b/chrome/browser/ash/crosapi/stateful_lacros_loader.cc
@@ -9,7 +9,6 @@
 #include "ash/constants/ash_switches.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/functional/bind.h"
 #include "base/logging.h"
@@ -19,10 +18,12 @@
 #include "base/task/thread_pool.h"
 #include "chrome/browser/ash/crosapi/browser_data_back_migrator.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
 #include "chrome/common/channel_info.h"
 #include "chromeos/ash/components/cryptohome/system_salt_getter.h"
 #include "components/component_updater/component_updater_paths.h"
+#include "components/component_updater/component_updater_service.h"
 
 namespace crosapi {
 
@@ -128,12 +129,15 @@
 StatefulLacrosLoader::StatefulLacrosLoader(
     scoped_refptr<component_updater::CrOSComponentManager> manager)
     : StatefulLacrosLoader(manager,
+                           g_browser_process->component_updater(),
                            browser_util::GetLacrosComponentInfo().name) {}
 
 StatefulLacrosLoader::StatefulLacrosLoader(
     scoped_refptr<component_updater::CrOSComponentManager> manager,
+    component_updater::ComponentUpdateService* updater,
     const std::string& lacros_component_name)
     : component_manager_(manager),
+      component_update_service_(updater),
       lacros_component_name_(lacros_component_name) {
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock()},
@@ -146,16 +150,18 @@
 
 void StatefulLacrosLoader::Load(LoadCompletionCallback callback) {
   LOG(WARNING) << "Loading stateful lacros.";
-  component_manager_->Load(
-      lacros_component_name_,
-      component_updater::CrOSComponentManager::MountPolicy::kMount,
-      // If a compatible installation exists, use that and download any updates
-      // in the background.
-      component_updater::CrOSComponentManager::UpdatePolicy::kDontForce,
-      // If `callback` is null, means stateful lacros-chrome should be
-      // installed/updated but rootfs lacros-chrome will be used.
-      base::BindOnce(&StatefulLacrosLoader::OnLoad, weak_factory_.GetWeakPtr(),
-                     std::move(callback)));
+
+  // If stateful lacros-chrome is already loaded once, run `callback`
+  // immediately with cached version and path values.
+  // This code path is used in most cases as they are already calculated on
+  // getting version except for the case where BrowserLoader is forced to select
+  // stateful lacros-chrome by lacros selection policy.
+  if (IsReady()) {
+    std::move(callback).Run(version_.value(), path_.value());
+    return;
+  }
+
+  LoadInternal(std::move(callback));
 }
 
 void StatefulLacrosLoader::Unload() {
@@ -171,6 +177,7 @@
   // TODO(crbug.com/1432069): Reset call while loading breaks the behavior. Need
   // to handle such edge cases.
   version_ = absl::nullopt;
+  path_ = absl::nullopt;
 }
 
 void StatefulLacrosLoader::GetVersion(
@@ -178,7 +185,7 @@
   // If version is already calculated, immediately return the cached value.
   // Calculate if not.
   // Note that version value is reset on reloading.
-  if (version_.has_value()) {
+  if (IsReady()) {
     std::move(callback).Run(version_.value());
     return;
   }
@@ -193,6 +200,23 @@
                      weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
+void StatefulLacrosLoader::LoadInternal(LoadCompletionCallback callback) {
+  component_manager_->Load(
+      lacros_component_name_,
+      component_updater::CrOSComponentManager::MountPolicy::kMount,
+      // If a compatible installation exists, use that and download any updates
+      // in the background.
+      component_updater::CrOSComponentManager::UpdatePolicy::kDontForce,
+      // If `callback` is null, means stateful lacros-chrome should be
+      // installed/updated but rootfs lacros-chrome will be used.
+      base::BindOnce(&StatefulLacrosLoader::OnLoad, weak_factory_.GetWeakPtr(),
+                     std::move(callback)));
+}
+
+bool StatefulLacrosLoader::IsReady() {
+  return version_.has_value() && path_.has_value();
+}
+
 void StatefulLacrosLoader::OnLoad(
     LoadCompletionCallback callback,
     component_updater::CrOSComponentManager::Error error,
@@ -206,30 +230,19 @@
       << "Error loading lacros component image: " << static_cast<int>(error)
       << ", " << path;
 
-  // If `version_` is already set, run `callback` immediately with the
-  // `version_` value. This code path is used in most cases except for the case
-  // where lacros selection is based on selection policy so that it skips the
-  // version comparison.
-  if (version_.has_value()) {
-    if (callback) {
-      std::move(callback).Run(version_.value(), path);
-    }
-    return;
-  }
+  version_ = is_stateful_lacros_available
+                 ? browser_util::GetInstalledLacrosComponentVersion(
+                       component_update_service_)
+                 : base::Version();
+  path_ = path;
 
-  component_manager_->GetVersion(
-      lacros_component_name_,
-      base::BindOnce(
-          &StatefulLacrosLoader::OnGetVersionFromComponentManager,
-          weak_factory_.GetWeakPtr(),
-          base::BindOnce(
-              [](LoadCompletionCallback callback, const base::FilePath& path,
-                 const base::Version& version) {
-                if (callback) {
-                  std::move(callback).Run(std::move(version), path);
-                }
-              },
-              std::move(callback), path)));
+  if (callback) {
+    std::move(callback).Run(version_.value(), path_.value());
+  } else {
+    LOG(WARNING)
+        << "stateful lacros-chrome installation completed in the background in "
+        << path << ", version is " << version_.value();
+  }
 }
 
 void StatefulLacrosLoader::OnCheckInstalledToGetVersion(
@@ -238,29 +251,20 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!is_installed) {
-    version_ = base::Version();
-    std::move(callback).Run(version_.value());
+    // Run `callback` immediately with empty version and start loading stateful
+    // lacros-chrome in the background.
+    // TODO(crbug.com/1432069): Reconsider `version_` and `path_` values
+    // semantics.
+    LoadInternal({});
+    std::move(callback).Run(base::Version());
     return;
   }
 
-  component_manager_->GetVersion(
-      lacros_component_name_,
-      base::BindOnce(&StatefulLacrosLoader::OnGetVersionFromComponentManager,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void StatefulLacrosLoader::OnGetVersionFromComponentManager(
-    base::OnceCallback<void(const base::Version&)> callback,
-    const base::Version& version) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  LOG_IF(WARNING, version.IsValid())
-      << "Error getting version of lacros component image";
-
-  version_ = version;
-  if (callback) {
-    std::move(callback).Run(version_.value());
-  }
+  LoadInternal(base::BindOnce(
+      [](base::OnceCallback<void(const base::Version&)> callback,
+         base::Version version,
+         const base::FilePath&) { std::move(callback).Run(version); },
+      std::move(callback)));
 }
 
 void StatefulLacrosLoader::OnCheckInstalledToUnload(bool was_installed) {
diff --git a/chrome/browser/ash/crosapi/stateful_lacros_loader.h b/chrome/browser/ash/crosapi/stateful_lacros_loader.h
index ed25c5b4..d4e0dcf 100644
--- a/chrome/browser/ash/crosapi/stateful_lacros_loader.h
+++ b/chrome/browser/ash/crosapi/stateful_lacros_loader.h
@@ -7,7 +7,9 @@
 
 #include <string>
 
+#include "base/files/file_path.h"
 #include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
@@ -16,9 +18,9 @@
 #include "chrome/browser/component_updater/cros_component_manager.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace base {
-class FilePath;
-}  // namespace base
+namespace component_updater {
+class ComponentUpdateService;
+}  // namespace component_updater
 
 namespace crosapi {
 
@@ -30,6 +32,7 @@
   // Constructor for testing.
   explicit StatefulLacrosLoader(
       scoped_refptr<component_updater::CrOSComponentManager> manager,
+      component_updater::ComponentUpdateService* updater,
       const std::string& lacros_component_name);
   StatefulLacrosLoader(const StatefulLacrosLoader&) = delete;
   StatefulLacrosLoader& operator=(const StatefulLacrosLoader&) = delete;
@@ -43,6 +46,12 @@
       base::OnceCallback<void(const base::Version&)> callback) override;
 
  private:
+  void LoadInternal(LoadCompletionCallback callback);
+
+  // Returns true if the stateful lacros-chrome is already loaded and both
+  // `version_` and `path_` are ready.
+  bool IsReady();
+
   // Called after Load.
   void OnLoad(LoadCompletionCallback callback,
               component_updater::CrOSComponentManager::Error error,
@@ -70,9 +79,15 @@
   // For cases where it failed to read the version, invalid `base::Version()` is
   // set.
   absl::optional<base::Version> version_;
+  // Cache the path to installed lacros-chrome path.
+  absl::optional<base::FilePath> path_;
 
   scoped_refptr<component_updater::CrOSComponentManager> component_manager_;
 
+  // May be null in tests.
+  const raw_ptr<component_updater::ComponentUpdateService, ExperimentalAsh>
+      component_update_service_;
+
   const std::string lacros_component_name_;
 
   // Used for DCHECKs to ensure method calls executed in the correct thread.
diff --git a/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc b/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc
index 949658e..ff2d7ef 100644
--- a/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc
+++ b/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/component_updater/fake_cros_component_manager.h"
 #include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
 #include "chromeos/ash/components/standalone_browser/browser_support.h"
+#include "components/component_updater/mock_component_updater_service.h"
 #include "components/update_client/update_client.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,7 +26,10 @@
 namespace crosapi {
 namespace {
 
+using testing::Return;
+
 constexpr char kLacrosComponentName[] = "lacros-dogfood-dev";
+constexpr char kLacrosComponentId[] = "ldobopbhiamakmncndpkeelenhdmgfhk";
 
 class StatefulLacrosLoaderTest : public testing::Test {
  public:
@@ -45,7 +49,8 @@
     browser_part_->InitializeCrosComponentManager(component_manager_);
 
     stateful_lacros_loader_ = std::make_unique<StatefulLacrosLoader>(
-        component_manager_, kLacrosComponentName);
+        component_manager_, &mock_component_update_service_,
+        kLacrosComponentName);
     EXPECT_TRUE(BrowserLoader::WillLoadStatefulComponentBuilds());
   }
 
@@ -58,12 +63,19 @@
  protected:
   content::BrowserTaskEnvironment task_environment_;
 
+  component_updater::MockComponentUpdateService mock_component_update_service_;
   scoped_refptr<component_updater::FakeCrOSComponentManager> component_manager_;
   std::unique_ptr<BrowserProcessPlatformPartTestApi> browser_part_;
   std::unique_ptr<StatefulLacrosLoader> stateful_lacros_loader_;
 };
 
 TEST_F(StatefulLacrosLoaderTest, LoadStatefulLacros) {
+  std::u16string lacros_component_name =
+      base::UTF8ToUTF16(base::StringPiece(kLacrosComponentName));
+  EXPECT_CALL(mock_component_update_service_, GetComponents())
+      .WillOnce(Return(std::vector<component_updater::ComponentInfo>{
+          {kLacrosComponentId, "", lacros_component_name, version, ""}}));
+
   // Set stateful lacros-chrome version. Wait until the version calculation is
   // completed before verifying the version.
   base::test::TestFuture<base::Version, const base::FilePath&> future;
diff --git a/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc b/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc
index 4f87a17..ec879fc 100644
--- a/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc
+++ b/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc
@@ -57,8 +57,8 @@
       return data_controls::Component::kUsb;
     case ::dlp::DlpComponent::GOOGLE_DRIVE:
       return data_controls::Component::kDrive;
-    case ::dlp::DlpComponent::MICROSOFT_ONEDRIVE:  // TODO(b/280575394): Handle
-                                                   // OneDrive properly.
+    case ::dlp::DlpComponent::MICROSOFT_ONEDRIVE:
+      return data_controls::Component::kOneDrive;
     case ::dlp::DlpComponent::UNKNOWN_COMPONENT:
     case ::dlp::DlpComponent::SYSTEM:
       return data_controls::Component::kUnknownComponent;
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc b/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc
index 83cd4c9..9396926 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_file_system.cc
@@ -270,6 +270,8 @@
       return VolumeType::VOLUME_TYPE_REMOVABLE;
     case Component::kDrive:
       return VolumeType::VOLUME_TYPE_DRIVE;
+    case Component::kOneDrive:
+      return VolumeType::VOLUME_TYPE_PROVIDED;
     case Component::kUnknownComponent:
       NOTREACHED() << "DLP component not set.";
       return {};
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 858c780..69e7e7ee 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -224,6 +224,11 @@
     return *this;
   }
 
+  TestCase& EnableDriveShortcuts() {
+    options.enable_drive_shortcuts = true;
+    return *this;
+  }
+
   TestCase& SetDeviceMode(DeviceMode device_mode) {
     options.device_mode = device_mode;
     return *this;
@@ -305,6 +310,10 @@
       full_name += "_DriveBulkPinning";
     }
 
+    if (options.enable_drive_shortcuts) {
+      full_name += "_DriveShortcuts";
+    }
+
     switch (options.device_mode) {
       case kDeviceModeNotSet:
         break;
@@ -1545,6 +1554,7 @@
         TestCase("driveAvailableOfflineDirectoryGearMenu"),
         TestCase("driveAvailableOfflineActionBar"),
         TestCase("driveLinkToDirectory"),
+        TestCase("driveLinkToDirectory").EnableDriveShortcuts(),
         TestCase("driveLinkOpenFileThroughLinkedDirectory"),
         TestCase("driveLinkOpenFileThroughTransitiveLink"),
         TestCase("driveWelcomeBanner"),
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 59df4d4..740642f 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -2159,6 +2159,12 @@
         ash::features::kFeatureManagementDriveFsBulkPinning);
   }
 
+  if (options.enable_drive_shortcuts) {
+    enabled_features.push_back(ash::features::kFilesDriveShortcuts);
+  } else {
+    disabled_features.push_back(ash::features::kFilesDriveShortcuts);
+  }
+
   if (options.feature_ids.size() > 0) {
     for (const std::string& feature_id : options.feature_ids) {
       base::AddTagToTestResult("feature_id", feature_id);
@@ -3354,6 +3360,11 @@
     return;
   }
 
+  if (name == "isDriveShortcutsEnabled") {
+    *output = options.enable_drive_shortcuts ? "true" : "false";
+    return;
+  }
+
   if (name == "isOsFeedbackEnabled") {
     *output = options.enable_os_feedback ? "true" : "false";
     return;
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 8b07328..fc16e5a9 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -179,6 +179,9 @@
     // Whether tests should enable the Google Drive bulk pinning feature.
     bool enable_drive_bulk_pinning = false;
 
+    // Whether to enable Drive shortcuts showing a badge or not.
+    bool enable_drive_shortcuts = false;
+
     // Feature IDs associated for mapping test cases and features.
     std::vector<std::string> feature_ids;
   };
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc
index f2b2ea4..caeb8f9c 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -220,6 +220,8 @@
              IDS_FILE_BROWSER_BULK_PINNING_OFFLINE_LABEL);
   SET_STRING("DRIVE_BULK_PINNING_NOT_ENOUGH_SPACE",
              IDS_FILE_BROWSER_BULK_PINNING_NOT_ENOUGH_SPACE_LABEL);
+  SET_STRING("DRIVE_PREPARING_TO_SYNC",
+             IDS_FILE_BROWSER_BULK_PINNING_PREPARING_TO_SYNC);
 }
 
 void AddStringsForMediaView(base::Value::Dict* dict) {
@@ -1093,6 +1095,8 @@
   SET_STRING("DLP_COMPONENT_PLAY", IDS_FILE_BROWSER_DLP_COMPONENT_PLAY);
   SET_STRING("DLP_COMPONENT_LINUX", IDS_FILE_BROWSER_DLP_COMPONENT_LINUX);
   SET_STRING("DLP_COMPONENT_VM", IDS_FILE_BROWSER_DLP_COMPONENT_VM);
+  SET_STRING("DLP_COMPONENT_MICROSOFT_ONEDRIVE",
+             IDS_FILE_BROWSER_DLP_COMPONENT_MICROSOFT_ONEDRIVE);
   SET_STRING("ONE_DRIVE_MOVED_FILE_NUDGE",
              IDS_FILE_BROWSER_ONE_DRIVE_MOVED_FILE_NUDGE);
   SET_STRING("DRIVE_MOVED_FILE_NUDGE", IDS_FILE_BROWSER_DRIVE_MOVED_FILE_NUDGE);
diff --git a/chrome/browser/ash/file_manager/io_task.cc b/chrome/browser/ash/file_manager/io_task.cc
index 51c1439..a662707 100644
--- a/chrome/browser/ash/file_manager/io_task.cc
+++ b/chrome/browser/ash/file_manager/io_task.cc
@@ -22,6 +22,12 @@
 
 void IOTask::CompleteWithError(PolicyErrorType policy_error) {}
 
+bool ConflictPauseParams::operator==(const ConflictPauseParams& other) const =
+    default;
+
+bool PolicyPauseParams::operator==(const PolicyPauseParams& other) const =
+    default;
+
 PauseParams::PauseParams() = default;
 
 PauseParams::PauseParams(const PauseParams& other) = default;
@@ -32,6 +38,11 @@
 
 PauseParams& PauseParams::operator=(PauseParams&& other) = default;
 
+bool PauseParams::operator==(const PauseParams& other) const {
+  return (conflict_params == other.conflict_params) &&
+         (policy_params == other.policy_params);
+}
+
 PauseParams::~PauseParams() = default;
 
 ResumeParams::ResumeParams() = default;
@@ -142,7 +153,29 @@
       base::BindOnce(&DummyIOTask::DoProgress, weak_ptr_factory_.GetWeakPtr()));
 }
 
+void DummyIOTask::Pause(PauseParams pause_params) {
+  progress_.state = State::kPaused;
+  progress_.pause_params = pause_params;
+}
+
+void DummyIOTask::Resume(ResumeParams resume_params) {
+  progress_.state = State::kInProgress;
+}
+
+void DummyIOTask::Cancel() {
+  progress_.state = State::kCancelled;
+}
+
+void DummyIOTask::CompleteWithError(PolicyErrorType policy_error) {
+  progress_.state = State::kError;
+  progress_.policy_error = policy_error;
+}
+
 void DummyIOTask::DoProgress() {
+  if (progress_.IsPaused()) {
+    return;
+  }
+
   progress_.bytes_transferred = 1;
   progress_callback_.Run(progress_);
 
@@ -160,8 +193,4 @@
   std::move(complete_callback_).Run(std::move(progress_));
 }
 
-void DummyIOTask::Cancel() {
-  progress_.state = State::kCancelled;
-}
-
 }  // namespace file_manager::io_task
diff --git a/chrome/browser/ash/file_manager/io_task.h b/chrome/browser/ash/file_manager/io_task.h
index 56c9eac..389b552 100644
--- a/chrome/browser/ash/file_manager/io_task.h
+++ b/chrome/browser/ash/file_manager/io_task.h
@@ -92,6 +92,8 @@
 
   // The conflict copy or move target URL.
   std::string conflict_target_url;
+
+  bool operator==(const ConflictPauseParams& other) const;
 };
 
 // I/O task state::PAUSED parameters when paused to show a policy warning.
@@ -99,6 +101,8 @@
 struct PolicyPauseParams {
   // One of kDlp, kEnterpriseConnectors.
   PolicyErrorType type;
+
+  bool operator==(const PolicyPauseParams& other) const;
 };
 
 // I/O task state::PAUSED parameters. Only one of conflict or policy params
@@ -112,6 +116,8 @@
   PauseParams(PauseParams&& other);
   PauseParams& operator=(PauseParams&& other);
 
+  bool operator==(const PauseParams& other) const;
+
   ~PauseParams();
 
   // Set iff pausing due to name conflict.
@@ -323,10 +329,13 @@
               bool show_notification = true);
   ~DummyIOTask() override;
 
+  // IOTask overrides:
   void Execute(ProgressCallback progress_callback,
                CompleteCallback complete_callback) override;
-
+  void Pause(PauseParams pause_params) override;
+  void Resume(ResumeParams resume_params) override;
   void Cancel() override;
+  void CompleteWithError(PolicyErrorType policy_error) override;
 
  private:
   void DoProgress();
diff --git a/chrome/browser/ash/file_manager/io_task_controller.cc b/chrome/browser/ash/file_manager/io_task_controller.cc
index d6072cf..8ffcb13 100644
--- a/chrome/browser/ash/file_manager/io_task_controller.cc
+++ b/chrome/browser/ash/file_manager/io_task_controller.cc
@@ -88,6 +88,19 @@
   return task_id;
 }
 
+void IOTaskController::Pause(IOTaskId task_id, PauseParams params) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto it = tasks_.find(task_id);
+  if (it != tasks_.end()) {
+    IOTask* task = it->second.get();
+    task->Pause(std::move(params));
+    NotifyIOTaskObservers(task->progress());
+  } else {
+    LOG(WARNING) << "Failed to pause task: " << task_id << " not found";
+  }
+}
+
 void IOTaskController::Resume(IOTaskId task_id, ResumeParams params) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -95,6 +108,7 @@
   if (it != tasks_.end()) {
     IOTask* task = it->second.get();
     task->Resume(std::move(params));
+    NotifyIOTaskObservers(task->progress());
   } else {
     LOG(WARNING) << "Failed to resume task: " << task_id << " not found";
   }
@@ -129,6 +143,21 @@
   }
 }
 
+void IOTaskController::CompleteWithError(IOTaskId task_id,
+                                         PolicyErrorType policy_error) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto it = tasks_.find(task_id);
+  if (it != tasks_.end()) {
+    IOTask* task = it->second.get();
+    task->CompleteWithError(std::move(policy_error));
+    NotifyIOTaskObservers(task->progress());
+    RemoveIOTask(task_id);
+  } else {
+    LOG(WARNING) << "Failed to abort task: " << task_id << " not found";
+  }
+}
+
 device::mojom::WakeLock* IOTaskController::GetWakeLock() {
   if (!wake_lock_) {
     mojo::Remote<device::mojom::WakeLockProvider> provider;
diff --git a/chrome/browser/ash/file_manager/io_task_controller.h b/chrome/browser/ash/file_manager/io_task_controller.h
index 185db0e0..a3cda298 100644
--- a/chrome/browser/ash/file_manager/io_task_controller.h
+++ b/chrome/browser/ash/file_manager/io_task_controller.h
@@ -47,6 +47,9 @@
   // Queues an IOTask and returns its ID.
   IOTaskId Add(std::unique_ptr<IOTask> task);
 
+  // Pauses a task from the queue.
+  void Pause(IOTaskId task_id, PauseParams params);
+
   // Resumes a task from the queue.
   void Resume(IOTaskId task_id, ResumeParams params);
 
@@ -56,6 +59,9 @@
   // Makes tasks in state::PAUSED emit (broadcast) their progress status.
   void ProgressPausedTasks();
 
+  // Aborts a task from the queue.
+  void CompleteWithError(IOTaskId task_id, PolicyErrorType policy_error);
+
   // For tests only; returns the current wake lock counter. This counter is
   // incremented by 1 for every time we get a wake lock and decremented every
   // time we release it.
diff --git a/chrome/browser/ash/file_manager/io_task_controller_unittest.cc b/chrome/browser/ash/file_manager/io_task_controller_unittest.cc
index 9584e1f..49fa37a8 100644
--- a/chrome/browser/ash/file_manager/io_task_controller_unittest.cc
+++ b/chrome/browser/ash/file_manager/io_task_controller_unittest.cc
@@ -147,6 +147,111 @@
   io_task_controller_.RemoveObserver(&observer);
 }
 
+TEST_F(IOTaskControllerTest, PauseResume) {
+  IOTaskStatusObserver observer;
+  io_task_controller_.AddObserver(&observer);
+
+  std::vector<storage::FileSystemURL> source_urls{
+      CreateFileSystemURL("filesystem:chrome-extension://abc/external/foo/src"),
+  };
+  auto dest = CreateFileSystemURL(
+      "filesystem:chrome-extension://abc/external/foo/dest");
+
+  // All progress statuses should return the same |type|, |source_urls| and
+  // |destination_folder| given, so set up a base matcher to check this.
+  auto base_matcher =
+      AllOf(Field(&ProgressStatus::type, OperationType::kMove),
+            Field(&ProgressStatus::sources, EntryStatusUrls(source_urls)),
+            Property(&ProgressStatus::GetDestinationFolder, dest));
+
+  // The controller should synchronously send out a progress status when queued.
+  EXPECT_CALL(observer, OnIOTaskStatus(
+                            AllOf(Field(&ProgressStatus::state, State::kQueued),
+                                  base_matcher)));
+
+  // The controller should also synchronously execute the I/O task, which will
+  // send out another status.
+  EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                            Field(&ProgressStatus::state, State::kInProgress),
+                            base_matcher)));
+
+  auto task_id = io_task_controller_.Add(
+      std::make_unique<DummyIOTask>(source_urls, dest, OperationType::kMove));
+
+  // Pause should synchronously send a progress status.
+  PauseParams pause_params;
+  pause_params.policy_params = PolicyPauseParams(PolicyErrorType::kDlp);
+  EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                            Field(&ProgressStatus::state, State::kPaused),
+                            Field(&ProgressStatus::task_id, task_id),
+                            Field(&ProgressStatus::pause_params, pause_params),
+                            base_matcher)));
+  io_task_controller_.Pause(task_id, pause_params);
+
+  // Resume should synchronously send a progress status.
+  EXPECT_CALL(observer,
+              OnIOTaskStatus(AllOf(
+                  Field(&ProgressStatus::state, State::kInProgress),
+                  Field(&ProgressStatus::task_id, task_id), base_matcher)));
+  io_task_controller_.Resume(task_id, ResumeParams());
+
+  // Wait for the task to finish successfully.
+  EXPECT_CALL(observer,
+              OnIOTaskStatus(AllOf(
+                  Field(&ProgressStatus::state, State::kSuccess),
+                  Field(&ProgressStatus::task_id, task_id), base_matcher)));
+  base::RunLoop().RunUntilIdle();
+
+  io_task_controller_.RemoveObserver(&observer);
+}
+
+TEST_F(IOTaskControllerTest, CompleteWithError) {
+  IOTaskStatusObserver observer;
+  io_task_controller_.AddObserver(&observer);
+
+  std::vector<storage::FileSystemURL> source_urls{
+      CreateFileSystemURL("filesystem:chrome-extension://abc/external/foo/src"),
+  };
+  auto dest = CreateFileSystemURL(
+      "filesystem:chrome-extension://abc/external/foo/dest");
+
+  // All progress statuses should return the same |type|, |source_urls| and
+  // |destination_folder| given, so set up a base matcher to check this.
+  auto base_matcher =
+      AllOf(Field(&ProgressStatus::type, OperationType::kMove),
+            Field(&ProgressStatus::sources, EntryStatusUrls(source_urls)),
+            Property(&ProgressStatus::GetDestinationFolder, dest));
+
+  // The controller should synchronously send out a progress status when queued.
+  EXPECT_CALL(observer, OnIOTaskStatus(
+                            AllOf(Field(&ProgressStatus::state, State::kQueued),
+                                  base_matcher)));
+
+  // The controller should also synchronously execute the I/O task, which will
+  // send out another status.
+  EXPECT_CALL(observer, OnIOTaskStatus(AllOf(
+                            Field(&ProgressStatus::state, State::kInProgress),
+                            base_matcher)));
+
+  auto task_id = io_task_controller_.Add(
+      std::make_unique<DummyIOTask>(source_urls, dest, OperationType::kMove));
+
+  // CompleteWithError should synchronously send a progress status.
+  EXPECT_CALL(observer,
+              OnIOTaskStatus(AllOf(
+                  Field(&ProgressStatus::state, State::kError),
+                  Field(&ProgressStatus::task_id, task_id),
+                  Field(&ProgressStatus::policy_error, PolicyErrorType::kDlp),
+                  base_matcher)));
+  io_task_controller_.CompleteWithError(task_id, PolicyErrorType::kDlp);
+
+  // No more observer notifications should come after CompleteWithError as the
+  // task is deleted.
+  base::RunLoop().RunUntilIdle();
+
+  io_task_controller_.RemoveObserver(&observer);
+}
+
 }  // namespace
 }  // namespace io_task
 }  // namespace file_manager
diff --git a/chrome/browser/ash/file_system_provider/extension_provider.cc b/chrome/browser/ash/file_system_provider/extension_provider.cc
index 1bd1a81..cb7f86a 100644
--- a/chrome/browser/ash/file_system_provider/extension_provider.cc
+++ b/chrome/browser/ash/file_system_provider/extension_provider.cc
@@ -13,12 +13,14 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/ash/file_system_provider/mount_request_handler.h"
+#include "chrome/browser/ash/file_system_provider/odfs_metrics.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system.h"
 #include "chrome/browser/ash/file_system_provider/request_dispatcher_impl.h"
 #include "chrome/browser/ash/file_system_provider/throttled_file_system.h"
 #include "chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "extensions/browser/event_router.h"
@@ -153,8 +155,16 @@
       base::BindRepeating(&ExtensionProvider::OnLacrosOperationForwarded,
                           weak_ptr_factory_.GetWeakPtr()),
       GetServiceWorkerLifetimeManager(profile));
+  if (chromeos::features::IsUploadOfficeToCloudEnabled() &&
+      provider_id_.GetExtensionId() == extension_misc::kODFSExtensionId) {
+    odfs_metrics_ = std::make_unique<ODFSMetrics>();
+  }
   request_manager_ = std::make_unique<RequestManager>(
       profile, /*notification_manager=*/nullptr, kDefaultMountTimeout);
+  if (chromeos::features::IsUploadOfficeToCloudEnabled() &&
+      provider_id_.GetExtensionId() == extension_misc::kODFSExtensionId) {
+    request_manager_->AddObserver(odfs_metrics_.get());
+  }
   ObserveAppServiceForIcons(profile);
 }
 
diff --git a/chrome/browser/ash/file_system_provider/extension_provider.h b/chrome/browser/ash/file_system_provider/extension_provider.h
index 8dde59b0..ec8fa02 100644
--- a/chrome/browser/ash/file_system_provider/extension_provider.h
+++ b/chrome/browser/ash/file_system_provider/extension_provider.h
@@ -27,6 +27,7 @@
 namespace file_system_provider {
 
 class RequestDispatcher;
+class ODFSMetrics;
 
 class ExtensionProvider : public ProviderInterface,
                           public apps::AppRegistryCache::Observer {
@@ -73,6 +74,7 @@
   std::string name_;
   IconSet icon_set_;
   std::unique_ptr<RequestDispatcher> request_dispatcher_;
+  std::unique_ptr<ODFSMetrics> odfs_metrics_;
   std::unique_ptr<RequestManager> request_manager_;
 
   base::WeakPtrFactory<ExtensionProvider> weak_ptr_factory_{this};
diff --git a/chrome/browser/ash/file_system_provider/odfs_metrics.cc b/chrome/browser/ash/file_system_provider/odfs_metrics.cc
new file mode 100644
index 0000000..00ed93c1
--- /dev/null
+++ b/chrome/browser/ash/file_system_provider/odfs_metrics.cc
@@ -0,0 +1,121 @@
+// 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/file_system_provider/odfs_metrics.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
+
+namespace ash::file_system_provider {
+
+namespace {
+
+const char* ToString(RequestType request_type) {
+  switch (request_type) {
+    case RequestType::kAbort:
+      return "onAbortRequested";
+    case RequestType::kAddWatcher:
+      return "onAddWatcherRequested";
+    case RequestType::kCloseFile:
+      return "onCloseFileRequested";
+    case RequestType::kConfigure:
+      return "onConfigureRequested";
+    case RequestType::kCopyEntry:
+      return "onCopyEntryRequested";
+    case RequestType::kCreateDirectory:
+      return "onCreateDirectoryRequested";
+    case RequestType::kCreateFile:
+      return "onCreateFileRequested";
+    case RequestType::kDeleteEntry:
+      return "onDeleteEntryRequested";
+    case RequestType::kExecuteAction:
+      return "onExecuteActionRequested";
+    case RequestType::kGetActions:
+      return "onGetActionsRequested";
+    case RequestType::kGetMetadata:
+      return "onGetMetadataRequested";
+    case RequestType::kMount:
+      return "onMountRequested";
+    case RequestType::kMoveEntry:
+      return "onMoveEntryRequested";
+    case RequestType::kOpenFile:
+      return "onOpenFileRequested";
+    case RequestType::kReadDirectory:
+      return "onReadDirectoryRequested";
+    case RequestType::kReadFile:
+      return "onReadFileRequested";
+    case RequestType::kRemoveWatcher:
+      return "onRemoveWatcherRequested";
+    case RequestType::kTruncate:
+      return "onTruncateRequested";
+    case RequestType::kUnmount:
+      return "onUnmountRequested";
+    case RequestType::kWriteFile:
+      return "onWriteFileRequested";
+  }
+}
+
+std::string GetHistogramName(const char* metric, RequestType request_type) {
+  return base::StrCat({"FileBrowser.OfficeFiles.ODFS.FileSystemProvider.",
+                       metric, ".", ToString(request_type)});
+}
+
+}  // namespace
+
+struct ODFSMetrics::Request {
+  RequestType request_type;
+  base::File::Error result = base::File::FILE_OK;
+  base::ElapsedTimer latency_timer;
+};
+
+ODFSMetrics::ODFSMetrics() = default;
+
+ODFSMetrics::~ODFSMetrics() = default;
+
+void ODFSMetrics::OnRequestCreated(int request_id, RequestType type) {
+  Request& request = requests_[request_id];
+  request.request_type = type;
+  request.latency_timer.Begin();
+}
+
+void ODFSMetrics::OnRequestDestroyed(int request_id) {
+  auto it = requests_.find(request_id);
+  if (it == requests_.end()) {
+    return;
+  }
+  Request& request = it->second;
+  base::UmaHistogramMediumTimes(GetHistogramName("Time", request.request_type),
+                                request.latency_timer.Elapsed());
+  requests_.erase(it);
+}
+
+void ODFSMetrics::OnRequestExecuted(int request_id) {}
+
+void ODFSMetrics::OnRequestFulfilled(int request_id,
+                                     const RequestValue& result,
+                                     bool has_more) {
+  if (!has_more) {
+    RecordResult(request_id, base::File::FILE_OK);
+  }
+}
+
+void ODFSMetrics::OnRequestRejected(int request_id,
+                                    const RequestValue& result,
+                                    base::File::Error error) {
+  RecordResult(request_id, error);
+}
+
+void ODFSMetrics::OnRequestTimedOut(int request_id) {}
+
+void ODFSMetrics::RecordResult(int request_id, base::File::Error error) {
+  auto it = requests_.find(request_id);
+  if (it == requests_.end()) {
+    return;
+  }
+  Request& request = it->second;
+  base::UmaHistogramExactLinear(GetHistogramName("Error", request.request_type),
+                                -error, -base::File::FILE_ERROR_MAX);
+}
+
+}  // namespace ash::file_system_provider
diff --git a/chrome/browser/ash/file_system_provider/odfs_metrics.h b/chrome/browser/ash/file_system_provider/odfs_metrics.h
new file mode 100644
index 0000000..829dc46
--- /dev/null
+++ b/chrome/browser/ash/file_system_provider/odfs_metrics.h
@@ -0,0 +1,41 @@
+// 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_FILE_SYSTEM_PROVIDER_ODFS_METRICS_H_
+#define CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_ODFS_METRICS_H_
+
+#include <map>
+
+#include "base/files/file.h"
+#include "base/timer/elapsed_timer.h"
+#include "chrome/browser/ash/file_system_provider/request_manager.h"
+
+namespace ash::file_system_provider {
+
+class ODFSMetrics : public RequestManager::Observer {
+ public:
+  ODFSMetrics();
+  ~ODFSMetrics() override;
+  // RequestManager::Observer overrides:
+  void OnRequestCreated(int request_id, RequestType type) override;
+  void OnRequestDestroyed(int request_id) override;
+  void OnRequestExecuted(int request_id) override;
+  void OnRequestFulfilled(int request_id,
+                          const RequestValue& result,
+                          bool has_more) override;
+  void OnRequestRejected(int request_id,
+                         const RequestValue& result,
+                         base::File::Error error) override;
+  void OnRequestTimedOut(int request_id) override;
+
+ private:
+  struct Request;
+  void RecordResult(int request_id, base::File::Error error);
+
+  std::map<int, Request> requests_;
+};
+
+}  // namespace ash::file_system_provider
+
+#endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_ODFS_METRICS_H_
diff --git a/chrome/browser/ash/file_system_provider/provided_file_system.cc b/chrome/browser/ash/file_system_provider/provided_file_system.cc
index 72fbf06..49a77ebd 100644
--- a/chrome/browser/ash/file_system_provider/provided_file_system.cc
+++ b/chrome/browser/ash/file_system_provider/provided_file_system.cc
@@ -15,6 +15,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/ash/file_system_provider/notification_manager.h"
+#include "chrome/browser/ash/file_system_provider/odfs_metrics.h"
 #include "chrome/browser/ash/file_system_provider/operation_request_manager.h"
 #include "chrome/browser/ash/file_system_provider/operations/abort.h"
 #include "chrome/browser/ash/file_system_provider/operations/add_watcher.h"
@@ -170,6 +171,11 @@
       base::BindRepeating(&ProvidedFileSystem::OnLacrosOperationForwarded,
                           weak_ptr_factory_.GetWeakPtr()),
       GetServiceWorkerLifetimeManager(profile_));
+  const ProviderId& provider_id = file_system_info_.provider_id();
+  if (chromeos::features::IsUploadOfficeToCloudEnabled() &&
+      provider_id.GetExtensionId() == extension_misc::kODFSExtensionId) {
+    odfs_metrics_ = std::make_unique<ODFSMetrics>();
+  }
   ConstructRequestManager();
 }
 
@@ -903,6 +909,11 @@
 
   request_manager_ = std::make_unique<OperationRequestManager>(
       profile_, extension_id, notification_manager_.get(), operation_timeout);
+
+  if (chromeos::features::IsUploadOfficeToCloudEnabled() &&
+      extension_id == extension_misc::kODFSExtensionId) {
+    request_manager_->AddObserver(odfs_metrics_.get());
+  }
 }
 
 }  // namespace file_system_provider
diff --git a/chrome/browser/ash/file_system_provider/provided_file_system.h b/chrome/browser/ash/file_system_provider/provided_file_system.h
index c0b8137f..8dee964 100644
--- a/chrome/browser/ash/file_system_provider/provided_file_system.h
+++ b/chrome/browser/ash/file_system_provider/provided_file_system.h
@@ -44,6 +44,7 @@
 
 class NotificationManagerInterface;
 class RequestDispatcher;
+class ODFSMetrics;
 
 // Automatically calls the |update_callback| after all of the callbacks created
 // with |CreateCallback| are called.
@@ -257,6 +258,7 @@
   ProvidedFileSystemInfo file_system_info_;
   std::unique_ptr<NotificationManagerInterface> notification_manager_;
   std::unique_ptr<RequestDispatcher> request_dispatcher_;
+  std::unique_ptr<ODFSMetrics> odfs_metrics_;
   std::unique_ptr<OperationRequestManager> request_manager_;
   Watchers watchers_;
   Queue watcher_queue_;
diff --git a/chrome/browser/ash/login/app_mode/test/kiosk_enterprise_browsertest.cc b/chrome/browser/ash/login/app_mode/test/kiosk_enterprise_browsertest.cc
index 36abf13b..553a6ff 100644
--- a/chrome/browser/ash/login/app_mode/test/kiosk_enterprise_browsertest.cc
+++ b/chrome/browser/ash/login/app_mode/test/kiosk_enterprise_browsertest.cc
@@ -258,17 +258,9 @@
   WaitForAppLaunchSuccess();
 }
 
-// TODO(crbug.com/1446486): Flaky on Chrome OS.
-#if BUILDFLAG(IS_CHROMEOS)
-#define MAYBE_LaunchingAppThatRequiresNetworkWhilstOfflineShouldShowNetworkScreen \
-  DISABLED_LaunchingAppThatRequiresNetworkWhilstOfflineShouldShowNetworkScreen
-#else
-#define MAYBE_LaunchingAppThatRequiresNetworkWhilstOfflineShouldShowNetworkScreen \
-  LaunchingAppThatRequiresNetworkWhilstOfflineShouldShowNetworkScreen
-#endif
 IN_PROC_BROWSER_TEST_F(
     KioskEnterpriseTest,
-    MAYBE_LaunchingAppThatRequiresNetworkWhilstOfflineShouldShowNetworkScreen) {
+    LaunchingAppThatRequiresNetworkWhilstOfflineShouldShowNetworkScreen) {
   ScopedCanConfigureNetwork can_configure_network(true);
 
   // Start app launch with network portal state.
diff --git a/chrome/browser/ash/login/ui/login_display_host_webui.cc b/chrome/browser/ash/login/ui/login_display_host_webui.cc
index 32c56eda..340e0df 100644
--- a/chrome/browser/ash/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/ash/login/ui/login_display_host_webui.cc
@@ -838,7 +838,9 @@
   // Subscribe to crash events.
   content::WebContentsObserver::Observe(login_view_->GetWebContents());
   login_view_->LoadURL(url);
-  login_window_->Show();
+  if (!features::IsOobeSimonEnabled()) {
+    login_window_->Show();
+  }
   CHECK(GetOobeUI());
   GetOobeUI()->AddObserver(this);
 }
diff --git a/chrome/browser/ash/login/wizard_controller_browsertest.cc b/chrome/browser/ash/login/wizard_controller_browsertest.cc
index 05ecd048..78bd92e 100644
--- a/chrome/browser/ash/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/ash/login/wizard_controller_browsertest.cc
@@ -1723,6 +1723,8 @@
   EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
             GetErrorScreen()->GetParentScreen());
   test::OobeJS().ExpectHiddenPath(kGuestSessionLink);
+  histogram_tester()->ExpectBucketCount(
+      "Enterprise.AutoEnrollmentControllerTimeout", 3 /*kTimeoutUnified*/, 1);
 }
 
 // Tests that AutoEnrollmentController does not create another
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
index 9e8f928..4fbb8ec 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h"
 #include "chromeos/dbus/dlp/dlp_client.h"
 #include "chromeos/dbus/dlp/dlp_service.pb.h"
 #include "chromeos/ui/base/file_icon_util.h"
@@ -176,6 +177,20 @@
     return data_controls::Component::kDrive;
   }
 
+  if (ash::cloud_upload::CloudUploadDialog::IsODFSMounted(profile)) {
+    auto* service = ash::file_system_provider::Service::Get(profile);
+    auto provider_id =
+        ash::file_system_provider::ProviderId::CreateFromExtensionId(
+            file_manager::file_tasks::GetODFSExtensionId(profile));
+    auto one_drive_file_systems =
+        service->GetProvidedFileSystemInfoList(provider_id);
+    CHECK(one_drive_file_systems.size() == 1);
+
+    if (one_drive_file_systems[0].mount_path().IsParent(file_path)) {
+      return data_controls::Component::kOneDrive;
+    }
+  }
+
   base::FilePath linux_files =
       file_manager::util::GetCrostiniMountDirectory(profile);
   if (linux_files == file_path || linux_files.IsParent(file_path)) {
@@ -213,6 +228,8 @@
       return ::dlp::DlpComponent::USB;
     case data_controls::Component::kDrive:
       return ::dlp::DlpComponent::GOOGLE_DRIVE;
+    case data_controls::Component::kOneDrive:
+      return ::dlp::DlpComponent::MICROSOFT_ONEDRIVE;
   }
 }
 
@@ -440,6 +457,8 @@
       return ::dlp::DlpComponent::USB;
     case data_controls::Component::kDrive:
       return ::dlp::DlpComponent::GOOGLE_DRIVE;
+    case data_controls::Component::kOneDrive:
+      return ::dlp::DlpComponent::MICROSOFT_ONEDRIVE;
   }
 }
 
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_browsertest.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_browsertest.cc
index 4dad80a8..05dd39b 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_browsertest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_browsertest.cc
@@ -8,14 +8,22 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_piece_forward.h"
+#include "base/test/mock_callback.h"
+#include "chrome/browser/ash/file_manager/file_manager_test_util.h"
+#include "chrome/browser/ash/file_system_provider/fake_extension_provider.h"
+#include "chrome/browser/ash/file_system_provider/service.h"
 #include "chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h"
+#include "chrome/browser/chromeos/policy/dlp/dlp_policy_event.pb.h"
+#include "chrome/browser/chromeos/policy/dlp/dlp_reporting_manager.h"
+#include "chrome/browser/chromeos/policy/dlp/dlp_reporting_manager_test_helper.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
 #include "chrome/browser/chromeos/policy/dlp/mock_dlp_rules_manager.h"
 #include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
 #include "chrome/browser/file_select_helper.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/file_select_listener.h"
@@ -114,6 +122,72 @@
 };
 
 IN_PROC_BROWSER_TEST_F(DlpFilesControllerAshBrowserTest,
+                       CheckIfDownloadAllowed_OneDrive) {
+  // Mount OneDrive file system.
+  auto fake_provider = ash::file_system_provider::FakeExtensionProvider::Create(
+      extension_misc::kODFSExtensionId);
+  const auto providerId = fake_provider->GetId();
+  auto* service = ash::file_system_provider::Service::Get(browser()->profile());
+  service->RegisterProvider(std::move(fake_provider));
+
+  const auto mount_options = ash::file_system_provider::MountOptions(
+      "test-filesystem", "OneDrive Test FileSystem");
+  service->MountFileSystem(providerId, mount_options);
+
+  const auto file_system_list =
+      service->GetProvidedFileSystemInfoList(providerId);
+  EXPECT_EQ(file_system_list.size(), 1UL);
+
+  // Setup the reporting manager.
+  std::vector<DlpPolicyEvent> events;
+  auto reporting_manager = std::make_unique<DlpReportingManager>();
+  SetReportQueueForReportingManager(
+      reporting_manager.get(), events,
+      base::SequencedTaskRunner::GetCurrentDefault());
+  ON_CALL(*mock_rules_manager_, GetReportingManager)
+      .WillByDefault(::testing::Return(reporting_manager.get()));
+
+  const std::string rule_name = "Rule name";
+  const std::string rule_id = "Rule ID";
+
+  const DlpRulesManager::RuleMetadata ruleMetadata(rule_name, rule_id);
+
+  EXPECT_CALL(
+      *mock_rules_manager_,
+      IsRestrictedComponent(_, data_controls::Component::kOneDrive, _, _, _))
+      .WillOnce(
+          testing::DoAll(testing::SetArgPointee<3>(kExampleUrl),
+                         testing::SetArgPointee<4>(ruleMetadata),
+                         testing::Return(DlpRulesManager::Level::kBlock)));
+
+  EXPECT_CALL(*mock_rules_manager_, GetReportingManager())
+      .Times(::testing::AnyNumber());
+
+  testing::StrictMock<
+      base::MockCallback<DlpFilesControllerAsh::CheckIfDlpAllowedCallback>>
+      cb;
+  EXPECT_CALL(cb, Run(/*is_allowed=*/false)).Times(1);
+
+  const std::string file_path = "Downloads/file.txt";
+
+  files_controller_->CheckIfDownloadAllowed(
+      DlpFileDestination(kExampleUrl),
+      base::FilePath(file_system_list[0].mount_path().Append(file_path)),
+      cb.Get());
+
+  ASSERT_EQ(events.size(), 1u);
+
+  auto event_builder = DlpPolicyEventBuilder::Event(
+      kExampleUrl, rule_name, rule_id, DlpRulesManager::Restriction::kFiles,
+      DlpRulesManager::Level::kBlock);
+
+  event_builder->SetDestinationComponent(data_controls::Component::kOneDrive);
+  event_builder->SetContentName(base::FilePath(file_path).BaseName().value());
+
+  EXPECT_THAT(events[0], IsDlpPolicyEvent(event_builder->Create()));
+}
+
+IN_PROC_BROWSER_TEST_F(DlpFilesControllerAshBrowserTest,
                        FilesUploadCallerPassed) {
   ui::FakeSelectFileDialog::Factory* select_file_dialog_factory =
       ui::FakeSelectFileDialog::RegisterFactory();
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc
index 5d65125..00025ea8 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc
@@ -997,6 +997,8 @@
       data_controls::Component::kUsb);
   components[DlpRulesManager::Level::kWarn].insert(
       data_controls::Component::kDrive);
+  components[DlpRulesManager::Level::kReport].insert(
+      data_controls::Component::kOneDrive);
 
   EXPECT_CALL(*rules_manager_, GetAggregatedDestinations)
       .WillOnce(testing::Return(destinations));
@@ -1006,7 +1008,7 @@
   ASSERT_TRUE(files_controller_);
   auto result = files_controller_->GetDlpRestrictionDetails(kExampleUrl1);
 
-  ASSERT_EQ(result.size(), 3u);
+  ASSERT_EQ(result.size(), 4u);
   std::vector<std::string> expected_urls;
   std::vector<data_controls::Component> expected_components;
   // Block:
@@ -1022,13 +1024,20 @@
   EXPECT_EQ(result[1].level, DlpRulesManager::Level::kAllow);
   EXPECT_EQ(result[1].urls, expected_urls);
   EXPECT_EQ(result[1].components, expected_components);
+  // Report:
+  expected_urls.clear();
+  expected_components.clear();
+  expected_components.push_back(data_controls::Component::kOneDrive);
+  EXPECT_EQ(result[2].level, DlpRulesManager::Level::kReport);
+  EXPECT_EQ(result[2].urls, expected_urls);
+  EXPECT_EQ(result[2].components, expected_components);
   // Warn:
   expected_urls.clear();
   expected_components.clear();
   expected_components.push_back(data_controls::Component::kDrive);
-  EXPECT_EQ(result[2].level, DlpRulesManager::Level::kWarn);
-  EXPECT_EQ(result[2].urls, expected_urls);
-  EXPECT_EQ(result[2].components, expected_components);
+  EXPECT_EQ(result[3].level, DlpRulesManager::Level::kWarn);
+  EXPECT_EQ(result[3].urls, expected_urls);
+  EXPECT_EQ(result[3].components, expected_components);
 }
 
 TEST_F(DlpFilesControllerAshTest, GetDlpRestrictionDetails_Components) {
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_controller.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_controller.cc
index f1511e5..21420134 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_controller.cc
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_controller.cc
@@ -153,10 +153,13 @@
 }
 
 enum class AutoEnrollmentControllerTimeoutReport {
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
   kTimeoutCancelled = 0,
-  kTimeoutFRE,
-  kTimeout,
-  kMaxValue = kTimeout,
+  kTimeoutFRE = 1,
+  kTimeout = 2,
+  kTimeoutUnified = 3,
+  kMaxValue = kTimeoutUnified
 };
 
 void ReportTimeoutUMA(AutoEnrollmentControllerTimeoutReport report) {
@@ -644,7 +647,7 @@
     // keeps the connection open.
     LOG(ERROR) << "EnrollmentStateFetcher didn't complete within time limit.";
     UpdateState(AutoEnrollmentState::kConnectionError);
-    // TODO(b/265923216): Report unified enrollment timeouts to UMA.
+    ReportTimeoutUMA(AutoEnrollmentControllerTimeoutReport::kTimeoutUnified);
     return;
   }
 
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker.cc
index 4256be01..a8112f5 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker.cc
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker.cc
@@ -12,11 +12,13 @@
 #include "base/functional/callback.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "build/branding_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chromeos/ash/components/system/factory_ping_embargo_check.h"
 #include "chromeos/ash/components/system/statistics_provider.h"
+#include "components/policy/core/common/cloud/enterprise_metrics.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/resource_request.h"
@@ -60,7 +62,7 @@
 }
 
 // Kill switch config request parameters.
-const net::NetworkTrafficAnnotationTag kKSConfigTrafficAnnotation =
+constexpr net::NetworkTrafficAnnotationTag kKSConfigTrafficAnnotation =
     net::DefineNetworkTrafficAnnotation(
         "unified_state_determination_kill_switch",
         R"(
@@ -90,13 +92,17 @@
               setting: "This feature cannot be controlled by Chrome settings."
               chrome_policy {}
             })");
-const char kKSConfigUrl[] =
+constexpr char kKSConfigUrl[] =
     "https://www.gstatic.com/chromeos-usd-experiment/v1.json";
-const base::TimeDelta kKSConfigFetchTimeout = base::Seconds(1);
-const int kKSConfigFetchRetries = 4;
-const size_t kKSConfigMaxSize = 1024;  // 1KB
-const char kKSConfigFetchMethod[] = "GET";
-const char kKSConfigDisableUpToVersionKey[] = "disable_up_to_version";
+constexpr base::TimeDelta kKSConfigFetchTimeout = base::Seconds(1);
+constexpr int kKSConfigFetchTries = 4;
+constexpr size_t kKSConfigMaxSize = 1024;  // 1KB
+constexpr char kKSConfigFetchMethod[] = "GET";
+constexpr char kKSConfigDisableUpToVersionKey[] = "disable_up_to_version";
+constexpr int kUMAKSFetchNumTriesMinValue = 1;
+constexpr int kUMAKSFetchNumTriesExclusiveMaxValue = 51;
+constexpr int kUMAKSFetchNumTriesBuckets =
+    kUMAKSFetchNumTriesExclusiveMaxValue - kUMAKSFetchNumTriesMinValue;
 
 // This value represents current version of the code. After we have enabled kill
 // switch for a particular version, we can increment it after fixing the logic.
@@ -108,6 +114,13 @@
 // When set to true, unified state determination is disabled.
 absl::optional<bool> g_unified_state_determination_kill_switch;
 
+void ReportKillSwitchFetchTries(int tries) {
+  base::UmaHistogramCustomCounts(kUMAStateDeterminationKillSwitchFetchNumTries,
+                                 tries, kUMAKSFetchNumTriesMinValue,
+                                 kUMAKSFetchNumTriesExclusiveMaxValue,
+                                 kUMAKSFetchNumTriesBuckets);
+}
+
 void ParseKSConfig(base::OnceClosure init_callback,
                    const std::string& response) {
   absl::optional<base::Value> config = base::JSONReader::Read(response);
@@ -134,10 +147,16 @@
 void FetchKSConfig(
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
     base::OnceClosure init_callback,
-    int retries_left,
+    int tries_left,
     std::unique_ptr<network::SimpleURLLoader> loader = nullptr,
     std::unique_ptr<std::string> response = nullptr) {
-  if (!response && retries_left) {
+  if (loader) {
+    base::UmaHistogramSparse(
+        kUMAStateDeterminationKillSwitchFetchNetworkErrorCode,
+        -loader->NetError());
+  }
+
+  if (!response && tries_left) {
     auto request = std::make_unique<network::ResourceRequest>();
     request->url = GURL(kKSConfigUrl);
     request->method = kKSConfigFetchMethod;
@@ -152,7 +171,7 @@
     loader_ptr->DownloadToString(
         loader_factory.get(),
         base::BindOnce(FetchKSConfig, loader_factory, std::move(init_callback),
-                       retries_left - 1, std::move(loader)),
+                       tries_left - 1, std::move(loader)),
         kKSConfigMaxSize);
     return;
   }
@@ -162,12 +181,14 @@
   if (!response) {
     LOG(ERROR) << "Kill switch config request failed with code "
                << loader->NetError();
+    ReportKillSwitchFetchTries(kKSConfigFetchTries);
     std::move(init_callback).Run();
     return;
   }
 
   VLOG(1) << "Received kill switch config response after "
-          << (kKSConfigFetchRetries - retries_left) << " tries: " << *response;
+          << (kKSConfigFetchTries - tries_left) << " tries: " << *response;
+  ReportKillSwitchFetchTries(kKSConfigFetchTries - tries_left);
   ParseKSConfig(std::move(init_callback), *response);
 }
 
@@ -184,8 +205,7 @@
 void AutoEnrollmentTypeChecker::Initialize(
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
     base::OnceClosure init_callback) {
-  FetchKSConfig(loader_factory, std::move(init_callback),
-                kKSConfigFetchRetries);
+  FetchKSConfig(loader_factory, std::move(init_callback), kKSConfigFetchTries);
 }
 
 // static
diff --git a/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc b/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc
index a1a46139..6fc9233 100644
--- a/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc
+++ b/chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "ash/constants/ash_switches.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_command_line.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
@@ -18,6 +19,7 @@
 #include "chromeos/ash/components/system/factory_ping_embargo_check.h"
 #include "chromeos/ash/components/system/fake_statistics_provider.h"
 #include "chromeos/ash/components/system/statistics_provider.h"
+#include "components/policy/core/common/cloud/enterprise_metrics.h"
 #include "net/base/load_flags.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
@@ -447,6 +449,34 @@
   EXPECT_FALSE(AutoEnrollmentTypeChecker::Initialized());
 }
 
+TEST_F(AutoEnrollmentTypeCheckerInitializationTest, UmaHistograms) {
+  base::HistogramTester histograms;
+  base::test::TestFuture<void> future;
+  network::URLLoaderCompletionStatus status;
+
+  AutoEnrollmentTypeChecker::Initialize(test_shared_loader_factory_,
+                                        future.GetCallback());
+
+  status.error_code = net::ERR_NETWORK_CHANGED;
+  test_url_loader_factory_.SimulateResponseForPendingRequest(
+      GURL("https://www.gstatic.com/chromeos-usd-experiment/v1.json"), status,
+      network::mojom::URLResponseHead::New(), "");
+  test_url_loader_factory_.AddResponse(
+      "https://www.gstatic.com/chromeos-usd-experiment/v1.json",
+      R"({"disable_up_to_version": 1})", net::HTTP_OK);
+
+  ASSERT_TRUE(future.Wait());
+  histograms.ExpectTotalCount(
+      kUMAStateDeterminationKillSwitchFetchNetworkErrorCode, 2);
+  histograms.ExpectBucketCount(
+      kUMAStateDeterminationKillSwitchFetchNetworkErrorCode,
+      -net::ERR_NETWORK_CHANGED, 1);
+  histograms.ExpectBucketCount(
+      kUMAStateDeterminationKillSwitchFetchNetworkErrorCode, -net::OK, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationKillSwitchFetchNumTries,
+                                2, 1);
+}
+
 TEST_F(AutoEnrollmentTypeCheckerInitializationTest, KilledBeforeInitStarted) {
   EXPECT_FALSE(AutoEnrollmentTypeChecker::Initialized());
   EXPECT_TRUE(AutoEnrollmentTypeChecker::
@@ -524,7 +554,7 @@
   base::test::TestFuture<void> future;
   test_url_loader_factory_.AddResponse(
       "https://www.gstatic.com/chromeos-usd-experiment/v1.json",
-      "{\"disable_up_to_version\": 1}", net::HTTP_OK);
+      R"({"disable_up_to_version": 1})", net::HTTP_OK);
 
   AutoEnrollmentTypeChecker::Initialize(test_shared_loader_factory_,
                                         future.GetCallback());
@@ -539,7 +569,7 @@
   test_url_loader_factory_.AddResponse(
       "https://www.gstatic.com/chromeos-usd-experiment/v1.json",
       // TODO(b/265923216): Change to 0 when kCodeVersion is 1.
-      "{\"disable_up_to_version\": -1}", net::HTTP_OK);
+      R"({"disable_up_to_version": -1})", net::HTTP_OK);
 
   AutoEnrollmentTypeChecker::Initialize(test_shared_loader_factory_,
                                         future.GetCallback());
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc
index 8940b67..02b5a0a 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc
+++ b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc
@@ -14,6 +14,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/time/time.h"
 #include "base/types/expected.h"
@@ -33,6 +34,7 @@
 #include "chromeos/ash/components/dbus/system_clock/system_clock_sync_observation.h"
 #include "chromeos/ash/components/system/factory_ping_embargo_check.h"
 #include "chromeos/ash/components/system/statistics_provider.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/dmserver_job_configurations.h"
 #include "components/policy/core/common/cloud/enterprise_metrics.h"
 #include "components/policy/proto/device_management_backend.pb.h"
@@ -47,9 +49,6 @@
 
 namespace em = enterprise_management;
 
-// TODO(b/265923216): Review UMA stats in this file and compare them to stats
-// reported by auto_enrollment_client_impl.cc. Add missing, remove unnecessary.
-
 // TODO(b/265923216): Wrap callbacks into an object ensuring they are called.
 
 RlwePlaintextId ConstructPlainttextId(const std::string& rlz_brand_code,
@@ -110,9 +109,6 @@
   // membership for. Must be set before RlweOprf and RlweQuery steps.
   std::unique_ptr<private_membership::rlwe::PrivateMembershipRlweClient>
       psm_rlwe_client;
-
-  // Time at which OPRF request was sent. Used to compute PSM protocol time.
-  base::TimeTicks oprf_request_time_;
 };
 
 void StorePsmError(PrefService* local_state) {
@@ -215,8 +211,42 @@
             .value_or(""));
     out_serial_number =
         std::string(statistics_provider->GetMachineID().value_or(""));
+    ReportDeviceIdentifierStatus(out_serial_number.empty(),
+                                 out_rlz_brand_code.empty());
     return !out_serial_number.empty() && !out_rlz_brand_code.empty();
   }
+
+ private:
+  static void ReportDeviceIdentifierStatus(bool serial_number_missing,
+                                           bool rlz_brand_code_missing) {
+    enum class DeviceIdentifierStatus {
+      // These values are persisted to logs. Entries should not be renumbered
+      // and numeric values should never be reused.
+      kAllPresent = 0,
+      kSerialNumberMissing = 1,
+      kRlzBrandCodeMissing = 2,
+      kAllMissing = 3,
+      kMaxValue = kAllMissing
+    };
+
+    if (serial_number_missing && rlz_brand_code_missing) {
+      base::UmaHistogramEnumeration(
+          kUMAStateDeterminationDeviceIdentifierStatus,
+          DeviceIdentifierStatus::kAllMissing);
+    } else if (serial_number_missing) {
+      base::UmaHistogramEnumeration(
+          kUMAStateDeterminationDeviceIdentifierStatus,
+          DeviceIdentifierStatus::kSerialNumberMissing);
+    } else if (rlz_brand_code_missing) {
+      base::UmaHistogramEnumeration(
+          kUMAStateDeterminationDeviceIdentifierStatus,
+          DeviceIdentifierStatus::kRlzBrandCodeMissing);
+    } else {
+      base::UmaHistogramEnumeration(
+          kUMAStateDeterminationDeviceIdentifierStatus,
+          DeviceIdentifierStatus::kAllPresent);
+    }
+  }
 };
 
 // Class to obtain state keys.
@@ -303,7 +333,6 @@
          ->mutable_oprf_request() = *oprf_request;
 
     VLOG(1) << "Send PSM RLWE OPRF request";
-    context.oprf_request_time_ = base::TimeTicks::Now();
     job_ = context.device_management_service->CreateJob(std::move(config));
   }
 
@@ -311,6 +340,12 @@
   void OnRequestDone(CompletionCallback completion_callback,
                      DMServerJobResult result) {
     // Handle errors
+    base::UmaHistogramEnumeration(
+        kUMAStateDeterminationPsmRlweOprfRequestDmStatusCode, result.dm_status,
+        static_cast<policy::DeviceManagementStatus>(DM_STATUS_SERVICE_MAX + 1));
+    base::UmaHistogramSparse(
+        kUMAStateDeterminationPsmRlweOprfRequestNetworkErrorCode,
+        -result.net_error);
     switch (result.dm_status) {
       case DM_STATUS_SUCCESS: {
         if (!result.response.has_private_set_membership_response() ||
@@ -389,8 +424,7 @@
         /*oauth_token=*/absl::nullopt, context.url_loader_factory,
         base::BindOnce(&RlweQuery::OnRequestDone, weak_factory_.GetWeakPtr(),
                        base::Unretained(context.psm_rlwe_client.get()),
-                       std::move(completion_callback),
-                       context.oprf_request_time_));
+                       std::move(completion_callback)));
 
     *config->request()
          ->mutable_private_set_membership_request()
@@ -404,9 +438,14 @@
   void OnRequestDone(
       private_membership::rlwe::PrivateMembershipRlweClient* psm_rlwe_client,
       CompletionCallback completion_callback,
-      base::TimeTicks oprf_request_time,
       DMServerJobResult result) {
     // Handle errors
+    base::UmaHistogramEnumeration(
+        kUMAStateDeterminationPsmRlweQueryRequestDmStatusCode, result.dm_status,
+        static_cast<policy::DeviceManagementStatus>(DM_STATUS_SERVICE_MAX + 1));
+    base::UmaHistogramSparse(
+        kUMAStateDeterminationPsmRlweQueryRequestNetworkErrorCode,
+        -result.net_error);
     switch (result.dm_status) {
       case DM_STATUS_SUCCESS: {
         // Check if the RLWE query response is empty.
@@ -500,7 +539,7 @@
         /*oauth_token=*/absl::nullopt, context.url_loader_factory,
         base::BindOnce(&EnrollmentState::OnRequestDone,
                        weak_factory_.GetWeakPtr(),
-                       std::move(completion_callback), base::TimeTicks::Now()));
+                       std::move(completion_callback)));
 
     auto* request = config->request()->mutable_device_state_retrieval_request();
     if (context.state_key.has_value()) {
@@ -514,9 +553,13 @@
   }
 
   void OnRequestDone(CompletionCallback completion_callback,
-                     base::TimeTicks start_time,
                      DMServerJobResult result) {
     // Handle errors
+    base::UmaHistogramEnumeration(
+        kUMAStateDeterminationStateRequestDmStatusCode, result.dm_status,
+        static_cast<policy::DeviceManagementStatus>(DM_STATUS_SERVICE_MAX + 1));
+    base::UmaHistogramSparse(kUMAStateDeterminationStateRequestNetworkErrorCode,
+                             -result.net_error);
     switch (result.dm_status) {
       case DM_STATUS_SUCCESS: {
         if (!result.response.has_device_state_retrieval_response()) {
@@ -793,15 +836,21 @@
         context_(std::move(context)) {}
 
   void Start() {
-    if (!AutoEnrollmentTypeChecker::IsUnifiedStateDeterminationEnabled()) {
+    fetch_started_ = base::TimeTicks::Now();
+    const bool enabled =
+        AutoEnrollmentTypeChecker::IsUnifiedStateDeterminationEnabled();
+    base::UmaHistogramBoolean(kUMAStateDeterminationEnabled, enabled);
+    if (!enabled) {
       VLOG(1) << "Unified state determination is disabled";
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
+      return ReportResult(AutoEnrollmentState::kNoEnrollment);
     }
 
     // Flex devices do not support FRE, hence there is no need to perform state
     // determination. Users are still able to manually enroll devices though.
-    if (ash::switches::IsRevenBranding()) {
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
+    const bool is_on_flex = ash::switches::IsRevenBranding();
+    base::UmaHistogramBoolean(kUMAStateDeterminationOnFlex, is_on_flex);
+    if (is_on_flex) {
+      return ReportResult(AutoEnrollmentState::kNoEnrollment);
     }
     // TODO(b/265923216): Investigate the possibility of using bypassing PSM and
     // using state key to directly request state when identifiers are missing.
@@ -809,24 +858,75 @@
                                       context_.rlz_brand_code,
                                       context_.serial_number)) {
       // Skip enrollment if serial number or brand code are missing.
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
+      return ReportResult(AutoEnrollmentState::kNoEnrollment);
     }
 
+    step_started_ = base::TimeTicks::Now();
     system_clock_.Sync(context_.system_clock_client,
                        base::BindOnce(&Sequence::OnSystemClockSynced,
                                       weak_factory_.GetWeakPtr()));
   }
 
  private:
-  void OnSystemClockSynced(bool synchronized) {
-    if (!synchronized) {
-      LOG(ERROR) << "System clock failed to synchronize";
-      return std::move(report_result_)
-          .Run(AutoEnrollmentState::kConnectionError);
+  void ReportTotalDuration(base::TimeDelta fetch_duration,
+                           AutoEnrollmentState state) {
+    std::string uma_suffix;
+    switch (state) {
+      case AutoEnrollmentState::kIdle:
+      case AutoEnrollmentState::kPending:
+        NOTREACHED();
+        break;
+      case AutoEnrollmentState::kConnectionError:
+        uma_suffix = kUMASuffixConnectionError;
+        break;
+      case AutoEnrollmentState::kDisabled:
+        uma_suffix = kUMASuffixDisabled;
+        break;
+      case AutoEnrollmentState::kEnrollment:
+        uma_suffix = kUMASuffixEnrollment;
+        break;
+      case AutoEnrollmentState::kNoEnrollment:
+        uma_suffix = kUMASuffixNoEnrollment;
+        break;
+      case AutoEnrollmentState::kServerError:
+        uma_suffix = kUMASuffixServerError;
+        break;
     }
 
-    if (!embargo_date_.Passed(context_)) {
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
+    base::UmaHistogramMediumTimes(kUMAStateDeterminationTotalDuration,
+                                  fetch_duration);
+    base::UmaHistogramMediumTimes(
+        base::StrCat({kUMAStateDeterminationTotalDurationByState, uma_suffix}),
+        fetch_duration);
+  }
+
+  void ReportStepDurationAndResetTimer(base::StringPiece uma_step_suffix) {
+    base::UmaHistogramTimes(
+        base::StrCat({kUMAStateDeterminationStepDuration, uma_step_suffix}),
+        base::TimeTicks::Now() - step_started_);
+    step_started_ = base::TimeTicks::Now();
+  }
+
+  void ReportResult(AutoEnrollmentState state) {
+    DCHECK(state != AutoEnrollmentState::kIdle);
+    DCHECK(state != AutoEnrollmentState::kPending);
+    ReportTotalDuration(base::TimeTicks::Now() - fetch_started_, state);
+    std::move(report_result_).Run(state);
+  }
+
+  void OnSystemClockSynced(bool synchronized) {
+    ReportStepDurationAndResetTimer(kUMASuffixSystemClockSync);
+    base::UmaHistogramBoolean(kUMAStateDeterminationSystemClockSynchronized,
+                              synchronized);
+    if (!synchronized) {
+      LOG(ERROR) << "System clock failed to synchronize";
+      return ReportResult(AutoEnrollmentState::kConnectionError);
+    }
+
+    const bool passed = embargo_date_.Passed(context_);
+    base::UmaHistogramBoolean(kUMAStateDeterminationEmbargoDatePassed, passed);
+    if (!passed) {
+      return ReportResult(AutoEnrollmentState::kNoEnrollment);
     }
 
     ownership_.Check(context_.device_settings_service,
@@ -835,14 +935,19 @@
   }
 
   void OnOwnershipChecked(ash::DeviceSettingsService::OwnershipStatus status) {
+    ReportStepDurationAndResetTimer(kUMASuffixOwnershipCheck);
+    base::UmaHistogramEnumeration(
+        kUMAStateDeterminationOwnershipStatus, status,
+        static_cast<ash::DeviceSettingsService::OwnershipStatus>(
+            ash::DeviceSettingsService::OwnershipStatus::OWNERSHIP_MAX + 1));
     if (status == ash::DeviceSettingsService::OWNERSHIP_UNKNOWN) {
       LOG(ERROR) << "Device ownership is unknown. Skipping enrollment";
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
+      return ReportResult(AutoEnrollmentState::kNoEnrollment);
     }
 
     if (status == ash::DeviceSettingsService::OWNERSHIP_TAKEN) {
       VLOG(1) << "Device ownership is already taken. Skipping enrollment";
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
+      return ReportResult(AutoEnrollmentState::kNoEnrollment);
     }
 
     state_keys_.Retrieve(context_.state_key_broker,
@@ -851,6 +956,9 @@
   }
 
   void OnStateKeysRetrieved(absl::optional<std::string> state_key) {
+    ReportStepDurationAndResetTimer(kUMASuffixStateKeyRetrieval);
+    base::UmaHistogramBoolean(kUMAStateDeterminationStateKeysRetrieved,
+                              state_key.has_value());
     LOG_IF(WARNING, !state_key) << "Failed to obtain state keys";
     context_.state_key = state_key;
     context_.psm_rlwe_client = context_.rlwe_client_factory.Run(
@@ -860,9 +968,10 @@
   }
 
   void OnOprfRequestDone(RlweOprf::Result result) {
+    ReportStepDurationAndResetTimer(kUMASuffixOPRFRequest);
     if (!result.has_value()) {
       StorePsmError(local_state_);
-      return std::move(report_result_).Run(result.error());
+      return ReportResult(result.error());
     }
     query_.Request(context_, result.value(),
                    base::BindOnce(&Sequence::OnQueryRequestDone,
@@ -870,9 +979,10 @@
   }
 
   void OnQueryRequestDone(RlweQuery::Result result) {
+    ReportStepDurationAndResetTimer(kUMASuffixQueryRequest);
     if (!result.has_value()) {
       StorePsmError(local_state_);
-      return std::move(report_result_).Run(result.error());
+      return ReportResult(result.error());
     }
 
     RlwePlaintextId psm_id =
@@ -882,8 +992,10 @@
                  << psm_id.sensitive_id() << " is "
                  << (result.value() ? "" : " not") << " present on the server";
 
+    base::UmaHistogramBoolean(kUMAStateDeterminationPsmReportedAvailableState,
+                              result.value());
     if (!result.value()) {
-      return std::move(report_result_).Run(AutoEnrollmentState::kNoEnrollment);
+      return ReportResult(AutoEnrollmentState::kNoEnrollment);
     }
     query_.StoreResponse(local_state_, result.value());
     state_.Request(context_, base::BindOnce(&Sequence::OnStateRequestDone,
@@ -891,17 +1003,24 @@
   }
 
   void OnStateRequestDone(EnrollmentState::Result result) {
+    ReportStepDurationAndResetTimer(kUMASuffixStateRequest);
+    base::UmaHistogramBoolean(kUMAStateDeterminationStateReturned,
+                              result.has_value());
     if (!result.has_value()) {
-      return std::move(report_result_).Run(result.error());
+      return ReportResult(result.error());
     }
     state_.StoreResponse(local_state_, result->dict);
-    return std::move(report_result_).Run(result->state);
+    return ReportResult(result->state);
   }
 
   // Used to report an error or the determined enrollment state. In production
   // code, this will point to `AutoEnrollmentController::UpdateState`.
   base::OnceCallback<void(AutoEnrollmentState)> report_result_;
 
+  // Time at which overall fetch or individual step has been started.
+  base::TimeTicks fetch_started_;
+  base::TimeTicks step_started_;
+
   // Used to store the initial enrollment state (if available) in a dict at
   // `prefs::kServerBackedDeviceState`.
   // Must not be nullptr for initial enrollment state determination.
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc
index 1b1755e..96604d9 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc
+++ b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc
@@ -8,8 +8,10 @@
 
 #include "ash/constants/ash_switches.h"
 #include "base/functional/bind.h"
+#include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/gmock_callback_support.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_command_line.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
@@ -26,7 +28,9 @@
 #include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
 #include "chromeos/ash/components/system/fake_statistics_provider.h"
 #include "chromeos/ash/components/system/statistics_provider.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
+#include "components/policy/core/common/cloud/enterprise_metrics.h"
 #include "components/policy/core/common/cloud/mock_device_management_service.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -50,6 +54,10 @@
 const char kTestPsmId[] = "474F4F47/test-serial-number";
 const char kTestDisabledMessage[] = "test-disabled-message";
 
+using base::test::RunOnceCallback;
+using testing::DoAll;
+using testing::InvokeWithoutArgs;
+
 class MockStateKeyBroker : public ServerBackedStateKeysBroker {
  public:
   MockStateKeyBroker() : ServerBackedStateKeysBroker(nullptr) {}
@@ -125,10 +133,11 @@
          state_request.brand_code() == brand_code;
 }
 
+MATCHER(WithAnyOprfRequest, "") {
+  return arg.has_oprf_request();
+}
+
 MATCHER_P(WithOprfRequestFor, test_case, "") {
-  if (!test_case) {
-    return arg.has_oprf_request();
-  }
   return arg.oprf_request().SerializeAsString() ==
          test_case->expected_oprf_request().SerializeAsString();
 }
@@ -142,6 +151,9 @@
 
 class EnrollmentStateFetcherTest : public testing::Test {
  public:
+  EnrollmentStateFetcherTest()
+      : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
   void SetUp() override {
     psm_test_case_ = psm::testing::LoadTestCase(/*is_member=*/true);
     fake_dm_service_ =
@@ -176,27 +188,31 @@
   }
 
  protected:
-  void ExpectOwnershipCheck() {
+  void ExpectOwnershipCheck(base::TimeDelta time = base::TimeDelta()) {
     EXPECT_CALL(device_settings_service_, GetOwnershipStatusAsync)
-        .WillOnce(base::test::RunOnceCallback<0>(
-            ash::DeviceSettingsService::OWNERSHIP_NONE));
+        .WillOnce(DoAll(
+            InvokeWithoutArgs([=]() { task_environment_.AdvanceClock(time); }),
+            RunOnceCallback<0>(ash::DeviceSettingsService::OWNERSHIP_NONE)));
   }
 
-  void ExpectStateKeysRequest() {
+  void ExpectStateKeysRequest(base::TimeDelta time = base::TimeDelta()) {
     EXPECT_CALL(state_key_broker_, RequestStateKeys)
-        .WillOnce(base::test::RunOnceCallback<0>(
-            std::vector<std::string>{kTestStateKey}));
+        .WillOnce(DoAll(
+            InvokeWithoutArgs([=]() { task_environment_.AdvanceClock(time); }),
+            RunOnceCallback<0>(std::vector<std::string>{kTestStateKey})));
   }
 
-  void ExpectOprfRequest(bool any = false) {
+  void ExpectOprfRequest(base::TimeDelta time = base::TimeDelta()) {
     EXPECT_CALL(job_creation_handler_,
-                OnJobCreation(JobWithPsmRlweRequest(
-                    WithOprfRequestFor((any ? nullptr : &psm_test_case_)))))
-        .WillOnce(fake_dm_service_->SendJobOKAsync(
-            CreatePsmOprfResponse(psm_test_case_)));
+                OnJobCreation(
+                    JobWithPsmRlweRequest(WithOprfRequestFor(&psm_test_case_))))
+        .WillOnce(DoAll(
+            InvokeWithoutArgs([=]() { task_environment_.AdvanceClock(time); }),
+            fake_dm_service_->SendJobOKAsync(
+                CreatePsmOprfResponse(psm_test_case_))));
   }
 
-  void ExpectQueryRequest() {
+  void ExpectQueryRequest(base::TimeDelta time = base::TimeDelta()) {
     em::DeviceManagementResponse response;
     auto* rlwe_response = response.mutable_private_set_membership_response()
                               ->mutable_rlwe_response();
@@ -204,7 +220,20 @@
     EXPECT_CALL(job_creation_handler_,
                 OnJobCreation(JobWithPsmRlweRequest(
                     WithQueryRequestFor(&psm_test_case_))))
-        .WillOnce(fake_dm_service_->SendJobOKAsync(response));
+        .WillOnce(DoAll(
+            InvokeWithoutArgs([=]() { task_environment_.AdvanceClock(time); }),
+            fake_dm_service_->SendJobOKAsync(response)));
+  }
+
+  void ExpectStateRequest(base::TimeDelta time = base::TimeDelta()) {
+    em::DeviceManagementResponse response;
+    response.mutable_device_state_retrieval_response();
+    EXPECT_CALL(job_creation_handler_,
+                OnJobCreation(JobWithStateRequest(
+                    kTestStateKey, kTestSerialNumber, kTestBrandCode)))
+        .WillOnce(DoAll(
+            InvokeWithoutArgs([=]() { task_environment_.AdvanceClock(time); }),
+            fake_dm_service_->SendJobOKAsync(response)));
   }
 
   content::BrowserTaskEnvironment task_environment_;
@@ -255,6 +284,17 @@
   EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
 }
 
+TEST_F(EnrollmentStateFetcherTest, DisabledOnFlex) {
+  base::HistogramTester histograms;
+  command_line_.GetProcessCommandLine()->AppendSwitch(
+      ash::switches::kRevenBranding);
+
+  AutoEnrollmentState state = FetchEnrollmentState();
+
+  EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationOnFlex, true, 1);
+}
+
 TEST_F(EnrollmentStateFetcherTest, SystemClockNotSyncronized) {
   system_clock_.DisableService();
 
@@ -278,26 +318,45 @@
 }
 
 TEST_F(EnrollmentStateFetcherTest, RlzBrandCodeMissing) {
+  base::HistogramTester histograms;
   statistics_provider_.ClearMachineStatistic(ash::system::kRlzBrandCodeKey);
 
   AutoEnrollmentState state = FetchEnrollmentState();
 
   EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationDeviceIdentifierStatus,
+                                2 /*kRlzBrandCodeMissing*/, 1);
 }
 
 TEST_F(EnrollmentStateFetcherTest, SerialNumberMissing) {
+  base::HistogramTester histograms;
   statistics_provider_.ClearMachineStatistic(
       ash::system::kSerialNumberKeyForTest);
 
   AutoEnrollmentState state = FetchEnrollmentState();
 
   EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationDeviceIdentifierStatus,
+                                1 /*kRlzBrandCodeMissing*/, 1);
+}
+
+TEST_F(EnrollmentStateFetcherTest, RlzBrandCodeAndSerialNumberMissing) {
+  base::HistogramTester histograms;
+  statistics_provider_.ClearMachineStatistic(ash::system::kRlzBrandCodeKey);
+  statistics_provider_.ClearMachineStatistic(
+      ash::system::kSerialNumberKeyForTest);
+
+  AutoEnrollmentState state = FetchEnrollmentState();
+
+  EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationDeviceIdentifierStatus,
+                                3 /*kAllMissing*/, 1);
 }
 
 TEST_F(EnrollmentStateFetcherTest, OwnershipTaken) {
   EXPECT_CALL(device_settings_service_, GetOwnershipStatusAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(
-          ash::DeviceSettingsService::OWNERSHIP_TAKEN));
+      .WillOnce(
+          RunOnceCallback<0>(ash::DeviceSettingsService::OWNERSHIP_TAKEN));
 
   AutoEnrollmentState state = FetchEnrollmentState();
 
@@ -306,8 +365,8 @@
 
 TEST_F(EnrollmentStateFetcherTest, OwnershipUnknown) {
   EXPECT_CALL(device_settings_service_, GetOwnershipStatusAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(
-          ash::DeviceSettingsService::OWNERSHIP_UNKNOWN));
+      .WillOnce(
+          RunOnceCallback<0>(ash::DeviceSettingsService::OWNERSHIP_UNKNOWN));
 
   AutoEnrollmentState state = FetchEnrollmentState();
 
@@ -317,8 +376,7 @@
 TEST_F(EnrollmentStateFetcherTest, ProceedWithMissingStateKeys) {
   ExpectOwnershipCheck();
   EXPECT_CALL(state_key_broker_, RequestStateKeys)
-      .WillRepeatedly(
-          base::test::RunOnceCallback<0>(std::vector<std::string>{}));
+      .WillRepeatedly(RunOnceCallback<0>(std::vector<std::string>{}));
   ExpectOprfRequest();
   ExpectQueryRequest();
   EXPECT_CALL(job_creation_handler_, OnJobCreation(JobWithStateRequest(
@@ -373,7 +431,10 @@
 TEST_F(EnrollmentStateFetcherTest, FailToCreateQueryRequest) {
   ExpectOwnershipCheck();
   ExpectStateKeysRequest();
-  ExpectOprfRequest(/*any=*/true);
+  EXPECT_CALL(job_creation_handler_,
+              OnJobCreation(JobWithPsmRlweRequest(WithAnyOprfRequest())))
+      .WillOnce(fake_dm_service_->SendJobOKAsync(
+          CreatePsmOprfResponse(psm_test_case_)));
   base::test::TestFuture<AutoEnrollmentState> future;
   auto fetcher = EnrollmentStateFetcher::Create(
       future.GetCallback(), &local_state_,
@@ -438,6 +499,21 @@
   EXPECT_EQ(state, AutoEnrollmentState::kServerError);
 }
 
+TEST_F(EnrollmentStateFetcherTest, PsmReportsNoState) {
+  base::HistogramTester histograms;
+  psm_test_case_ = psm::testing::LoadTestCase(/*is_member=*/false);
+  ExpectOwnershipCheck();
+  ExpectStateKeysRequest();
+  ExpectOprfRequest();
+  ExpectQueryRequest();
+
+  AutoEnrollmentState state = FetchEnrollmentState();
+
+  EXPECT_EQ(state, AutoEnrollmentState::kNoEnrollment);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationPsmReportedAvailableState,
+                                false, 1);
+}
+
 TEST_F(EnrollmentStateFetcherTest, EmptyEnrollmentStateResponse) {
   ExpectOwnershipCheck();
   ExpectStateKeysRequest();
@@ -505,6 +581,81 @@
   EXPECT_TRUE(device_state.empty());
 }
 
+TEST_F(EnrollmentStateFetcherTest, UmaHistogramsCounts) {
+  base::HistogramTester histograms;
+  ExpectOwnershipCheck();
+  ExpectStateKeysRequest();
+  ExpectOprfRequest();
+  ExpectQueryRequest();
+  ExpectStateRequest();
+
+  FetchEnrollmentState();
+
+  histograms.ExpectUniqueSample(kUMAStateDeterminationDeviceIdentifierStatus,
+                                0 /*kAllPresent*/, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationEmbargoDatePassed, true,
+                                1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationEnabled, true, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationOnFlex, false, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationSystemClockSynchronized,
+                                true, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationOwnershipStatus,
+                                ash::DeviceSettingsService::OWNERSHIP_NONE, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationStateKeysRetrieved, true,
+                                1);
+  histograms.ExpectUniqueSample(
+      kUMAStateDeterminationPsmRlweOprfRequestDmStatusCode, DM_STATUS_SUCCESS,
+      1);
+  histograms.ExpectUniqueSample(
+      kUMAStateDeterminationPsmRlweOprfRequestNetworkErrorCode, net::OK, 1);
+  histograms.ExpectUniqueSample(
+      kUMAStateDeterminationPsmRlweQueryRequestDmStatusCode, DM_STATUS_SUCCESS,
+      1);
+  histograms.ExpectUniqueSample(
+      kUMAStateDeterminationPsmRlweQueryRequestNetworkErrorCode, net::OK, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationPsmReportedAvailableState,
+                                true, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationStateRequestDmStatusCode,
+                                DM_STATUS_SUCCESS, 1);
+  histograms.ExpectUniqueSample(
+      kUMAStateDeterminationStateRequestNetworkErrorCode, net::OK, 1);
+  histograms.ExpectUniqueSample(kUMAStateDeterminationStateReturned, true, 1);
+}
+
+TEST_F(EnrollmentStateFetcherTest, UmaHistogramsTimes) {
+  base::HistogramTester histograms;
+  ExpectOwnershipCheck(/*time=*/base::Seconds(1));
+  ExpectStateKeysRequest(/*time=*/base::Seconds(2));
+  ExpectOprfRequest(/*time=*/base::Seconds(3));
+  ExpectQueryRequest(/*time=*/base::Seconds(4));
+  ExpectStateRequest(/*time=*/base::Seconds(5));
+
+  FetchEnrollmentState();
+
+  const char* ds = kUMAStateDeterminationTotalDurationByState;
+  histograms.ExpectUniqueTimeSample(base::StrCat({ds, kUMASuffixNoEnrollment}),
+                                    base::Seconds(15), 1);
+  histograms.ExpectTotalCount(base::StrCat({ds, kUMASuffixConnectionError}), 0);
+  histograms.ExpectTotalCount(base::StrCat({ds, kUMASuffixDisabled}), 0);
+  histograms.ExpectTotalCount(base::StrCat({ds, kUMASuffixEnrollment}), 0);
+  histograms.ExpectTotalCount(base::StrCat({ds, kUMASuffixServerError}), 0);
+  histograms.ExpectTotalCount(kUMAStateDeterminationTotalDuration, 1);
+
+  const char* step_d = kUMAStateDeterminationStepDuration;
+  histograms.ExpectUniqueTimeSample(
+      base::StrCat({step_d, kUMASuffixSystemClockSync}), base::Seconds(0), 1);
+  histograms.ExpectUniqueTimeSample(
+      base::StrCat({step_d, kUMASuffixOwnershipCheck}), base::Seconds(1), 1);
+  histograms.ExpectUniqueTimeSample(
+      base::StrCat({step_d, kUMASuffixStateKeyRetrieval}), base::Seconds(2), 1);
+  histograms.ExpectUniqueTimeSample(
+      base::StrCat({step_d, kUMASuffixOPRFRequest}), base::Seconds(3), 1);
+  histograms.ExpectUniqueTimeSample(
+      base::StrCat({step_d, kUMASuffixQueryRequest}), base::Seconds(4), 1);
+  histograms.ExpectUniqueTimeSample(
+      base::StrCat({step_d, kUMASuffixStateRequest}), base::Seconds(5), 1);
+}
+
 TEST_F(EnrollmentStateFetcherTest, PackagedLicenseWithoutEnrollment) {
   ExpectOwnershipCheck();
   ExpectStateKeysRequest();
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc b/chrome/browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc
index 4fff30a3..63e2bdb3 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_reboot_job_browsertest.cc
@@ -6,6 +6,8 @@
 
 #include "base/time/time.h"
 #include "chrome/browser/ash/login/app_mode/test/kiosk_apps_mixin.h"
+#include "chrome/browser/ash/login/app_mode/test/kiosk_base_test.h"
+#include "chrome/browser/ash/login/app_mode/test/web_kiosk_base_test.h"
 #include "chrome/browser/ash/login/login_manager_test.h"
 #include "chrome/browser/ash/login/test/device_state_mixin.h"
 #include "chrome/browser/ash/login/test/login_manager_mixin.h"
@@ -50,7 +52,7 @@
 };
 }  // namespace
 
-class DeviceCommandRebootJobKioskBrowserTest
+class DeviceCommandRebootJobAutoLaunchKioskBrowserTest
     : public DeviceCommandRebootBaseTest<ash::LoginManagerTest> {
  protected:
   void SetUpInProcessBrowserTestFixture() override {
@@ -68,23 +70,66 @@
       ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
 };
 
-IN_PROC_BROWSER_TEST_F(DeviceCommandRebootJobKioskBrowserTest,
-                       RebootsKioskInstantly) {
+IN_PROC_BROWSER_TEST_F(DeviceCommandRebootJobAutoLaunchKioskBrowserTest,
+                       RebootsInstantly) {
   ASSERT_TRUE(ash::LoginState::Get()->IsKioskSession());
   ASSERT_EQ(
       chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 0);
 
-  em::RemoteCommandResult result =
-      SendRemoteCommand(RemoteCommandBuilder()
-                            .SetType(em::RemoteCommand_Type_DEVICE_REBOOT)
-                            .Build());
+  em::RemoteCommandResult result = SendRemoteCommand(
+      RemoteCommandBuilder().SetType(em::RemoteCommand::DEVICE_REBOOT).Build());
 
-  EXPECT_EQ(result.result(), em::RemoteCommandResult_ResultType_RESULT_SUCCESS);
+  EXPECT_EQ(result.result(), em::RemoteCommandResult::RESULT_SUCCESS);
   EXPECT_EQ(
       chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 1);
 }
 
-// TODO(b/225913691) Add test case for manually launched kiosk.
+class DeviceCommandRebootJobKioskBrowserTest
+    : public DeviceCommandRebootBaseTest<ash::KioskBaseTest> {
+ private:
+  ash::DeviceStateMixin device_state_{
+      &mixin_host_,
+      ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
+};
+
+IN_PROC_BROWSER_TEST_F(DeviceCommandRebootJobKioskBrowserTest,
+                       RebootsInstantly) {
+  StartAppLaunchFromLoginScreen(
+      ash::NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
+  WaitForAppLaunchWithOptions(false /* check launch data */,
+                              false /* terminate app */,
+                              true /* keep app open */);
+
+  ASSERT_TRUE(ash::LoginState::Get()->IsKioskSession());
+  ASSERT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 0);
+
+  em::RemoteCommandResult result = SendRemoteCommand(
+      RemoteCommandBuilder().SetType(em::RemoteCommand::DEVICE_REBOOT).Build());
+
+  EXPECT_EQ(result.result(), em::RemoteCommandResult::RESULT_SUCCESS);
+  EXPECT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 1);
+}
+
+class DeviceCommandRebootJobWebKioskBrowserTest
+    : public DeviceCommandRebootBaseTest<ash::WebKioskBaseTest> {};
+
+IN_PROC_BROWSER_TEST_F(DeviceCommandRebootJobWebKioskBrowserTest,
+                       RebootsInstantly) {
+  InitializeRegularOnlineKiosk();
+
+  ASSERT_TRUE(ash::LoginState::Get()->IsKioskSession());
+  ASSERT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 0);
+
+  em::RemoteCommandResult result = SendRemoteCommand(
+      RemoteCommandBuilder().SetType(em::RemoteCommand::DEVICE_REBOOT).Build());
+
+  EXPECT_EQ(result.result(), em::RemoteCommandResult::RESULT_SUCCESS);
+  EXPECT_EQ(
+      chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 1);
+}
 
 class DeviceCommandRebootJobUserBrowserTest
     : public DeviceCommandRebootBaseTest<MixinBasedInProcessBrowserTest> {
@@ -104,12 +149,10 @@
   ASSERT_EQ(
       chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 0);
 
-  em::RemoteCommandResult result =
-      SendRemoteCommand(RemoteCommandBuilder()
-                            .SetType(em::RemoteCommand_Type_DEVICE_REBOOT)
-                            .Build());
+  em::RemoteCommandResult result = SendRemoteCommand(
+      RemoteCommandBuilder().SetType(em::RemoteCommand::DEVICE_REBOOT).Build());
 
-  EXPECT_EQ(result.result(), em::RemoteCommandResult_ResultType_RESULT_SUCCESS);
+  EXPECT_EQ(result.result(), em::RemoteCommandResult::RESULT_SUCCESS);
   EXPECT_EQ(
       chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(), 1);
 }
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_start_crd_session_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_start_crd_session_job.cc
index 45cc4deb..6f53517 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_start_crd_session_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_start_crd_session_job.cc
@@ -287,12 +287,6 @@
   curtain_local_user_session_ =
       (crd_session_type == CrdSessionType::REMOTE_ACCESS_SESSION);
 
-  if (base::FeatureList::IsEnabled(
-          remoting::features::kForceCrdAdminRemoteAccess)) {
-    CRD_LOG(WARNING) << "Forcing remote access";
-    curtain_local_user_session_ = true;
-  }
-
   if (curtain_local_user_session_ &&
       !base::FeatureList::IsEnabled(
           remoting::features::kEnableCrdAdminRemoteAccess)) {
diff --git a/chrome/browser/ash/settings/device_settings_service.h b/chrome/browser/ash/settings/device_settings_service.h
index 6f3b3bd..15b2733 100644
--- a/chrome/browser/ash/settings/device_settings_service.h
+++ b/chrome/browser/ash/settings/device_settings_service.h
@@ -53,12 +53,15 @@
  public:
   // Indicates ownership status of the device (listed in upgrade order).
   enum OwnershipStatus {
+    // These values are persisted to logs. Entries should not be renumbered and
+    // numeric values should never be reused.
     OWNERSHIP_UNKNOWN = 0,
     // Not yet owned.
-    OWNERSHIP_NONE,
-    // Either consumer ownership, cloud management or Active Directory
-    // management.
-    OWNERSHIP_TAKEN
+    OWNERSHIP_NONE = 1,
+    // Either consumer ownership or cloud management.
+    OWNERSHIP_TAKEN = 2,
+    // TODO(b/265923216): Convert to enum class and rename this to kMaxValue.
+    OWNERSHIP_MAX = OWNERSHIP_TAKEN
   };
 
   using OwnershipStatusCallback = base::OnceCallback<void(OwnershipStatus)>;
diff --git a/chrome/browser/autofill/autofill_across_iframes_browsertest.cc b/chrome/browser/autofill/autofill_across_iframes_browsertest.cc
index b8fa2a7..c046b41 100644
--- a/chrome/browser/autofill/autofill_across_iframes_browsertest.cc
+++ b/chrome/browser/autofill/autofill_across_iframes_browsertest.cc
@@ -503,29 +503,15 @@
 // Test fixture for "shared-autofill". The parameter indicates whether or not
 // shared-autofill has the "relaxed" semantics.
 class AutofillAcrossIframesTest_SharedAutofill
-    : public AutofillAcrossIframesTest_Simple,
-      public ::testing::WithParamInterface<bool> {
- public:
-  AutofillAcrossIframesTest_SharedAutofill() {
-    feature_list_.InitAndEnableFeatureWithParameters(
-        features::kAutofillSharedAutofill,
-        {{features::kAutofillSharedAutofillRelaxedParam.name,
-          is_relaxed() ? "true" : "false"}});
-  }
-
-  bool is_relaxed() const { return GetParam(); }
-
+    : public AutofillAcrossIframesTest_Simple {
  private:
-  base::test::ScopedFeatureList feature_list_;
+  base::test::ScopedFeatureList feature_list_{
+      features::kAutofillSharedAutofill};
 };
 
-INSTANTIATE_TEST_SUITE_P(AutofillAcrossIframesTest,
-                         AutofillAcrossIframesTest_SharedAutofill,
-                         ::testing::Bool());
-
 // Tests that autofilling on a main-origin field also fills cross-origin fields
 // whose frames have shared-autofill enabled.
-IN_PROC_BROWSER_TEST_P(AutofillAcrossIframesTest_SharedAutofill,
+IN_PROC_BROWSER_TEST_F(AutofillAcrossIframesTest_SharedAutofill,
                        FillWhenTriggeredOnMainOrigin) {
   const FormStructure* form =
       LoadForm({"$1", "$2", "$3", "$4"}, {"", "", "", "allow=shared-autofill"});
@@ -534,27 +520,15 @@
               ElementsAre(kNameFull, "", "", kCvc));
 }
 
-// Tests that autofilling on a cross-origin field also fills cross-origin fields
-// whose frames have shared-autofill enabled iff shared-autofill is relaxed.
-IN_PROC_BROWSER_TEST_P(AutofillAcrossIframesTest_SharedAutofill,
+// Tests that autofilling on a cross-origin field does not fill cross-origin
+// fields, even if shared-autofill in their document.
+IN_PROC_BROWSER_TEST_F(AutofillAcrossIframesTest_SharedAutofill,
                        FillWhenTriggeredOnNonMainOriginIffRelaxed) {
   const FormStructure* form =
       LoadForm({"$1", "$2", "$3", "$4"}, {"", "", "", "allow=shared-autofill"});
   ASSERT_TRUE(form);
   EXPECT_THAT(FillForm(*form, *form->field(1)),
-              ElementsAre(kNameFull, kNumber, "", is_relaxed() ? kCvc : ""));
-}
-
-// Tests that autofilling on a cross-origin field also fills main-origin fields
-// irrespective of their type if shared-autofill is relaxed.
-IN_PROC_BROWSER_TEST_P(
-    AutofillAcrossIframesTest_SharedAutofill,
-    FillEverythingOnMainOriginWhenTriggeredOnNonMainOriginIffRelaxed) {
-  const FormStructure* form =
-      LoadForm({"$1", "$2", "$1", "$1"}, {"", "", "", "allow=shared-autofill"});
-  ASSERT_TRUE(form);
-  EXPECT_THAT(FillForm(*form, *form->field(1)),
-              ElementsAre(kNameFull, kNumber, kExp, is_relaxed() ? kCvc : ""));
+              ElementsAre(kNameFull, kNumber, "", ""));
 }
 
 // Test fixture where a form changes dynamically when it is filled.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 774f642..a7b1f7b3 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1862,9 +1862,15 @@
 std::unique_ptr<content::WebContentsViewDelegate>
 ChromeContentBrowserClient::GetWebContentsViewDelegate(
     content::WebContents* web_contents) {
-  if (auto* registry =
-          performance_manager::PerformanceManagerRegistry::GetInstance()) {
-    registry->MaybeCreatePageNodeForWebContents(web_contents);
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  // Do not track web contents performance for profiles that have Keyed Services
+  // disabled.
+  if (!AreKeyedServicesDisabledForProfileByDefault(profile)) {
+    if (auto* registry =
+            performance_manager::PerformanceManagerRegistry::GetInstance()) {
+      registry->MaybeCreatePageNodeForWebContents(web_contents);
+    }
   }
   return CreateWebContentsViewDelegate(web_contents);
 }
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc b/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
index 7f250812..13207a96 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
+++ b/chrome/browser/chromeos/kcer_nss/kcer_nss_unittest.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
 #include "crypto/scoped_test_nss_db.h"
+#include "crypto/secure_hash.h"
 #include "crypto/signature_verifier.h"
 #include "net/cert/pem.h"
 #include "net/test/cert_builder.h"
@@ -159,6 +160,27 @@
   return StrToBytes(tokenizer.data());
 }
 
+// Returns |hash| prefixed with DER-encoded PKCS#1 DigestInfo with
+// AlgorithmIdentifier=id-sha256.
+// This is useful for testing Kcer::SignRsaPkcs1Raw which only
+// appends PKCS#1 v1.5 padding before signing.
+std::vector<uint8_t> PrependSHA256DigestInfo(base::span<const uint8_t> hash) {
+  // DER-encoded PKCS#1 DigestInfo "prefix" with
+  // AlgorithmIdentifier=id-sha256.
+  // The encoding is taken from https://tools.ietf.org/html/rfc3447#page-43
+  const std::vector<uint8_t> kDigestInfoSha256DerData = {
+      0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+      0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+
+  std::vector<uint8_t> result;
+  result.reserve(kDigestInfoSha256DerData.size() + hash.size());
+
+  result.insert(result.end(), kDigestInfoSha256DerData.begin(),
+                kDigestInfoSha256DerData.end());
+  result.insert(result.end(), hash.begin(), hash.end());
+  return result;
+}
+
 // A helper class to work with tokens (that exist on the IO thread) from the UI
 // thread.
 class TokenHolder {
@@ -363,6 +385,10 @@
   base::test::TestFuture<base::expected<Signature, Error>> sign_waiter;
   kcer->Sign(PrivateKeyHandle(PublicKeySpki()), SigningScheme::kRsaPkcs1Sha512,
              DataToSign({1, 2, 3}), sign_waiter.GetCallback());
+  base::test::TestFuture<base::expected<Signature, Error>> sign_digest_waiter;
+  kcer->SignRsaPkcs1Raw(PrivateKeyHandle(PublicKeySpki()),
+                        DigestWithPrefix({1, 2, 3}),
+                        sign_digest_waiter.GetCallback());
   base::test::TestFuture<base::expected<TokenInfo, Error>>
       get_token_info_waiter;
   kcer->GetTokenInfo(Token::kUser, get_token_info_waiter.GetCallback());
@@ -416,6 +442,9 @@
             Error::kTokenInitializationFailed);
   ASSERT_FALSE(sign_waiter.Get().has_value());
   EXPECT_EQ(sign_waiter.Get().error(), Error::kTokenInitializationFailed);
+  ASSERT_FALSE(sign_digest_waiter.Get().has_value());
+  EXPECT_EQ(sign_digest_waiter.Get().error(),
+            Error::kTokenInitializationFailed);
   ASSERT_FALSE(get_token_info_waiter.Get().has_value());
   EXPECT_EQ(get_token_info_waiter.Get().error(),
             Error::kTokenInitializationFailed);
@@ -542,6 +571,56 @@
   }
 }
 
+// Test that `Kcer::SignRsaPkcs1Raw()` produces a correct signature.
+TEST_F(KcerNssTest, SignRsaPkcs1Raw) {
+  TokenHolder user_token(Token::kUser);
+  user_token.Initialize();
+
+  std::unique_ptr<Kcer> kcer = internal::CreateKcer(
+      IOTaskRunner(), user_token.GetWeakPtr(), /*device_token=*/nullptr);
+
+  base::test::TestFuture<base::expected<PublicKey, Error>> generate_key_waiter;
+  kcer->GenerateRsaKey(Token::kUser, /*modulus_length_bits=*/2048,
+                       /*hardware_backed=*/true,
+                       generate_key_waiter.GetCallback());
+  ASSERT_TRUE(generate_key_waiter.Get().has_value());
+  const PublicKey& public_key = generate_key_waiter.Get().value();
+
+  DataToSign data_to_sign({1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
+
+  // A caller would need to hash the data themself before calling
+  // `SignRsaPkcs1Raw`, do that here.
+  auto hasher = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
+  hasher->Update(data_to_sign->data(), data_to_sign->size());
+  std::vector<uint8_t> hash(hasher->GetHashLength());
+  hasher->Finish(hash.data(), hash.size());
+  DigestWithPrefix digest_with_prefix(PrependSHA256DigestInfo(hash));
+
+  // Generate the signature.
+  base::test::TestFuture<base::expected<Signature, Error>> sign_waiter;
+  kcer->SignRsaPkcs1Raw(PrivateKeyHandle(public_key),
+                        std::move(digest_with_prefix),
+                        sign_waiter.GetCallback());
+  ASSERT_TRUE(sign_waiter.Get().has_value());
+  const Signature& signature = sign_waiter.Get().value();
+
+  // Verify the signature.
+  crypto::SignatureVerifier signature_verifier;
+  ASSERT_TRUE(signature_verifier.VerifyInit(
+      crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256,
+      signature.value(), public_key.GetSpki().value()));
+  signature_verifier.VerifyUpdate(data_to_sign.value());
+  EXPECT_TRUE(signature_verifier.VerifyFinal());
+
+  // Verify that manual hashing + `SignRsaPkcs1Raw` produces the same
+  // signature as just `Sign`.
+  base::test::TestFuture<base::expected<Signature, Error>> normal_sign_waiter;
+  kcer->Sign(PrivateKeyHandle(public_key), SigningScheme::kRsaPkcs1Sha256,
+             data_to_sign, normal_sign_waiter.GetCallback());
+  ASSERT_TRUE(normal_sign_waiter.Get().has_value());
+  EXPECT_EQ(sign_waiter.Get().value(), normal_sign_waiter.Get().value());
+}
+
 // Test that Kcer::GetTokenInfo() method returns meaningful values.
 TEST_F(KcerNssTest, GetTokenInfo) {
   TokenHolder user_token(Token::kUser);
@@ -640,8 +719,8 @@
   // Hardware- vs software-backed indicators on real devices are provided by
   // Chaps and are wrong in unit tests.
   expected_key_info.is_hardware_backed = true;
-  // NSS sets an empty nickname by default, this doesn't have to be like this in
-  // general.
+  // NSS sets an empty nickname by default, this doesn't have to be like this
+  // in general.
   expected_key_info.nickname = "";
   // Custom attributes are stored differently in tests and have empty values by
   // default.
@@ -655,8 +734,8 @@
     ASSERT_TRUE(key_info_waiter.Get().has_value());
     const KeyInfo& key_info = key_info_waiter.Get().value();
 
-    // Copy some fields, their values are covered by dedicated tests, this test
-    // only checks that they don't change when they shouldn't.
+    // Copy some fields, their values are covered by dedicated tests, this
+    // test only checks that they don't change when they shouldn't.
     expected_key_info.key_type = key_info.key_type;
     expected_key_info.supported_signing_schemes =
         key_info.supported_signing_schemes;
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
index d41e6ac6..827760a 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
+++ b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.cc
@@ -464,6 +464,83 @@
   return std::move(callback).Run(Signature(std::move(signature)));
 }
 
+// Checks whether |input_length| is lower or equal to the maximum input length
+// for a RSA PKCS#1 v1.5 signature generated using |private_key| with PK11_Sign.
+// Returns false if |input_length| is too large.
+// If the maximum input length can not be determined (which is possible because
+// it queries the PKCS#11 module), returns true and logs a warning.
+bool CheckRsaPkcs1SignDigestInputLength(SECKEYPrivateKey* private_key,
+                                        size_t input_length) {
+  // For RSA keys, PK11_Sign will perform PKCS#1 v1.5 padding, which needs at
+  // least 11 bytes. RSA Sign can process an input of max. modulus length.
+  // Thus the maximum input length for the sign operation is
+  // |modulus_length - 11|.
+  int modulus_length_bytes = PK11_GetPrivateModulusLen(private_key);
+  if (modulus_length_bytes <= 0) {
+    LOG(WARNING) << "Could not determine modulus length";
+    return true;
+  }
+  size_t max_input_length_after_padding =
+      static_cast<size_t>(modulus_length_bytes);
+  // PKCS#1 v1.5 Padding needs at least this many bytes.
+  size_t kMinPaddingLength = 11u;
+  return input_length + kMinPaddingLength <= max_input_length_after_padding;
+}
+
+// Performs "raw" PKCS1 v1.5 padding + signing by calling PK11_Sign on |key|.
+// TODO(b/244408117): This method is mostly a copy of
+// `PlatformKeysService::SignRSAPKCS1Raw` from platform_keys_service_nss.cc .
+// The original method should be replaced during the upcoming refactoring to
+// remove direct usages of NSS.
+void SignRsaPkcs1RawOnWorkerThread(crypto::ScopedPK11Slot slot,
+                                   PrivateKeyHandle key,
+                                   DigestWithPrefix digest_with_prefix,
+                                   Kcer::SignCallback callback) {
+  base::expected<crypto::ScopedSECKEYPrivateKey, Error> private_key =
+      GetSECKEYPrivateKey(slot, key);
+  if (!private_key.has_value()) {
+    return std::move(callback).Run(base::unexpected(private_key.error()));
+  }
+  const crypto::ScopedSECKEYPrivateKey& sec_private_key = private_key.value();
+  if (sec_private_key->keyType != ::KeyType::rsaKey) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kKeyDoesNotSupportSigningScheme));
+  }
+
+  static_assert(
+      sizeof(*digest_with_prefix->data()) == sizeof(char),
+      "Can't reinterpret data if its characters are not 8 bit large.");
+  SECItem input = {siBuffer,
+                   const_cast<unsigned char*>(digest_with_prefix->data()),
+                   static_cast<unsigned int>(digest_with_prefix->size())};
+
+  // Compute signature of hash.
+  int signature_len = PK11_SignatureLen(sec_private_key.get());
+  if (signature_len <= 0) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kFailedToSignBadSignatureLength));
+  }
+
+  std::vector<unsigned char> signature(signature_len);
+  SECItem signature_output = {siBuffer, signature.data(),
+                              static_cast<unsigned int>(signature.size())};
+  if (PK11_Sign(sec_private_key.get(), &signature_output, &input) !=
+      SECSuccess) {
+    // Input size is checked after a failure - obtaining max input size
+    // involves extracting key modulus length which is not a free operation, so
+    // don't bother if signing succeeded.
+    // Note: It would be better if this could be determined from some library
+    // return code (e.g. PORT_GetError), but this was not possible with
+    // NSS+chaps at this point.
+    if (!CheckRsaPkcs1SignDigestInputLength(sec_private_key.get(),
+                                            digest_with_prefix->size())) {
+      return std::move(callback).Run(base::unexpected(Error::kInputTooLong));
+    }
+    return std::move(callback).Run(base::unexpected(Error::kFailedToSign));
+  }
+  return std::move(callback).Run(Signature(std::move(signature)));
+}
+
 std::vector<SigningScheme> GetSigningSchemes(bool supports_pss,
                                              KeyType key_type) {
   std::vector<SigningScheme> result;
@@ -981,10 +1058,29 @@
 }
 
 void KcerTokenImplNss::SignRsaPkcs1Raw(PrivateKeyHandle key,
-                                       SigningScheme signing_scheme,
                                        DigestWithPrefix digest_with_prefix,
                                        Kcer::SignCallback callback) {
-  // TODO(244408716): Implement.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  if (UNLIKELY(state_ == State::kInitializationFailed)) {
+    return HandleInitializationFailed(std::move(callback));
+  }
+  if (is_blocked_) {
+    return task_queue_.push(base::BindOnce(
+        &KcerTokenImplNss::SignRsaPkcs1Raw, weak_factory_.GetWeakPtr(),
+        std::move(key), std::move(digest_with_prefix), std::move(callback)));
+  }
+
+  // Block task queue, attach unblocking task to the callback.
+  auto unblocking_callback = std::move(callback).Then(BlockQueueGetUnblocker());
+
+  base::ThreadPool::PostTask(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&SignRsaPkcs1RawOnWorkerThread,
+                     crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())),
+                     std::move(key), std::move(digest_with_prefix),
+                     std::move(unblocking_callback)));
 }
 
 void KcerTokenImplNss::GetTokenInfo(Kcer::GetTokenInfoCallback callback) {
diff --git a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h
index 348a153..dca805c 100644
--- a/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h
+++ b/chrome/browser/chromeos/kcer_nss/kcer_token_impl_nss.h
@@ -94,7 +94,6 @@
             DataToSign data,
             Kcer::SignCallback callback) override;
   void SignRsaPkcs1Raw(PrivateKeyHandle key,
-                       SigningScheme signing_scheme,
                        DigestWithPrefix digest_with_prefix,
                        Kcer::SignCallback callback) override;
   void GetTokenInfo(Kcer::GetTokenInfoCallback callback) override;
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.cc b/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.cc
index de9de482..e9aa24c 100644
--- a/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.cc
+++ b/chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/files/file_path.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/chromeos/policy/dlp/dialogs/policy_dialog_base.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_confidential_file.h"
@@ -56,6 +57,9 @@
           IDS_POLICY_DLP_FILES_DESTINATION_REMOVABLE_STORAGE);
     case data_controls::Component::kDrive:
       return l10n_util::GetStringUTF16(IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL);
+    case data_controls::Component::kOneDrive:
+      return l10n_util::GetStringUTF16(
+          IDS_FILE_BROWSER_DLP_COMPONENT_MICROSOFT_ONEDRIVE);
     case data_controls::Component::kUnknownComponent:
       NOTREACHED();
       return u"";
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h b/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h
index ce28d2f7..bdf75394 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h
@@ -22,6 +22,7 @@
 constexpr char kCrostini[] = "CROSTINI";
 constexpr char kPluginVm[] = "PLUGIN_VM";
 constexpr char kDrive[] = "DRIVE";
+constexpr char kOneDrive[] = "ONEDRIVE";
 constexpr char kUsb[] = "USB";
 
 constexpr char kAllowLevel[] = "ALLOW";
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_policy_event.proto b/chrome/browser/chromeos/policy/dlp/dlp_policy_event.proto
index a84daeb..2768a909 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_policy_event.proto
+++ b/chrome/browser/chromeos/policy/dlp/dlp_policy_event.proto
@@ -21,6 +21,7 @@
     PLUGIN_VM = 3;
     USB = 4;
     DRIVE = 5;
+    ONEDRIVE = 6;
   }
 
   // Either |url| or |component| should be set.
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager.cc b/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager.cc
index 90ae5577..5b0a9653 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager.cc
@@ -205,6 +205,10 @@
       event_destination->set_component(
           DlpPolicyEventDestination_Component_DRIVE);
       break;
+    case (data_controls::Component::kOneDrive):
+      event_destination->set_component(
+          DlpPolicyEventDestination_Component_ONEDRIVE);
+      break;
     case (data_controls::Component::kUnknownComponent):
       event_destination->set_component(
           DlpPolicyEventDestination_Component_UNDEFINED_COMPONENT);
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager_unittest.cc
index cf6db22..119941c3 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_reporting_manager_unittest.cc
@@ -162,10 +162,13 @@
                                DlpPolicyEventDestination_Component_USB, 3u);
   ReportEventAndCheckComponent(data_controls::Component::kDrive,
                                DlpPolicyEventDestination_Component_DRIVE, 4u);
+  ReportEventAndCheckComponent(data_controls::Component::kOneDrive,
+                               DlpPolicyEventDestination_Component_ONEDRIVE,
+                               5u);
   ReportEventAndCheckComponent(
       data_controls::Component::kUnknownComponent,
-      DlpPolicyEventDestination_Component_UNDEFINED_COMPONENT, 5u);
-  EXPECT_EQ(manager_.events_reported(), 6u);
+      DlpPolicyEventDestination_Component_UNDEFINED_COMPONENT, 6u);
+  EXPECT_EQ(manager_.events_reported(), 7u);
 }
 
 TEST_F(DlpReportingManagerTest, ReportEventWithoutNameAndRuleId) {
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h
index 92e5526..ca8df884c 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h
@@ -26,10 +26,10 @@
  public:
   // List of all possible component values, used to simplify iterating over all
   // the options.
-  constexpr static const std::array<data_controls::Component, 5> components = {
-      data_controls::Component::kArc, data_controls::Component::kCrostini,
+  constexpr static const std::array<data_controls::Component, 6> components = {
+      data_controls::Component::kArc,      data_controls::Component::kCrostini,
       data_controls::Component::kPluginVm, data_controls::Component::kUsb,
-      data_controls::Component::kDrive};
+      data_controls::Component::kDrive,    data_controls::Component::kOneDrive};
 
   // Represents file metadata.
   struct FileMetadata {
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc
index ef9dad0..5ffd666b 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc
@@ -62,6 +62,7 @@
 constexpr char kWildCardMatching[] = "*";
 
 constexpr char kDrivePattern[] = "drive.google.com";
+constexpr char kOneDrivePattern[] = "onedrive.live.com";
 
 DlpRulesManager::Restriction GetClassMapping(const std::string& restriction) {
   static constexpr auto kRestrictionsMap =
@@ -102,6 +103,7 @@
            {dlp::kCrostini, data_controls::Component::kCrostini},
            {dlp::kPluginVm, data_controls::Component::kPluginVm},
            {dlp::kDrive, data_controls::Component::kDrive},
+           {dlp::kOneDrive, data_controls::Component::kOneDrive},
            {dlp::kUsb, data_controls::Component::kUsb}});
 
   auto* it = kComponentsMap.find(component);
@@ -179,7 +181,13 @@
   switch (component) {
     case data_controls::Component::kDrive:
       return {kDrivePattern};
-    default:
+    case data_controls::Component::kOneDrive:
+      return {kOneDrivePattern};
+    case data_controls::Component::kUnknownComponent:
+    case data_controls::Component::kArc:
+    case data_controls::Component::kCrostini:
+    case data_controls::Component::kPluginVm:
+    case data_controls::Component::kUsb:
       return {};
   }
 }
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc
index 13a049ca..5d71a16 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc
@@ -40,6 +40,7 @@
 constexpr char kGmailUrl[] = "https://www.gmail.com";
 constexpr char kCompanyUrl[] = "https://company.com";
 constexpr char kDriveUrl[] = "https://drive.google.com";
+constexpr char kOneDriveUrl[] = "https://onedrive.live.com";
 
 constexpr char kHttpsPrefix[] = "https://www.";
 
@@ -50,6 +51,7 @@
 constexpr char kCompanyPattern[] = ".company.com";
 constexpr char kGooglePattern[] = "google.com";
 constexpr char kMailPattern[] = "mail.google.com";
+constexpr char kOneDrivePattern[] = "onedrive.live.com";
 
 constexpr char kWrongRestriction[] = "WrongRestriction";
 constexpr char kWrongComponent[] = "WrongComponent";
@@ -343,6 +345,7 @@
   dlp_test_util::DlpRule rule(kRuleName1, "Block", kRuleId1);
   rule.AddSrcUrl(kExampleUrl)
       .AddDstComponent(dlp::kDrive)
+      .AddDstComponent(dlp::kOneDrive)
       .AddRestriction(dlp::kFilesRestriction, dlp::kBlockLevel);
 
   UpdatePolicyPref({rule});
@@ -352,6 +355,11 @@
       DlpRulesManager::Restriction::kFiles, DlpRulesManager::Level::kBlock,
       kExampleUrl, DlpRulesManager::RuleMetadata(kRuleName1, kRuleId1));
 
+  CheckIsRestrictedComponent(
+      kExampleUrl, data_controls::Component::kOneDrive,
+      DlpRulesManager::Restriction::kFiles, DlpRulesManager::Level::kBlock,
+      kExampleUrl, DlpRulesManager::RuleMetadata(kRuleName1, kRuleId1));
+
   // Make sure that blocking the components also blocks their associated
   // website.
   CheckIsRestrictedDestination(
@@ -359,6 +367,11 @@
       DlpRulesManager::Level::kBlock, kExampleUrl, kDrivePattern,
       DlpRulesManager::RuleMetadata(kRuleName1, kRuleId1));
 
+  CheckIsRestrictedDestination(
+      kExampleUrl, kOneDriveUrl, DlpRulesManager::Restriction::kFiles,
+      DlpRulesManager::Level::kBlock, kExampleUrl, kOneDrivePattern,
+      DlpRulesManager::RuleMetadata(kRuleName1, kRuleId1));
+
   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
       FROM_HERE, run_loop_.QuitClosure());
 
@@ -918,6 +931,8 @@
       data_controls::Component::kUsb);
   expected[DlpRulesManager::Level::kAllow].insert(
       data_controls::Component::kDrive);
+  expected[DlpRulesManager::Level::kAllow].insert(
+      data_controls::Component::kOneDrive);
 
   EXPECT_EQ(result, expected);
 
diff --git a/chrome/browser/enterprise/data_controls/component.h b/chrome/browser/enterprise/data_controls/component.h
index f8d2031..3750aa2 100644
--- a/chrome/browser/enterprise/data_controls/component.h
+++ b/chrome/browser/enterprise/data_controls/component.h
@@ -18,7 +18,8 @@
   kPluginVm,  // Plugin VM (Parallels/Windows) as a Guest OS.
   kUsb,       // Removable disk.
   kDrive,     // Google drive for file storage.
-  kMaxValue = kDrive
+  kOneDrive,  // Microsoft OneDrive for file storage.
+  kMaxValue = kOneDrive
 };
 
 }  // namespace data_controls
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index aa8af296..0e218df 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -69,14 +69,6 @@
     "expiry_milestone": 118
   },
   {
-    "name": "add-edu-account-for-supervised-users",
-    "owners": [
-      "mlbipin",
-      "chrome-kids-eng@google.com"
-    ],
-    "expiry_milestone": 118
-  },
-  {
     "name": "add-identity-in-can-make-payment",
     "owners": [ "rouslan", "chrome-payments-team@google.com" ],
     "expiry_milestone": 115
@@ -6545,6 +6537,11 @@
     "expiry_milestone": 118
   },
   {
+    "name": "replace-sync-promos-with-sign-in-promos",
+    "owners": [ "treib", "mastiz", "jood@google.com", "bling-flags@google.com", "chrome-sync-dev@google.com", "chrome-signin-team"],
+    "expiry_milestone": 119
+  },
+  {
     "name": "request-desktop-site-additions",
     "owners": [ "shuyng@google.com", "skavuluru@google.com", "twellington", "clank-app-team@google.com" ],
     "expiry_milestone": 116
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 3703cce..7d91aca 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -44,13 +44,6 @@
 const char kPdfUseSkiaRendererDescription[] = "Use Skia as the PDF renderer.";
 #endif
 
-extern const char kAddEduAccountFromAccountSettingsForSupervisedUsersName[] =
-    "Add Edu Account From Account Settings For Supervised Users";
-extern const char
-    kAddEduAccountFromAccountSettingsForSupervisedUsersDescription[] =
-        "Enables supervised users to add additional Edu accounts and "
-        "simplifies settings UI";
-
 const char kAppDeduplicationServiceFondueName[] =
     "Identify duplicate app groups.";
 const char kAppDeduplicationServiceFondueDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 6365fbf..001810a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -59,10 +59,6 @@
 extern const char kPdfUseSkiaRendererDescription[];
 #endif
 
-extern const char kAddEduAccountFromAccountSettingsForSupervisedUsersName[];
-extern const char
-    kAddEduAccountFromAccountSettingsForSupervisedUsersDescription[];
-
 extern const char kAlignWakeUpsName[];
 extern const char kAlignWakeUpsDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index f1fab85..ac679a27 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -156,7 +156,6 @@
     &kAdaptiveButtonInTopToolbarTranslate,
     &kAdaptiveButtonInTopToolbarAddToBookmarks,
     &kAdaptiveButtonInTopToolbarCustomizationV2,
-    &kAddEduAccountFromAccountSettingsForSupervisedUsers,
     &kAddToHomescreenIPH,
     &kAllowNewIncognitoTabIntents,
     &kAndroidAppIntegration,
@@ -432,10 +431,6 @@
              "AdaptiveButtonInTopToolbarCustomizationV2",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kAddEduAccountFromAccountSettingsForSupervisedUsers,
-             "AddEduAccountFromAccountSettingsForSupervisedUsers",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kAddToHomescreenIPH,
              "AddToHomescreenIPH",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 6abef2b..934e2f2 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -17,7 +17,6 @@
 BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarTranslate);
 BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarAddToBookmarks);
 BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarCustomizationV2);
-BASE_DECLARE_FEATURE(kAddEduAccountFromAccountSettingsForSupervisedUsers);
 BASE_DECLARE_FEATURE(kAddToHomescreenIPH);
 BASE_DECLARE_FEATURE(kAllowNewIncognitoTabIntents);
 BASE_DECLARE_FEATURE(kAndroidAppIntegration);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 7f81e8a4d..28ea868 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -105,8 +105,6 @@
             "AdaptiveButtonInTopToolbarAddToBookmarks";
     public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2 =
             "AdaptiveButtonInTopToolbarCustomizationV2";
-    public static final String ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS =
-            "AddEduAccountFromAccountSettingsForSupervisedUsers";
     public static final String ADD_TO_HOMESCREEN_IPH = "AddToHomescreenIPH";
     public static final String ALLOW_NEW_INCOGNITO_TAB_INTENTS = "AllowNewIncognitoTabIntents";
     public static final String ANDROID_APP_INTEGRATION = "AndroidAppIntegration";
diff --git a/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc b/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
index ea4fd16..cc949b53 100644
--- a/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/android/build_info.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
@@ -1013,6 +1014,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, ShowCredManReentry) {
+  if (!base::android::BuildInfo::GetInstance()->is_at_least_u()) {
+    return;
+  }
   base::test::ScopedFeatureList enable_feature(device::kWebAuthnAndroidCredMan);
   CreateSheetController();
   cred_man_delegate()->OnCredManConditionalRequestPending(
@@ -1028,6 +1032,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, HideCredManReentryWithoutResult) {
+  if (!base::android::BuildInfo::GetInstance()->is_at_least_u()) {
+    return;
+  }
   base::test::ScopedFeatureList enable_feature(device::kWebAuthnAndroidCredMan);
   CreateSheetController();
   cred_man_delegate()->OnCredManConditionalRequestPending(
diff --git a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
index 815022ec..131d30b 100644
--- a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
+++ b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
@@ -35,6 +35,7 @@
     "//chrome/browser/password_manager/android:password_manager_resource_provider_java",
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//components/browser_ui/bottomsheet/android:java",
+    "//components/browser_ui/widget/android:java",
     "//components/version_info/android:version_constants_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_appcompat_appcompat_java",
@@ -48,6 +49,8 @@
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediator.java",
+    "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOnClickHandler.java",
+    "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOptionsFragment.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningProperties.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java",
     "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java",
@@ -113,10 +116,14 @@
 }
 
 android_resources("java_resources") {
-  deps = [ "//ui/android:ui_java_resources" ]
+  deps = [
+    "//components/browser_ui/widget/android:java_resources",
+    "//ui/android:ui_java_resources",
+  ]
   sources = [
     "java/res/layout/pwd_migration_warning.xml",
     "java/res/layout/pwd_migration_warning_intro_fragment.xml",
+    "java/res/layout/pwd_migration_warning_options.xml",
     "java/res/values/dimens.xml",
   ]
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_intro_fragment.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_intro_fragment.xml
index c537287..69bea78 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_intro_fragment.xml
+++ b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_intro_fragment.xml
@@ -14,8 +14,8 @@
       android:id="@+id/migration_warning_sheet_subtitle"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
-      android:layout_marginBottom="@dimen/pwd_migration_warning_margin"
       android:layout_gravity="center_horizontal"
+      android:layout_marginBottom="@dimen/pwd_migration_warning_margin"
       android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/>
 
   <org.chromium.ui.widget.ButtonCompat
@@ -23,9 +23,9 @@
       android:id="@+id/acknowledge_password_migration_button"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:layout_marginBottom="12dp"
-      android:minHeight="@dimen/pwd_migration_warning_button_height"
       android:layout_gravity="center_horizontal"
+      android:layout_marginBottom="@dimen/pwd_migration_warning_button_spacing"
+      android:minHeight="@dimen/pwd_migration_warning_button_height"
       android:ellipsize="end"
       android:singleLine="true"
       android:text="@string/password_migration_warning_acknowledge"
@@ -36,9 +36,9 @@
       android:id="@+id/password_migration_more_options_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
+      android:layout_gravity="center_horizontal"
       android:layout_marginBottom="@dimen/pwd_migration_warning_margin"
       android:minHeight="@dimen/pwd_migration_warning_button_height"
-      android:layout_gravity="center_horizontal"
       android:ellipsize="end"
       android:singleLine="true"
       android:text="@string/password_migration_warning_other_options"
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_options.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_options.xml
new file mode 100644
index 0000000..6080126
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning_options.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal">
+
+    <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout
+        android:id="@+id/radio_button_layout"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/pwd_migration_warning_margin">
+
+        <org.chromium.components.browser_ui.widget.RadioButtonWithDescription
+            android:id="@+id/radio_sign_in_or_sync"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:primaryText="@string/password_migration_warning_turn_on_sync"
+            app:descriptionText="@string/password_migration_warning_turn_on_sync_subtitle" />
+
+        <org.chromium.components.browser_ui.widget.RadioButtonWithDescription
+            android:id="@+id/radio_password_export"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:primaryText="@string/password_migration_warning_password_export" />
+    </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout>
+
+  <org.chromium.ui.widget.ButtonCompat
+      android:descendantFocusability="blocksDescendants"
+      android:id="@+id/password_migration_next_button"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_gravity="center_horizontal"
+      android:layout_marginBottom="@dimen/pwd_migration_warning_button_spacing"
+      android:minHeight="@dimen/pwd_migration_warning_button_height"
+      android:ellipsize="end"
+      android:singleLine="true"
+      android:text="@string/password_migration_warning_next"
+      style="@style/FilledButton.Flat"/>
+
+  <org.chromium.ui.widget.ButtonCompat
+      android:descendantFocusability="blocksDescendants"
+      android:id="@+id/password_migration_cancel_button"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_gravity="center_horizontal"
+      android:layout_marginBottom="@dimen/pwd_migration_warning_margin"
+      android:minHeight="@dimen/pwd_migration_warning_button_height"
+      android:ellipsize="end"
+      android:singleLine="true"
+      android:text="@string/password_migration_warning_cancel"
+      style="@style/TextButton"/>
+</LinearLayout>
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/values/dimens.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/values/dimens.xml
index f32d911f..cbaa6ed 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/res/values/dimens.xml
+++ b/chrome/browser/password_manager/android/pwd_migration/java/res/values/dimens.xml
@@ -9,4 +9,5 @@
     <dimen name="pwd_migration_warning_margin">24dp</dimen>
     <dimen name="pwd_migration_warning_button_height">48dp</dimen>
     <dimen name="pwd_migration_warning_icon_size">32dp</dimen>
+    <dimen name="pwd_migration_warning_button_spacing">12dp</dimen>
 </resources>
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
index b71b7c6..3695d89 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningCoordinator.java
@@ -8,6 +8,7 @@
 
 import androidx.annotation.Nullable;
 
+import org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.ScreenType;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -19,14 +20,15 @@
 
     public PasswordMigrationWarningCoordinator(
             @Nullable Context context, BottomSheetController sheetController) {
-        mMediator.initialize(
-                PasswordMigrationWarningProperties.createDefaultModel(mMediator::onDismissed));
+        PropertyModel model = PasswordMigrationWarningProperties.createDefaultModel(
+                mMediator::onDismissed, mMediator);
+        mMediator.initialize(model);
         setUpModelChangeProcessors(
-                mMediator.getModel(), new PasswordMigrationWarningView(context, sheetController));
+                model, new PasswordMigrationWarningView(context, sheetController));
     }
 
     public void showWarning() {
-        mMediator.showWarning();
+        mMediator.showWarning(ScreenType.INTRO_SCREEN);
     }
 
     static void setUpModelChangeProcessors(PropertyModel model, PasswordMigrationWarningView view) {
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java
index f3467829..3a19d1a 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningIntroFragment.java
@@ -7,40 +7,37 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.view.View;
+import android.widget.Button;
 
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
 
-import org.chromium.components.version_info.VersionInfo;
 import org.chromium.ui.widget.TextViewWithLeading;
 
 /** This fragment contains the UI for the first page of the password migration warning. */
 public class PasswordMigrationWarningIntroFragment extends Fragment {
     private Context mContext;
+    private Runnable mAcknowledgeCallback;
+    private Runnable mMoreOptionsCallback;
+    private String mChannelString;
 
-    public PasswordMigrationWarningIntroFragment(Context context) {
+    public PasswordMigrationWarningIntroFragment(Context context, Runnable acknowledgeCallback,
+            Runnable moreOptionsCallback, String channelString) {
         super(R.layout.pwd_migration_warning_intro_fragment);
         mContext = context;
+        mAcknowledgeCallback = acknowledgeCallback;
+        mMoreOptionsCallback = moreOptionsCallback;
+        mChannelString = channelString;
     }
 
     @Override
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         TextViewWithLeading subtitleView = view.findViewById(R.id.migration_warning_sheet_subtitle);
         subtitleView.setText(mContext.getString(R.string.password_migration_warning_subtitle)
-                                     .replace("%1$s", getChannelString()));
-    }
-
-    private String getChannelString() {
-        if (VersionInfo.isCanaryBuild()) {
-            return "Canary";
-        }
-        if (VersionInfo.isDevBuild()) {
-            return "Dev";
-        }
-        if (VersionInfo.isBetaBuild()) {
-            return "Beta";
-        }
-        assert !VersionInfo.isStableBuild();
-        return "";
+                                     .replace("%1$s", mChannelString));
+        Button acknowledgeButton = view.findViewById(R.id.acknowledge_password_migration_button);
+        Button moreOptionsButton = view.findViewById(R.id.password_migration_more_options_button);
+        acknowledgeButton.setOnClickListener((unusedView) -> mAcknowledgeCallback.run());
+        moreOptionsButton.setOnClickListener((unusedView) -> mMoreOptionsCallback.run());
     }
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediator.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediator.java
index 67f9297..9eac7db 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediator.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediator.java
@@ -4,8 +4,11 @@
 
 package org.chromium.chrome.browser.pwd_migration;
 
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.CURRENT_SCREEN;
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
 
+import org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.ScreenType;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -13,14 +16,15 @@
  * Contains the logic for the local passwords migration warning. It sets the state of the model and
  * reacts to events.
  */
-class PasswordMigrationWarningMediator {
+class PasswordMigrationWarningMediator implements PasswordMigrationWarningOnClickHandler {
     private PropertyModel mModel;
 
     void initialize(PropertyModel model) {
         mModel = model;
     }
 
-    void showWarning() {
+    void showWarning(int screenType) {
+        mModel.set(CURRENT_SCREEN, screenType);
         mModel.set(VISIBLE, true);
     }
 
@@ -29,7 +33,23 @@
         mModel.set(VISIBLE, false);
     }
 
-    PropertyModel getModel() {
-        return mModel;
+    @Override
+    public void onAcknowledge(BottomSheetController bottomSheetController) {
+        bottomSheetController.collapseSheet(true);
+    }
+
+    @Override
+    public void onMoreOptions() {
+        mModel.set(CURRENT_SCREEN, ScreenType.OPTIONS_SCREEN);
+    }
+
+    @Override
+    public void onNext() {
+        // TODO(crbug.com/1445065): Launch the password Export flow.
+    }
+
+    @Override
+    public void onCancel(BottomSheetController bottomSheetController) {
+        bottomSheetController.collapseSheet(true);
     }
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java
index d7d4838..e3aaefd 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningMediatorTest.java
@@ -4,10 +4,13 @@
 
 package org.chromium.chrome.browser.pwd_migration;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
 
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.CURRENT_SCREEN;
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.DISMISS_HANDLER;
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
 
@@ -24,6 +27,7 @@
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Batch;
+import org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.ScreenType;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
@@ -42,6 +46,7 @@
     public TestRule mProcessor = new Features.JUnitProcessor();
 
     private PasswordMigrationWarningMediator mMediator = new PasswordMigrationWarningMediator();
+    private PropertyModel mModel;
 
     @Mock
     private BottomSheetController mBottomSheetController;
@@ -49,35 +54,50 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mMediator.initialize(
-                PasswordMigrationWarningProperties.createDefaultModel(mMediator::onDismissed));
+        mModel = PasswordMigrationWarningProperties.createDefaultModel(
+                mMediator::onDismissed, mMediator);
+        mMediator.initialize(mModel);
     }
 
     @Test
     public void testShowWarningChangesVisibility() {
-        PropertyModel model = mMediator.getModel();
-        assertFalse(model.get(VISIBLE));
-        mMediator.showWarning();
-        assertTrue(model.get(VISIBLE));
+        mModel.set(VISIBLE, false);
+        mMediator.showWarning(ScreenType.INTRO_SCREEN);
+        assertTrue(mModel.get(VISIBLE));
     }
 
     @Test
-    public void testOnDismissedChangesVisibility() {
-        PropertyModel model = mMediator.getModel();
-        mMediator.showWarning();
-        assertTrue(model.get(VISIBLE));
+    public void testOnDismissedHidesTheSheet() {
+        mMediator.showWarning(ScreenType.INTRO_SCREEN);
         mMediator.onDismissed(StateChangeReason.NONE);
-        assertFalse(model.get(VISIBLE));
+        assertFalse(mModel.get(VISIBLE));
     }
 
     @Test
-    public void testDismissHandlerChangesVisibility() {
-        PropertyModel model = mMediator.getModel();
-        assertNotNull(model.get(DISMISS_HANDLER));
-        assertFalse(model.get(VISIBLE));
-        mMediator.showWarning();
-        assertTrue(model.get(VISIBLE));
-        model.get(DISMISS_HANDLER).onResult(StateChangeReason.NONE);
-        assertFalse(model.get(VISIBLE));
+    public void testDismissHandlerHidesTheSheet() {
+        assertNotNull(mModel.get(DISMISS_HANDLER));
+        mMediator.showWarning(ScreenType.INTRO_SCREEN);
+        mModel.get(DISMISS_HANDLER).onResult(StateChangeReason.NONE);
+        assertFalse(mModel.get(VISIBLE));
+    }
+
+    @Test
+    public void testOnMoreOptionsChangesTheModel() {
+        mMediator.showWarning(ScreenType.INTRO_SCREEN);
+        assertEquals(mModel.get(CURRENT_SCREEN), ScreenType.INTRO_SCREEN);
+        mMediator.onMoreOptions();
+        assertEquals(mModel.get(CURRENT_SCREEN), ScreenType.OPTIONS_SCREEN);
+    }
+
+    @Test
+    public void testOnAcknowledgeCollapsesTheSheet() {
+        mMediator.onAcknowledge(mBottomSheetController);
+        verify(mBottomSheetController).collapseSheet(true);
+    }
+
+    @Test
+    public void testOnCancelCollapsesTheSheet() {
+        mMediator.onCancel(mBottomSheetController);
+        verify(mBottomSheetController).collapseSheet(true);
     }
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOnClickHandler.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOnClickHandler.java
new file mode 100644
index 0000000..e726d766
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOnClickHandler.java
@@ -0,0 +1,41 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.pwd_migration;
+
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+
+/**
+ * Contains the logic for the on click listeners of all the buttons on the
+ * password migration warning sheet.
+ */
+interface PasswordMigrationWarningOnClickHandler {
+    /**
+     * Closes the sheet and marks that the user acknowledged the notice by
+     * clicking on the "Got it" button.
+     *
+     * @param bottomSheetController used to close the sheet.
+     */
+    void onAcknowledge(BottomSheetController bottomSheetController);
+
+    /**
+     * Shows a screen with more options when the "More options" button is
+     * clicked.
+     */
+    void onMoreOptions();
+
+    /**
+     * Starts the sign-in/sync flow or the export flow depending on the user
+     * choice in the screen with more options.
+     */
+    void onNext();
+
+    /**
+     * Closes the sheet when the "Cancel" button is clicked, but doesn't mark
+     * that the user acknowledged the notice.
+     *
+     * @param bottomSheetController used to close the sheet.
+     */
+    void onCancel(BottomSheetController bottomSheetController);
+}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOptionsFragment.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOptionsFragment.java
new file mode 100644
index 0000000..4cf115d
--- /dev/null
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningOptionsFragment.java
@@ -0,0 +1,54 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+package org.chromium.chrome.browser.pwd_migration;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import org.chromium.components.browser_ui.widget.RadioButtonWithDescription;
+
+/**
+ * This fragment contains the UI for the second page of the password migration
+ * warning. The page shows alternative options for users who didn't acknowledge
+ * the upcoming merge of passwords for different Chrome channels. The offered
+ * alternatives are to export the passwords or to start syncing passwords.
+ */
+public class PasswordMigrationWarningOptionsFragment extends Fragment {
+    private Context mContext;
+    private boolean mShouldSignIn = true;
+    private Runnable mNextCallback;
+    private Runnable mCancelCallback;
+    private String mChannelString;
+
+    public PasswordMigrationWarningOptionsFragment(
+            Context context, Runnable nextCallback, Runnable cancelCallback, String channelString) {
+        super(R.layout.pwd_migration_warning_options);
+        mContext = context;
+        mNextCallback = nextCallback;
+        mCancelCallback = cancelCallback;
+        mChannelString = channelString;
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        RadioButtonWithDescription signInOrSyncButton =
+                view.findViewById(R.id.radio_sign_in_or_sync);
+        RadioButtonWithDescription passwordExportButton =
+                view.findViewById(R.id.radio_password_export);
+        Button nextButton = view.findViewById(R.id.password_migration_next_button);
+        Button cancelButton = view.findViewById(R.id.password_migration_cancel_button);
+
+        signInOrSyncButton.setChecked(true);
+        passwordExportButton.setDescriptionText(
+                mContext.getString(R.string.password_migration_warning_password_export_subtitle)
+                        .replace("%1$s", mChannelString));
+        nextButton.setOnClickListener((unusedView) -> mNextCallback.run());
+        cancelButton.setOnClickListener((unusedView) -> mCancelCallback.run());
+    }
+}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningProperties.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningProperties.java
index 7e9d2f90..9baf042 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningProperties.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningProperties.java
@@ -4,22 +4,44 @@
 
 package org.chromium.chrome.browser.pwd_migration;
 
+import androidx.annotation.IntDef;
+
 import org.chromium.base.Callback;
 import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * Properties defined here reflect the visible state of the local passwords migration warning.
  */
 class PasswordMigrationWarningProperties {
-    static final PropertyModel.WritableBooleanPropertyKey VISIBLE =
-            new PropertyModel.WritableBooleanPropertyKey("visible");
-    static final PropertyModel.ReadableObjectPropertyKey<Callback<Integer>> DISMISS_HANDLER =
-            new PropertyModel.ReadableObjectPropertyKey<>("dismiss_handler");
+    /**
+     * The different screens that can be shown on the sheet.
+     */
+    @IntDef({ScreenType.INTRO_SCREEN, ScreenType.OPTIONS_SCREEN})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScreenType {
+        int INTRO_SCREEN = 0;
+        int OPTIONS_SCREEN = 1;
+    }
 
-    static PropertyModel createDefaultModel(Callback<Integer> dismissHandler) {
-        return new PropertyModel.Builder(VISIBLE, DISMISS_HANDLER)
-                .with(VISIBLE, false)
+    static final WritableBooleanPropertyKey VISIBLE = new WritableBooleanPropertyKey("visible");
+    static final ReadableObjectPropertyKey<Callback<Integer>> DISMISS_HANDLER =
+            new ReadableObjectPropertyKey<>("dismiss_handler");
+    static final ReadableObjectPropertyKey<PasswordMigrationWarningOnClickHandler>
+            ON_CLICK_HANDLER = new ReadableObjectPropertyKey<>("on_click_handler");
+    public static final WritableIntPropertyKey CURRENT_SCREEN =
+            new WritableIntPropertyKey("current_screen");
+
+    static PropertyModel createDefaultModel(Callback<Integer> dismissHandler,
+            PasswordMigrationWarningOnClickHandler onClickHandler) {
+        return new PropertyModel.Builder(VISIBLE, DISMISS_HANDLER, ON_CLICK_HANDLER, CURRENT_SCREEN)
                 .with(DISMISS_HANDLER, dismissHandler)
+                .with(ON_CLICK_HANDLER, onClickHandler)
                 .build();
     }
 
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java
index bf392bc..1e79378 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.pwd_migration;
 
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.CURRENT_SCREEN;
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
 import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
 import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting;
@@ -30,6 +31,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
+import org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.ScreenType;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
@@ -57,6 +59,8 @@
 
     @Mock
     private Callback<Integer> mDismissCallback;
+    @Mock
+    private PasswordMigrationWarningOnClickHandler mOnClickHandler;
 
     private BottomSheetController mBottomSheetController;
     private PasswordMigrationWarningView mView;
@@ -67,7 +71,7 @@
     @Rule
     public final ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus()
-                    .setRevision(1)
+                    .setRevision(2)
                     .setBugComponent(Component.UI_BROWSER_AUTOFILL)
                     .build();
 
@@ -86,7 +90,8 @@
                                          .getRootUiCoordinatorForTesting()
                                          .getBottomSheetController();
         runOnUiThreadBlocking(() -> {
-            mModel = PasswordMigrationWarningProperties.createDefaultModel(mDismissCallback);
+            mModel = PasswordMigrationWarningProperties.createDefaultModel(
+                    mDismissCallback, mOnClickHandler);
             mView = new PasswordMigrationWarningView(
                     mActivityTestRule.getActivity(), mBottomSheetController);
             PropertyModelChangeProcessor.create(mModel, mView,
@@ -111,6 +116,7 @@
     @MediumTest
     @Feature({"RenderTest"})
     public void testShowsPasswordMigrationWwarningFirstPage() throws Exception {
+        runOnUiThreadBlocking(() -> mModel.set(CURRENT_SCREEN, ScreenType.INTRO_SCREEN));
         runOnUiThreadBlocking(() -> mModel.set(VISIBLE, true));
 
         BottomSheetTestSupport.waitForOpen(mBottomSheetController);
@@ -119,4 +125,20 @@
                 mActivityTestRule.getActivity().findViewById(R.id.pwd_migration_warning_sheet);
         mRenderTestRule.render(bottomSheetView, "pwd_migration_warning_first_page");
     }
+
+    @Test
+    @MediumTest
+    @Feature({"RenderTest"})
+    public void testShowsPasswordMigrationWarningSecondPageWithNoUserSignedIn() throws Exception {
+        runOnUiThreadBlocking(() -> mModel.set(CURRENT_SCREEN, ScreenType.OPTIONS_SCREEN));
+        runOnUiThreadBlocking(() -> mModel.set(VISIBLE, true));
+
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        View bottomSheetView =
+                mActivityTestRule.getActivity().findViewById(R.id.pwd_migration_warning_sheet);
+
+        mRenderTestRule.render(
+                bottomSheetView, "pwd_migration_warning_second_page_no_user_signed_in");
+    }
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
index fb312989..b09b07c 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
@@ -17,10 +17,12 @@
 
 import org.chromium.base.Callback;
 import org.chromium.chrome.browser.password_manager.PasswordManagerResourceProviderFactory;
+import org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.ScreenType;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
 import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
+import org.chromium.components.version_info.VersionInfo;
 
 /**
  * This class is responsible for rendering the bottom sheet that shows the passwords
@@ -29,9 +31,10 @@
 class PasswordMigrationWarningView implements BottomSheetContent {
     private final BottomSheetController mBottomSheetController;
     private Callback<Integer> mDismissHandler;
+    private PasswordMigrationWarningOnClickHandler mOnClickHandler;
     private FragmentManager mFragmentManager;
-    private PasswordMigrationWarningIntroFragment mIntroFragment;
     private final RelativeLayout mContentView;
+    private Context mContext;
 
     private final BottomSheetObserver mBottomSheetObserver = new EmptyBottomSheetObserver() {
         @Override
@@ -53,6 +56,7 @@
     };
 
     PasswordMigrationWarningView(Context context, BottomSheetController bottomSheetController) {
+        mContext = context;
         mBottomSheetController = bottomSheetController;
         mContentView = (RelativeLayout) LayoutInflater.from(context).inflate(
                 R.layout.pwd_migration_warning, null);
@@ -60,15 +64,17 @@
                 mContentView.findViewById(R.id.touch_to_fill_sheet_header_image);
         sheetHeaderImage.setImageDrawable(AppCompatResources.getDrawable(
                 context, PasswordManagerResourceProviderFactory.create().getPasswordManagerIcon()));
-
         mFragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
-        mIntroFragment = new PasswordMigrationWarningIntroFragment(context);
     }
 
     void setDismissHandler(Callback<Integer> dismissHandler) {
         mDismissHandler = dismissHandler;
     }
 
+    void setOnClickHandler(PasswordMigrationWarningOnClickHandler onClickHandler) {
+        mOnClickHandler = onClickHandler;
+    }
+
     boolean setVisible(boolean isVisible) {
         if (!isVisible) {
             mBottomSheetController.hideContent(this, true);
@@ -79,14 +85,47 @@
             mBottomSheetController.removeObserver(mBottomSheetObserver);
             return false;
         }
-        mFragmentManager.beginTransaction()
-                .setReorderingAllowed(true)
-                .add(R.id.fragment_container_view, mIntroFragment,
-                        "PasswordMigrationWarningFragment")
-                .commit();
         return true;
     }
 
+    void setScreen(int screenType) {
+        if (screenType == ScreenType.INTRO_SCREEN) {
+            PasswordMigrationWarningIntroFragment introFragment =
+                    new PasswordMigrationWarningIntroFragment(mContext,
+                            ()
+                                    -> mOnClickHandler.onAcknowledge(mBottomSheetController),
+                            () -> mOnClickHandler.onMoreOptions(), getChannelString());
+            mFragmentManager.beginTransaction()
+                    .setReorderingAllowed(true)
+                    .replace(R.id.fragment_container_view, introFragment)
+                    .commit();
+        } else if (screenType == ScreenType.OPTIONS_SCREEN) {
+            PasswordMigrationWarningOptionsFragment optionsFragment =
+                    new PasswordMigrationWarningOptionsFragment(mContext, mOnClickHandler::onNext,
+                            ()
+                                    -> mOnClickHandler.onCancel(mBottomSheetController),
+                            getChannelString());
+            mFragmentManager.beginTransaction()
+                    .setReorderingAllowed(true)
+                    .replace(R.id.fragment_container_view, optionsFragment)
+                    .commit();
+        }
+    }
+
+    private String getChannelString() {
+        if (VersionInfo.isCanaryBuild()) {
+            return "Canary";
+        }
+        if (VersionInfo.isDevBuild()) {
+            return "Dev";
+        }
+        if (VersionInfo.isBetaBuild()) {
+            return "Beta";
+        }
+        assert !VersionInfo.isStableBuild();
+        return "";
+    }
+
     @Nullable
     @Override
     public View getContentView() {
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java
index ba17aa65..7ed2a51 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewBinder.java
@@ -4,7 +4,9 @@
 
 package org.chromium.chrome.browser.pwd_migration;
 
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.CURRENT_SCREEN;
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.DISMISS_HANDLER;
+import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.ON_CLICK_HANDLER;
 import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE;
 
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
@@ -28,10 +30,15 @@
             view.setDismissHandler(model.get(DISMISS_HANDLER));
         } else if (propertyKey == VISIBLE) {
             boolean visibilityChangeSuccessful = view.setVisible(model.get(VISIBLE));
+            // TODO(crbug.com/1446996): Move this logic out of the view binder.
             if (!visibilityChangeSuccessful && model.get(VISIBLE)) {
                 assert model.get(DISMISS_HANDLER) != null;
                 model.get(DISMISS_HANDLER).onResult(BottomSheetController.StateChangeReason.NONE);
             }
+        } else if (propertyKey == CURRENT_SCREEN) {
+            view.setScreen(model.get(CURRENT_SCREEN));
+        } else if (propertyKey == ON_CLICK_HANDLER) {
+            view.setOnClickHandler(model.get(ON_CLICK_HANDLER));
         } else {
             assert false : "Unhandled update to property:" + propertyKey;
         }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java
index 66a8f12a..57272f2 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java
@@ -49,6 +49,8 @@
 
     @Mock
     private Callback<Integer> mDismissCallback;
+    @Mock
+    private PasswordMigrationWarningOnClickHandler mOnClickHandler;
 
     private BottomSheetController mBottomSheetController;
     private PasswordMigrationWarningView mView;
@@ -62,7 +64,8 @@
                                          .getRootUiCoordinatorForTesting()
                                          .getBottomSheetController();
         runOnUiThreadBlocking(() -> {
-            mModel = PasswordMigrationWarningProperties.createDefaultModel(mDismissCallback);
+            mModel = PasswordMigrationWarningProperties.createDefaultModel(
+                    mDismissCallback, mOnClickHandler);
             mView = new PasswordMigrationWarningView(
                     mActivityTestRule.getActivity(), mBottomSheetController);
             PropertyModelChangeProcessor.create(mModel, mView,
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade_factory.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade_factory.cc
index e543a12..e027a20 100644
--- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade_factory.cc
+++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade_factory.cc
@@ -48,7 +48,6 @@
           ProfileSelections::Builder()
               .WithRegular(ProfileSelection::kOwnInstance)
               .WithGuest(ProfileSelection::kOwnInstance)
-              .WithSystem(ProfileSelection::kOwnInstance)
               .Build()) {
   DependsOn(HistoryServiceFactory::GetInstance());
 }
diff --git a/chrome/browser/profiles/profile_keyed_service_browsertest.cc b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
index f75bd2a6..f2e9d01 100644
--- a/chrome/browser/profiles/profile_keyed_service_browsertest.cc
+++ b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
@@ -172,13 +172,6 @@
 
 IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
                        SystemProfileOTR_NeededServices) {
-  // clang-format off
-  // List of services expected to be created for the System OTR Profile.
-  std::set<std::string> system_otr_active_services {
-    "SiteDataCacheFacadeFactory"
-  };
-  // clang-format on
-
   Profile* system_profile =
       CreateProfileAndWaitForAllTasks(ProfileManager::GetSystemProfilePath());
   ASSERT_TRUE(system_profile->HasAnyOffTheRecordProfile());
@@ -186,23 +179,17 @@
   ASSERT_TRUE(system_profile_otr->IsOffTheRecord());
   ASSERT_TRUE(system_profile_otr->IsSystemProfile());
   TestKeyedProfileServicesActives(system_profile_otr,
-                                  system_otr_active_services);
+                                  /*expected_active_services_names=*/{});
 }
 
 IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
                        SystemProfileParent_NeededServices) {
-  // clang-format off
-  // List of services expected to be created for the Parent System Profile.
-  std::set<std::string> system_active_services {
-    "SiteDataCacheFacadeFactory"
-  };
-  // clang-format on
-
   Profile* system_profile =
       CreateProfileAndWaitForAllTasks(ProfileManager::GetSystemProfilePath());
   ASSERT_FALSE(system_profile->IsOffTheRecord());
   ASSERT_TRUE(system_profile->IsSystemProfile());
-  TestKeyedProfileServicesActives(system_profile, system_active_services);
+  TestKeyedProfileServicesActives(system_profile,
+                                  /*expected_active_services_names=*/{});
 }
 
 IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
diff --git a/chrome/browser/resources/password_manager/password_details_section.html b/chrome/browser/resources/password_manager/password_details_section.html
index 1fdcf92..ce4713d3 100644
--- a/chrome/browser/resources/password_manager/password_details_section.html
+++ b/chrome/browser/resources/password_manager/password_details_section.html
@@ -15,6 +15,10 @@
     --site-favicon-height: 20px;
     --site-favicon-width: 20px;
   }
+
+  #title {
+    line-height: normal;
+  }
 </style>
 <div id="header">
   <cr-icon-button class="icon-arrow-back" id="backButton"
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 4996864..d9ea0b4f6 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -352,17 +352,17 @@
     return true;
   }
 
-  // If sync is running in transport-only mode, every type is "preferred", so
-  // IsTrustedVaultKeyRequiredForPreferredDataTypes() could return true even if
-  // the user isn't trying to sync any of the encrypted types. The check below
-  // tries to avoid showing an unexpected "You couldn't sync X" error in that
-  // case. It works fine if IsEncryptEverythingEnabled() is false, since
-  // PASSWORDS is the only one of AlwaysEncryptedUserTypes() currently
-  // supporting transport mode. Otherwise, it should really be OR-ed with other
-  // checks.
-  // TODO(crbug.com/1134090): Fix the definition of preferred types for
-  // transport mode so calling IsTrustedVaultKeyRequiredForPreferredDataTypes()
-  // is enough.
+  // On desktop transport mode, IsTrustedVaultKeyRequiredForPreferredDataTypes()
+  // returns true even if the user isn't trying to sync any of the encrypted
+  // types. The check below tries to avoid showing an unexpected "You couldn't
+  // sync X" error in that case. It works fine if IsEncryptEverythingEnabled()
+  // is false, since PASSWORDS is the only one of AlwaysEncryptedUserTypes()
+  // currently supporting transport mode. Otherwise, it should really be OR-ed
+  // with other checks.
+  // TODO(crbug.com/1447083): Once the Desktop precondition for
+  // EnablePasswordsAccountStorage becomes "PASSWORDS is a selected type", and
+  // not a PreconditionState of the controller, this function can be replaced
+  // with a single IsTrustedVaultKeyRequiredForPreferredDataTypes() check.
   //
   // WARNING: Must match CredentialModelTypeController::GetPreconditionState().
   return password_manager::features_util::IsOptedInForAccountStorage(
@@ -381,16 +381,16 @@
     return true;
   }
 
-  // In transport-only mode, IsTrustedVaultRecoverabilityDegraded() returns true
-  // even if the user isn't trying to sync any of the encrypted types. The check
-  // below tries to avoid unnecessarily showing the error in that case. It works
-  // fine if IsEncryptEverythingEnabled() is false, since PASSWORDS is the only
-  // one of AlwaysEncryptedUserTypes() currently supporting transport mode.
+  // On desktop transport mode, IsTrustedVaultRecoverabilityDegraded() returns
+  // true even if the user isn't trying to sync any of the encrypted types. The
+  // check below tries to avoid unnecessarily showing the error in that case. It
+  // works fine if IsEncryptEverythingEnabled() is false, since PASSWORDS is the
+  // only one of AlwaysEncryptedUserTypes() currently supporting transport mode.
   // Otherwise, it should really be OR-ed with other checks.
-  // TODO(crbug.com/1134090): Fix the definition of preferred types for
-  // transport mode so calling IsTrustedVaultRecoverabilityDegraded() is enough
-  // (SyncUserSettingsImpl::IsEncryptedDatatypeEnabled() relies on the preferred
-  // types).
+  // TODO(crbug.com/1447083): Once the Desktop precondition for
+  // EnablePasswordsAccountStorage becomes "PASSWORDS is a selected type", and
+  // not a PreconditionState of the controller, this function can be replaced
+  // with a single IsTrustedVaultRecoverabilityDegraded() check.
   //
   // WARNING: Must match CredentialModelTypeController::GetPreconditionState().
   return password_manager::features_util::IsOptedInForAccountStorage(
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac.cc b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac.cc
index a5e629848..4b30dbf 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac.cc
@@ -41,26 +41,6 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegration,
-    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_40Client2_46Standalone_1Standalone_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `docs/webapps/why-is-this-test-failing.md` or
-  // `docs/webapps/integration-testing-framework` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed(Site::kStandalone);
-  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
-  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
-                                           IsShown::kNotShown);
-  helper_.ClosePwa();
-  helper_.SwitchProfileClients(ProfileClient::kClient2);
-  helper_.InstallLocally(Site::kStandalone);
-  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegration,
     WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_40Client2_45Standalone_46Standalone_7Standalone_12Standalone_1Standalone_127) {
   // Test contents are generated by script. Please do not modify!
   // See `docs/webapps/why-is-this-test-failing.md` or
@@ -143,5 +123,27 @@
   helper_.CheckWindowCreated();
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone_40Client2_46Standalone_1Standalone_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.SwitchProfileClients(ProfileClient::kClient2);
+  helper_.InstallLocally(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckWindowCreated();
+}
+
 }  // namespace
 }  // namespace web_app::integration_tests
diff --git a/chrome/browser/touch_to_fill/payments/DIR_METADATA b/chrome/browser/touch_to_fill/payments/DIR_METADATA
index 110957a..d9bf029 100644
--- a/chrome/browser/touch_to_fill/payments/DIR_METADATA
+++ b/chrome/browser/touch_to_fill/payments/DIR_METADATA
@@ -1,3 +1,3 @@
 monorail: {
-  component: "UI>Browser>Autofill>UI"
+  component: "UI>Browser>Autofill>Payments"
 }
diff --git a/chrome/browser/ui/DEPS b/chrome/browser/ui/DEPS
index b56a704e..a9e4f632 100644
--- a/chrome/browser/ui/DEPS
+++ b/chrome/browser/ui/DEPS
@@ -63,4 +63,7 @@
   "signin_intercept_first_run_experience_dialog_browsertest.cc": [
     "+chrome/browser/ui/views/profiles/avatar_toolbar_button.h",
   ],
+  "save_update_address_profile_bubble_controller_impl_interactive_uitest.cc": [
+    "+chrome/browser/ui/views/autofill"
+  ]
 }
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index b05b731a..f3aba28c 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -747,7 +747,24 @@
       <message name="IDS_PASSWORD_MIGRATION_WARNING_OTHER_OPTIONS" desc="The text on the button that leads to other options in the password migration warning sheet.">
         Other options
       </message>
-
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC" desc="The text that describes the option to start syncing that is offered in the password migration warning sheet.">
+        Save the passwords on this device in your Google Account by turning on sync
+      </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC_SUBTITLE" desc="The subtitle that appears under the option to turn on sync in the password migration warning sheet if the user is not signed in.">
+        You’ll be asked to sign in to your Google Account
+      </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT" desc="The text that describes the option to export the passwords that is offered in the password migration warning sheet.">
+        Export &amp; delete passwords saved to this device
+      </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT_SUBTITLE" desc="The subtitle that explaint the password export option in the password migration warning sheet.">
+        All passwords will be downloaded on your device and removed from Chrome <ph name="CHROME_CHANNEL">%1$s<ex>Dev</ex></ph>
+      </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_NEXT" desc="The text for the next button in the password migration warning sheet. It starts one of the flows offered on the sheet.">
+        Next
+      </message>
+      <message name="IDS_PASSWORD_MIGRATION_WARNING_CANCEL" desc="The text for the cancel button in the password migration warning sheet. It closes the sheet">
+        Cancel
+      </message>
 
       <!-- Lock Screen Fragment -->
       <message name="IDS_LOCKSCREEN_DESCRIPTION_COPY" desc="When a user attempts to copy a password for a particular website into clipboard in Chrome's settings, Chrome launches a lock screen to verify the user's identity and displays the following explanation.">
@@ -1963,30 +1980,6 @@
       </message>
 
       <!-- Child accounts -->
-      <message name="IDS_ACCOUNT_MANAGEMENT_PARENTAL_SETTINGS" desc="Title of parental settings section of account page for child account.">
-        Parental Settings
-      </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_NO_PARENTAL_DATA" desc="String saying that we are waiting for family information.">
-        Waiting for details of parents.
-      </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_ONE_PARENT_NAME" desc="String for name of single parent for child account.">
-        This browser is managed by <ph name="PARENT_NAME">%1$s<ex>parent1@gmail.com</ex></ph>.
-      </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_TWO_PARENT_NAMES" desc="String for names of two parents for child account.">
-        This browser is managed by <ph name="PARENT_NAME_1">%1$s<ex>parent1@gmail.com</ex></ph> and <ph name="PARENT_NAME_2">%2$s<ex>parent2@gmail.com</ex></ph>.
-      </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_CHILD_CONTENT_TITLE" desc="Title of the Content setting, which controls which websites a child is allowed to visit.">
-        Content
-      </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_CHILD_CONTENT_APPROVED" desc="Setting that permits child accounts to visit only sites approved by their parents.">
-        Only allow certain sites
-      </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_CHILD_CONTENT_FILTER_MATURE" desc="Setting that permits child accounts to visit any websites that don't have mature contents. As the filter is not perfect, the browser can only attempt to block these sites.">
-        Try to block mature sites
-      </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_CHILD_CONTENT_ALL" desc="Setting that permits child accounts to visit any websites.">
-        Allow all sites
-      </message>
       <message name="IDS_ACCOUNT_MANAGEMENT_HEADER_NO_PARENTAL_DATA" desc="String saying that child should go to parent for help for child account.">
         If you need help, ask your parent
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_ONE_PARENT_NAME.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_ONE_PARENT_NAME.png.sha1
deleted file mode 100644
index 65262e2..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_ONE_PARENT_NAME.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-4b08d2bcd2cf01c731b627606f9a61a493a6e510
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_TWO_PARENT_NAMES.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_TWO_PARENT_NAMES.png.sha1
deleted file mode 100644
index 45327087f..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_TWO_PARENT_NAMES.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-34718a5428024af7781bac690b64386af9b19ec0
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_CANCEL.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_CANCEL.png.sha1
new file mode 100644
index 0000000..9b9ac1e
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_CANCEL.png.sha1
@@ -0,0 +1 @@
+d45ee4610ee415649d0636e8f6cc38a5feacc2b0
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_NEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_NEXT.png.sha1
new file mode 100644
index 0000000..9b9ac1e
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_NEXT.png.sha1
@@ -0,0 +1 @@
+d45ee4610ee415649d0636e8f6cc38a5feacc2b0
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT.png.sha1
new file mode 100644
index 0000000..9b9ac1e
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT.png.sha1
@@ -0,0 +1 @@
+d45ee4610ee415649d0636e8f6cc38a5feacc2b0
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT_SUBTITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT_SUBTITLE.png.sha1
new file mode 100644
index 0000000..9b9ac1e
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_PASSWORD_EXPORT_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+d45ee4610ee415649d0636e8f6cc38a5feacc2b0
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC.png.sha1
new file mode 100644
index 0000000..9b9ac1e
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC.png.sha1
@@ -0,0 +1 @@
+d45ee4610ee415649d0636e8f6cc38a5feacc2b0
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC_SUBTITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC_SUBTITLE.png.sha1
new file mode 100644
index 0000000..9b9ac1e
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TURN_ON_SYNC_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+d45ee4610ee415649d0636e8f6cc38a5feacc2b0
\ No newline at end of file
diff --git a/chrome/browser/ui/autofill/DIR_METADATA b/chrome/browser/ui/autofill/DIR_METADATA
index 8dc897c..b597ffd 100644
--- a/chrome/browser/ui/autofill/DIR_METADATA
+++ b/chrome/browser/ui/autofill/DIR_METADATA
@@ -1,3 +1,3 @@
 monorail {
-  component: "UI>Browser>Autofill>UI"
+  component: "UI>Browser>Autofill"
 }
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index 23b20e76..7379ddf 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -397,7 +397,9 @@
     std::u16string* body) {
   return delegate_->GetDeletionConfirmationText(
       suggestions_[list_index].main_text.value,
-      suggestions_[list_index].frontend_id, title, body);
+      suggestions_[list_index].frontend_id,
+      suggestions_[list_index].GetPayload<Suggestion::BackendId>(), title,
+      body);
 }
 
 bool AutofillPopupControllerImpl::RemoveSuggestion(int list_index) {
@@ -411,8 +413,10 @@
   // TODO(crbug.com/1209792): Replace these checks with a stronger identifier.
   if (list_index < 0 || static_cast<size_t>(list_index) >= suggestions_.size())
     return false;
-  if (!delegate_->RemoveSuggestion(suggestions_[list_index].main_text.value,
-                                   suggestions_[list_index].frontend_id)) {
+  if (!delegate_->RemoveSuggestion(
+          suggestions_[list_index].main_text.value,
+          suggestions_[list_index].frontend_id,
+          suggestions_[list_index].GetPayload<Suggestion::BackendId>())) {
     return false;
   }
 
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
index 34d8211..1db8b780 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -110,7 +110,8 @@
                            Suggestion::FrontendId frontend_id,
                            const Suggestion::BackendId& backend_id) override {}
   bool RemoveSuggestion(const std::u16string& value,
-                        Suggestion::FrontendId frontend_id) override {
+                        Suggestion::FrontendId frontend_id,
+                        Suggestion::BackendId backend_id) override {
     return true;
   }
   base::WeakPtr<AutofillExternalDelegate> GetWeakPtr() {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index ef184707..36ebcfa 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -386,8 +386,6 @@
     AutofillDriver* driver) {
   auto* cad = static_cast<ContentAutofillDriver*>(driver);
   content::RenderFrameHost* rfh = cad->render_frame_host();
-  if (!rfh)
-    return nullptr;
 #if BUILDFLAG(IS_ANDROID)
   return std::make_unique<InternalAuthenticatorAndroid>(rfh);
 #else
diff --git a/chrome/browser/ui/autofill/payments/DIR_METADATA b/chrome/browser/ui/autofill/payments/DIR_METADATA
new file mode 100644
index 0000000..d9bf029
--- /dev/null
+++ b/chrome/browser/ui/autofill/payments/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Browser>Autofill>Payments"
+}
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_browsertest.cc b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_browsertest.cc
deleted file mode 100644
index 5bbd78b..0000000
--- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_browsertest.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h"
-
-#include "base/functional/callback_helpers.h"
-#include "base/memory/raw_ptr.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/test/test_browser_dialog.h"
-#include "components/autofill/content/browser/content_autofill_client.h"
-#include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/common/autofill_features.h"
-#include "content/public/test/browser_test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace autofill {
-
-class SaveUpdateAddressProfileBubbleControllerImplTest
-    : public DialogBrowserTest {
- public:
-  SaveUpdateAddressProfileBubbleControllerImplTest() = default;
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    DialogBrowserTest::SetUpCommandLine(command_line);
-  }
-
-  // DialogBrowserTest:
-  void ShowUi(const std::string& name) override {
-    content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    autofill::ContentAutofillClient* autofill_client =
-        autofill::ContentAutofillClient::FromWebContents(web_contents);
-    AutofillProfile profile = test::GetFullProfile();
-    AutofillProfile* original_profile = (name == "Update") ? &profile : nullptr;
-    autofill_client->ConfirmSaveAddressProfile(
-        profile, original_profile,
-        AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
-        base::DoNothing());
-    DCHECK(controller());
-  }
-
-  SaveUpdateAddressProfileBubbleControllerImpl* controller() {
-    content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    DCHECK(web_contents);
-    return SaveUpdateAddressProfileBubbleControllerImpl::FromWebContents(
-        web_contents);
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
-                       InvokeUi_Save) {
-  ShowAndVerifyUi();
-}
-
-IN_PROC_BROWSER_TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
-                       InvokeUi_Update) {
-  ShowAndVerifyUi();
-}
-
-IN_PROC_BROWSER_TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
-                       InvokeUi_SaveCloseThenReopen) {
-  ShowAndVerifyUi();
-  controller()->OnBubbleClosed();
-  ShowAndVerifyUi();
-}
-
-IN_PROC_BROWSER_TEST_F(SaveUpdateAddressProfileBubbleControllerImplTest,
-                       CloseTabWhileBubbleIsOpen) {
-  ShowAndVerifyUi();
-  content::WebContents* tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  tab->Close();
-}
-
-}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_interactive_uitest.cc b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_interactive_uitest.cc
new file mode 100644
index 0000000..29f8f59
--- /dev/null
+++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_interactive_uitest.cc
@@ -0,0 +1,277 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h"
+
+#include "base/functional/bind.h"
+#include "chrome/browser/ui/views/autofill/edit_address_profile_view.h"
+#include "chrome/browser/ui/views/autofill/save_address_profile_view.h"
+#include "chrome/browser/ui/views/autofill/update_address_profile_view.h"
+#include "chrome/test/interaction/interactive_browser_test.h"
+#include "components/autofill/content/browser/content_autofill_client.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "content/public/test/browser_test.h"
+#include "ui/base/interaction/element_identifier.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/window/dialog_client_view.h"
+
+namespace autofill {
+
+constexpr char kSuppressedScreenshotError[] =
+    "Screenshot can only run in pixel_tests on Windows.";
+
+class BaseSaveUpdateAddressProfileBubbleControllerImplTest
+    : public InteractiveBrowserTest {
+ protected:
+  autofill::ContentAutofillClient* autofill_client() {
+    content::WebContents* web_contents =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    return autofill::ContentAutofillClient::FromWebContents(web_contents);
+  }
+
+  virtual void TriggerBubble() = 0;
+
+  InteractiveTestApi::StepBuilder ShowInitBubble() {
+    return Do([this]() {
+      user_decision_ =
+          AutofillClient::SaveAddressProfileOfferUserDecision::kUndefined;
+      TriggerBubble();
+    });
+  }
+
+  InteractiveTestApi::StepBuilder EnsureClosedWithDecision(
+      AutofillClient::SaveAddressProfileOfferUserDecision
+          expected_user_decision) {
+    return Do([this, expected_user_decision]() {
+      ASSERT_EQ(expected_user_decision, user_decision_);
+    });
+  }
+
+  void OnUserDecision(
+      AutofillClient::SaveAddressProfileOfferUserDecision decision,
+      AutofillProfile profile) {
+    user_decision_ = decision;
+  }
+
+ private:
+  // The latest user decisive interaction with a popup, e.g. Save/Update
+  // or Cancel the prompt, it is set in the AddressProfileSavePromptCallback
+  // passed to the prompt.
+  AutofillClient::SaveAddressProfileOfferUserDecision user_decision_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SaveAddressProfileTest
+
+class SaveAddressProfileTest
+    : public BaseSaveUpdateAddressProfileBubbleControllerImplTest {
+  void TriggerBubble() override {
+    autofill_client()->ConfirmSaveAddressProfile(
+        test::GetFullProfile(), nullptr,
+        AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
+        base::BindOnce(&SaveAddressProfileTest::OnUserDecision,
+                       base::Unretained(this)));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(SaveAddressProfileTest, SaveAccept) {
+  RunTestSequence(
+      ShowInitBubble(),
+      PressButton(views::DialogClientView::kOkButtonElementId),
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted));
+}
+
+IN_PROC_BROWSER_TEST_F(SaveAddressProfileTest, SaveDecline) {
+  RunTestSequence(
+      ShowInitBubble(),
+      PressButton(views::DialogClientView::kCancelButtonElementId),
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined));
+}
+
+IN_PROC_BROWSER_TEST_F(SaveAddressProfileTest, SaveWithEdit) {
+  RunTestSequence(
+      ShowInitBubble(),
+      SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
+                              kSuppressedScreenshotError),
+      Screenshot(SaveAddressProfileView::kTopViewId, "save_popup", "4535916"),
+      PressButton(SaveAddressProfileView::kEditButtonViewId),
+
+      // The editor popup resides in a different context on MacOS.
+      InAnyContext(
+          Steps(WaitForShow(EditAddressProfileView::kTopViewId),
+                Screenshot(EditAddressProfileView::kTopViewId, "edit_popup",
+                           "4535916"),
+                PressButton(views::DialogClientView::kCancelButtonElementId))),
+
+      WaitForShow(SaveAddressProfileView::kTopViewId),
+      PressButton(views::DialogClientView::kOkButtonElementId),
+      WaitForHide(SaveAddressProfileView::kTopViewId),
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted));
+}
+
+IN_PROC_BROWSER_TEST_F(SaveAddressProfileTest, SaveInEdit) {
+  RunTestSequence(
+      SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
+                              kSuppressedScreenshotError),
+      ShowInitBubble(), PressButton(SaveAddressProfileView::kEditButtonViewId),
+
+      InAnyContext(
+          Steps(WaitForShow(EditAddressProfileView::kTopViewId),
+                PressButton(views::DialogClientView::kOkButtonElementId))),
+
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted));
+}
+
+IN_PROC_BROWSER_TEST_F(SaveAddressProfileTest, SaveCloseAndOpenAgain) {
+  RunTestSequence(
+      ShowInitBubble(),
+      SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
+                              kSuppressedScreenshotError),
+      Screenshot(SaveAddressProfileView::kTopViewId, "save_popup", "4535916"),
+
+      PressButton(views::BubbleFrameView::kCloseButtonElementId),
+      // Make sure the popup gets closed before subsequent reopening.
+      EnsureNotPresent(SaveAddressProfileView::kTopViewId),
+
+      ShowInitBubble(),
+      Screenshot(SaveAddressProfileView::kTopViewId, "reopened_save_popup",
+                 "4535916"));
+}
+
+IN_PROC_BROWSER_TEST_F(SaveAddressProfileTest, NoCrashesOnTabClose) {
+  RunTestSequence(
+      ShowInitBubble(), EnsurePresent(SaveAddressProfileView::kTopViewId),
+      Do([this]() {
+        browser()->tab_strip_model()->GetActiveWebContents()->Close();
+      }));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// UpdateAddressProfileTest
+
+class UpdateAddressProfileTest
+    : public BaseSaveUpdateAddressProfileBubbleControllerImplTest {
+ protected:
+  void TriggerBubble() override {
+    autofill_client()->ConfirmSaveAddressProfile(
+        test::GetFullProfile(), &original_profile_,
+        AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
+        base::BindOnce(&UpdateAddressProfileTest::OnUserDecision,
+                       base::Unretained(this)));
+  }
+
+  AutofillProfile original_profile_ = test::GetFullProfile2();
+};
+
+IN_PROC_BROWSER_TEST_F(UpdateAddressProfileTest, UpdateThroughEdit) {
+  RunTestSequence(
+      ShowInitBubble(),
+      SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
+                              kSuppressedScreenshotError),
+      Screenshot(UpdateAddressProfileView::kTopViewId, "update_popup",
+                 "4535916"),
+      PressButton(UpdateAddressProfileView::kEditButtonViewId),
+
+      // The editor popup resides in a different context on MacOS.
+      InAnyContext(
+          Steps(WaitForShow(EditAddressProfileView::kTopViewId),
+                Screenshot(EditAddressProfileView::kTopViewId, "edit_popup",
+                           "4535916"),
+                PressButton(views::DialogClientView::kCancelButtonElementId))),
+
+      WaitForShow(UpdateAddressProfileView::kTopViewId),
+      PressButton(views::DialogClientView::kOkButtonElementId),
+      WaitForHide(UpdateAddressProfileView::kTopViewId),
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// UpdateAccountAddressProfileTest
+
+class UpdateAccountAddressProfileTest : public UpdateAddressProfileTest {
+  void TriggerBubble() override {
+    original_profile_.set_source_for_testing(AutofillProfile::Source::kAccount);
+    autofill_client()->ConfirmSaveAddressProfile(
+        test::GetFullProfile(), &original_profile_,
+        AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
+        base::BindOnce(&UpdateAccountAddressProfileTest::OnUserDecision,
+                       base::Unretained(this)));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(UpdateAccountAddressProfileTest, UpdateThroughEdit) {
+  RunTestSequence(
+      ShowInitBubble(),
+      SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
+                              kSuppressedScreenshotError),
+      Screenshot(UpdateAddressProfileView::kTopViewId, "update_popup",
+                 "4535916"),
+      PressButton(UpdateAddressProfileView::kEditButtonViewId),
+
+      // The editor popup resides in a different context on MacOS.
+      InAnyContext(
+          Steps(WaitForShow(EditAddressProfileView::kTopViewId),
+                Screenshot(EditAddressProfileView::kTopViewId, "edit_popup",
+                           "4535916"),
+                PressButton(views::DialogClientView::kCancelButtonElementId))),
+
+      WaitForShow(UpdateAddressProfileView::kTopViewId),
+      PressButton(views::DialogClientView::kOkButtonElementId),
+      WaitForHide(UpdateAddressProfileView::kTopViewId),
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SaveAddressProfileTest
+
+class MigrateToProfileAddressProfileTest
+    : public BaseSaveUpdateAddressProfileBubbleControllerImplTest {
+  void TriggerBubble() override {
+    autofill_client()->ConfirmSaveAddressProfile(
+        test::GetFullProfile(), nullptr,
+        AutofillClient::SaveAddressProfilePromptOptions{
+            .show_prompt = true, .is_migration_to_account = true},
+        base::BindOnce(&MigrateToProfileAddressProfileTest::OnUserDecision,
+                       base::Unretained(this)));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(MigrateToProfileAddressProfileTest, SaveDecline) {
+  RunTestSequence(
+      ShowInitBubble(),
+      PressButton(views::DialogClientView::kCancelButtonElementId),
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kNever));
+}
+
+IN_PROC_BROWSER_TEST_F(MigrateToProfileAddressProfileTest, SaveWithEdit) {
+  RunTestSequence(
+      ShowInitBubble(),
+      SetOnIncompatibleAction(OnIncompatibleAction::kIgnoreAndContinue,
+                              kSuppressedScreenshotError),
+      Screenshot(SaveAddressProfileView::kTopViewId, "save_popup", "4535916"),
+      PressButton(SaveAddressProfileView::kEditButtonViewId),
+
+      // The editor popup resides in a different context on MacOS.
+      InAnyContext(
+          Steps(WaitForShow(EditAddressProfileView::kTopViewId),
+                Screenshot(EditAddressProfileView::kTopViewId, "edit_popup",
+                           "4535916"),
+                PressButton(views::DialogClientView::kCancelButtonElementId))),
+
+      WaitForShow(SaveAddressProfileView::kTopViewId),
+      PressButton(views::DialogClientView::kOkButtonElementId),
+      WaitForHide(SaveAddressProfileView::kTopViewId),
+      EnsureClosedWithDecision(
+          AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted));
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/browser_list.cc b/chrome/browser/ui/browser_list.cc
index c16e80d..ad1fe8c9 100644
--- a/chrome/browser/ui/browser_list.cc
+++ b/chrome/browser/ui/browser_list.cc
@@ -54,7 +54,8 @@
 }  // namespace
 
 // static
-base::LazyInstance<base::ObserverList<BrowserListObserver>>::Leaky
+base::LazyInstance<base::ObserverList<BrowserListObserver>,
+                   BrowserList::ObserverListTraits>
     BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER;
 
 // static
diff --git a/chrome/browser/ui/browser_list.h b/chrome/browser/ui/browser_list.h
index 9f1e9b5..75b0d49 100644
--- a/chrome/browser/ui/browser_list.h
+++ b/chrome/browser/ui/browser_list.h
@@ -218,9 +218,21 @@
   // A vector of the browsers that are currently in the closing state.
   BrowserSet currently_closing_browsers_;
 
+  // If an observer is added while iterating over them and notifying, it should
+  // not be notified as it probably already saw the Browser* being added/removed
+  // in the BrowserList.
+  struct ObserverListTraits : base::internal::LeakyLazyInstanceTraits<
+                                  base::ObserverList<BrowserListObserver>> {
+    static base::ObserverList<BrowserListObserver>* New(void* instance) {
+      return new (instance) base::ObserverList<BrowserListObserver>(
+          base::ObserverListPolicy::EXISTING_ONLY);
+    }
+  };
+
   // A list of observers which will be notified of every browser addition and
   // removal across all BrowserLists.
-  static base::LazyInstance<base::ObserverList<BrowserListObserver>>::Leaky
+  static base::LazyInstance<base::ObserverList<BrowserListObserver>,
+                            ObserverListTraits>
       observers_;
 
   static BrowserList* instance_;
diff --git a/chrome/browser/ui/browser_list_unittest.cc b/chrome/browser/ui/browser_list_unittest.cc
index bc463b7..07f0906 100644
--- a/chrome/browser/ui/browser_list_unittest.cc
+++ b/chrome/browser/ui/browser_list_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/browser_list.h"
 
 #include <memory>
+#include <set>
 
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
@@ -74,3 +75,85 @@
   result = chrome::FindBrowserWithUiElementContext(ui::ElementContext(100));
   EXPECT_EQ(nullptr, result);
 }
+
+// Class that tries to observe all pre-existing and newly created browsers.
+// Ensures that for each browser there is a single OnBrowserAdded/Removed call
+// or it already existed in BrowserList.
+class BrowserObserverChild : public BrowserListObserver, TabStripModelObserver {
+ public:
+  explicit BrowserObserverChild(Browser* created_for_browser)
+      : created_for_browser_(created_for_browser) {
+    BrowserList* browser_list = BrowserList::GetInstance();
+    for (Browser* browser : *browser_list) {
+      EXPECT_FALSE(base::Contains(observed_browsers_, browser));
+      observed_browsers_.insert(browser);
+      browser->tab_strip_model()->AddObserver(this);
+    }
+    EXPECT_TRUE(base::Contains(observed_browsers_, created_for_browser_));
+    browser_list->AddObserver(this);
+  }
+
+  ~BrowserObserverChild() override {
+    BrowserList* browser_list = BrowserList::GetInstance();
+    for (Browser* browser : *browser_list) {
+      EXPECT_TRUE(base::Contains(observed_browsers_, browser));
+      observed_browsers_.erase(browser);
+      browser->tab_strip_model()->RemoveObserver(this);
+    }
+    browser_list->RemoveObserver(this);
+  }
+
+  void OnBrowserAdded(Browser* browser) override {
+    EXPECT_NE(browser, created_for_browser_);
+    EXPECT_FALSE(base::Contains(observed_browsers_, browser));
+    observed_browsers_.insert(browser);
+    browser->tab_strip_model()->AddObserver(this);
+  }
+
+  void OnBrowserRemoved(Browser* browser) override {
+    browser->tab_strip_model()->RemoveObserver(this);
+    EXPECT_TRUE(base::Contains(observed_browsers_, browser));
+    observed_browsers_.erase(browser);
+  }
+
+ private:
+  std::set<Browser*> observed_browsers_;
+  raw_ptr<Browser> created_for_browser_;
+};
+
+// Class that creates BrowserObserverChild when a Browser is created;
+class BrowserObserverParent : public BrowserListObserver {
+ public:
+  BrowserObserverParent() { BrowserList::GetInstance()->AddObserver(this); }
+
+  void OnBrowserAdded(Browser* browser) override {
+    if (!child_observer_) {
+      child_observer_ = std::make_unique<BrowserObserverChild>(browser);
+    }
+  }
+
+  ~BrowserObserverParent() override {
+    BrowserList::GetInstance()->RemoveObserver(this);
+  }
+
+ protected:
+  std::unique_ptr<BrowserObserverChild> child_observer_;
+};
+
+TEST_F(BrowserListUnitTest, ObserverAddedInFlight) {
+  BrowserObserverParent parent_observer;
+
+  const BrowserList* browser_list = BrowserList::GetInstance();
+  EXPECT_EQ(1U, browser_list->size());
+
+  // Adding second browser should not trigger double-observation.
+  Browser::CreateParams native_params(profile(), true);
+  std::unique_ptr<Browser> browser2(
+      CreateBrowserWithTestWindowForParams(native_params));
+  EXPECT_EQ(2U, browser_list->size());
+
+  // Create one more browser to trigger BrowserObserverChild::OnBrowserAdded.
+  std::unique_ptr<Browser> browser3(
+      CreateBrowserWithTestWindowForParams(native_params));
+  EXPECT_EQ(3U, browser_list->size());
+}
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index aad2654..0351510 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -112,15 +112,9 @@
   bool IsGeolocationAllowedOnASystemLevel();
   bool IsGeolocationPermissionDetermined();
 
-  void AppCeasesToUseGeolocation();
-  void AppAttemptsToUseGeolocation();
-
   std::unique_ptr<ContentSettingBubbleModel> CreateBubbleModelImpl(
       ContentSettingBubbleModel::Delegate* delegate,
       WebContents* web_contents) override;
-
- private:
-  bool active_ = false;
 };
 
 class ContentSettingRPHImageModel : public ContentSettingSimpleImageModel {
@@ -522,9 +516,7 @@
 ContentSettingGeolocationImageModel::ContentSettingGeolocationImageModel()
     : ContentSettingImageModel(ImageType::GEOLOCATION, kNotifyAccessibility) {}
 
-ContentSettingGeolocationImageModel::~ContentSettingGeolocationImageModel() {
-  AppCeasesToUseGeolocation();
-}
+ContentSettingGeolocationImageModel::~ContentSettingGeolocationImageModel() {}
 
 bool ContentSettingGeolocationImageModel::UpdateAndGetVisibility(
     WebContents* web_contents) {
@@ -533,7 +525,6 @@
           web_contents->GetPrimaryMainFrame());
   set_should_auto_open_bubble(false);
   if (!content_settings) {
-    AppCeasesToUseGeolocation();
     return false;
   }
 
@@ -543,7 +534,6 @@
       content_settings->IsContentBlocked(ContentSettingsType::GEOLOCATION);
 
   if (!is_allowed && !is_blocked) {
-    AppCeasesToUseGeolocation();
     return false;
   }
 
@@ -595,7 +585,6 @@
         set_explanatory_string_id(IDS_GEOLOCATION_TURNED_OFF);
 #endif  // BUILDFLAG(IS_MAC)
       }
-      AppAttemptsToUseGeolocation();
       return true;
     }
   }
@@ -607,7 +596,6 @@
   set_tooltip(l10n_util::GetStringUTF16(message_id));
   set_accessibility_string_id(message_id);
 
-  AppAttemptsToUseGeolocation();
   return true;
 }
 
@@ -640,30 +628,6 @@
 #endif
 }
 
-void ContentSettingGeolocationImageModel::AppAttemptsToUseGeolocation() {
-  if (!active_) {
-    active_ = true;
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
-    device::GeolocationManager* geolocation_manager =
-        g_browser_process->geolocation_manager();
-    CHECK(geolocation_manager);
-    geolocation_manager->AppAttemptsToUseGeolocation();
-#endif
-  }
-}
-
-void ContentSettingGeolocationImageModel::AppCeasesToUseGeolocation() {
-  if (active_) {
-    active_ = false;
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
-    device::GeolocationManager* geolocation_manager =
-        g_browser_process->geolocation_manager();
-    CHECK(geolocation_manager);
-    geolocation_manager->AppCeasesToUseGeolocation();
-#endif
-  }
-}
-
 std::unique_ptr<ContentSettingBubbleModel>
 ContentSettingGeolocationImageModel::CreateBubbleModelImpl(
     ContentSettingBubbleModel::Delegate* delegate,
diff --git a/chrome/browser/ui/fast_checkout/DIR_METADATA b/chrome/browser/ui/fast_checkout/DIR_METADATA
index aa2a9fdd5..0da2312 100644
--- a/chrome/browser/ui/fast_checkout/DIR_METADATA
+++ b/chrome/browser/ui/fast_checkout/DIR_METADATA
@@ -1,4 +1,4 @@
 monorail {
-  component: "UI>Browser>Autofill>Assistant"
+  component: "UI>Browser>Autofill"
 }
 team_email: "chrome-duplex@google.com"
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
index c0d6b18..216cf1af 100644
--- a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
@@ -17,6 +17,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
+#include "ui/views/view_class_properties.h"
 
 namespace autofill {
 
@@ -45,6 +46,7 @@
   set_margins(ChromeLayoutProvider::Get()->GetInsetsMetric(
       views::InsetsMetric::INSETS_DIALOG));
 
+  SetProperty(views::kElementIdentifierKey, kTopViewId);
   SetTitle(controller_->GetWindowTitle());
   SetButtonLabel(ui::DIALOG_BUTTON_OK, controller_->GetOkButtonLabel());
   SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
@@ -117,4 +119,6 @@
   SetButtonEnabled(ui::DIALOG_BUTTON_OK, is_valid);
 }
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(EditAddressProfileView, kTopViewId);
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view.h b/chrome/browser/ui/views/autofill/edit_address_profile_view.h
index a603367..bec2e80 100644
--- a/chrome/browser/ui/views/autofill/edit_address_profile_view.h
+++ b/chrome/browser/ui/views/autofill/edit_address_profile_view.h
@@ -25,6 +25,8 @@
 class EditAddressProfileView : public AutofillBubbleBase,
                                public views::DialogDelegateView {
  public:
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kTopViewId);
+
   explicit EditAddressProfileView(
       EditAddressProfileDialogController* controller);
 
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.cc b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
index 35ee611d..4265b128 100644
--- a/chrome/browser/ui/views/autofill/save_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
@@ -161,6 +161,8 @@
   // it would have been an update prompt.
   DCHECK(!controller_->GetOriginalProfile());
 
+  set_close_on_deactivate(false);
+
   // TODO(crbug.com/1167060): Accept action should consider the selected
   // nickname when saving the address.
   SetAcceptCallback(base::BindOnce(
@@ -171,6 +173,7 @@
       &SaveUpdateAddressProfileBubbleController::OnUserDecision,
       base::Unretained(controller_), controller_->GetCancelCallbackValue()));
 
+  SetProperty(views::kElementIdentifierKey, kTopViewId);
   SetTitle(controller_->GetWindowTitle());
   SetButtonLabel(ui::DIALOG_BUTTON_OK, controller_->GetOkButtonLabel());
   SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
@@ -227,6 +230,7 @@
       details_section->AddChildView(CreateEditButton(base::BindRepeating(
           &SaveUpdateAddressProfileBubbleController::OnEditButtonClicked,
           base::Unretained(controller_))));
+  edit_button_->SetProperty(views::kElementIdentifierKey, kEditButtonViewId);
 
   std::u16string address = controller_->GetAddressSummary();
   if (!address.empty()) {
@@ -365,4 +369,8 @@
   }
 }
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(SaveAddressProfileView, kTopViewId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(SaveAddressProfileView,
+                                      kEditButtonViewId);
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.h b/chrome/browser/ui/views/autofill/save_address_profile_view.h
index f9f682c..cce2512 100644
--- a/chrome/browser/ui/views/autofill/save_address_profile_view.h
+++ b/chrome/browser/ui/views/autofill/save_address_profile_view.h
@@ -27,6 +27,9 @@
 class SaveAddressProfileView : public AutofillBubbleBase,
                                public LocationBarBubbleDelegateView {
  public:
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kTopViewId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kEditButtonViewId);
+
   SaveAddressProfileView(views::View* anchor_view,
                          content::WebContents* web_contents,
                          SaveUpdateAddressProfileBubbleController* controller);
diff --git a/chrome/browser/ui/views/autofill/update_address_profile_view.cc b/chrome/browser/ui/views/autofill/update_address_profile_view.cc
index 6d3663d..dc3d561 100644
--- a/chrome/browser/ui/views/autofill/update_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/update_address_profile_view.cc
@@ -123,6 +123,9 @@
   if (are_new_values) {
     std::unique_ptr<views::ImageButton> edit_button =
         CreateEditButton(std::move(edit_button_callback));
+
+    edit_button->SetProperty(views::kElementIdentifierKey,
+                             UpdateAddressProfileView::kEditButtonViewId);
     layout_view->AddChildView(std::move(edit_button));
   }
 }
@@ -168,6 +171,7 @@
       base::Unretained(controller_),
       AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined));
 
+  SetProperty(views::kElementIdentifierKey, kTopViewId);
   SetTitle(controller_->GetWindowTitle());
   SetButtonLabel(ui::DIALOG_BUTTON_OK,
                  l10n_util::GetStringUTF16(
@@ -294,4 +298,8 @@
   controller_ = nullptr;
 }
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(UpdateAddressProfileView, kTopViewId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(UpdateAddressProfileView,
+                                      kEditButtonViewId);
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/update_address_profile_view.h b/chrome/browser/ui/views/autofill/update_address_profile_view.h
index 55292e5..49618118 100644
--- a/chrome/browser/ui/views/autofill/update_address_profile_view.h
+++ b/chrome/browser/ui/views/autofill/update_address_profile_view.h
@@ -25,6 +25,9 @@
 class UpdateAddressProfileView : public AutofillBubbleBase,
                                  public LocationBarBubbleDelegateView {
  public:
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kTopViewId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kEditButtonViewId);
+
   UpdateAddressProfileView(
       views::View* anchor_view,
       content::WebContents* web_contents,
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc
index 34401fd1..7c747186 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc
@@ -2128,5 +2128,23 @@
   helper_.CheckPlatformShortcutAndIcon(Site::kSubApp1);
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+}
+
 }  // namespace
 }  // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc
index a9b15a5..2953d02 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc
@@ -188,46 +188,6 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegration,
-    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_149Standalone_1Standalone_22One_163Standalone) {
-  // Test contents are generated by script. Please do not modify!
-  // See `docs/webapps/why-is-this-test-failing.md` or
-  // `docs/webapps/integration-testing-framework` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed(Site::kStandalone);
-  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
-  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
-                                           IsShown::kNotShown);
-  helper_.ClosePwa();
-  helper_.SetOpenInTabFromAppSettings(Site::kStandalone);
-  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
-  helper_.CheckTabCreated(Number::kOne);
-  helper_.CheckAppLoadedInTab(Site::kStandalone);
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegration,
-    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_147Standalone_1Standalone_22One_163Standalone) {
-  // Test contents are generated by script. Please do not modify!
-  // See `docs/webapps/why-is-this-test-failing.md` or
-  // `docs/webapps/integration-testing-framework` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed(Site::kStandalone);
-  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
-  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
-                                           IsShown::kNotShown);
-  helper_.ClosePwa();
-  helper_.SetOpenInTabFromAppHome(Site::kStandalone);
-  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
-  helper_.CheckTabCreated(Number::kOne);
-  helper_.CheckAppLoadedInTab(Site::kStandalone);
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegration,
     WAI_31Standalone_24_12Standalone_7Standalone_112StandaloneNotShown_28_149Standalone_1Standalone_22One_163Standalone) {
   // Test contents are generated by script. Please do not modify!
   // See `docs/webapps/why-is-this-test-failing.md` or
@@ -1244,72 +1204,6 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegration,
-    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_160Profile2_29StandaloneWindowed_164Standalone_1Standalone_165StandaloneOneProfile2) {
-  // Test contents are generated by script. Please do not modify!
-  // See `docs/webapps/why-is-this-test-failing.md` or
-  // `docs/webapps/integration-testing-framework` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed(Site::kStandalone);
-  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
-  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
-                                           IsShown::kNotShown);
-  helper_.ClosePwa();
-  helper_.SwitchActiveProfile(ProfileName::kProfile2);
-  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
-  helper_.QuitAppShim(Site::kStandalone);
-  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
-  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
-                                         ProfileName::kProfile2);
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegration,
-    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_160Profile2_31Standalone_164Standalone_1Standalone_165StandaloneOneProfile2) {
-  // Test contents are generated by script. Please do not modify!
-  // See `docs/webapps/why-is-this-test-failing.md` or
-  // `docs/webapps/integration-testing-framework` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed(Site::kStandalone);
-  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
-  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
-                                           IsShown::kNotShown);
-  helper_.ClosePwa();
-  helper_.SwitchActiveProfile(ProfileName::kProfile2);
-  helper_.InstallOmniboxIcon(InstallableSite::kStandalone);
-  helper_.QuitAppShim(Site::kStandalone);
-  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
-  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
-                                         ProfileName::kProfile2);
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegration,
-    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_160Profile2_47Standalone_164Standalone_1Standalone_165StandaloneOneProfile2) {
-  // Test contents are generated by script. Please do not modify!
-  // See `docs/webapps/why-is-this-test-failing.md` or
-  // `docs/webapps/integration-testing-framework` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed(Site::kStandalone);
-  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
-  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
-                                           IsShown::kNotShown);
-  helper_.ClosePwa();
-  helper_.SwitchActiveProfile(ProfileName::kProfile2);
-  helper_.InstallMenuOption(InstallableSite::kStandalone);
-  helper_.QuitAppShim(Site::kStandalone);
-  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
-  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
-                                         ProfileName::kProfile2);
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegration,
     WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_160Profile2_29StandaloneWindowed_164Standalone_1Standalone_165StandaloneOneDefault_165StandaloneOneProfile2) {
   // Test contents are generated by script. Please do not modify!
   // See `docs/webapps/why-is-this-test-failing.md` or
@@ -2094,5 +1988,121 @@
                                          ProfileName::kProfile2);
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone_149Standalone_1Standalone_22One_163Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.SetOpenInTabFromAppSettings(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckTabCreated(Number::kOne);
+  helper_.CheckAppLoadedInTab(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone_147Standalone_1Standalone_22One_163Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.SetOpenInTabFromAppHome(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckTabCreated(Number::kOne);
+  helper_.CheckAppLoadedInTab(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone_160Profile2_29StandaloneWindowed_164Standalone_1Standalone_165StandaloneOneProfile2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.SwitchActiveProfile(ProfileName::kProfile2);
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.QuitAppShim(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
+                                         ProfileName::kProfile2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone_160Profile2_31Standalone_164Standalone_1Standalone_165StandaloneOneProfile2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.SwitchActiveProfile(ProfileName::kProfile2);
+  helper_.InstallOmniboxIcon(InstallableSite::kStandalone);
+  helper_.QuitAppShim(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
+                                         ProfileName::kProfile2);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone_160Profile2_47Standalone_164Standalone_1Standalone_165StandaloneOneProfile2) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.SwitchActiveProfile(ProfileName::kProfile2);
+  helper_.InstallMenuOption(InstallableSite::kStandalone);
+  helper_.QuitAppShim(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
+                                         ProfileName::kProfile2);
+}
+
 }  // namespace
 }  // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
index ceeb3f3..92a3c2c 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
@@ -12,6 +12,16 @@
 
 // Manual tests:
 
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationTest, Testing_2) {
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.MaybeClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckWindowCreated();
+  helper_.CheckInstallIconNotShown();
+}
+
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationTest, LaunchFromPlatformShortcut) {
   helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
   helper_.CheckWindowCreated();
@@ -5728,5 +5738,44 @@
   helper_.CheckBrowserNavigationIsAppSettings(Site::kStandalone);
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneBrowser_11Standalone_7Standalone_1Standalone_22One_31Standalone_165StandaloneOneDefault) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kBrowser);
+  helper_.CheckAppInListTabbed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckTabCreated(Number::kOne);
+  helper_.InstallOmniboxIcon(InstallableSite::kStandalone);
+  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
+                                         ProfileName::kDefault);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_29StandaloneWindowed_24_12Standalone_7Standalone_112StandaloneNotShown_28_12Standalone_7Standalone_1Standalone_165StandaloneOneDefault_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.CheckWindowControlsOverlayToggle(Site::kStandalone,
+                                           IsShown::kNotShown);
+  helper_.ClosePwa();
+  helper_.CheckAppInListWindowed(Site::kStandalone);
+  helper_.CheckPlatformShortcutAndIcon(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckPwaWindowCreatedInProfile(Site::kStandalone, Number::kOne,
+                                         ProfileName::kDefault);
+  helper_.CheckLaunchIconNotShown();
+}
+
 }  // namespace
 }  // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/webui/ash/edu_account_login_handler_unittest.cc b/chrome/browser/ui/webui/ash/edu_account_login_handler_unittest.cc
index f086755..e02b483 100644
--- a/chrome/browser/ui/webui/ash/edu_account_login_handler_unittest.cc
+++ b/chrome/browser/ui/webui/ash/edu_account_login_handler_unittest.cc
@@ -275,9 +275,9 @@
 
   // Simulate failed fetching of family members.
   handler()->OnListFamilyMembersFailure(
-      KidsExternalFetcherStatus::NetOrHttpError(net::ERR_IO_PENDING));
+      KidsExternalFetcherStatus::HttpStatusOrNetError(net::ERR_IO_PENDING));
   const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-  VerifyJavascriptCallbackResolved(data, callback_id, false /*success*/);
+  VerifyJavascriptCallbackResolved(data, callback_id, /*success=*/false);
 
   ASSERT_EQ(base::Value::List(), *data.arg3());
 }
diff --git a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
index 212f774..bd45226 100644
--- a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
+++ b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
@@ -269,7 +269,7 @@
     "chrome://connection-help",
     "chrome://connection-monitoring-detected",
 // TODO(crbug.com/1446612): Re-enable this test
-#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
     "chrome://credits",
 #endif
     "chrome://customize-chrome-side-panel.top-chrome",
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 0b6a96d..9ea2e4c 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1684727980-51662d2f1f6daef2312757edd2dffb5841d13efb.profdata
+chrome-chromeos-amd64-generic-main-1684741965-9877198816133fde5c1e2b04561d5ea49365a2fb.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index dc93529..379d6bc0 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1684727980-0fd0c1177220325145c620a12d6fed55ccff088a.profdata
+chrome-mac-arm-main-1684749276-3baf89d503def7b008db9225d5ba5149e86f5300.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 82f6ca4..d0a491d 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1684713069-d6dbd61c3725118a77b672bdb8468711f45ae782.profdata
+chrome-mac-main-1684735120-b681ef3f762e90652c2a427d586e72382e8dca3a.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index ece5d468..2c228ca 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1684724274-6e95f936d76f98a2b96f8aa1501e17607cf9e5a3.profdata
+chrome-win32-main-1684745810-e281aa73a34471fde8607f6aed8c228e9efbc681.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index bb0d47d0..698d92a6 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1684724274-88cd05cd95f5a6b07bf8ea8b3618abbc9f5bad19.profdata
+chrome-win64-main-1684745810-b231356e5ab799996dbf86d8f839a83a4ffcd54b.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 6e85bb36..1409296 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2317,7 +2317,6 @@
       "../browser/ui/autofill/payments/card_unmask_prompt_view_browsertest.cc",
       "../browser/ui/autofill/payments/save_card_bubble_controller_impl_browsertest.cc",
       "../browser/ui/autofill/payments/save_upi_bubble_controller_impl_browsertest.cc",
-      "../browser/ui/autofill/save_update_address_profile_bubble_controller_impl_browsertest.cc",
       "../browser/ui/blocked_content/popup_opener_tab_helper_browsertest.cc",
       "../browser/ui/blocked_content/popup_tracker_browsertest.cc",
       "../browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_browsertest.cc",
@@ -3900,6 +3899,7 @@
         "../browser/ash/arc/user_session/arc_user_session_service_browsertest.cc",
         "../browser/ash/base/locale_util_browsertest.cc",
         "../browser/ash/bluetooth/hats_bluetooth_revamp_trigger_impl_browsertest.cc",
+        "../browser/ash/bruschetta/bruschetta_download_browsertest.cc",
         "../browser/ash/child_accounts/family_user_device_metrics_browsertest.cc",
         "../browser/ash/child_accounts/parent_access_code/parent_access_service_browsertest.cc",
         "../browser/ash/child_accounts/screen_time_controller_browsertest.cc",
@@ -10143,6 +10143,7 @@
     if (toolkit_views) {
       sources += [
         "../browser/media/webrtc/conditional_focus_browsertest.cc",
+        "../browser/ui/autofill/save_update_address_profile_bubble_controller_impl_interactive_uitest.cc",
         "../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",
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
index c4ef347..6ae78b3 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
@@ -211,16 +211,12 @@
   // to allow Chrome to write out all the net logs to the log path.
   kill_gracefully = kill_gracefully || command_.HasSwitch("log-net-log");
   if (kill_gracefully) {
-    Status status{kOk};
-    if (!devtools_websocket_client_->IsConnected())
-      status = devtools_websocket_client_->Connect();
-    if (status.IsOk()) {
-      status = devtools_websocket_client_->SendCommandAndIgnoreResponse(
-          "Browser.close", base::Value::Dict());
-      // If status is not okay, we will try the old method of KillProcess
-      if (status.IsOk() &&
-          process_.WaitForExitWithTimeout(base::Seconds(10), nullptr))
-        return status;
+    Status status = devtools_websocket_client_->SendCommandAndIgnoreResponse(
+        "Browser.close", base::Value::Dict());
+    // If status is not okay, we will try the old method of KillProcess
+    if (status.IsOk() &&
+        process_.WaitForExitWithTimeout(base::Seconds(10), nullptr)) {
+      return status;
     }
   }
 
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.cc b/chrome/test/chromedriver/chrome/chrome_impl.cc
index d86ef40..66b8704b 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_impl.cc
@@ -212,80 +212,11 @@
   }
 
   *client = std::make_unique<DevToolsClientImpl>(id, session_id);
-  (*client)->SetFrontendCloserFunc(base::BindRepeating(
-      &ChromeImpl::CloseFrontends, base::Unretained(this), id));
   (*client)->SetMainPage(true);
 
   return status;
 }
 
-Status ChromeImpl::CloseFrontends(const std::string& for_client_id) {
-  WebViewsInfo views_info;
-  Status status = GetWebViewsInfo(&views_info);
-  if (status.IsError())
-    return status;
-
-  // Close frontends. Usually frontends are docked in the same page, although
-  // some may be in tabs (undocked, chrome://inspect, the DevTools
-  // discovery page, etc.). Tabs can be closed via the DevTools HTTP close
-  // URL, but docked frontends can only be closed, by design, by connecting
-  // to them and clicking the close button. Close the tab frontends first
-  // in case one of them is debugging a docked frontend, which would prevent
-  // the code from being able to connect to the docked one.
-  std::list<std::string> tab_frontend_ids;
-  std::list<std::string> docked_frontend_ids;
-  for (size_t i = 0; i < views_info.GetSize(); ++i) {
-    const WebViewInfo& view_info = views_info.Get(i);
-    if (view_info.IsFrontend()) {
-      if (view_info.type == WebViewInfo::kPage)
-        tab_frontend_ids.push_back(view_info.id);
-      else if (view_info.type == WebViewInfo::kOther)
-        docked_frontend_ids.push_back(view_info.id);
-      else
-        return Status(kUnknownError, "unknown type of DevTools frontend");
-    }
-  }
-
-  for (std::list<std::string>::const_iterator it = tab_frontend_ids.begin();
-       it != tab_frontend_ids.end(); ++it) {
-    status = CloseWebView(*it);
-    if (status.IsError())
-      return status;
-  }
-
-  for (std::list<std::string>::const_iterator it = docked_frontend_ids.begin();
-       it != docked_frontend_ids.end(); ++it) {
-    std::unique_ptr<DevToolsClientImpl> client;
-    status = CreateClient(*it, &client);
-    if (status.IsError())
-      return status;
-    std::unique_ptr<WebViewImpl> web_view(new WebViewImpl(
-        *it, false, nullptr, devtools_http_client_->browser_info(),
-        std::move(client), absl::nullopt, page_load_strategy_));
-
-    DevToolsClientImpl* parent =
-        static_cast<DevToolsClientImpl*>(devtools_websocket_client_.get());
-    status = web_view->AttachTo(parent);
-    if (status.IsError()) {
-      return status;
-    }
-
-    status = CloseWebView(*it);
-    // Ignore disconnected error, because it may be closed already.
-    if (status.IsError() && status.code() != kDisconnected)
-      return status;
-  }
-
-  status = GetWebViewsInfo(&views_info);
-  if (status.IsError())
-    return status;
-
-  const WebViewInfo* view_info = views_info.GetForId(for_client_id);
-  if (!view_info)
-    return Status(kNoSuchWindow, "window was already closed");
-  return Status(kOk);
-}
-
 Status ChromeImpl::GetWindow(const std::string& target_id, Window* window) {
   base::Value::Dict params;
   params.Set("targetId", target_id);
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.h b/chrome/test/chromedriver/chrome/chrome_impl.h
index d81a71b2..af45b7d 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_impl.h
@@ -72,7 +72,6 @@
 
   Status CreateClient(const std::string& id,
                       std::unique_ptr<DevToolsClientImpl>* client);
-  Status CloseFrontends(const std::string& for_client_id);
   Status CloseTarget(const std::string& id);
 
   struct Window {
diff --git a/chrome/test/chromedriver/chrome/console_logger_unittest.cc b/chrome/test/chromedriver/chrome/console_logger_unittest.cc
index 1ab92c6..86fa031 100644
--- a/chrome/test/chromedriver/chrome/console_logger_unittest.cc
+++ b/chrome/test/chromedriver/chrome/console_logger_unittest.cc
@@ -25,7 +25,7 @@
  public:
   explicit FakeDevToolsClient(const std::string& id)
       : id_(id), listener_(nullptr) {}
-  ~FakeDevToolsClient() override {}
+  ~FakeDevToolsClient() override = default;
 
   std::string PopSentCommand() {
     std::string command;
@@ -41,9 +41,6 @@
     return listener_->OnEvent(this, method, params);
   }
 
-  // Overridden from DevToolsClient:
-  Status Connect() override { return listener_->OnConnected(this); }
-
   Status SendCommandAndGetResult(const std::string& method,
                                  const base::Value::Dict& params,
                                  base::Value::Dict* result) override {
diff --git a/chrome/test/chromedriver/chrome/devtools_client.h b/chrome/test/chromedriver/chrome/devtools_client.h
index f30ea49..5715d34 100644
--- a/chrome/test/chromedriver/chrome/devtools_client.h
+++ b/chrome/test/chromedriver/chrome/devtools_client.h
@@ -47,9 +47,6 @@
 
   virtual bool IsConnected() const = 0;
 
-  // Connect to DevTools if the DevToolsClient is disconnected.
-  virtual Status Connect() = 0;
-
   virtual Status PostBidiCommand(base::Value::Dict command) = 0;
 
   virtual Status SendCommand(const std::string& method,
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 3bd5a68..607d091 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -70,10 +70,6 @@
   return Status(kOk);
 }
 
-Status FakeCloseFrontends() {
-  return Status(kOk);
-}
-
 struct SessionId {
   explicit SessionId(const std::string session_id) : session_id_(session_id) {}
   std::string session_id_;
@@ -187,13 +183,13 @@
 
 namespace internal {
 
-InspectorEvent::InspectorEvent() {}
+InspectorEvent::InspectorEvent() = default;
 
-InspectorEvent::~InspectorEvent() {}
+InspectorEvent::~InspectorEvent() = default;
 
-InspectorCommandResponse::InspectorCommandResponse() {}
+InspectorCommandResponse::InspectorCommandResponse() = default;
 
-InspectorCommandResponse::~InspectorCommandResponse() {}
+InspectorCommandResponse::~InspectorCommandResponse() = default;
 
 }  // namespace internal
 
@@ -202,30 +198,9 @@
 const char DevToolsClientImpl::kBidiChannelSuffix[] = "/bidi";
 
 DevToolsClientImpl::DevToolsClientImpl(const std::string& id,
-                                       const std::string& session_id,
-                                       const std::string& url,
-                                       const SyncWebSocketFactory& factory)
-    : socket_(factory.Run()),
-      url_(url),
-      session_id_(session_id),
-      id_(id),
-      frontend_closer_func_(base::BindRepeating(&FakeCloseFrontends)),
-      parser_func_(base::BindRepeating(&internal::ParseInspectorMessage)) {
-  socket_->SetId(id_);
-  // If error happens during proactive event consumption we ignore it
-  // as there is no active user request where the error might be returned.
-  // Unretained 'this' won't cause any problems as we reset the callback in the
-  // .dtor.
-  socket_->SetNotificationCallback(base::BindRepeating(
-      base::IgnoreResult(&DevToolsClientImpl::HandleReceivedEvents),
-      base::Unretained(this)));
-}
-
-DevToolsClientImpl::DevToolsClientImpl(const std::string& id,
                                        const std::string& session_id)
     : session_id_(session_id),
       id_(id),
-      frontend_closer_func_(base::BindRepeating(&FakeCloseFrontends)),
       parser_func_(base::BindRepeating(&internal::ParseInspectorMessage)) {}
 
 DevToolsClientImpl::~DevToolsClientImpl() {
@@ -247,11 +222,6 @@
   parser_func_ = parser_func;
 }
 
-void DevToolsClientImpl::SetFrontendCloserFunc(
-    const FrontendCloserFunc& frontend_closer_func) {
-  frontend_closer_func_ = frontend_closer_func;
-}
-
 const std::string& DevToolsClientImpl::GetId() {
   return id_;
 }
@@ -422,13 +392,8 @@
     return Status{kUnknownError,
                   "DevToolsClientImpl can be attached only to a root client"};
   }
-  if (parent->IsNull()) {
-    // parent.IsNull <=> (parent.parent == null) && (parent.socket == null)
-    // As, basing on the checks above, we know that parent.parent == null is
-    // true The expression above can be simplified to parent.IsNull <=>
-    // parent.socket == null
-    return Status{kUnknownError,
-                  "cannot attach to a parent that has no socket"};
+  if (!parent->IsConnected()) {
+    return Status{kUnknownError, "cannot attach to a disconnected parent"};
   }
 
   Status status{kOk};
@@ -445,25 +410,23 @@
   return status;
 }
 
-Status DevToolsClientImpl::Connect() {
-  if (stack_count_)
-    return Status(kUnknownError, "cannot connect when nested");
-  if (!socket_) {
-    return Status(kUnknownError, "cannot connect without a socket");
+Status DevToolsClientImpl::SetSocket(std::unique_ptr<SyncWebSocket> socket) {
+  if (!socket) {
+    return Status{kUnknownError, "socket cannot be nullptr"};
   }
-  if (socket_->IsConnected())
-    return Status(kOk);
-
+  if (!socket->IsConnected()) {
+    return Status{kUnknownError, "socket must be connected"};
+  }
   ResetListeners();
-
-  if (!socket_->Connect(url_)) {
-    // Try to close devtools frontend and then reconnect.
-    Status status = frontend_closer_func_.Run();
-    if (status.IsError())
-      return status;
-    if (!socket_->Connect(url_))
-      return Status(kDisconnected, "unable to connect to renderer");
-  }
+  socket_ = std::move(socket);
+  socket_->SetId(id_);
+  // If error happens during proactive event consumption we ignore it
+  // as there is no active user request where the error might be returned.
+  // Unretained 'this' won't cause any problems as we reset the callback in the
+  // .dtor.
+  socket_->SetNotificationCallback(base::BindRepeating(
+      base::IgnoreResult(&DevToolsClientImpl::HandleReceivedEvents),
+      base::Unretained(this)));
 
   return OnConnected();
 }
@@ -723,7 +686,7 @@
 DevToolsClientImpl::ResponseInfo::ResponseInfo(const std::string& method)
     : state(kWaiting), method(method) {}
 
-DevToolsClientImpl::ResponseInfo::~ResponseInfo() {}
+DevToolsClientImpl::ResponseInfo::~ResponseInfo() = default;
 
 DevToolsClient* DevToolsClientImpl::GetRootClient() {
   return parent_ ? parent_->GetRootClient() : this;
@@ -901,7 +864,6 @@
                                               bool log_timeout,
                                               const Timeout& timeout,
                                               DevToolsClientImpl* caller) {
-  ScopedIncrementer increment_stack_count(&stack_count_);
   if (!IsConnected()) {
     LOG(WARNING) << "Processing messages while being disconnected";
   }
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.h b/chrome/test/chromedriver/chrome/devtools_client_impl.h
index b0ac036..40338607 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.h
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.h
@@ -58,13 +58,6 @@
   static const char kCdpTunnelChannel[];
   static const char kBidiChannelSuffix[];
 
-  // Postcondition: !IsNull()
-  // Postcondition: !IsConnected()
-  DevToolsClientImpl(const std::string& id,
-                     const std::string& session_id,
-                     const std::string& url,
-                     const SyncWebSocketFactory& factory);
-
   typedef base::RepeatingCallback<Status()> FrontendCloserFunc;
 
   // Postcondition: IsNull()
@@ -85,19 +78,26 @@
   ~DevToolsClientImpl() override;
 
   void SetParserFuncForTesting(const ParserFunc& parser_func);
-  void SetFrontendCloserFunc(const FrontendCloserFunc& frontend_closer_func);
   // Make this DevToolsClient a child of 'parent'.
   // All the commands of the child are routed via the parent.
   // The parent demultiplexes the incoming events to the appropriate children.
-  // If the parent->IsConnected() this object changes its state to connected,
-  // it sets up the remote end and notifies the listeners about the connection.
   // Precondition: parent != nullptr
+  // Precondition: parent.IsConnected()
   // Precondition: IsNull()
   // The next precondition secures the class invariant about flat hierarchy
   // Precondition: parent->GetParentClient() == nullptr.
   // Postcondition: result.IsError() || !IsNull()
+  // Postcondition: result.IsError() || IsConnected()
   Status AttachTo(DevToolsClientImpl* parent);
 
+  // Set the socket for communication with the remote end.
+  // All listeners are notified about the connection.
+  // Precondition: socket != nullptr
+  // Precondition: socket.IsConnected()
+  // Precondition: IsNull()
+  // Postcondition: result.IsError() || IsConnected()
+  Status SetSocket(std::unique_ptr<SyncWebSocket> socket);
+
   // Overridden from DevToolsClient:
   const std::string& GetId() override;
   // Session id used to annotate the CDP commands.
@@ -121,13 +121,6 @@
   bool IsNull() const override;
   bool IsConnected() const override;
   bool WasCrashed() override;
-  // Connect and configure the remote end.
-  // The children are also connected and their remote ends are configured.
-  // The listeners and the listeners of the children are notified appropriately.
-  // Does nothing if the connection is already established.
-  // Precondition: socket != nullptr
-  // Postcondition: result.IsError() || IsConnected()
-  Status Connect() override;
   Status PostBidiCommand(base::Value::Dict command) override;
   Status SendCommand(const std::string& method,
                      const base::Value::Dict& params) override;
@@ -223,7 +216,6 @@
   Status SetUpDevTools();
 
   std::unique_ptr<SyncWebSocket> socket_;
-  GURL url_;
   // WebViewImpl that owns this instance; nullptr for browser-wide DevTools.
   raw_ptr<WebViewImpl> owner_ = nullptr;
   const std::string session_id_;
@@ -238,7 +230,6 @@
   // For the top-level session, this is the target id.
   // For child sessions, it's the session id.
   const std::string id_;
-  FrontendCloserFunc frontend_closer_func_;
   ParserFunc parser_func_;
   std::list<DevToolsEventListener*> listeners_;
   std::list<DevToolsEventListener*> unnotified_connect_listeners_;
@@ -248,7 +239,6 @@
   scoped_refptr<ResponseInfo> unnotified_cmd_response_info_;
   std::map<int, scoped_refptr<ResponseInfo>> response_info_map_;
   int next_id_ = 1;  // The id identifying a particular request.
-  int stack_count_ = 0;
   bool is_main_page_ = false;
   bool bidi_server_is_launched_ = false;
   // Event tunneling is temporarily disabled in production.
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
index 3194bced..0ffbc46 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -24,7 +24,6 @@
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/status.h"
 #include "chrome/test/chromedriver/net/sync_websocket.h"
-#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 #include "chrome/test/chromedriver/net/timeout.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -178,6 +177,211 @@
                         std::move(mapper_session_id), evt);
 }
 
+class SyncWebSocketWrapper : public SyncWebSocket {
+ public:
+  explicit SyncWebSocketWrapper(SyncWebSocket* socket) : socket_(socket) {}
+  ~SyncWebSocketWrapper() override = default;
+
+  bool IsConnected() override { return socket_->IsConnected(); }
+
+  bool Connect(const GURL& url) override { return socket_->Connect(url); }
+
+  bool Send(const std::string& message) override {
+    return socket_->Send(message);
+  }
+
+  SyncWebSocket::StatusCode ReceiveNextMessage(
+      std::string* message,
+      const Timeout& timeout) override {
+    return socket_->ReceiveNextMessage(message, timeout);
+  }
+
+  bool HasNextMessage() override { return socket_->HasNextMessage(); }
+
+ private:
+  raw_ptr<SyncWebSocket> socket_;
+};
+
+template <typename TSocket>
+class SocketHolder {
+ public:
+  template <typename... Args>
+  explicit SocketHolder(Args&&... args) : socket_{args...} {}
+
+  std::unique_ptr<SyncWebSocket> Wrapper() {
+    return std::unique_ptr<SyncWebSocket>(new SyncWebSocketWrapper(&socket_));
+  }
+
+  TSocket& Socket() { return socket_; }
+
+  bool ConnectSocket() { return socket_.Connect(GURL("http://url/")); }
+
+ private:
+  TSocket socket_;
+};
+
+struct SessionState {
+  bool handshake_add_script_handled = false;
+  bool handshake_runtime_eval_handled = false;
+  bool connect_complete = false;
+};
+
+class MultiSessionMockSyncWebSocket : public SyncWebSocket {
+ public:
+  MultiSessionMockSyncWebSocket() = default;
+  ~MultiSessionMockSyncWebSocket() override = default;
+
+  bool IsConnected() override { return connected_; }
+
+  bool Connect(const GURL& url) override {
+    EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str());
+    connected_ = true;
+    return true;
+  }
+
+  bool Send(const std::string& message) override {
+    EXPECT_TRUE(connected_);
+    int cmd_id;
+    std::string method;
+    base::Value::Dict params;
+    std::string session_id;
+
+    if (!ParseMessage(message, &cmd_id, &method, &params, &session_id)) {
+      return false;
+    }
+
+    SessionState& session_state = sesison_states_[session_id];
+
+    if (session_state.connect_complete) {
+      return OnUserCommand(&session_state, cmd_id, std::move(method),
+                           std::move(params), std::move(session_id));
+    } else {
+      return EnqueueHandshakeResponse(&session_state, cmd_id, std::move(method),
+                                      std::move(session_id));
+    }
+  }
+
+  SyncWebSocket::StatusCode ReceiveNextMessage(
+      std::string* message,
+      const Timeout& timeout) override {
+    if (!HasNextMessage() && timeout.IsExpired()) {
+      return SyncWebSocket::StatusCode::kTimeout;
+    }
+    EXPECT_TRUE(HasNextMessage());
+    if (PopMessage(message)) {
+      return SyncWebSocket::StatusCode::kOk;
+    } else {
+      return SyncWebSocket::StatusCode::kDisconnected;
+    }
+  }
+
+  bool HasNextMessage() override { return !queued_response_.empty(); }
+
+  virtual bool OnUserCommand(SessionState* session_state,
+                             int cmd_id,
+                             std::string method,
+                             base::Value::Dict params,
+                             std::string session_id) {
+    EXPECT_STREQ("method", method.c_str());
+    base::Value::Dict response;
+    Status status =
+        CreateDefaultCdpResponse(cmd_id, std::move(method), std::move(params),
+                                 std::move(session_id), &response);
+    EXPECT_TRUE(status.IsOk()) << status.message();
+    if (status.IsError()) {
+      return false;
+    }
+    std::string message;
+    status = SerializeAsJson(response, &message);
+    EXPECT_TRUE(status.IsOk()) << status.message();
+    if (status.IsError()) {
+      return false;
+    }
+    queued_response_.push(std::move(message));
+    return true;
+  }
+
+  Status CreateDefaultCdpResponse(int cmd_id,
+                                  std::string method,
+                                  base::Value::Dict params,
+                                  std::string session_id,
+                                  base::Value::Dict* response) {
+    base::Value::Dict result;
+    absl::optional<int> ping = params.FindInt("ping");
+    if (ping) {
+      result.Set("pong", *ping);
+    } else {
+      result.Set("param", 1);
+    }
+
+    return CreateCdpResponse(cmd_id, std::move(result), std::move(session_id),
+                             response);
+  }
+
+  bool EnqueueHandshakeResponse(SessionState* session_state,
+                                int cmd_id,
+                                std::string method,
+                                std::string session_id) {
+    if (method == "Page.addScriptToEvaluateOnNewDocument") {
+      EXPECT_FALSE(session_state->handshake_add_script_handled);
+      if (!session_state->handshake_add_script_handled) {
+        session_state->handshake_add_script_handled = true;
+      } else {
+        return false;
+      }
+    } else if (method == "Runtime.evaluate") {
+      EXPECT_FALSE(session_state->handshake_runtime_eval_handled);
+      if (!session_state->handshake_runtime_eval_handled) {
+        session_state->handshake_runtime_eval_handled = true;
+      } else {
+        return false;
+      }
+    } else {
+      // Unexpected handshake command
+      VLOG(0) << "unexpected handshake method: " << method;
+      ADD_FAILURE();
+      return false;
+    }
+
+    session_state->connect_complete =
+        session_state->handshake_add_script_handled &&
+        session_state->handshake_runtime_eval_handled;
+
+    base::Value::Dict result;
+    result.Set("param", 1);
+    base::Value::Dict response;
+    Status status =
+        CreateCdpResponse(cmd_id, std::move(result), session_id, &response);
+    EXPECT_TRUE(status.IsOk()) << status.message();
+    if (status.IsError()) {
+      return false;
+    }
+
+    std::string message;
+    status = SerializeAsJson(base::Value(std::move(response)), &message);
+    EXPECT_TRUE(status.IsOk()) << status.message();
+    if (status.IsError()) {
+      return false;
+    }
+    queued_response_.push(std::move(message));
+    return true;
+  }
+
+  bool PopMessage(std::string* dest) {
+    if (queued_response_.empty()) {
+      return false;
+    }
+    *dest = std::move(queued_response_.front());
+    queued_response_.pop();
+    return true;
+  }
+
+ protected:
+  bool connected_ = false;
+  std::map<std::string, SessionState> sesison_states_;
+  std::queue<std::string> queued_response_;
+};
+
 class MockSyncWebSocket : public SyncWebSocket {
  public:
   MockSyncWebSocket() = default;
@@ -290,11 +494,6 @@
   std::queue<std::string> queued_response_;
 };
 
-template <typename T>
-std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket() {
-  return std::unique_ptr<SyncWebSocket>(new T());
-}
-
 class DevToolsClientImplTest : public testing::Test {
  protected:
   DevToolsClientImplTest() : long_timeout_(base::Minutes(5)) {}
@@ -304,9 +503,7 @@
 
 }  // namespace
 
-TEST_F(DevToolsClientImplTest, Ctor1) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
+TEST_F(DevToolsClientImplTest, Ctor) {
   const std::string expected_id = "E2F4";
   const std::string expected_session_id = "BC80031";
   DevToolsClientImpl client(expected_id, expected_session_id);
@@ -323,56 +520,37 @@
   EXPECT_EQ(&client, client.GetRootClient());
 }
 
-TEST_F(DevToolsClientImplTest, Ctor2) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  const std::string expected_id = "E2F4";
-  const std::string expected_session_id = "BC80031";
-  DevToolsClientImpl client(expected_id, expected_session_id, "http://url",
-                            factory);
-  EXPECT_EQ(expected_id, client.GetId());
-  EXPECT_EQ(expected_session_id, client.SessionId());
-  EXPECT_EQ(std::string(), client.TunnelSessionId());
-  EXPECT_FALSE(client.IsMainPage());
-  EXPECT_FALSE(client.IsConnected());
-  EXPECT_FALSE(client.IsNull());
-  EXPECT_FALSE(client.WasCrashed());
-  EXPECT_EQ(1, client.NextMessageId());
-  EXPECT_EQ(nullptr, client.GetOwner());
-  EXPECT_EQ(nullptr, client.GetParentClient());
-  EXPECT_EQ(&client, client.GetRootClient());
-}
-
 TEST_F(DevToolsClientImplTest, SendCommand) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
   params.Set("param", 1);
-  ASSERT_EQ(kOk, client.SendCommand("method", params).code());
+  ASSERT_TRUE(StatusOk(client.SendCommand("method", params)));
 }
 
 TEST_F(DevToolsClientImplTest, SendCommandAndGetResult) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
   params.Set("param", 1);
   base::Value::Dict result;
-  Status status = client.SendCommandAndGetResult("method", params, &result);
-  ASSERT_EQ(kOk, status.code());
+  ASSERT_TRUE(
+      StatusOk(client.SendCommandAndGetResult("method", params, &result)));
   std::string json;
   base::JSONWriter::Write(base::Value(std::move(result)), &json);
   ASSERT_STREQ("{\"param\":1}", json.c_str());
 }
 
 TEST_F(DevToolsClientImplTest, SetMainPage) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("E2F4", "BC80031", "http://url", factory);
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("E2F4", "BC80031");
   client.SetMainPage(true);
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   EXPECT_TRUE(client.IsMainPage());
 }
 
@@ -390,10 +568,9 @@
   EXPECT_TRUE(client.SetTunnelSessionId("another_bidi_session").IsError());
 }
 
-TEST_F(DevToolsClientImplTest, ConnectWithoutSocket) {
+TEST_F(DevToolsClientImplTest, SetNullSocket) {
   DevToolsClientImpl client("page_client", "page_session");
-  Status status = client.Connect();
-  EXPECT_TRUE(status.IsError());
+  EXPECT_TRUE(client.SetSocket(nullptr).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, AttachToNull) {
@@ -408,12 +585,14 @@
 }
 
 TEST_F(DevToolsClientImplTest, AttachToAnotherRoot) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl root_client1("root_client_1", "root_session_1",
-                                  "http://url1", factory);
-  DevToolsClientImpl root_client2("root_client_2", "root_session_2",
-                                  "http://url2", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket> socket_holder1;
+  DevToolsClientImpl root_client1("root_client_1", "root_session_1");
+  ASSERT_TRUE(socket_holder1.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client1.SetSocket(socket_holder1.Wrapper())));
+  SocketHolder<MultiSessionMockSyncWebSocket> socket_holder2;
+  DevToolsClientImpl root_client2("root_client_2", "root_session_2");
+  ASSERT_TRUE(socket_holder2.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client2.SetSocket(socket_holder2.Wrapper())));
   DevToolsClientImpl client("page_client", "page_session");
   ASSERT_TRUE(StatusOk(client.AttachTo(&root_client1)));
   // Client cannot be re-attached
@@ -421,20 +600,22 @@
 }
 
 TEST_F(DevToolsClientImplTest, AttachRootToRoot) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl root_client1("root_client_1", "root_session_1",
-                                  "http://url1", factory);
-  DevToolsClientImpl root_client2("root_client_2", "root_session_2",
-                                  "http://url2", factory);
+  SocketHolder<MockSyncWebSocket> socket_holder1;
+  DevToolsClientImpl root_client1("root_client_1", "root_session_1");
+  ASSERT_TRUE(socket_holder1.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client1.SetSocket(socket_holder1.Wrapper())));
+  SocketHolder<MockSyncWebSocket> socket_holder2;
+  DevToolsClientImpl root_client2("root_client_2", "root_session_2");
+  ASSERT_TRUE(socket_holder2.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client2.SetSocket(socket_holder2.Wrapper())));
   EXPECT_TRUE(root_client2.AttachTo(&root_client1).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, AttachAsGrandChild) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl root_client("root_client", "root_session", "http://url",
-                                 factory);
+  SocketHolder<MultiSessionMockSyncWebSocket> socket_holder;
+  DevToolsClientImpl root_client("root_client", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl child_client("child_client", "child_session");
   ASSERT_TRUE(StatusOk(child_client.AttachTo(&root_client)));
   DevToolsClientImpl grand_child_client("grand_child_client",
@@ -444,41 +625,6 @@
 
 namespace {
 
-class MockSyncWebSocket2 : public SyncWebSocket {
- public:
-  MockSyncWebSocket2() = default;
-  ~MockSyncWebSocket2() override = default;
-
-  bool IsConnected() override { return false; }
-
-  bool Connect(const GURL& url) override { return false; }
-
-  bool Send(const std::string& message) override {
-    EXPECT_TRUE(false);
-    return false;
-  }
-
-  SyncWebSocket::StatusCode ReceiveNextMessage(
-      std::string* message,
-      const Timeout& timeout) override {
-    EXPECT_TRUE(false);
-    return SyncWebSocket::StatusCode::kDisconnected;
-  }
-
-  bool HasNextMessage() override { return true; }
-};
-
-}  // namespace
-
-TEST_F(DevToolsClientImplTest, ConnectIfNecessaryConnectFails) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket2>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kDisconnected, client.Connect().code());
-}
-
-namespace {
-
 class MockSyncWebSocket3 : public MockSyncWebSocket {
  public:
   explicit MockSyncWebSocket3(bool send_returns_after_connect)
@@ -529,27 +675,22 @@
   bool send_returns_after_connect_;
 };
 
-template <typename T>
-std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket_B(bool b1) {
-  return std::unique_ptr<SyncWebSocket>(new T(b1));
-}
-
 }  // namespace
 
 TEST_F(DevToolsClientImplTest, SendCommandSendFails) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_B<MockSyncWebSocket3>, false);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<MockSyncWebSocket3> socket_holder{false};
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
   ASSERT_TRUE(client.SendCommand("method", params).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, SendCommandReceiveNextMessageFails) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket_B<MockSyncWebSocket3>, true);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<MockSyncWebSocket3> socket_holder{true};
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
   ASSERT_TRUE(client.SendCommand("method", params).IsError());
 }
@@ -786,67 +927,67 @@
 
 }  // namespace
 
-TEST_F(DevToolsClientImplTest, SendCommandOnlyConnectsOnce) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
+TEST_F(DevToolsClientImplTest, FakeSyncWebSocketSelfTest) {
+  SocketHolder<FakeSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnCommand));
-  ASSERT_EQ(kOk, client.Connect().code());
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
-  ASSERT_TRUE(client.SendCommand("method", params).IsOk());
-  ASSERT_TRUE(client.SendCommand("method", params).IsOk());
+  ASSERT_TRUE(StatusOk(client.SendCommand("method", params)));
+  ASSERT_TRUE(StatusOk(client.SendCommand("method", params)));
 }
 
 TEST_F(DevToolsClientImplTest, SendCommandBadResponse) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<FakeSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnBadResponse));
   base::Value::Dict params;
   ASSERT_TRUE(client.SendCommand("method", params).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, SendCommandBadId) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<FakeSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnCommandBadId));
   base::Value::Dict params;
   ASSERT_TRUE(client.SendCommand("method", params).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, SendCommandUnexpectedId) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
   bool first = true;
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<FakeSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(
       base::BindRepeating(&ReturnUnexpectedIdThenResponse, &first));
   base::Value::Dict params;
-  ASSERT_TRUE(client.SendCommand("method", params).IsOk());
+  ASSERT_TRUE(StatusOk(client.SendCommand("method", params)));
 }
 
 TEST_F(DevToolsClientImplTest, SendCommandResponseError) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<FakeSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnCommandError));
   base::Value::Dict params;
   ASSERT_TRUE(client.SendCommand("method", params).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, SendCommandEventBeforeResponse) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
   MockListener listener;
   bool first = true;
-  DevToolsClientImpl client("id", "", "http://url", factory);
+  SocketHolder<FakeSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
   client.AddListener(&listener);
-  ASSERT_EQ(kOk, client.Connect().code());
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(
       base::BindRepeating(&ReturnEventThenResponse, &first));
   base::Value::Dict params;
@@ -1314,11 +1455,11 @@
 
 TEST_F(DevToolsClientImplTest, HandleEventsUntil) {
   MockListener listener;
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
   client.AddListener(&listener);
-  ASSERT_EQ(kOk, client.Connect().code());
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnEvent));
   Status status = client.HandleEventsUntil(base::BindRepeating(&AlwaysTrue),
                                            Timeout(long_timeout_));
@@ -1326,10 +1467,10 @@
 }
 
 TEST_F(DevToolsClientImplTest, HandleEventsUntilTimeout) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnEvent));
   Status status = client.HandleEventsUntil(base::BindRepeating(&AlwaysTrue),
                                            Timeout(base::TimeDelta()));
@@ -1337,21 +1478,21 @@
 }
 
 TEST_F(DevToolsClientImplTest, WaitForNextEventCommand) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnCommand));
-  ASSERT_EQ(kOk, client.Connect().code());
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   Status status = client.HandleEventsUntil(base::BindRepeating(&AlwaysTrue),
                                            Timeout(long_timeout_));
   ASSERT_EQ(kUnknownError, status.code());
 }
 
 TEST_F(DevToolsClientImplTest, WaitForNextEventError) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnError));
   Status status = client.HandleEventsUntil(base::BindRepeating(&AlwaysTrue),
                                            Timeout(long_timeout_));
@@ -1359,10 +1500,10 @@
 }
 
 TEST_F(DevToolsClientImplTest, WaitForNextEventConditionalFuncReturnsError) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  SocketHolder<MockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(base::BindRepeating(&ReturnEvent));
   Status status = client.HandleEventsUntil(base::BindRepeating(&AlwaysError),
                                            Timeout(long_timeout_));
@@ -1370,11 +1511,11 @@
 }
 
 TEST_F(DevToolsClientImplTest, NestedCommandsWithOutOfOrderResults) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket>);
+  SocketHolder<MockSyncWebSocket> socket_holder;
   int recurse_count = 0;
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_EQ(kOk, client.Connect().code());
+  DevToolsClientImpl client("id", "");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   client.SetParserFuncForTesting(
       base::BindRepeating(&ReturnOutOfOrderResponses, &recurse_count, &client));
   base::Value::Dict params;
@@ -1394,7 +1535,7 @@
       : method_(method), client_(client) {
     client_->AddListener(this);
   }
-  ~OnConnectedListener() override {}
+  ~OnConnectedListener() override = default;
 
   void VerifyCalled() {
     EXPECT_TRUE(on_connected_called_);
@@ -1489,13 +1630,13 @@
 }  // namespace
 
 TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnCommand) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
-  DevToolsClientImpl client("onconnected-id", "", "http://url", factory);
+  SocketHolder<OnConnectedSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("onconnected-id", "");
   OnConnectedListener listener1("DOM.getDocument", &client);
   OnConnectedListener listener2("Runtime.enable", &client);
   OnConnectedListener listener3("Page.enable", &client);
-  ASSERT_EQ(kOk, client.Connect().code());
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
   EXPECT_EQ(kOk, client.SendCommand("Runtime.execute", params).code());
   listener1.VerifyCalled();
@@ -1504,13 +1645,13 @@
 }
 
 TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnHandleEventsUntil) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
-  DevToolsClientImpl client("onconnected-id", "", "http://url", factory);
+  SocketHolder<OnConnectedSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("onconnected-id", "");
   OnConnectedListener listener1("DOM.getDocument", &client);
   OnConnectedListener listener2("Runtime.enable", &client);
   OnConnectedListener listener3("Page.enable", &client);
-  ASSERT_EQ(kOk, client.Connect().code());
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   EXPECT_EQ(kOk, client.HandleReceivedEvents().code());
   listener1.VerifyCalled();
   listener2.VerifyCalled();
@@ -1575,7 +1716,7 @@
                   OtherEventListener* other_listener)
       : client_(client),
         other_listener_(other_listener) {}
-  ~OnEventListener() override {}
+  ~OnEventListener() override = default;
 
   Status OnConnected(DevToolsClient* client) override {
     EXPECT_EQ(client_, client);
@@ -1599,96 +1740,16 @@
 }  // namespace
 
 TEST_F(DevToolsClientImplTest, ProcessOnEventFirst) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket5>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
+  SocketHolder<MockSyncWebSocket5> socket_holder;
+  DevToolsClientImpl client("id", "");
   OtherEventListener listener2;
   OnEventListener listener1(&client, &listener2);
   client.AddListener(&listener1);
   client.AddListener(&listener2);
-  Status status = client.Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
-  EXPECT_EQ(kOk, client.SendCommand("method", params).code());
-}
-
-namespace {
-
-class DisconnectedSyncWebSocket : public MockSyncWebSocket {
- public:
-  DisconnectedSyncWebSocket() = default;
-  ~DisconnectedSyncWebSocket() override = default;
-
-  bool Connect(const GURL& url) override {
-    connection_count_++;
-    connected_ = connection_count_ != 2;
-    return connected_;
-  }
-
-  bool Send(const std::string& message) override {
-    EXPECT_TRUE(connected_);
-    int cmd_id;
-    std::string method;
-    base::Value::Dict params;
-    std::string session_id;
-
-    if (!ParseMessage(message, &cmd_id, &method, &params, &session_id)) {
-      return false;
-    }
-
-    if (connect_complete_) {
-      command_count_++;
-      if (command_count_ == 1) {
-        connected_ = false;
-        handshake_add_script_handled_ = false;
-        handshake_runtime_eval_handled_ = false;
-        connect_complete_ = false;
-        while (!queued_response_.empty()) {
-          queued_response_.pop();
-        }
-        return false;
-      }
-      return MockSyncWebSocket::Send(message);
-    } else {
-      EnqueueHandshakeResponse(cmd_id, method);
-    }
-    return true;
-  }
-
- private:
-  int connection_count_ = 0;
-  int command_count_ = 0;
-};
-
-Status CheckCloserFuncCalled(bool* is_called) {
-  *is_called = true;
-  return Status(kOk);
-}
-
-}  // namespace
-
-TEST_F(DevToolsClientImplTest, Reconnect) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<DisconnectedSyncWebSocket>);
-  bool is_called = false;
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  client.SetFrontendCloserFunc(
-      base::BindRepeating(&CheckCloserFuncCalled, &is_called));
-  ASSERT_FALSE(is_called);
-  ASSERT_EQ(kOk, client.Connect().code());
-  ASSERT_FALSE(is_called);
-  base::Value::Dict params;
-  params.Set("param", 1);
-  is_called = false;
-  ASSERT_EQ(kDisconnected, client.SendCommand("method", params).code());
-  ASSERT_FALSE(is_called);
-  ASSERT_EQ(kDisconnected, client.HandleReceivedEvents().code());
-  ASSERT_FALSE(is_called);
-  ASSERT_EQ(kOk, client.Connect().code());
-  ASSERT_TRUE(is_called);
-  is_called = false;
-  ASSERT_EQ(kOk, client.SendCommand("method", params).code());
-  ASSERT_FALSE(is_called);
+  EXPECT_TRUE(StatusOk(client.SendCommand("method", params)));
 }
 
 namespace {
@@ -1754,20 +1815,14 @@
   int expected_blocked_id_ = -1;
 };
 
-std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket6(
-    std::list<std::string>* messages) {
-  return std::make_unique<MockSyncWebSocket6>(messages);
-}
-
 }  // namespace
 
 TEST_F(DevToolsClientImplTest, BlockedByAlert) {
   std::list<std::string> msgs;
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket6, &msgs);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  Status status = client.Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  SocketHolder<MockSyncWebSocket6> socket_holder{&msgs};
+  DevToolsClientImpl client("id", "");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   msgs.push_back(
       "{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
   msgs.push_back("{\"id\": 2, \"result\": {}}");
@@ -1795,13 +1850,12 @@
   //                       response for id5
   //                       response for id6
   std::list<std::string> msgs;
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket6, &msgs);
-  DevToolsClientImpl client("id", "", "http://url", factory);
+  SocketHolder<MockSyncWebSocket6> socket_holder{&msgs};
+  DevToolsClientImpl client("id", "");
   MockDevToolsEventListener listener;
   client.AddListener(&listener);
-  Status status = client.Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   int next_msg_id = client.NextMessageId();
   msgs.push_back("{\"method\": \"FirstEvent\", \"params\": {}}");
   msgs.push_back("{\"method\": \"SecondEvent\", \"params\": {}}");
@@ -1864,16 +1918,15 @@
 
 TEST_F(DevToolsClientImplTest, ReceivesCommandResponse) {
   std::list<std::string> msgs;
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket6, &msgs);
-  DevToolsClientImpl client("id", "", "http://url", factory);
+  SocketHolder<MockSyncWebSocket6> socket_holder{&msgs};
+  DevToolsClientImpl client("id", "");
   MockCommandListener listener1;
   listener1.callback_ = base::BindRepeating(&HandleReceivedEvents);
   MockCommandListener listener2;
   client.AddListener(&listener1);
   client.AddListener(&listener2);
-  Status status = client.Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   int next_msg_id = client.NextMessageId();
   msgs.push_back((std::stringstream()
                   << "{\"id\": " << next_msg_id++ << ", \"result\": {}}")
@@ -1886,68 +1939,11 @@
   ASSERT_EQ("event", listener2.msgs_.back());
 }
 
-namespace {
-
-class MockSyncWebSocket7 : public SyncWebSocket {
- public:
-  MockSyncWebSocket7() = default;
-  ~MockSyncWebSocket7() override = default;
-
-  bool IsConnected() override { return true; }
-
-  bool Connect(const GURL& url) override { return true; }
-
-  bool Send(const std::string& message) override {
-    absl::optional<base::Value> value = base::JSONReader::Read(message);
-    base::Value::Dict* dict = value->GetIfDict();
-    EXPECT_TRUE(dict);
-    if (!dict)
-      return false;
-    absl::optional<int> maybe_id = dict->FindInt("id");
-    EXPECT_TRUE(maybe_id);
-    if (!maybe_id)
-      return false;
-    id_ = *maybe_id;
-    std::string* method = dict->FindString("method");
-    EXPECT_TRUE(method);
-    EXPECT_STREQ("method", method->c_str());
-    base::Value::Dict* params = dict->FindDict("params");
-    if (!params)
-      return false;
-    sent_messages_++;
-    return true;
-  }
-
-  SyncWebSocket::StatusCode ReceiveNextMessage(
-      std::string* message,
-      const Timeout& timeout) override {
-    EXPECT_LE(sent_responses_, 1);
-    EXPECT_EQ(sent_messages_, 2);
-    base::Value::Dict response;
-    response.Set("id", (sent_responses_ == 0) ? 1 : 2);
-    base::Value result{base::Value::Type::DICT};
-    result.GetDict().Set("param", 1);
-    response.Set("result", result.Clone());
-    base::JSONWriter::Write(base::Value(std::move(response)), message);
-    sent_responses_++;
-    return SyncWebSocket::StatusCode::kOk;
-  }
-
-  bool HasNextMessage() override { return sent_messages_ > sent_responses_; }
-
- private:
-  int id_ = -1;
-  int sent_messages_ = 0;
-  int sent_responses_ = 0;
-};
-
-}  // namespace
-
 TEST_F(DevToolsClientImplTest, SendCommandAndIgnoreResponse) {
-  SyncWebSocketFactory factory =
-      base::BindRepeating(&CreateMockSyncWebSocket<MockSyncWebSocket7>);
-  DevToolsClientImpl client("id", "", "http://url", factory);
-  ASSERT_TRUE(StatusOk(client.Connect()));
+  SocketHolder<MultiSessionMockSyncWebSocket> socket_holder;
+  DevToolsClientImpl client("id", "");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(client.SetSocket(socket_holder.Wrapper())));
   base::Value::Dict params;
   params.Set("param", 1);
   ASSERT_TRUE(StatusOk(client.SendCommandAndIgnoreResponse("method", params)));
@@ -1956,167 +1952,6 @@
 
 namespace {
 
-struct SessionState {
-  bool handshake_add_script_handled = false;
-  bool handshake_runtime_eval_handled = false;
-  bool connect_complete = false;
-};
-
-class MultiSessionMockSyncWebSocket : public SyncWebSocket {
- public:
-  MultiSessionMockSyncWebSocket() = default;
-  ~MultiSessionMockSyncWebSocket() override = default;
-
-  bool IsConnected() override { return connected_; }
-
-  bool Connect(const GURL& url) override {
-    EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str());
-    connected_ = true;
-    return true;
-  }
-
-  bool Send(const std::string& message) override {
-    EXPECT_TRUE(connected_);
-    int cmd_id;
-    std::string method;
-    base::Value::Dict params;
-    std::string session_id;
-
-    if (!ParseMessage(message, &cmd_id, &method, &params, &session_id)) {
-      return false;
-    }
-
-    SessionState& session_state = sesison_states_[session_id];
-
-    if (session_state.connect_complete) {
-      return OnUserCommand(&session_state, cmd_id, std::move(method),
-                           std::move(params), std::move(session_id));
-    } else {
-      return EnqueueHandshakeResponse(&session_state, cmd_id, std::move(method),
-                                      std::move(session_id));
-    }
-  }
-
-  SyncWebSocket::StatusCode ReceiveNextMessage(
-      std::string* message,
-      const Timeout& timeout) override {
-    if (!HasNextMessage() && timeout.IsExpired())
-      return SyncWebSocket::StatusCode::kTimeout;
-    EXPECT_TRUE(HasNextMessage());
-    if (PopMessage(message)) {
-      return SyncWebSocket::StatusCode::kOk;
-    } else {
-      return SyncWebSocket::StatusCode::kDisconnected;
-    }
-  }
-
-  bool HasNextMessage() override { return !queued_response_.empty(); }
-
-  virtual bool OnUserCommand(SessionState* session_state,
-                             int cmd_id,
-                             std::string method,
-                             base::Value::Dict params,
-                             std::string session_id) {
-    EXPECT_STREQ("method", method.c_str());
-    base::Value::Dict response;
-    Status status =
-        CreateDefaultCdpResponse(cmd_id, std::move(method), std::move(params),
-                                 std::move(session_id), &response);
-    EXPECT_TRUE(status.IsOk()) << status.message();
-    if (status.IsError()) {
-      return false;
-    }
-    std::string message;
-    status = SerializeAsJson(response, &message);
-    EXPECT_TRUE(status.IsOk()) << status.message();
-    if (status.IsError()) {
-      return false;
-    }
-    queued_response_.push(std::move(message));
-    return true;
-  }
-
-  Status CreateDefaultCdpResponse(int cmd_id,
-                                  std::string method,
-                                  base::Value::Dict params,
-                                  std::string session_id,
-                                  base::Value::Dict* response) {
-    base::Value::Dict result;
-    absl::optional<int> ping = params.FindInt("ping");
-    if (ping) {
-      result.Set("pong", *ping);
-    } else {
-      result.Set("param", 1);
-    }
-
-    return CreateCdpResponse(cmd_id, std::move(result), std::move(session_id),
-                             response);
-  }
-
-  bool EnqueueHandshakeResponse(SessionState* session_state,
-                                int cmd_id,
-                                std::string method,
-                                std::string session_id) {
-    if (method == "Page.addScriptToEvaluateOnNewDocument") {
-      EXPECT_FALSE(session_state->handshake_add_script_handled);
-      if (!session_state->handshake_add_script_handled) {
-        session_state->handshake_add_script_handled = true;
-      } else {
-        return false;
-      }
-    } else if (method == "Runtime.evaluate") {
-      EXPECT_FALSE(session_state->handshake_runtime_eval_handled);
-      if (!session_state->handshake_runtime_eval_handled) {
-        session_state->handshake_runtime_eval_handled = true;
-      } else {
-        return false;
-      }
-    } else {
-      // Unexpected handshake command
-      VLOG(0) << "unexpected handshake method: " << method;
-      ADD_FAILURE();
-      return false;
-    }
-
-    session_state->connect_complete =
-        session_state->handshake_add_script_handled &&
-        session_state->handshake_runtime_eval_handled;
-
-    base::Value::Dict result;
-    result.Set("param", 1);
-    base::Value::Dict response;
-    Status status =
-        CreateCdpResponse(cmd_id, std::move(result), session_id, &response);
-    EXPECT_TRUE(status.IsOk()) << status.message();
-    if (status.IsError()) {
-      return false;
-    }
-
-    std::string message;
-    status = SerializeAsJson(base::Value(std::move(response)), &message);
-    EXPECT_TRUE(status.IsOk()) << status.message();
-    if (status.IsError()) {
-      return false;
-    }
-    queued_response_.push(std::move(message));
-    return true;
-  }
-
-  bool PopMessage(std::string* dest) {
-    if (queued_response_.empty()) {
-      return false;
-    }
-    *dest = std::move(queued_response_.front());
-    queued_response_.pop();
-    return true;
-  }
-
- protected:
-  bool connected_ = false;
-  std::map<std::string, SessionState> sesison_states_;
-  std::queue<std::string> queued_response_;
-};
-
 class PingingListener : public DevToolsEventListener {
  public:
   PingingListener() = default;
@@ -2225,47 +2060,40 @@
   std::string event_session_;
 };
 
-template <class T>
-std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket_S(
-    const std::string& arg) {
-  return std::make_unique<T>(arg);
-}
-
 }  // namespace
 
 TEST_F(DevToolsClientImplTest, AttachToConnected) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket<MultiSessionMockSyncWebSocket>);
-  DevToolsClientImpl root_client("root_client", "root_session", "http://url",
-                                 factory);
+  SocketHolder<MultiSessionMockSyncWebSocket> socket_holder;
+  DevToolsClientImpl root_client("root_client", "root_session");
   DevToolsClientImpl client("page_client", "page_session");
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   ASSERT_TRUE(root_client.IsConnected());
   EXPECT_TRUE(StatusOk(client.AttachTo(&root_client)));
   EXPECT_TRUE(client.IsConnected());
 }
 
 TEST_F(DevToolsClientImplTest, RoutingChildParent) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket<MultiSessionMockSyncWebSocket>);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket> socket_holder;
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl client("child", "child_session");
   ASSERT_TRUE(StatusOk(client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   base::Value::Dict params;
   params.Set("param", 1);
   ASSERT_TRUE(StatusOk(client.SendCommand("method", params)));
 }
 
 TEST_F(DevToolsClientImplTest, RoutingTwoChildren) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket<MultiSessionMockSyncWebSocket>);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket> socket_holder;
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl red_client("red_client", "red_session");
   DevToolsClientImpl blue_client("blue_client", "blue_session");
   ASSERT_TRUE(StatusOk(red_client.AttachTo(&root_client)));
   ASSERT_TRUE(StatusOk(blue_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   {
     base::Value::Dict params;
     params.Set("ping", 2);
@@ -2286,19 +2114,19 @@
 
 TEST_F(DevToolsClientImplTest, RoutingWithEvent) {
   const std::string blue_session = "blue_session";
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S<MultiSessionMockSyncWebSocket2>, blue_session);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket2> socket_holder{blue_session};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl red_client("red_client", "red_session");
   DevToolsClientImpl blue_client("blue_client", blue_session);
-  ASSERT_TRUE(StatusOk(red_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(blue_client.AttachTo(&root_client)));
   PingingListener blue_listener;
   blue_listener.SetPing(71);
   ASSERT_EQ(71, blue_listener.Ping());
   ASSERT_NE(71, blue_listener.Pong());
   blue_listener.AttachTo(&blue_client);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(red_client.AttachTo(&root_client)));
+  ASSERT_TRUE(StatusOk(blue_client.AttachTo(&root_client)));
   {
     base::Value::Dict params;
     params.Set("ping", 12);
@@ -2607,12 +2435,6 @@
   raw_ptr<int> wrapped_ping_counter_ = nullptr;
 };
 
-template <typename T>
-std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket_S_IPtr(std::string s,
-                                                              int* iptr) {
-  return std::unique_ptr<SyncWebSocket>(new T(s, iptr));
-}
-
 class BidiEventListener : public DevToolsEventListener {
  public:
   BidiEventListener() = default;
@@ -2654,14 +2476,14 @@
 
 TEST_F(DevToolsClientImplTest, BidiCommand) {
   std::string mapper_session = "mapper_session";
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S<BidiMockSyncWebSocket>, mapper_session);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiMockSyncWebSocket> socket_holder{mapper_session};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", mapper_session);
   BidiEventListener bidi_listener;
   mapper_client.AddListener(&bidi_listener);
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   ASSERT_TRUE(StatusOk(mapper_client.AppointAsBidiServerForTesting()));
   base::Value::Dict params;
   params.Set("ping", 196);
@@ -2683,14 +2505,14 @@
   // In this test we check that the response ids are restored in accordance to
   // the original command ids.
   std::string mapper_session = "mapper_session";
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S<BidiMockSyncWebSocket>, mapper_session);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiMockSyncWebSocket> socket_holder{mapper_session};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", mapper_session);
   BidiEventListener bidi_listener;
   mapper_client.AddListener(&bidi_listener);
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   ASSERT_TRUE(StatusOk(mapper_client.AppointAsBidiServerForTesting()));
 
   for (int cmd_id : {2, 3, 11, 1000021, 1000022, 1000023}) {
@@ -2708,15 +2530,15 @@
 
 TEST_F(DevToolsClientImplTest, CdpCommandTunneling) {
   int wrapped_counter = 0;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S_IPtr<MultiSessionMockSyncWebSocket3>,
-      "mapper_session", &wrapped_counter);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket3> socket_holder{"mapper_session",
+                                                             &wrapped_counter};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl page_client("page_client", "blue_session");
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   ASSERT_TRUE(StatusOk(page_client.AttachTo(&root_client)));
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   // Set the tunnel session after all connections to avoid handshake mocking
   ASSERT_TRUE(StatusOk(mapper_client.AppointAsBidiServerForTesting()));
   ASSERT_TRUE(
@@ -2875,15 +2697,14 @@
 
 TEST_F(DevToolsClientImplTest, BidiEvent) {
   std::string mapper_session = "mapper_session";
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S<MultiSessionMockSyncWebSocket4>,
-      mapper_session);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket4> socket_holder{mapper_session};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", mapper_session);
   BidiEventListener bidi_listener;
   mapper_client.AddListener(&bidi_listener);
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   ASSERT_TRUE(StatusOk(mapper_client.AppointAsBidiServerForTesting()));
   base::Value::Dict bidi_cmd;
   ASSERT_TRUE(StatusOk(CreateBidiCommand(37, "method", base::Value::Dict(),
@@ -2900,10 +2721,10 @@
 
 TEST_F(DevToolsClientImplTest, BidiEventCrossRouting) {
   std::string mapper_session = "mapper_session";
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S<MultiSessionMockSyncWebSocket4>,
-      mapper_session);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket4> socket_holder{mapper_session};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   // Green is the BiDiMapper in this test
   DevToolsClientImpl mapper_client("mapper_client", mapper_session);
   DevToolsClientImpl page_client("page_client", "blue_session");
@@ -2911,7 +2732,6 @@
   mapper_client.AddListener(&bidi_listener);
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   ASSERT_TRUE(StatusOk(page_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   ASSERT_TRUE(StatusOk(mapper_client.AppointAsBidiServerForTesting()));
   ASSERT_TRUE(
       StatusOk(page_client.SetTunnelSessionId(mapper_client.SessionId())));
@@ -2934,10 +2754,10 @@
 
 TEST_F(DevToolsClientImplTest, CdpEventTunneling) {
   std::string mapper_session = "mapper_session";
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S<MultiSessionMockSyncWebSocket4>,
-      mapper_session);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket4> socket_holder{mapper_session};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl page_client("page_client", "red_session");
   DevToolsClientImpl mapper_client("mapper_client", mapper_session);
   BidiEventListener mapper_bidi_listener;
@@ -2946,7 +2766,6 @@
   page_client.AddListener(&red_cdp_listener);
   ASSERT_TRUE(StatusOk(page_client.AttachTo(&root_client)));
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   ASSERT_TRUE(StatusOk(mapper_client.AppointAsBidiServerForTesting()));
   ASSERT_TRUE(
       StatusOk(page_client.SetTunnelSessionId(mapper_client.SessionId())));
@@ -2964,15 +2783,14 @@
 TEST_F(DevToolsClientImplTest, BidiChannels) {
   // Corner cases for channels
   std::string mapper_session = "mapper_session";
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_S<MultiSessionMockSyncWebSocket4>,
-      mapper_session);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<MultiSessionMockSyncWebSocket4> socket_holder{mapper_session};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", mapper_session);
   BidiEventListener mapper_bidi_listener;
   mapper_client.AddListener(&mapper_bidi_listener);
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   ASSERT_TRUE(StatusOk(mapper_client.AppointAsBidiServerForTesting()));
 
   for (std::string channel : {DevToolsClientImpl::kCdpTunnelChannel,
@@ -3106,25 +2924,18 @@
   raw_ptr<BidiMapperState> mapper_state_ = nullptr;
 };
 
-template <typename T>
-std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket_BidiMapperState(
-    BidiMapperState* mapper_state) {
-  return std::unique_ptr<SyncWebSocket>(new T(mapper_state));
-}
-
 }  // namespace
 
 TEST_F(DevToolsClientImplTest, StartBidiServer) {
   BidiMapperState mapper_state;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
 
   EXPECT_TRUE(StatusOk(mapper_client.StartBidiServer(kTestMapperScript)));
   EXPECT_TRUE(mapper_state.devtools_exposed);
@@ -3137,15 +2948,14 @@
 TEST_F(DevToolsClientImplTest, StartBidiServerWaitsForLaunched) {
   BidiMapperState mapper_state;
   mapper_state.emit_launched = false;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
 
   EXPECT_EQ(kTimeout,
             mapper_client
@@ -3155,44 +2965,40 @@
 
 TEST_F(DevToolsClientImplTest, StartBidiServerNotConnected) {
   BidiMapperState mapper_state;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
+  ASSERT_TRUE(mapper_client.AttachTo(&root_client).IsError());
 
   EXPECT_TRUE(mapper_client.StartBidiServer(kTestMapperScript).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, StartBidiServerNotAPageClient) {
   BidiMapperState mapper_state;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
 
   EXPECT_TRUE(mapper_client.StartBidiServer(kTestMapperScript).IsError());
 }
 
 TEST_F(DevToolsClientImplTest, StartBidiServerTunnelIsAlreadySet) {
   BidiMapperState mapper_state;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl pink_client("pink_client", "pink_session");
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
   mapper_client.SetMainPage(true);
   ASSERT_TRUE(StatusOk(pink_client.AttachTo(&root_client)));
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
   ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetTunnelSessionId(pink_client.SessionId());
 
@@ -3202,15 +3008,14 @@
 TEST_F(DevToolsClientImplTest, StartBidiServerFailOnAddBidiResponseBinding) {
   BidiMapperState mapper_state;
   mapper_state.fail_on_add_bidi_response_binding = true;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
 
   EXPECT_TRUE(mapper_client.StartBidiServer(kTestMapperScript).IsError());
 }
@@ -3218,15 +3023,14 @@
 TEST_F(DevToolsClientImplTest, StartBidiServerFailOnSetSelfTarget) {
   BidiMapperState mapper_state;
   mapper_state.fail_on_set_self_target_id = true;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
 
   EXPECT_TRUE(mapper_client.StartBidiServer(kTestMapperScript).IsError());
 }
@@ -3234,15 +3038,14 @@
 TEST_F(DevToolsClientImplTest, StartBidiServerFailOnExposeDevTools) {
   BidiMapperState mapper_state;
   mapper_state.fail_on_expose_devtools = true;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
 
   EXPECT_TRUE(mapper_client.StartBidiServer(kTestMapperScript).IsError());
 }
@@ -3250,15 +3053,14 @@
 TEST_F(DevToolsClientImplTest, StartBidiServerFailOnMapper) {
   BidiMapperState mapper_state;
   mapper_state.fail_on_mapper = true;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
 
   EXPECT_TRUE(mapper_client.StartBidiServer(kTestMapperScript).IsError());
 }
@@ -3266,15 +3068,14 @@
 TEST_F(DevToolsClientImplTest, StartBidiServerFailOnSubscribeToCdp) {
   BidiMapperState mapper_state;
   mapper_state.fail_on_subscribe_to_cdp = true;
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket_BidiMapperState<BidiServerMockSyncWebSocket>,
-      &mapper_state);
-  DevToolsClientImpl root_client("root", "root_session", "http://url", factory);
+  SocketHolder<BidiServerMockSyncWebSocket> socket_holder{&mapper_state};
+  DevToolsClientImpl root_client("root", "root_session");
+  ASSERT_TRUE(socket_holder.ConnectSocket());
+  ASSERT_TRUE(StatusOk(root_client.SetSocket(socket_holder.Wrapper())));
   DevToolsClientImpl mapper_client("mapper_client", "mapper_session");
   mapper_client.EnableEventTunnelingForTesting();
-  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
   mapper_client.SetMainPage(true);
-  ASSERT_TRUE(StatusOk(root_client.Connect()));
+  ASSERT_TRUE(StatusOk(mapper_client.AttachTo(&root_client)));
 
   EXPECT_TRUE(mapper_client.StartBidiServer(kTestMapperScript).IsError());
 }
diff --git a/chrome/test/chromedriver/chrome/stub_devtools_client.cc b/chrome/test/chromedriver/chrome/stub_devtools_client.cc
index eac0988..98329e7 100644
--- a/chrome/test/chromedriver/chrome/stub_devtools_client.cc
+++ b/chrome/test/chromedriver/chrome/stub_devtools_client.cc
@@ -48,11 +48,6 @@
   return false;
 }
 
-Status StubDevToolsClient::Connect() {
-  is_connected_ = true;
-  return Status(kOk);
-}
-
 Status StubDevToolsClient::PostBidiCommand(base::Value::Dict command) {
   return Status{kOk};
 }
diff --git a/chrome/test/chromedriver/chrome/stub_devtools_client.h b/chrome/test/chromedriver/chrome/stub_devtools_client.h
index a0d32f4..97a20c4 100644
--- a/chrome/test/chromedriver/chrome/stub_devtools_client.h
+++ b/chrome/test/chromedriver/chrome/stub_devtools_client.h
@@ -28,7 +28,6 @@
   bool IsNull() const override;
   bool WasCrashed() override;
   bool IsConnected() const override;
-  Status Connect() override;
   Status PostBidiCommand(base::Value::Dict command) override;
   Status SendCommand(const std::string& method,
                      const base::Value::Dict& params) override;
diff --git a/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc b/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc
index 1aa4647b..1904b8f4 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc
@@ -26,7 +26,6 @@
 #include "chrome/test/chromedriver/chrome/status.h"
 #include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
 #include "chrome/test/chromedriver/net/sync_websocket.h"
-#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 #include "chrome/test/chromedriver/net/timeout.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -214,6 +213,49 @@
   ASSERT_TRUE(result.empty());
 }
 
+class SyncWebSocketWrapper : public SyncWebSocket {
+ public:
+  explicit SyncWebSocketWrapper(SyncWebSocket* socket) : socket_(socket) {}
+  ~SyncWebSocketWrapper() override = default;
+
+  bool IsConnected() override { return socket_->IsConnected(); }
+
+  bool Connect(const GURL& url) override { return socket_->Connect(url); }
+
+  bool Send(const std::string& message) override {
+    return socket_->Send(message);
+  }
+
+  SyncWebSocket::StatusCode ReceiveNextMessage(
+      std::string* message,
+      const Timeout& timeout) override {
+    return socket_->ReceiveNextMessage(message, timeout);
+  }
+
+  bool HasNextMessage() override { return socket_->HasNextMessage(); }
+
+ private:
+  raw_ptr<SyncWebSocket> socket_;
+};
+
+template <typename TSocket>
+class SocketHolder {
+ public:
+  template <typename... Args>
+  explicit SocketHolder(Args&&... args) : socket_{args...} {}
+
+  std::unique_ptr<SyncWebSocket> Wrapper() {
+    return std::unique_ptr<SyncWebSocket>(new SyncWebSocketWrapper(&socket_));
+  }
+
+  TSocket& Socket() { return socket_; }
+
+  bool ConnectSocket() { return socket_.Connect(GURL("http://url/")); }
+
+ private:
+  TSocket socket_;
+};
+
 }  // namespace
 
 TEST(EvaluateScript, CommandError) {
@@ -381,51 +423,20 @@
   SyncWebSocket::StatusCode next_status_;
 };
 
-std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket(
-    SyncWebSocket::StatusCode next_status) {
-  return std::make_unique<MockSyncWebSocket>(next_status);
-}
-
-class SyncWebSocketWrapper : public SyncWebSocket {
- public:
-  explicit SyncWebSocketWrapper(SyncWebSocket* socket) : socket_(socket) {}
-  ~SyncWebSocketWrapper() override = default;
-
-  bool IsConnected() override { return socket_->IsConnected(); }
-
-  bool Connect(const GURL& url) override { return socket_->Connect(url); }
-
-  bool Send(const std::string& message) override {
-    return socket_->Send(message);
-  }
-
-  SyncWebSocket::StatusCode ReceiveNextMessage(
-      std::string* message,
-      const Timeout& timeout) override {
-    return socket_->ReceiveNextMessage(message, timeout);
-  }
-
-  bool HasNextMessage() override { return socket_->HasNextMessage(); }
-
- private:
-  raw_ptr<SyncWebSocket> socket_;
-};
-
 }  // namespace
 
 TEST(CreateChild, MultiLevel) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
+  SocketHolder<MockSyncWebSocket> socket_holder{SyncWebSocket::StatusCode::kOk};
   // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
   std::unique_ptr<DevToolsClientImpl> client_uptr =
-      std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
+      std::make_unique<DevToolsClientImpl>("id", "");
   DevToolsClientImpl* client_ptr = client_uptr.get();
   BrowserInfo browser_info;
   WebViewImpl level1(client_ptr->GetId(), true, nullptr, &browser_info,
                      std::move(client_uptr), absl::nullopt,
                      PageLoadStrategy::kEager);
-  Status status = client_ptr->Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  EXPECT_TRUE(StatusOk(client_ptr->SetSocket(socket_holder.Wrapper())));
   std::string sessionid = "2";
   std::unique_ptr<WebViewImpl> level2 =
       std::unique_ptr<WebViewImpl>(level1.CreateChild(sessionid, "1234"));
@@ -441,18 +452,17 @@
 }
 
 TEST(CreateChild, IsNonBlocking_NoErrors) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
+  SocketHolder<MockSyncWebSocket> socket_holder{SyncWebSocket::StatusCode::kOk};
   // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
   std::unique_ptr<DevToolsClientImpl> client_uptr =
-      std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
+      std::make_unique<DevToolsClientImpl>("id", "");
   DevToolsClientImpl* client_ptr = client_uptr.get();
   BrowserInfo browser_info;
   WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
                           std::move(client_uptr), absl::nullopt,
                           PageLoadStrategy::kEager);
-  Status status = client_ptr->Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  EXPECT_TRUE(StatusOk(client_ptr->SetSocket(socket_holder.Wrapper())));
   ASSERT_FALSE(parent_view.IsNonBlocking());
 
   std::string sessionid = "2";
@@ -464,18 +474,17 @@
 }
 
 TEST(CreateChild, Load_NoErrors) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
+  SocketHolder<MockSyncWebSocket> socket_holder{SyncWebSocket::StatusCode::kOk};
   // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
   std::unique_ptr<DevToolsClientImpl> client_uptr =
-      std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
+      std::make_unique<DevToolsClientImpl>("id", "");
   DevToolsClientImpl* client_ptr = client_uptr.get();
   BrowserInfo browser_info;
   WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
                           std::move(client_uptr), absl::nullopt,
                           PageLoadStrategy::kNone);
-  Status status = client_ptr->Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  EXPECT_TRUE(StatusOk(client_ptr->SetSocket(socket_holder.Wrapper())));
   std::string sessionid = "2";
   std::unique_ptr<WebViewImpl> child_view =
       std::unique_ptr<WebViewImpl>(parent_view.CreateChild(sessionid, "1234"));
@@ -485,47 +494,40 @@
 }
 
 TEST(CreateChild, WaitForPendingNavigations_NoErrors) {
-  std::unique_ptr<MockSyncWebSocket> socket =
-      std::make_unique<MockSyncWebSocket>(SyncWebSocket::StatusCode::kOk);
-  SyncWebSocketFactory factory = base::BindRepeating(
-      [](SyncWebSocket* socket) {
-        return std::unique_ptr<SyncWebSocket>(new SyncWebSocketWrapper(socket));
-      },
-      socket.get());
+  SocketHolder<MockSyncWebSocket> socket_holder{SyncWebSocket::StatusCode::kOk};
   // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
   std::unique_ptr<DevToolsClientImpl> client_uptr =
-      std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
+      std::make_unique<DevToolsClientImpl>("id", "");
   DevToolsClientImpl* client_ptr = client_uptr.get();
   BrowserInfo browser_info;
   WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
                           std::move(client_uptr), absl::nullopt,
                           PageLoadStrategy::kNone);
-  Status status = client_ptr->Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  EXPECT_TRUE(StatusOk(client_ptr->SetSocket(socket_holder.Wrapper())));
   std::string sessionid = "2";
   std::unique_ptr<WebViewImpl> child_view =
       std::unique_ptr<WebViewImpl>(parent_view.CreateChild(sessionid, "1234"));
   child_view->AttachTo(client_ptr);
 
   // child_view gets no socket...
-  socket->SetNexStatusCode(SyncWebSocket::StatusCode::kTimeout);
+  socket_holder.Socket().SetNexStatusCode(SyncWebSocket::StatusCode::kTimeout);
   ASSERT_NO_FATAL_FAILURE(child_view->WaitForPendingNavigations(
       "1234", Timeout(base::Milliseconds(10)), true));
 }
 
 TEST(CreateChild, IsPendingNavigation_NoErrors) {
-  SyncWebSocketFactory factory = base::BindRepeating(
-      &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
+  SocketHolder<MockSyncWebSocket> socket_holder{SyncWebSocket::StatusCode::kOk};
   // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
   std::unique_ptr<DevToolsClientImpl> client_uptr =
-      std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
+      std::make_unique<DevToolsClientImpl>("id", "");
   DevToolsClientImpl* client_ptr = client_uptr.get();
   BrowserInfo browser_info;
   WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
                           std::move(client_uptr), absl::nullopt,
                           PageLoadStrategy::kNormal);
-  Status status = client_ptr->Connect();
-  ASSERT_EQ(kOk, status.code()) << status.message();
+  EXPECT_TRUE(socket_holder.ConnectSocket());
+  EXPECT_TRUE(StatusOk(client_ptr->SetSocket(socket_holder.Wrapper())));
   std::string sessionid = "2";
   std::unique_ptr<WebViewImpl> child_view =
       std::unique_ptr<WebViewImpl>(parent_view.CreateChild(sessionid, "1234"));
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 2c5122b..9929294 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -52,6 +52,8 @@
 #include "chrome/test/chromedriver/log_replay/chrome_replay_impl.h"
 #include "chrome/test/chromedriver/log_replay/replay_http_client.h"
 #include "chrome/test/chromedriver/net/net_util.h"
+#include "chrome/test/chromedriver/net/sync_websocket.h"
+#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 #include "components/crx_file/crx_verifier.h"
 #include "components/embedder_support/switches.h"
 #include "crypto/rsa_private_key.h"
@@ -343,9 +345,10 @@
   if (url.length() == 0) {
     url = endpoint.GetBrowserDebuggerUrl();
   }
-  std::unique_ptr<DevToolsClient> client(
-      new DevToolsClientImpl(DevToolsClientImpl::kBrowserwideDevToolsClientId,
-                             "", url, socket_factory));
+  std::unique_ptr<SyncWebSocket> socket = socket_factory.Run();
+  SyncWebSocket* socket_ptr = socket.get();
+  std::unique_ptr<DevToolsClientImpl> client(new DevToolsClientImpl(
+      DevToolsClientImpl::kBrowserwideDevToolsClientId, ""));
   for (const auto& listener : devtools_event_listeners) {
     // Only add listeners that subscribe to the browser-wide |DevToolsClient|.
     // Otherwise, listeners will think this client is associated with a webview,
@@ -354,8 +357,12 @@
       client->AddListener(listener.get());
   }
 
+  DevToolsClientImpl* client_impl = client.get();
   *browser_client = std::move(client);
-  return (*browser_client)->Connect();
+  if (!socket_ptr->Connect(GURL(url))) {
+    return Status(kDisconnected, "unable to connect to renderer");
+  }
+  return client_impl->SetSocket(std::move(socket));
 }
 
 Status LaunchRemoteChromeSession(
diff --git a/chrome/test/chromedriver/net/sync_websocket.h b/chrome/test/chromedriver/net/sync_websocket.h
index ac4c564..7f5109d 100644
--- a/chrome/test/chromedriver/net/sync_websocket.h
+++ b/chrome/test/chromedriver/net/sync_websocket.h
@@ -17,7 +17,7 @@
  public:
   enum class StatusCode { kOk = 0, kTimeout, kDisconnected };
 
-  virtual ~SyncWebSocket() {}
+  virtual ~SyncWebSocket() = default;
 
   virtual void SetId(const std::string& socket_id) {}
 
diff --git a/chrome/test/chromedriver/net/websocket.h b/chrome/test/chromedriver/net/websocket.h
index ec400d3..685237c5 100644
--- a/chrome/test/chromedriver/net/websocket.h
+++ b/chrome/test/chromedriver/net/websocket.h
@@ -93,7 +93,7 @@
 // WebSocket.
 class WebSocketListener {
  public:
-  virtual ~WebSocketListener() {}
+  virtual ~WebSocketListener() = default;
 
   // Called when a WebSocket message is received.
   virtual void OnMessageReceived(const std::string& message) = 0;
diff --git a/chrome/test/chromedriver/performance_logger_unittest.cc b/chrome/test/chromedriver/performance_logger_unittest.cc
index 5a742bb..898644f 100644
--- a/chrome/test/chromedriver/performance_logger_unittest.cc
+++ b/chrome/test/chromedriver/performance_logger_unittest.cc
@@ -30,7 +30,7 @@
       : method(in_method) {
     params.reset(in_params);
   }
-  ~DevToolsCommand() {}
+  ~DevToolsCommand() = default;
 
   std::string method;
   std::unique_ptr<base::Value::Dict> params;
@@ -38,9 +38,8 @@
 
 class FakeDevToolsClient : public StubDevToolsClient {
  public:
-  explicit FakeDevToolsClient(const std::string& id)
-      : id_(id), listener_(nullptr), command_index_(0) {}
-  ~FakeDevToolsClient() override {}
+  explicit FakeDevToolsClient(const std::string& id) : id_(id) {}
+  ~FakeDevToolsClient() override = default;
 
   bool PopSentCommand(DevToolsCommand** out_command) {
     if (sent_commands_.size() > command_index_) {
@@ -59,9 +58,6 @@
     return TriggerEvent(method, base::Value::Dict());
   }
 
-  // Overridden from DevToolsClient:
-  Status Connect() override { return listener_->OnConnected(this); }
-
   Status SendCommandAndGetResult(const std::string& method,
                                  const base::Value::Dict& params,
                                  base::Value::Dict* result) override {
@@ -87,9 +83,9 @@
   const std::string id_;  // WebView id.
   std::vector<std::unique_ptr<DevToolsCommand>>
       sent_commands_;                // Commands that were sent.
-  raw_ptr<DevToolsEventListener>
-      listener_;  // The fake allows only one event listener.
-  size_t command_index_;
+  raw_ptr<DevToolsEventListener> listener_ =
+      nullptr;  // The fake allows only one event listener.
+  size_t command_index_ = 0;
 };
 
 struct LogEntry {
@@ -227,7 +223,7 @@
   ExpectEnableDomains(&client1);
   ExpectEnableDomains(&client2);
   // OnConnected sends the enable command only to that client, not others.
-  client1.Connect();
+  logger.OnConnected(&client1);
   ExpectEnableDomains(&client1);
   DevToolsCommand* cmd;
   ASSERT_FALSE(client2.PopSentCommand(&cmd));
@@ -267,9 +263,8 @@
 class FakeBrowserwideClient : public FakeDevToolsClient {
  public:
   FakeBrowserwideClient()
-      : FakeDevToolsClient(DevToolsClientImpl::kBrowserwideDevToolsClientId),
-        events_handled_(false) {}
-  ~FakeBrowserwideClient() override {}
+      : FakeDevToolsClient(DevToolsClientImpl::kBrowserwideDevToolsClientId) {}
+  ~FakeBrowserwideClient() override = default;
 
   bool events_handled() const {
     return events_handled_;
@@ -284,7 +279,7 @@
   }
 
  private:
-  bool events_handled_;
+  bool events_handled_ = false;
 };
 
 }  // namespace
diff --git a/chrome/test/data/bruschetta/download_file.img b/chrome/test/data/bruschetta/download_file.img
new file mode 100644
index 0000000..0e1a730
--- /dev/null
+++ b/chrome/test/data/bruschetta/download_file.img
@@ -0,0 +1 @@
+The contents don't matter and neither do the points
diff --git a/chrome/test/webapps/coverage/coverage_cros.tsv b/chrome/test/webapps/coverage/coverage_cros.tsv
index 72d347b..38e15b0 100644
--- a/chrome/test/webapps/coverage/coverage_cros.tsv
+++ b/chrome/test/webapps/coverage/coverage_cros.tsv
@@ -157,6 +157,11 @@
 install_policy_app_NotPromotable_WithShortcut_Browser_WebApp🌓	check_platform_shortcut_and_icon_NotPromotable🌓
 create_shortcut_NotPromotable_Windowed🌕	check_platform_shortcut_and_icon_NotPromotable🌓
 create_shortcut_NotPromotable_Browser🌕	check_platform_shortcut_and_icon_NotPromotable🌓
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌑	check_tab_created_One🌑
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌑	install_omnibox_icon_Standalone🌑	check_pwa_window_created_in_profile_Standalone_One_Default🌑
+create_shortcut_Standalone_Windowed🌕	check_window_created🌕
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	check_app_in_list_windowed_Standalone🌓	check_platform_shortcut_and_icon_Standalone🌓
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	launch_from_platform_shortcut_Standalone🌑	check_pwa_window_created_in_profile_Standalone_One_Default🌑	check_launch_icon_not_shown🌑
 create_shortcut_Standalone_Browser🌕	uninstall_from_list_Standalone🌕	check_app_not_in_list_Standalone🌓
 create_shortcut_Standalone_Browser🌕	uninstall_from_list_Standalone🌕	navigate_browser_Standalone🌕	check_install_icon_shown🌕
 create_shortcut_Standalone_Browser🌕	uninstall_from_list_Standalone🌕	navigate_browser_Standalone🌕	check_launch_icon_not_shown🌕
diff --git a/chrome/test/webapps/coverage/coverage_linux.tsv b/chrome/test/webapps/coverage/coverage_linux.tsv
index 19677957..e913eaa 100644
--- a/chrome/test/webapps/coverage/coverage_linux.tsv
+++ b/chrome/test/webapps/coverage/coverage_linux.tsv
@@ -373,6 +373,11 @@
 install_policy_app_NotPromotable_WithShortcut_Browser_WebApp🌓	check_platform_shortcut_and_icon_NotPromotable🌓
 create_shortcut_NotPromotable_Windowed🌕	check_platform_shortcut_and_icon_NotPromotable🌓
 create_shortcut_NotPromotable_Browser🌕	check_platform_shortcut_and_icon_NotPromotable🌓
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌓	check_tab_created_One🌕
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌓	install_omnibox_icon_Standalone🌕	check_pwa_window_created_in_profile_Standalone_One_Default🌕
+create_shortcut_Standalone_Windowed🌕	check_window_created🌕
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	check_app_in_list_windowed_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	launch_from_platform_shortcut_Standalone🌓	check_pwa_window_created_in_profile_Standalone_One_Default🌕	check_launch_icon_not_shown🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_list_Standalone🌕	check_app_not_in_list_Standalone🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_menu_Standalone🌕	check_app_not_in_list_Standalone🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_os_Standalone🌑	check_app_not_in_list_Standalone🌑
diff --git a/chrome/test/webapps/coverage/coverage_mac.tsv b/chrome/test/webapps/coverage/coverage_mac.tsv
index 61ec13d..ee6527c 100644
--- a/chrome/test/webapps/coverage/coverage_mac.tsv
+++ b/chrome/test/webapps/coverage/coverage_mac.tsv
@@ -373,6 +373,11 @@
 install_policy_app_NotPromotable_WithShortcut_Browser_WebApp🌓	check_platform_shortcut_and_icon_NotPromotable🌕
 create_shortcut_NotPromotable_Windowed🌕	check_platform_shortcut_and_icon_NotPromotable🌕
 create_shortcut_NotPromotable_Browser🌕	check_platform_shortcut_and_icon_NotPromotable🌕
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌓	check_tab_created_One🌕
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌓	install_omnibox_icon_Standalone🌕	check_pwa_window_created_in_profile_Standalone_One_Default🌕
+create_shortcut_Standalone_Windowed🌕	check_window_created🌕
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	check_app_in_list_windowed_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌕
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	launch_from_platform_shortcut_Standalone🌓	check_pwa_window_created_in_profile_Standalone_One_Default🌕	check_launch_icon_not_shown🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_list_Standalone🌕	check_app_not_in_list_Standalone🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_menu_Standalone🌕	check_app_not_in_list_Standalone🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_os_Standalone🌑	check_app_not_in_list_Standalone🌑
diff --git a/chrome/test/webapps/coverage/coverage_win.tsv b/chrome/test/webapps/coverage/coverage_win.tsv
index f056945..1fb6d68 100644
--- a/chrome/test/webapps/coverage/coverage_win.tsv
+++ b/chrome/test/webapps/coverage/coverage_win.tsv
@@ -373,6 +373,11 @@
 install_policy_app_NotPromotable_WithShortcut_Browser_WebApp🌓	check_platform_shortcut_and_icon_NotPromotable🌓
 create_shortcut_NotPromotable_Windowed🌕	check_platform_shortcut_and_icon_NotPromotable🌓
 create_shortcut_NotPromotable_Browser🌕	check_platform_shortcut_and_icon_NotPromotable🌓
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌓	check_tab_created_One🌕
+create_shortcut_Standalone_Browser🌕	launch_from_platform_shortcut_Standalone🌓	install_omnibox_icon_Standalone🌕	check_pwa_window_created_in_profile_Standalone_One_Default🌕
+create_shortcut_Standalone_Windowed🌕	check_window_created🌕
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	check_app_in_list_windowed_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
+create_shortcut_Standalone_Windowed🌕	close_pwa🌕	launch_from_platform_shortcut_Standalone🌓	check_pwa_window_created_in_profile_Standalone_One_Default🌕	check_launch_icon_not_shown🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_list_Standalone🌕	check_app_not_in_list_Standalone🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_menu_Standalone🌕	check_app_not_in_list_Standalone🌕
 create_shortcut_Standalone_Windowed🌕	uninstall_from_os_Standalone🌕	check_app_not_in_list_Standalone🌕
diff --git a/chrome/test/webapps/data/critical_user_journeys.md b/chrome/test/webapps/data/critical_user_journeys.md
index 473c77a..a01130e 100644
--- a/chrome/test/webapps/data/critical_user_journeys.md
+++ b/chrome/test/webapps/data/critical_user_journeys.md
@@ -84,7 +84,11 @@
 | WMLC | install_or_shortcut_windowed(NotPromotable) | navigate_browser(NotPromotable) | check_launch_icon_shown |
 | WMLC | install_or_shortcut_with_shortcut | check_platform_shortcut_and_icon |
 | WMLC | install_or_shortcut_with_shortcut(NotPromotable) | check_platform_shortcut_and_icon(NotPromotable) |
-
+| WMLC | install_or_shortcut_by_user_tabbed(Standalone) | launch_from_platform_shortcut(Standalone) | check_tab_created(One) |
+| WMLC | install_or_shortcut_by_user_tabbed(Standalone) | launch_from_platform_shortcut(Standalone) | install_omnibox_icon(Standalone) | check_pwa_window_created_in_profile(Standalone, One, Default)
+| WMLC | create_shortcut(Standalone, Windowed) | check_window_created |
+| WMLC | create_shortcut(Standalone, Windowed) | close_pwa | check_app_in_list_windowed(Standalone) | check_platform_shortcut_and_icon(Standalone) |
+| WMLC | create_shortcut(Standalone, Windowed) | close_pwa | launch_from_platform_shortcut(Standalone) | check_pwa_window_created_in_profile(Standalone, One, Default) | check_launch_icon_not_shown |
 
 ## Uninstallation
 | #Platforms | Test -> | | | | | | | | | | | | | | | | |
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 3be0c515..f19f4ab 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -695,7 +695,7 @@
     ]
     if (is_win) {
       sources += [
-        # TODO(crbug.com/1402743) - eliminate the dependency on //chrome/test.
+        # TODO(crbug.com/1447274) - eliminate the dependency on //chrome/test.
         "//chrome/test/base/process_inspector_win.cc",
         "//chrome/test/base/process_inspector_win.h",
       ]
diff --git a/chrome/updater/activity_impl_win.cc b/chrome/updater/activity_impl_win.cc
index 2216416..92a92be 100644
--- a/chrome/updater/activity_impl_win.cc
+++ b/chrome/updater/activity_impl_win.cc
@@ -135,9 +135,7 @@
 bool GetActiveBit(UpdaterScope scope, const std::string& id) {
   switch (scope) {
     case UpdaterScope::kUser:
-      // TODO(crbug/1159498): Standardize registry access.
       return GetUserActiveBit(id);
-
     case UpdaterScope::kSystem:
       return GetSystemActiveBit(id);
   }
@@ -146,10 +144,8 @@
 void ClearActiveBit(UpdaterScope scope, const std::string& id) {
   switch (scope) {
     case UpdaterScope::kUser:
-      // TODO(crbug/1159498): Standardize registry access.
       ClearUserActiveBit(id);
       break;
-
     case UpdaterScope::kSystem:
       ClearSystemActiveBit(id);
       break;
diff --git a/chrome/updater/app/app_install.cc b/chrome/updater/app/app_install.cc
index 9aaf280f..31969ac 100644
--- a/chrome/updater/app/app_install.cc
+++ b/chrome/updater/app/app_install.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/check.h"
-#include "base/check_op.h"
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
@@ -131,8 +130,7 @@
   const tagging::TagArgs tag_args =
       tag_parsing_result.tag_args.value_or(tagging::TagArgs());
   if (!tag_args.apps.empty()) {
-    // TODO(crbug.com/1128631): support bundles. For now, assume one app.
-    CHECK_EQ(tag_args.apps.size(), size_t{1});
+    // Assume only one app is present since bundles are not supported.
     const tagging::AppArgs& app_args = tag_args.apps.front();
     app_id_ = app_args.app_id;
     app_name_ = app_args.app_name;
diff --git a/chrome/updater/app/app_wake.cc b/chrome/updater/app/app_wake.cc
index b52c117..0e3a5ce 100644
--- a/chrome/updater/app/app_wake.cc
+++ b/chrome/updater/app/app_wake.cc
@@ -29,12 +29,6 @@
 };
 
 void AppWake::FirstTaskRun() {
-  // The service creation might need task runners and the update service
-  // internal needs to be instantiated after the base class has initialized
-  // the thread pool.
-  //
-  // TODO(crbug.com/1113448) - consider initializing the thread pool in the
-  // constructor of the base class or earlier, in the updater main.
   update_service_internal_ = CreateUpdateServiceInternalProxy(updater_scope());
   update_service_internal_->Run(
       base::BindOnce(&AppWake::Shutdown, this, kErrorOk));
diff --git a/chrome/updater/app/server/win/com_classes.h b/chrome/updater/app/server/win/com_classes.h
index f3b8f9c..ac542b7 100644
--- a/chrome/updater/app/server/win/com_classes.h
+++ b/chrome/updater/app/server/win/com_classes.h
@@ -15,15 +15,8 @@
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/util/win_util.h"
 
-// Definitions for native COM updater classes.
-
 namespace updater {
 
-// TODO(crbug.com/1065712): these classes do not have to be visible in the
-// updater namespace. Additionally, there is some code duplication for the
-// registration and unregistration code in both server and service_main
-// compilation units.
-//
 // This class implements the IUpdateState interface and exposes it as a COM
 // object. The purpose of this class is to remote the state of the
 // |UpdateService|. Instances of this class are typically passed as arguments
diff --git a/chrome/updater/app/server/win/com_classes_legacy.cc b/chrome/updater/app/server/win/com_classes_legacy.cc
index ddce9ba..3112378 100644
--- a/chrome/updater/app/server/win/com_classes_legacy.cc
+++ b/chrome/updater/app/server/win/com_classes_legacy.cc
@@ -565,7 +565,7 @@
           // compatibility.
           error_code = GOOPDATEINSTALL_E_INSTALLER_FAILED;
 
-          // TODO(1095133): this string needs localization.
+          // TODO(crbug.com/1447293): this string needs localization.
           completion_message = L"Installer failed.";
           installer_result_code = state_update_->extra_code1;
         }
diff --git a/chrome/updater/app/server/win/updater_legacy_idl.template b/chrome/updater/app/server/win/updater_legacy_idl.template
index e043fe1..7a897e3 100644
--- a/chrome/updater/app/server/win/updater_legacy_idl.template
+++ b/chrome/updater/app/server/win/updater_legacy_idl.template
@@ -21,8 +21,6 @@
   STATE_DOWNLOAD_COMPLETE = 8,
   STATE_EXTRACTING = 9,
   STATE_APPLYING_DIFFERENTIAL_PATCH = 10,
-  // TODO(omaha3): Should we move STATE_DOWNLOAD_COMPLETE here and eliminate
-  // STATE_READY_TO_INSTALL?
   STATE_READY_TO_INSTALL = 11,
   STATE_WAITING_TO_INSTALL = 12,
   STATE_INSTALLING = 13,
@@ -65,7 +63,6 @@
   // Returns the count of the Packages in the AppVersion.
   [propget] HRESULT packageCount([out, retval] long* count);
 
-  // TODO(omaha3): Implement this after a security review.
   // Returns an IDispatch of the Package in the AppVersion at the specified
   // 0-based index.
   [propget] HRESULT packageWeb([in] long index,
@@ -91,7 +88,6 @@
 ]
 interface ICurrentState : IDispatch {
   // This interface is exposed to web clients!
-  // TODO(omaha3): Update valid comments once we settle on an implementation.
 
   // A value from the CurrentState enum. This value determines which of the
   // properties below are valid.
@@ -120,8 +116,6 @@
 
   [propget] HRESULT nextRetryTime([out, retval] ULONGLONG*);
 
-  // TODO(omaha 3): Need some way to indicate reconnecting, retrying, etc.
-
   // The following two properties are only valid when stateValue is
   // STATE_INSTALLING or STATE_INSTALL_COMPLETE.
 
@@ -147,12 +141,8 @@
 
   // The following three properties are only valid when stateValue is
   // STATE_ERROR or STATE_INSTALL_COMPLETE.
-  // TODO(omaha3): If STATE_DOWNLOAD_COMPLETE or STATE_READY_TO_INSTALL becomes
-  // a terminal state, does it support completion messages?
-
+  //
   // Completion message, localized in the specified language.
-  // TODO(omaha3): If we're going to have bundle error messages too, should the
-  // language be at bundle level? Should bundle have its own language setter?
   [propget] HRESULT completionMessage([out, retval] BSTR*);
 
   // Application installer result code. This is to be used as additional
diff --git a/chrome/updater/installer.cc b/chrome/updater/installer.cc
index bf584f0a..c838e70 100644
--- a/chrome/updater/installer.cc
+++ b/chrome/updater/installer.cc
@@ -32,14 +32,6 @@
 namespace updater {
 namespace {
 
-// This task joins a process, hence .WithBaseSyncPrimitives().
-// TODO(crbug.com/1376713) - implement a way to express priority for
-// foreground/background installs.
-static constexpr base::TaskTraits kTaskTraitsBlockWithSyncPrimitives = {
-    base::MayBlock(), base::WithBaseSyncPrimitives(),
-    base::TaskPriority::USER_VISIBLE,
-    base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
-
 // Returns the full path to the installation directory for the application
 // identified by the |app_id|.
 absl::optional<base::FilePath> GetAppInstallDir(UpdaterScope scope,
@@ -48,7 +40,6 @@
   if (!app_install_dir) {
     return absl::nullopt;
   }
-
   return app_install_dir->AppendASCII(kAppsDir).AppendASCII(app_id);
 }
 
@@ -60,7 +51,6 @@
                  const base::Version& app_version,
                  const base::FilePath& ecp)
     : scope(scope), app_id(app_id), ap(ap), version(app_version), ecp(ecp) {}
-
 AppInfo::AppInfo(const AppInfo&) = default;
 AppInfo& AppInfo::operator=(const AppInfo&) = default;
 AppInfo::~AppInfo() = default;
@@ -89,9 +79,7 @@
       crx_verifier_format_(crx_verifier_format),
       usage_stats_enabled_(persisted_data->GetUsageStatsEnabled()) {}
 
-Installer::~Installer() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
+Installer::~Installer() = default;
 
 update_client::CrxComponent Installer::MakeCrxComponent() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -222,7 +210,10 @@
                         ProgressCallback progress_callback,
                         Callback callback) {
   base::ThreadPool::PostTask(
-      FROM_HERE, kTaskTraitsBlockWithSyncPrimitives,
+      FROM_HERE,
+      {base::MayBlock(), base::WithBaseSyncPrimitives(),
+       base::TaskPriority::USER_VISIBLE,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
       base::BindOnce(&Installer::InstallWithSyncPrimitives, this, unpack_path,
                      std::move(install_params), std::move(progress_callback),
                      std::move(callback)));
diff --git a/chrome/updater/linux/setup/setup.cc b/chrome/updater/linux/setup/setup.cc
index d81f0b3..36bd5af 100644
--- a/chrome/updater/linux/setup/setup.cc
+++ b/chrome/updater/linux/setup/setup.cc
@@ -19,8 +19,6 @@
 #include "chrome/updater/util/util.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-// TODO(1382547): There is a overlap between the Mac and Linux setup functions.
-// We should find a way to merge these.
 namespace updater {
 
 int Setup(UpdaterScope scope) {
diff --git a/chrome/updater/persisted_data.h b/chrome/updater/persisted_data.h
index ba2f6a8..c5c193e 100644
--- a/chrome/updater/persisted_data.h
+++ b/chrome/updater/persisted_data.h
@@ -34,11 +34,6 @@
 
 // PersistedData uses the PrefService to persist updater data that outlives
 // the updater processes.
-//
-// This class has sequence affinity.
-//
-// A mechanism to remove apps or app versions from prefs is needed.
-// TODO(sorin): crbug.com/1056450
 class PersistedData : public base::RefCountedThreadSafe<PersistedData> {
  public:
   // Constructs a provider using the specified |pref_service|.
@@ -158,7 +153,7 @@
   SEQUENCE_CHECKER(sequence_checker_);
 
   const UpdaterScope scope_;
-  raw_ptr<PrefService> pref_service_ = nullptr;  // Not owned by this class.
+  raw_ptr<PrefService> pref_service_ = nullptr;
 };
 
 void RegisterPersistedDataPrefs(scoped_refptr<PrefRegistrySimple> registry);
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h
index c0b2c2a3..71da42c 100644
--- a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h
+++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h
@@ -9,9 +9,6 @@
 
 #include "chrome/updater/policy/manager.h"
 
-// TODO: crbug/1073980
-//     Add a doc link for the managed preferences dictionary format.
-//
 // An example of the managed preferences policy dictionary in plist format:
 //  <dict>
 //    <key>updatePolicies</key>
diff --git a/chrome/updater/protos/message_set.proto b/chrome/updater/protos/message_set.proto
index 498e8f3..cb6f2b8 100644
--- a/chrome/updater/protos/message_set.proto
+++ b/chrome/updater/protos/message_set.proto
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO: crbug/1082836
+// TODO: crbug.com/1082836
 // This file is currently manually tweaked for Chromium use. Find a
 // way to automatically sync from source and make the following necessary
 // changes:
diff --git a/chrome/updater/protos/omaha_settings.proto b/chrome/updater/protos/omaha_settings.proto
index cc0b49c..5313cb9f6 100644
--- a/chrome/updater/protos/omaha_settings.proto
+++ b/chrome/updater/protos/omaha_settings.proto
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO: crbug/1082836
+// TODO: crbug.com/1082836
 // This file is currently manually tweaked for Chromium use. Find a
 // way to automatically sync from source and make the following necessary
 // changes:
diff --git a/chrome/updater/run_all_unittests.cc b/chrome/updater/run_all_unittests.cc
index a43532d..089b2c4 100644
--- a/chrome/updater/run_all_unittests.cc
+++ b/chrome/updater/run_all_unittests.cc
@@ -169,10 +169,9 @@
   VLOG(0) << "Process priority: " << base::Process::Current().GetPriority();
   VLOG(0) << updater::GetUACState();
 
-  // TODO(crbug.com/1245429): remove when the bug is fixed.
-  // Typically, the test suite runner expects the swarming task to run with
-  // normal priority but for some reason, on the updater bots with UAC on, the
-  // swarming task runs with a priority below normal.
+  // The test suite runner expects the swarming task to run with normal priority
+  // but for some reason, on the updater bots with UAC on, the swarming task
+  // runs with a priority below normal (see crbug.com/1245429).
   FixExecutionPriorities();
 
   auto scoped_com_initializer =
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 252732e..ddb5c9b 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -135,9 +135,6 @@
     ExpectNoCrashes();
 
     PrintLog();
-
-    // TODO(crbug.com/1159189): Use a specific test output directory
-    // because Uninstall() deletes the files under GetInstallDirectory().
     CopyLog();
 
     DMCleanup();
@@ -897,7 +894,6 @@
   ASSERT_NO_FATAL_FAILURE(InstallApp("test1"));
   ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
   ASSERT_TRUE(WaitForUpdaterExit());
-  // TODO(crbug.com/1287235): The test is flaky without the following line.
   ASSERT_NO_FATAL_FAILURE(SetServerStarts(24));
   ASSERT_NO_FATAL_FAILURE(RunWake(0));
   ASSERT_TRUE(WaitForUpdaterExit());
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc
index 705959e..070c6036 100644
--- a/chrome/updater/test/integration_tests_impl.cc
+++ b/chrome/updater/test/integration_tests_impl.cc
@@ -356,7 +356,6 @@
 // each failed test. It is useful to capture a few logs from previous failures
 // instead of the log of the last run only.
 void CopyLog(const base::FilePath& src_dir) {
-  // TODO(crbug.com/1159189): copy other test artifacts.
   base::FilePath dest_dir = GetLogDestinationDir();
   const base::FilePath log_path = src_dir.AppendASCII("updater.log");
   if (!dest_dir.empty() && base::PathExists(dest_dir) &&
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index 3a443239..2e55745 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -671,7 +671,6 @@
 }
 
 void SetActive(UpdaterScope /*scope*/, const std::string& id) {
-  // TODO(crbug.com/1159498): Standardize registry access.
   base::win::RegKey key;
   ASSERT_EQ(key.Create(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
                        Wow6432(KEY_WRITE)),
@@ -680,7 +679,6 @@
 }
 
 void ExpectActive(UpdaterScope /*scope*/, const std::string& id) {
-  // TODO(crbug.com/1159498): Standardize registry access.
   base::win::RegKey key;
   ASSERT_EQ(key.Open(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
                      Wow6432(KEY_READ)),
@@ -691,7 +689,6 @@
 }
 
 void ExpectNotActive(UpdaterScope /*scope*/, const std::string& id) {
-  // TODO(crbug.com/1159498): Standardize registry access.
   base::win::RegKey key;
   if (key.Open(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
                Wow6432(KEY_READ)) == ERROR_SUCCESS) {
diff --git a/chrome/updater/update_block_check_win.cc b/chrome/updater/update_block_check_win.cc
index a9b2e76..e2d0382c 100644
--- a/chrome/updater/update_block_check_win.cc
+++ b/chrome/updater/update_block_check_win.cc
@@ -26,18 +26,16 @@
   return true;
 }
 
-// TODO(crbug.com/1254492): Protect against deadlocks in NLM.
 bool IsConnectionedMetered() {
-  // No NLM before Win 8.1. Connections will be considered non-metered.
-  // Also, NLM could deadlock in Win10 versions pre-RS5, so we don't run the
-  // code for those versions.
+  // No NLM before Win 8.1. Connections will be considered non-metered. Also,
+  // because NLM could deadlock in Win10 versions pre-RS5, don't run the code
+  // for those versions (see crbug.com/1254492).
   if (base::win::GetVersion() < base::win::Version::WIN10_RS5)
     return false;
 
   Microsoft::WRL::ComPtr<INetworkCostManager> network_cost_manager;
-  HRESULT hr =
-      ::CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_ALL,
-                         IID_INetworkCostManager, &network_cost_manager);
+  HRESULT hr = ::CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_ALL,
+                                  IID_PPV_ARGS(&network_cost_manager));
   if (FAILED(hr))
     return false;
 
diff --git a/chrome/updater/updater_scope.cc b/chrome/updater/updater_scope.cc
index 1c97af57..d5501249 100644
--- a/chrome/updater/updater_scope.cc
+++ b/chrome/updater/updater_scope.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/updater/updater_scope.h"
 
-#include "base/check_op.h"
 #include "base/command_line.h"
 #include "build/build_config.h"
 #include "chrome/updater/constants.h"
@@ -45,12 +44,11 @@
     return UpdaterScope::kSystem;
   }
 
-  // TODO(crbug.com/1128631): support bundles. For now, assume one app.
+  // Assume only one app is present since bundles are not supported.
   const absl::optional<tagging::TagArgs> tag_args =
       GetTagArgsForCommandLine(command_line).tag_args;
   if (tag_args && !tag_args->apps.empty() &&
       tag_args->apps.front().needs_admin) {
-    CHECK_EQ(tag_args->apps.size(), size_t{1});
     switch (*tag_args->apps.front().needs_admin) {
       case tagging::AppArgs::NeedsAdmin::kYes:
         return UpdaterScope::kSystem;
@@ -62,9 +60,6 @@
                    : UpdaterScope::kSystem;
     }
   }
-
-  // crbug.com(1214058): consider handling the elevation case by
-  // calling IsUserAdmin().
   return UpdaterScope::kUser;
 #else
   return IsSystemProcessForCommandLine(command_line) ? UpdaterScope::kSystem
diff --git a/chromeos/components/kcer/kcer.h b/chromeos/components/kcer/kcer.h
index dd64c464..488296f2 100644
--- a/chromeos/components/kcer/kcer.h
+++ b/chromeos/components/kcer/kcer.h
@@ -72,6 +72,7 @@
   kFailedToSign = 23,
   kFailedToSignBadSignatureLength = 24,
   kFailedToDerEncode = 25,
+  kInputTooLong = 26,
 };
 
 // Handles for tokens on ChromeOS.
diff --git a/chromeos/components/kcer/kcer_impl.cc b/chromeos/components/kcer/kcer_impl.cc
index 3a036021..e5a1d224 100644
--- a/chromeos/components/kcer/kcer_impl.cc
+++ b/chromeos/components/kcer/kcer_impl.cc
@@ -258,7 +258,37 @@
 void KcerImpl::SignRsaPkcs1Raw(PrivateKeyHandle key,
                                DigestWithPrefix digest_with_prefix,
                                SignCallback callback) {
-  // TODO(244408716): Implement.
+  if (key.GetTokenInternal().has_value()) {
+    return SignRsaPkcs1RawWithToken(std::move(digest_with_prefix),
+                                    std::move(callback), std::move(key));
+  }
+
+  auto on_find_key_done = base::BindOnce(
+      &KcerImpl::SignRsaPkcs1RawWithToken, weak_factory_.GetWeakPtr(),
+      std::move(digest_with_prefix), std::move(callback));
+  return PopulateTokenForKey(std::move(key), std::move(on_find_key_done));
+}
+
+void KcerImpl::SignRsaPkcs1RawWithToken(
+    DigestWithPrefix digest_with_prefix,
+    SignCallback callback,
+    base::expected<PrivateKeyHandle, Error> key_or_error) {
+  if (!key_or_error.has_value()) {
+    return std::move(callback).Run(base::unexpected(key_or_error.error()));
+  }
+  PrivateKeyHandle key = std::move(key_or_error).value();
+
+  const base::WeakPtr<KcerToken>& kcer_token =
+      GetToken(key.GetTokenInternal().value());
+  if (!kcer_token.MaybeValid()) {
+    return std::move(callback).Run(
+        base::unexpected(Error::kTokenIsNotAvailable));
+  }
+  token_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&KcerToken::SignRsaPkcs1Raw, kcer_token, std::move(key),
+                     std::move(digest_with_prefix),
+                     base::BindPostTaskToCurrentDefault(std::move(callback))));
 }
 
 base::flat_set<Token> KcerImpl::GetAvailableTokens() {
diff --git a/chromeos/components/kcer/kcer_impl.h b/chromeos/components/kcer/kcer_impl.h
index 55c48723..72445d5 100644
--- a/chromeos/components/kcer/kcer_impl.h
+++ b/chromeos/components/kcer/kcer_impl.h
@@ -123,6 +123,11 @@
                      SignCallback callback,
                      base::expected<PrivateKeyHandle, Error> key_or_error);
 
+  void SignRsaPkcs1RawWithToken(
+      DigestWithPrefix digest_with_prefix,
+      SignCallback callback,
+      base::expected<PrivateKeyHandle, Error> key_or_error);
+
   void GetKeyInfoWithToken(
       GetKeyInfoCallback callback,
       base::expected<PrivateKeyHandle, Error> key_or_error);
diff --git a/chromeos/components/kcer/kcer_token.h b/chromeos/components/kcer/kcer_token.h
index 44607b2..a096418 100644
--- a/chromeos/components/kcer/kcer_token.h
+++ b/chromeos/components/kcer/kcer_token.h
@@ -66,7 +66,6 @@
                     DataToSign data,
                     Kcer::SignCallback callback) = 0;
   virtual void SignRsaPkcs1Raw(PrivateKeyHandle key,
-                               SigningScheme signing_scheme,
                                DigestWithPrefix digest_with_prefix,
                                Kcer::SignCallback callback) = 0;
   virtual void GetTokenInfo(Kcer::GetTokenInfoCallback callback) = 0;
diff --git a/chromeos/profiles/arm-exp.afdo.newest.txt b/chromeos/profiles/arm-exp.afdo.newest.txt
index 87f550f..5c8862e7 100644
--- a/chromeos/profiles/arm-exp.afdo.newest.txt
+++ b/chromeos/profiles/arm-exp.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-exp-115-5735.18-1684144513-benchmark-115.0.5784.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-exp-115-5735.18-1684144513-benchmark-115.0.5785.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index c9be1f2..51d3051 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-115-5735.18-1684150800-benchmark-115.0.5784.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-115-5735.18-1684150800-benchmark-115.0.5785.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index bc9ce88..3e7010af 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-115-5735.18-1684144513-benchmark-115.0.5784.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-115-5735.18-1684144513-benchmark-115.0.5785.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index bf5a5dc0..266d437 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-115-5735.18-1684149627-benchmark-115.0.5784.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-115-5735.18-1684149627-benchmark-115.0.5785.0-r1-redacted.afdo.xz
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc
index f236ca7..a790e09e 100644
--- a/components/autofill/content/browser/content_autofill_driver.cc
+++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -64,7 +64,7 @@
 ContentAutofillDriver::ContentAutofillDriver(
     content::RenderFrameHost* render_frame_host,
     ContentAutofillDriverFactory* owner)
-    : render_frame_host_(render_frame_host),
+    : render_frame_host_(*render_frame_host),
       owner_(*owner),
       suppress_showing_ime_callback_(base::BindRepeating(
           [](const ContentAutofillDriver* driver) {
@@ -168,7 +168,7 @@
 }
 
 bool ContentAutofillDriver::IsInAnyMainFrame() const {
-  return render_frame_host_->GetMainFrame() == render_frame_host_;
+  return render_frame_host_->GetMainFrame() == render_frame_host();
 }
 
 bool ContentAutofillDriver::IsInFencedFrameRoot() const {
@@ -353,8 +353,9 @@
 
 void ContentAutofillDriver::SetFormToBeProbablySubmitted(
     const absl::optional<FormData>& form) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().SetFormToBeProbablySubmitted(
       this,
       form ? absl::make_optional<FormData>(
@@ -369,8 +370,9 @@
 void ContentAutofillDriver::FormsSeen(
     const std::vector<FormData>& raw_updated_forms,
     const std::vector<FormRendererId>& raw_removed_forms) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   std::vector<FormData> updated_forms = raw_updated_forms;
   for (FormData& form : updated_forms)
     SetFrameAndFormMetaData(form, nullptr);
@@ -394,8 +396,9 @@
     const FormData& raw_form,
     bool known_success,
     mojom::SubmissionSource submission_source) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().FormSubmitted(
       this, GetFormWithFrameAndFormMetaData(raw_form), known_success,
       submission_source,
@@ -420,8 +423,9 @@
                                                const FormFieldData& raw_field,
                                                const gfx::RectF& bounding_box,
                                                base::TimeTicks timestamp) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   FormData form = raw_form;
   FormFieldData field = raw_field;
   SetFrameAndFormMetaData(form, &field);
@@ -439,8 +443,9 @@
 void ContentAutofillDriver::TextFieldDidScroll(const FormData& raw_form,
                                                const FormFieldData& raw_field,
                                                const gfx::RectF& bounding_box) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   FormData form = raw_form;
   FormFieldData field = raw_field;
   SetFrameAndFormMetaData(form, &field);
@@ -458,8 +463,9 @@
     const FormData& raw_form,
     const FormFieldData& raw_field,
     const gfx::RectF& bounding_box) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   FormData form = raw_form;
   FormFieldData field = raw_field;
   SetFrameAndFormMetaData(form, &field);
@@ -479,8 +485,9 @@
     const gfx::RectF& bounding_box,
     AutoselectFirstSuggestion autoselect_first_suggestion,
     FormElementWasClicked form_element_was_clicked) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   FormData form = raw_form;
   FormFieldData field = raw_field;
   SetFrameAndFormMetaData(form, &field);
@@ -499,8 +506,9 @@
 }
 
 void ContentAutofillDriver::HidePopup() {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().HidePopup(this, [](ContentAutofillDriver* target) {
     DCHECK(!target->IsPrerendering())
         << "We should never affect UI while prerendering";
@@ -514,8 +522,9 @@
 }
 
 void ContentAutofillDriver::FocusNoLongerOnForm(bool had_interacted_form) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().FocusNoLongerOnForm(
       this, had_interacted_form,
       [](ContentAutofillDriver* target, bool had_interacted_form) {
@@ -526,8 +535,9 @@
 void ContentAutofillDriver::FocusOnFormField(const FormData& raw_form,
                                              const FormFieldData& raw_field,
                                              const gfx::RectF& bounding_box) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   FormData form = raw_form;
   FormFieldData field = raw_field;
   SetFrameAndFormMetaData(form, &field);
@@ -543,8 +553,9 @@
 
 void ContentAutofillDriver::DidFillAutofillFormData(const FormData& raw_form,
                                                     base::TimeTicks timestamp) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().DidFillAutofillFormData(
       this, GetFormWithFrameAndFormMetaData(raw_form), timestamp,
       [](ContentAutofillDriver* target, const FormData& form,
@@ -555,8 +566,9 @@
 }
 
 void ContentAutofillDriver::DidPreviewAutofillFormData() {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().DidPreviewAutofillFormData(
       this, [](ContentAutofillDriver* target) {
         target->autofill_manager_->OnDidPreviewAutofillFormData();
@@ -564,8 +576,9 @@
 }
 
 void ContentAutofillDriver::DidEndTextFieldEditing() {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().DidEndTextFieldEditing(
       this, [](ContentAutofillDriver* target) {
         target->autofill_manager_->OnDidEndTextFieldEditing();
@@ -574,8 +587,9 @@
 
 void ContentAutofillDriver::SelectFieldOptionsDidChange(
     const FormData& raw_form) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   autofill_router().SelectFieldOptionsDidChange(
       this, GetFormWithFrameAndFormMetaData(raw_form),
       [](ContentAutofillDriver* target, const FormData& form) {
@@ -588,8 +602,9 @@
     const FormData& raw_form,
     const FormFieldData& raw_field,
     const std::u16string& old_value) {
-  if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
+  if (!bad_message::CheckFrameNotPrerendering(render_frame_host())) {
     return;
+  }
   FormData form = raw_form;
   FormFieldData field = raw_field;
   SetFrameAndFormMetaData(form, &field);
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h
index 9576fba..9e9782e9 100644
--- a/components/autofill/content/browser/content_autofill_driver.h
+++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -131,7 +131,10 @@
   }
   AutofillManager* autofill_manager() { return autofill_manager_.get(); }
 
-  content::RenderFrameHost* render_frame_host() { return render_frame_host_; }
+  content::RenderFrameHost* render_frame_host() { return &*render_frame_host_; }
+  const content::RenderFrameHost* render_frame_host() const {
+    return &*render_frame_host_;
+  }
 
   // Expose the events that originate from the browser and renderer processes,
   // respectively.
@@ -312,9 +315,11 @@
   // not be using the router if we're prerendering).
   ContentAutofillRouter& autofill_router();
 
-  // Weak ref to the RenderFrameHost the driver is associated with. Should
-  // always be non-NULL and valid for lifetime of |this|.
-  const raw_ptr<content::RenderFrameHost> render_frame_host_ = nullptr;
+  // The frame/document to which this driver is associated. Outlives `this`.
+  // RFH is corresponds to neither a frame nor a document: it may survive
+  // navigations that documents don't, but it may not survive cross-origin
+  // navigations.
+  const raw_ref<content::RenderFrameHost> render_frame_host_;
 
   // The factory that created this driver. Outlives `this`.
   const raw_ref<ContentAutofillDriverFactory> owner_;
@@ -328,8 +333,6 @@
   // to avoid duplicates fired by AutofillAgent.
   std::set<FormGlobalId> submitted_forms_;
 
-  // AutofillManager instance via which this object drives the shared Autofill
-  // code.
   std::unique_ptr<AutofillManager> autofill_manager_ = nullptr;
 
   content::RenderWidgetHost::KeyPressEventCallback key_press_handler_;
diff --git a/components/autofill/content/browser/content_autofill_router.cc b/components/autofill/content/browser/content_autofill_router.cc
index 784f6568..31b3cfa3 100644
--- a/components/autofill/content/browser/content_autofill_router.cc
+++ b/components/autofill/content/browser/content_autofill_router.cc
@@ -191,9 +191,10 @@
 // Calls TriggerReparse() on all ContentAutofillDrivers in |form_forest_| as
 // well as their ancestor ContentAutofillDrivers.
 //
-// An ancestor might not be contained in the form tree itself: if the ancestor
-// contained only invisible iframe(s) and no interesting fields, it would not be
-// sent to the browser. In the meantime, these frames may have become visible.
+// An ancestor might not be contained in the form tree known to FormForest: if
+// the ancestor contained only invisible iframe(s) and no interesting fields, it
+// would not be sent to the browser. In the meantime, these frames may have
+// become visible. Therefore, we also call TriggerReparse() in all ancestors.
 //
 // The typical use case is that some frame triggers reparses on its own
 // initiative and triggers an event. Then ContentAutofillRouter's event handler
@@ -201,16 +202,18 @@
 void ContentAutofillRouter::TriggerReparseExcept(
     ContentAutofillDriver* exception) {
   DCHECK(base::FeatureList::IsEnabled(features::kAutofillAcrossIframes));
-
   base::flat_set<AutofillDriver*> already_triggered;
   ForEachFrame(form_forest_, [&](AutofillDriver* driver) mutable {
     do {
-      // Trigger reparse for |driver| and all its ancestors (as some ancestors
-      // may not be in the forest).
-      if (driver != exception && !base::Contains(already_triggered, driver)) {
-        driver->TriggerReparse();
-        already_triggered.insert(driver);
+      if (!already_triggered.insert(driver).second) {
+        // An earlier invocation of this lambda has executed the rest of this
+        // loop's body for `driver` and hence also for all its ancestors.
+        break;
       }
+      if (driver == exception) {
+        continue;
+      }
+      driver->TriggerReparse();
     } while ((driver = driver->GetParent()) != nullptr);
   });
 }
diff --git a/components/autofill/content/browser/form_forest.cc b/components/autofill/content/browser/form_forest.cc
index aab85c4e..3e5a529d 100644
--- a/components/autofill/content/browser/form_forest.cc
+++ b/components/autofill/content/browser/form_forest.cc
@@ -619,19 +619,12 @@
       auto it = field_type_map.find(field.global_id());
       ServerFieldType field_type =
           it != field_type_map.end() ? it->second : UNKNOWN_TYPE;
-      if (features::kAutofillSharedAutofillRelaxedParam.Get()) {
-        return field.origin == triggered_origin ||
-               (HasSharedAutofillPermission(renderer_form->host_frame) &&
-                (field.origin != main_origin ||
-                 field_type != CREDIT_CARD_NUMBER));
-      } else {
-        return field.origin == triggered_origin ||
-               (field.origin == main_origin &&
-                HasSharedAutofillPermission(renderer_form->host_frame) &&
-                !IsSensitiveFieldType(field_type)) ||
-               (triggered_origin == main_origin &&
-                HasSharedAutofillPermission(renderer_form->host_frame));
-      }
+      return field.origin == triggered_origin ||
+             (field.origin == main_origin &&
+              !IsSensitiveFieldType(field_type) &&
+              HasSharedAutofillPermission(renderer_form->host_frame)) ||
+             (triggered_origin == main_origin &&
+              HasSharedAutofillPermission(renderer_form->host_frame));
     };
 
     renderer_form->fields.push_back(browser_field);
diff --git a/components/autofill/content/browser/form_forest.h b/components/autofill/content/browser/form_forest.h
index d786f9104..771b908 100644
--- a/components/autofill/content/browser/form_forest.h
+++ b/components/autofill/content/browser/form_forest.h
@@ -260,9 +260,8 @@
   // The |field_type_map| should contain the field types of the fields in
   // |browser_form|.
   //
-  // There are two modes that determine whether a field is *safe to fill*.
-  // By default, a field is safe to fill iff at least one of the conditions
-  // (1–3) and additionally condition (4) hold:
+  // A field is *safe to fill* iff at least one of the conditions (1–3) and
+  // additionally condition (4) hold:
   //
   // (1) The field's origin is the |triggered_origin|.
   // (2) The field's origin is the main origin, the field's type in
@@ -271,16 +270,8 @@
   //     frame.
   // (3) The |triggered_origin| is the main origin and the policy-controlled
   //     feature shared-autofill is enabled in the field's frame.
-  // (4) No frame on the shortest path from the field on which Autofill was
-  //     triggered to the field in question, except perhaps the shallowest
-  //     frame, is a fenced frame.
-  //
-  // If the Finch parameter relax_shared_autofill is true, the restriction to
-  // the main origin in condition 3 is lifted. Thus, conditions (2) and (3)
-  // reduce to the following:
-  //
-  // (2+3) The policy-controlled feature shared-autofill is enabled in the
-  //       field's document.
+  // (4) The field is in the same frame tree as the field on which Autofill was
+  //     triggered.
   //
   // The *origin of a field* is the origin of the frame that contains the
   // corresponding form-control element.
diff --git a/components/autofill/content/browser/form_forest_unittest.cc b/components/autofill/content/browser/form_forest_unittest.cc
index 8c1c6b3..d70f58c 100644
--- a/components/autofill/content/browser/form_forest_unittest.cc
+++ b/components/autofill/content/browser/form_forest_unittest.cc
@@ -318,13 +318,6 @@
   // FormForest::GetBrowserForm() for details).
   enum class Policy { kDefault, kSharedAutofill, kNoSharedAutofill };
 
-  explicit FormForestTest(bool relax_shared_autofill = false) {
-    feature_list_.InitAndEnableFeatureWithParameters(
-        features::kAutofillSharedAutofill,
-        {{features::kAutofillSharedAutofillRelaxedParam.name,
-          relax_shared_autofill ? "true" : "false"}});
-  }
-
   void SetUp() override {
     RenderViewHostTestHarness::SetUp();
     CHECK(kOpaqueOrigin.opaque());
@@ -423,7 +416,8 @@
         /*matches_opaque_src=*/false)};
   }
 
-  base::test::ScopedFeatureList feature_list_;
+  base::test::ScopedFeatureList feature_list_{
+      features::kAutofillSharedAutofill};
   test::AutofillUnitTestEnvironment autofill_test_environment_;
   TestAutofillClientInjector<TestContentAutofillClient>
       autofill_client_injector_;
@@ -463,10 +457,6 @@
     size_t count = base::dynamic_extent;
   };
 
-  explicit FormForestTestWithMockedTree(bool relax_shared_autofill = false)
-      : FormForestTest(
-            /*relax_shared_autofill=*/relax_shared_autofill) {}
-
   void TearDown() override {
     TestApi(mocked_forms_).Reset();
     TestApi(flattened_forms_).Reset();
@@ -1445,11 +1435,6 @@
 // Tests of FormForest::GetRendererFormsOfBrowserForm().
 
 class FormForestTestUnflatten : public FormForestTestWithMockedTree {
- public:
-  explicit FormForestTestUnflatten(bool relax_shared_autofill = false)
-      : FormForestTestWithMockedTree(
-            /*relax_shared_autofill=*/relax_shared_autofill) {}
-
  protected:
   // The subject of this test fixture.
   std::vector<FormData> GetRendererFormsOfBrowserForm(
@@ -1622,17 +1607,9 @@
 }
 
 // Fixture for the shared-autofill policy tests.
-// The parameter controls the value of relax_shared_autofill.
 class FormForestTestUnflattenSharedAutofillPolicy
-    : public FormForestTestUnflatten,
-      public ::testing::WithParamInterface<bool> {
+    : public FormForestTestUnflatten {
  public:
-  FormForestTestUnflattenSharedAutofillPolicy()
-      : FormForestTestUnflatten(
-            /*relax_shared_autofill=*/relax_shared_autofill()) {}
-
-  bool relax_shared_autofill() const { return GetParam(); }
-
   void SetUp() override {
     FormForestTestUnflatten::SetUp();
     MockFormForest(
@@ -1649,7 +1626,7 @@
 };
 
 // Tests filling into frames with shared-autofill policy from the main origin.
-TEST_P(FormForestTestUnflattenSharedAutofillPolicy, FromMainOrigin) {
+TEST_F(FormForestTestUnflattenSharedAutofillPolicy, FromMainOrigin) {
   MockFlattening({{"main"}, {"disallowed"}, {"allowed"}});
   std::vector<FormData> expectation = {
       WithValues(GetMockedForm("main"), Profile(0)),
@@ -1660,18 +1637,12 @@
 }
 
 // Tests filling into frames with shared-autofill policy from the main origin.
-TEST_P(FormForestTestUnflattenSharedAutofillPolicy, FromOtherOrigin) {
+TEST_F(FormForestTestUnflattenSharedAutofillPolicy, FromOtherOrigin) {
   MockFlattening({{"main"}, {"disallowed"}, {"allowed"}});
-  std::vector<FormData> expectation;
-  if (!relax_shared_autofill()) {
-    expectation = {WithoutValues(GetMockedForm("main")),
-                   WithValues(GetMockedForm("disallowed"), Profile(1)),
-                   WithoutValues(GetMockedForm("allowed"))};
-  } else {
-    expectation = {WithValues(GetMockedForm("main"), Profile(0)),
-                   WithValues(GetMockedForm("disallowed"), Profile(1)),
-                   WithValues(GetMockedForm("allowed"), Profile(2))};
-  }
+  std::vector<FormData> expectation = {
+      WithoutValues(GetMockedForm("main")),
+      WithValues(GetMockedForm("disallowed"), Profile(1)),
+      WithoutValues(GetMockedForm("allowed"))};
   EXPECT_THAT(GetRendererFormsOfBrowserForm("main", Origin(kOtherUrl), {}),
               UnorderedArrayEquals(expectation));
 }
@@ -1746,10 +1717,6 @@
   EXPECT_EQ(num_equals_calls_, GetParam().expected_comparisons);
 }
 
-INSTANTIATE_TEST_SUITE_P(FormForestTest,
-                         FormForestTestUnflattenSharedAutofillPolicy,
-                         testing::Bool());
-
 INSTANTIATE_TEST_SUITE_P(
     FormForestTest,
     ForEachInSetDifferenceTest,
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc
index bfce095..5d30b998 100644
--- a/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -200,7 +200,7 @@
 
   // Only preview the data if it is a profile or a virtual card.
   if (frontend_id.as_int() > 0) {
-    FillAutofillFormData(frontend_id, true,
+    FillAutofillFormData(frontend_id, backend_id, true,
                          AutofillTriggerSource::kKeyboardAccessory);
   } else if (frontend_id == PopupItemId::kAutocompleteEntry ||
              frontend_id == PopupItemId::kIbanEntry ||
@@ -298,8 +298,9 @@
         autofill_metrics::LogAutofillSuggestionAcceptedIndex(
             position, popup_type_, manager_->client()->IsOffTheRecord());
       }
-      FillAutofillFormData(suggestion.frontend_id, false,
-                           AutofillTriggerSource::kPopup);
+      FillAutofillFormData(suggestion.frontend_id,
+                           suggestion.GetPayload<Suggestion::BackendId>(),
+                           false, AutofillTriggerSource::kPopup);
       break;
   }
 
@@ -321,16 +322,19 @@
 bool AutofillExternalDelegate::GetDeletionConfirmationText(
     const std::u16string& value,
     Suggestion::FrontendId frontend_id,
+    Suggestion::BackendId backend_id,
     std::u16string* title,
     std::u16string* body) {
-  return manager_->GetDeletionConfirmationText(value, frontend_id, title, body);
+  return manager_->GetDeletionConfirmationText(value, frontend_id, backend_id,
+                                               title, body);
 }
 
 bool AutofillExternalDelegate::RemoveSuggestion(
     const std::u16string& value,
-    Suggestion::FrontendId frontend_id) {
+    Suggestion::FrontendId frontend_id,
+    Suggestion::BackendId backend_id) {
   if (frontend_id.as_int() > 0) {
-    return manager_->RemoveAutofillProfileOrCreditCard(frontend_id);
+    return manager_->RemoveAutofillProfileOrCreditCard(backend_id);
   }
 
   if (frontend_id == PopupItemId::kAutocompleteEntry) {
@@ -386,12 +390,14 @@
 }
 
 void AutofillExternalDelegate::FillAutofillFormData(
-    Suggestion::FrontendId unique_id,
+    Suggestion::FrontendId frontend_id,
+    Suggestion::BackendId backend_id,
     bool is_preview,
     const AutofillTriggerSource trigger_source) {
   // If the selected element is a warning we don't want to do anything.
-  if (IsAutofillWarningEntry(unique_id))
+  if (IsAutofillWarningEntry(frontend_id)) {
     return;
+  }
 
   mojom::RendererFormDataAction renderer_action =
       is_preview ? mojom::RendererFormDataAction::kPreview
@@ -400,7 +406,7 @@
   DCHECK(driver_->RendererIsAvailable());
   // Fill the values for the whole form.
   manager_->FillOrPreviewForm(renderer_action, query_form_, query_field_,
-                              unique_id, trigger_source);
+                              backend_id, trigger_source);
 }
 
 void AutofillExternalDelegate::PossiblyRemoveAutofillWarnings(
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h
index 5dac03a..3798f420 100644
--- a/components/autofill/core/browser/autofill_external_delegate.h
+++ b/components/autofill/core/browser/autofill_external_delegate.h
@@ -54,10 +54,12 @@
   void DidAcceptSuggestion(const Suggestion& suggestion, int position) override;
   bool GetDeletionConfirmationText(const std::u16string& value,
                                    Suggestion::FrontendId frontend_id,
+                                   Suggestion::BackendId backend_id,
                                    std::u16string* title,
                                    std::u16string* body) override;
   bool RemoveSuggestion(const std::u16string& value,
-                        Suggestion::FrontendId frontend_id) override;
+                        Suggestion::FrontendId frontend_id,
+                        Suggestion::BackendId backend_id) override;
   void ClearPreviewedForm() override;
 
   // Returns PopupType::kUnspecified for all popups prior to |onQuery|, or the
@@ -125,11 +127,12 @@
   void OnCreditCardScanned(const AutofillTriggerSource trigger_source,
                            const CreditCard& card);
 
-  // Fills the form with the Autofill data corresponding to |unique_id|.
-  // If |is_preview| is true then this is just a preview to show the user what
-  // would be selected and if |is_preview| is false then the user has selected
+  // Fills the form with the Autofill data corresponding to `backend_id`.
+  // If `is_preview` is true then this is just a preview to show the user what
+  // would be selected and if `is_preview` is false then the user has selected
   // this data.
-  void FillAutofillFormData(Suggestion::FrontendId unique_id,
+  void FillAutofillFormData(Suggestion::FrontendId frontend_id,
+                            Suggestion::BackendId backend_id,
                             bool is_preview,
                             const AutofillTriggerSource trigger_source);
 
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index 28c1ce0..905baf6 100644
--- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -154,7 +154,7 @@
               (mojom::RendererFormDataAction action,
                const FormData& form,
                const FormFieldData& field,
-               Suggestion::FrontendId unique_id,
+               Suggestion::BackendId backend_id,
                const AutofillTriggerSource trigger_source),
               (override));
   MOCK_METHOD(void,
@@ -684,9 +684,9 @@
   EXPECT_CALL(autofill_client_,
               HideAutofillPopup(PopupHidingReason::kAcceptSuggestion));
   std::u16string dummy_string(u"John Legend");
-  EXPECT_CALL(*browser_autofill_manager_,
-              FillOrPreviewForm(mojom::RendererFormDataAction::kFill, _, _,
-                                kAutofillProfileId, _));
+  EXPECT_CALL(
+      *browser_autofill_manager_,
+      FillOrPreviewForm(mojom::RendererFormDataAction::kFill, _, _, _, _));
 
   external_delegate_->DidAcceptSuggestion(
       test::CreateAutofillSuggestion(kAutofillProfileId, dummy_string),
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index f8dbd93f..a8bc68d6 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -80,6 +80,7 @@
 #include "components/autofill/core/browser/suggestions_context.h"
 #include "components/autofill/core/browser/ui/payments/bubble_show_options.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
+#include "components/autofill/core/browser/ui/suggestion.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autocomplete_parsing_util.h"
 #include "components/autofill/core/common/autofill_clock.h"
@@ -1341,7 +1342,7 @@
     mojom::RendererFormDataAction action,
     const FormData& form,
     const FormFieldData& field,
-    Suggestion::FrontendId unique_id,
+    Suggestion::BackendId backend_id,
     const AutofillTriggerSource trigger_source) {
   if (!IsValidFormData(form) || !IsValidFormFieldData(field))
     return;
@@ -1351,8 +1352,8 @@
   if (!RefreshDataModels() || !driver()->RendererIsAvailable())
     return;
 
-  const AutofillProfile* profile = GetProfile(unique_id);
-  const CreditCard* credit_card = GetCreditCard(unique_id);
+  const AutofillProfile* profile = GetProfile(backend_id);
+  const CreditCard* credit_card = GetCreditCard(backend_id);
 
   if (credit_card) {
     FillOrPreviewCreditCardForm(action, form, field, credit_card,
@@ -1566,6 +1567,7 @@
 bool BrowserAutofillManager::GetDeletionConfirmationText(
     const std::u16string& value,
     Suggestion::FrontendId identifier,
+    Suggestion::BackendId backend_id,
     std::u16string* title,
     std::u16string* body) {
   if (identifier == PopupItemId::kAutocompleteEntry) {
@@ -1583,8 +1585,8 @@
     return false;
   }
 
-  const CreditCard* credit_card = GetCreditCard(identifier);
-  const AutofillProfile* profile = GetProfile(identifier);
+  const CreditCard* credit_card = GetCreditCard(backend_id);
+  const AutofillProfile* profile = GetProfile(backend_id);
 
   if (credit_card) {
     return credit_card_access_manager_->GetDeletionConfirmationText(
@@ -1614,13 +1616,13 @@
 }
 
 bool BrowserAutofillManager::RemoveAutofillProfileOrCreditCard(
-    Suggestion::FrontendId unique_id) {
-  const CreditCard* credit_card = GetCreditCard(unique_id);
+    Suggestion::BackendId backend_id) {
+  const CreditCard* credit_card = GetCreditCard(backend_id);
   if (credit_card) {
     return credit_card_access_manager_->DeleteCard(credit_card);
   }
 
-  const AutofillProfile* profile = GetProfile(unique_id);
+  const AutofillProfile* profile = GetProfile(backend_id);
   if (profile) {
     bool is_local = profile->record_type() == AutofillProfile::LOCAL_PROFILE;
     if (is_local)
@@ -2134,19 +2136,14 @@
 }
 
 CreditCard* BrowserAutofillManager::GetCreditCard(
-    Suggestion::FrontendId unique_id) {
-  Suggestion::BackendId credit_card_id =
-      suggestion_generator_->GetBackendIdFromFrontendId(unique_id);
+    Suggestion::BackendId unique_id) {
   return client()->GetPersonalDataManager()->GetCreditCardByGUID(
-      credit_card_id.value());
+      unique_id.value());
 }
 
 AutofillProfile* BrowserAutofillManager::GetProfile(
-    Suggestion::FrontendId unique_id) {
-  Suggestion::BackendId profile_id =
-      suggestion_generator_->GetBackendIdFromFrontendId(unique_id);
-
-  std::string guid = profile_id.value();
+    Suggestion::BackendId unique_id) {
+  std::string guid = unique_id.value();
   if (base::Uuid::ParseCaseInsensitive(guid).is_valid()) {
     return client()->GetPersonalDataManager()->GetProfileByGUID(guid);
   }
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h
index eecd7ab..4957fff 100644
--- a/components/autofill/core/browser/browser_autofill_manager.h
+++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -147,7 +147,7 @@
   virtual void FillOrPreviewForm(mojom::RendererFormDataAction action,
                                  const FormData& form,
                                  const FormFieldData& field,
-                                 Suggestion::FrontendId unique_id,
+                                 Suggestion::BackendId backend_id,
                                  const AutofillTriggerSource trigger_source);
   void FillCreditCardFormImpl(const FormData& form,
                               const FormFieldData& field,
@@ -190,12 +190,13 @@
   // |title| and |body| with relevant user-facing text.
   bool GetDeletionConfirmationText(const std::u16string& value,
                                    Suggestion::FrontendId identifier,
+                                   Suggestion::BackendId backend_id,
                                    std::u16string* title,
                                    std::u16string* body);
 
-  // Remove the credit card or Autofill profile that matches |unique_id|
+  // Remove the credit card or Autofill profile that matches |backend_id|
   // from the database. Returns true if deletion is allowed.
-  bool RemoveAutofillProfileOrCreditCard(Suggestion::FrontendId unique_id);
+  bool RemoveAutofillProfileOrCreditCard(Suggestion::BackendId backend_id);
 
   // Remove the specified suggestion from single field filling. |frontend_id| is
   // the PopupItemId of the suggestion.
@@ -523,15 +524,14 @@
   // Returns false if Autofill is disabled or if no Autofill data is available.
   bool RefreshDataModels();
 
-  // TODO(crbug.com/1249665): Change unique_id to frontend_id and move the
-  // functions to AutofillSuggestionGenerator.
+  // TODO(crbug.com/1249665): Move the functions to AutofillSuggestionGenerator.
   // Gets the card referred to by the guid |unique_id|. Returns |nullptr| if
   // card does not exist.
-  CreditCard* GetCreditCard(Suggestion::FrontendId unique_id);
+  CreditCard* GetCreditCard(Suggestion::BackendId unique_id);
 
   // Gets the profile referred to by the guid |unique_id|. Returns |nullptr| if
   // profile does not exist.
-  AutofillProfile* GetProfile(Suggestion::FrontendId unique_id);
+  AutofillProfile* GetProfile(Suggestion::BackendId unique_id);
 
   // Determines whether a fill on |form| initiated from |triggered_field| will
   // wind up filling a credit card number. This is useful to determine if we
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index cd13cec4..7b32b21 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -739,13 +739,13 @@
 
   void FillAutofillFormData(const FormData& form,
                             const FormFieldData& field,
-                            Suggestion::FrontendId unique_id) {
+                            std::string guid) {
     browser_autofill_manager_->OnAskForValuesToFill(
         form, field, {}, AutoselectFirstSuggestion(true),
         FormElementWasClicked(false));
     browser_autofill_manager_->FillOrPreviewForm(
-        mojom::RendererFormDataAction::kFill, form, field, unique_id,
-        AutofillTriggerSource::kPopup);
+        mojom::RendererFormDataAction::kFill, form, field,
+        Suggestion::BackendId(guid), AutofillTriggerSource::kPopup);
   }
 
   // Calls |browser_autofill_manager_->OnFillAutofillFormData()| with the
@@ -754,12 +754,12 @@
   // parameter of that call into the |response_data| output parameter.
   void FillAutofillFormDataAndSaveResults(const FormData& input_form,
                                           const FormFieldData& input_field,
-                                          Suggestion::FrontendId unique_id,
+                                          std::string guid,
                                           FormData* response_data) {
     EXPECT_CALL(*autofill_driver_, FillOrPreviewForm(_, _, _, _))
         .WillOnce(DoAll(testing::SaveArg<1>(response_data),
                         testing::Return(std::vector<FieldGlobalId>{})));
-    FillAutofillFormData(input_form, input_field, unique_id);
+    FillAutofillFormData(input_form, input_field, guid);
   }
 
   void PreviewVirtualCardDataAndSaveResults(
@@ -2771,8 +2771,7 @@
 
   FormData response_data;
   FillAutofillFormDataAndSaveResults(form, form.fields[index_of_trigger_field],
-                                     MakeFrontendId({.profile_id = guid}),
-                                     &response_data);
+                                     guid, &response_data);
   // Extract the sections into individual forms to reduce boiler plate code.
   size_t mid = response_data.fields.size() / 2;
   FormData section1 = response_data;
@@ -3551,8 +3550,7 @@
   EXPECT_NE(base::Time(), profile->use_date());
 
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 
@@ -3620,8 +3618,7 @@
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
   base::HistogramTester histogram_tester;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   // Cardholder name, card number, expiration data were autofilled but cvc was
   // not be autofilled.
@@ -3637,8 +3634,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 }
@@ -3661,8 +3657,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000008";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 }
@@ -3686,8 +3681,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000009";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 }
@@ -3711,8 +3705,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000007";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
                    card_fill_data);
@@ -3736,8 +3729,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000007";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
                    card_fill_data);
@@ -3762,8 +3754,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000007";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
                    card_fill_data);
@@ -3786,8 +3777,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000007";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledForm(response_data, /*address_fill_data=*/absl::nullopt,
                    card_fill_data);
@@ -3823,8 +3813,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledField("Card Name", "cardname", "Elvis", "text",
                     response_data.fields[0]);
@@ -3873,8 +3862,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledField("Card Name", "cardname", "Elvis", "text",
                     response_data.fields[0]);
@@ -3922,8 +3910,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledField("Card Name", "cardname", "Elvis", "text",
                     response_data.fields[0]);
@@ -3970,8 +3957,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledField("Card Name", "cardname", "Elvis", "text",
                     response_data.fields[0]);
@@ -4045,8 +4031,7 @@
   personal_data().AddProfile(profile);
 
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
 
   // Verify the correct filling of the name entries.
@@ -4095,8 +4080,7 @@
   FormData response_data;
   {
     SCOPED_TRACE("Address");
-    FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                       MakeFrontendId({.profile_id = guid}),
+    FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                        &response_data);
     ExpectFilledAddressFormElvis(response_data, true);
   }
@@ -4104,9 +4088,8 @@
   // Now fill the credit card data.
   const char guid2[] = "00000000-0000-0000-0000-000000000004";
   {
-    FillAutofillFormDataAndSaveResults(
-        form, form.fields.back(), MakeFrontendId({.credit_card_id = guid2}),
-        &response_data);
+    FillAutofillFormDataAndSaveResults(form, form.fields.back(), guid2,
+                                       &response_data);
     SCOPED_TRACE("Credit card");
     ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/true);
   }
@@ -4228,8 +4211,7 @@
   FormData response_data;
   FillAutofillFormDataAndSaveResults(
       form, form.fields[0],
-      MakeFrontendId({.credit_card_id = params.cc_guid,
-                      .profile_id = params.profile_guid}),
+      params.cc_guid.empty() ? params.profile_guid : params.cc_guid,
       &response_data);
 
   ASSERT_EQ(response_data.fields.size(), params.expected_form_fields.size());
@@ -4262,8 +4244,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
 
   // All fields should be filled.
@@ -4310,8 +4291,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000009";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
 
   // The credit card name, type and number should be filled.
@@ -4397,8 +4377,7 @@
   // Fill the form
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
 
   // All the visible fields should be filled as all the fields belong to the
@@ -4433,8 +4412,7 @@
   // Fill the first section.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   {
     SCOPED_TRACE("Address 1");
@@ -4454,8 +4432,7 @@
   const char guid2[] = "00000000-0000-0000-0000-000000000001";
   ASSERT_LT(9U, kAddressFormSize);
   FillAutofillFormDataAndSaveResults(form, form.fields[kAddressFormSize + 9],
-                                     MakeFrontendId({.profile_id = guid2}),
-                                     &response_data);
+                                     guid2, &response_data);
   {
     SCOPED_TRACE("Address 2");
     ASSERT_EQ(response_data.fields.size(), form.fields.size());
@@ -4538,8 +4515,7 @@
   // Fill the unnamed section.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[1],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[1], guid,
                                      &response_data);
   {
     SCOPED_TRACE("Unnamed section");
@@ -4566,8 +4542,7 @@
 
   // Fill the address portion of the billing section.
   const char guid2[] = "00000000-0000-0000-0000-000000000001";
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid2}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid2,
                                      &response_data);
   {
     SCOPED_TRACE("Billing address");
@@ -4594,8 +4569,7 @@
   // Fill the credit card portion of the billing section.
   const char guid3[] = "00000000-0000-0000-0000-000000000004";
   FillAutofillFormDataAndSaveResults(form, form.fields[form.fields.size() - 2],
-                                     MakeFrontendId({.credit_card_id = guid3}),
-                                     &response_data);
+                                     guid3, &response_data);
   {
     SCOPED_TRACE("Credit card");
     EXPECT_EQ(u"MyForm", response_data.name);
@@ -4634,8 +4608,7 @@
   // Fill the form.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
 
   // The second email address should be filled.
@@ -4662,8 +4635,7 @@
   // First fill the address data.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   {
     SCOPED_TRACE("Address");
@@ -4675,8 +4647,7 @@
 
   // Now fill the credit card data.
   const char guid2[] = "00000000-0000-0000-0000-000000000004";
-  FillAutofillFormDataAndSaveResults(form, form.fields.back(),
-                                     MakeFrontendId({.credit_card_id = guid2}),
+  FillAutofillFormDataAndSaveResults(form, form.fields.back(), guid2,
                                      &response_data);
   {
     SCOPED_TRACE("Credit card 1");
@@ -4690,8 +4661,7 @@
   }
 
   FillAutofillFormDataAndSaveResults(form, form.fields[form.fields.size() - 2],
-                                     MakeFrontendId({.credit_card_id = guid2}),
-                                     &response_data);
+                                     guid2, &response_data);
   {
     SCOPED_TRACE("Credit card 2");
     TestCardFillData expected_card_fill_data = kEmptyCardFillData;
@@ -4719,8 +4689,7 @@
   // First fill the address data.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   {
     SCOPED_TRACE("Address");
@@ -4738,8 +4707,7 @@
 
   // Now fill the credit card data.
   const char guid2[] = "00000000-0000-0000-0000-000000000004";
-  FillAutofillFormDataAndSaveResults(form, form.fields.back(),
-                                     MakeFrontendId({.credit_card_id = guid2}),
+  FillAutofillFormDataAndSaveResults(form, form.fields.back(), guid2,
                                      &response_data);
   {
     SCOPED_TRACE("Credit card 1");
@@ -4770,8 +4738,7 @@
   // First fill the address data.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   {
     SCOPED_TRACE("Address");
@@ -4783,8 +4750,7 @@
 
   // Now fill the credit card data.
   const char guid2[] = "00000000-0000-0000-0000-000000000004";
-  FillAutofillFormDataAndSaveResults(form, form.fields.back(),
-                                     MakeFrontendId({.credit_card_id = guid2}),
+  FillAutofillFormDataAndSaveResults(form, form.fields.back(), guid2,
                                      &response_data);
   {
     SCOPED_TRACE("Credit card 1");
@@ -4849,8 +4815,7 @@
   FormData response_data1;
   FillAutofillFormDataAndSaveResults(
       form_with_us_number_max_length,
-      *form_with_us_number_max_length.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data1);
+      *form_with_us_number_max_length.fields.begin(), guid, &response_data1);
 
   ASSERT_EQ(5U, response_data1.fields.size());
   EXPECT_EQ(u"1", response_data1.fields[0].value);
@@ -4860,9 +4825,9 @@
   EXPECT_EQ(std::u16string(), response_data1.fields[4].value);
 
   FormData response_data2;
-  FillAutofillFormDataAndSaveResults(
-      form_with_autocompletetype, *form_with_autocompletetype.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data2);
+  FillAutofillFormDataAndSaveResults(form_with_autocompletetype,
+                                     *form_with_autocompletetype.fields.begin(),
+                                     guid, &response_data2);
 
   ASSERT_EQ(5U, response_data2.fields.size());
   EXPECT_EQ(u"1", response_data2.fields[0].value);
@@ -4877,8 +4842,7 @@
   FormData response_data3;
   FillAutofillFormDataAndSaveResults(
       form_with_us_number_max_length,
-      *form_with_us_number_max_length.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data3);
+      *form_with_us_number_max_length.fields.begin(), guid, &response_data3);
 
   ASSERT_EQ(5U, response_data3.fields.size());
   EXPECT_EQ(u"4", response_data3.fields[0].value);
@@ -4888,9 +4852,9 @@
   EXPECT_EQ(std::u16string(), response_data3.fields[4].value);
 
   FormData response_data4;
-  FillAutofillFormDataAndSaveResults(
-      form_with_autocompletetype, *form_with_autocompletetype.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data4);
+  FillAutofillFormDataAndSaveResults(form_with_autocompletetype,
+                                     *form_with_autocompletetype.fields.begin(),
+                                     guid, &response_data4);
 
   ASSERT_EQ(5U, response_data4.fields.size());
   EXPECT_EQ(u"44", response_data4.fields[0].value);
@@ -4945,8 +4909,8 @@
   FormData response_data;
   FillAutofillFormDataAndSaveResults(
       form_with_multiple_componentized_phone_fields,
-      *form_with_multiple_componentized_phone_fields.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data);
+      *form_with_multiple_componentized_phone_fields.fields.begin(), guid,
+      &response_data);
 
   // Verify only the first complete set of phone number fields are filled.
   ASSERT_EQ(8U, response_data.fields.size());
@@ -4991,8 +4955,8 @@
   FormData response_data;
   FillAutofillFormDataAndSaveResults(
       form_with_multiple_whole_number_fields,
-      *form_with_multiple_whole_number_fields.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data);
+      *form_with_multiple_whole_number_fields.fields.begin(), guid,
+      &response_data);
 
   // Verify only the first complete set of phone number fields are filled.
   ASSERT_EQ(4U, response_data.fields.size());
@@ -5048,8 +5012,8 @@
   FormData response_data;
   FillAutofillFormDataAndSaveResults(
       form_with_multiple_componentized_phone_fields,
-      *form_with_multiple_componentized_phone_fields.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data);
+      *form_with_multiple_componentized_phone_fields.fields.begin(), guid,
+      &response_data);
 
   // Verify only the first complete set of phone number fields are filled,
   // and phone components are not filled more than once.
@@ -5105,8 +5069,7 @@
   FormData response_data;
   FillAutofillFormDataAndSaveResults(
       form_with_misclassified_extension,
-      *form_with_misclassified_extension.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data);
+      *form_with_misclassified_extension.fields.begin(), guid, &response_data);
 
   // Verify the misclassified extension field is not filled.
   ASSERT_EQ(5U, response_data.fields.size());
@@ -5154,8 +5117,7 @@
   FormData response_data;
   FillAutofillFormDataAndSaveResults(
       form_with_no_complete_number,
-      *form_with_no_complete_number.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data);
+      *form_with_no_complete_number.fields.begin(), guid, &response_data);
 
   // Verify when there is no complete phone number fields, we do best effort
   // filling.
@@ -5202,8 +5164,7 @@
   // Move it to point to "shipping number".
   std::advance(it, 3);
   FillAutofillFormDataAndSaveResults(form_with_multiple_whole_number_fields,
-                                     *it, MakeFrontendId({.profile_id = guid}),
-                                     &response_data);
+                                     *it, guid, &response_data);
 
   // Verify when the second phone number field is being focused, we fill
   // that field *AND* the first phone number field.
@@ -5248,8 +5209,8 @@
   FormData response_data;
   FillAutofillFormDataAndSaveResults(
       form_with_multiple_whole_number_fields,
-      *form_with_multiple_whole_number_fields.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data);
+      *form_with_multiple_whole_number_fields.fields.begin(), guid,
+      &response_data);
 
   // Verify hidden/non-focusable phone field is set to only_fill_when_focused.
   ASSERT_EQ(4U, response_data.fields.size());
@@ -5309,8 +5270,7 @@
   FormData response_data;
   base::HistogramTester histogram_tester;
 
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   histogram_tester.ExpectTotalCount(
       "Autofill.HiddenOrPresentationalSelectFieldsFilled", 2);
@@ -5373,7 +5333,7 @@
   // Fill first sections.
   FillAutofillFormDataAndSaveResults(
       form_with_multiple_sections, *form_with_multiple_sections.fields.begin(),
-      MakeFrontendId({.profile_id = guid}), &response_data);
+      guid, &response_data);
 
   // Verify first section is filled with rationalization.
   ASSERT_EQ(9U, response_data.fields.size());
@@ -5391,8 +5351,7 @@
   auto it = form_with_multiple_sections.fields.begin();
   std::advance(it, 6);  // Pointing to second section.
 
-  FillAutofillFormDataAndSaveResults(form_with_multiple_sections, *it,
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form_with_multiple_sections, *it, guid,
                                      &response_data);
 
   // Verify second section is filled with rationalization.
@@ -5428,8 +5387,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 }
@@ -5457,8 +5415,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 }
@@ -5497,8 +5454,7 @@
   // filled.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
 
   ASSERT_EQ(5U, response_data.fields.size());
@@ -5522,8 +5478,7 @@
   FormData later_response_data;
   const char guid2[] = "00000000-0000-0000-0000-000000000002";
   FillAutofillFormDataAndSaveResults(response_data, response_data.fields[4],
-                                     MakeFrontendId({.profile_id = guid2}),
-                                     &later_response_data);
+                                     guid2, &later_response_data);
   ASSERT_EQ(5U, later_response_data.fields.size());
   ExpectFilledField("First Name", "first_name", "Elvis", "text",
                     later_response_data.fields[0]);
@@ -5547,8 +5502,7 @@
   // Fill the form.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 
@@ -5568,8 +5522,7 @@
   // Fill the form.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 
@@ -5683,8 +5636,7 @@
   // Fill the form.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 
@@ -5764,8 +5716,7 @@
   profile1.set_guid(guid);
   personal_data().AddProfile(profile1);
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
 
   TestAddressFillData expected_address_fill_data = address_fill_data;
@@ -5863,8 +5814,7 @@
   profile1.set_guid(guid);
   personal_data().AddProfile(profile1);
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
 
   TestAddressFillData expected_address_fill_data = address_fill_data;
@@ -5874,8 +5824,7 @@
   // Refill the address data with all the field values.
   const char guid2[] = "00000000-0000-0000-0000-000000000001";
   FillAutofillFormDataAndSaveResults(
-      response_data, *response_data.fields.begin(),
-      MakeFrontendId({.profile_id = guid2}), &response_data);
+      response_data, *response_data.fields.begin(), guid2, &response_data);
 
   expected_address_fill_data.first = "Elvis";
   expected_address_fill_data.phone = "12345678901";
@@ -5974,8 +5923,7 @@
   // Fill the form.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 
@@ -6059,8 +6007,7 @@
   // Fill the form by triggering the suggestion from "Name on Card" field.
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &response_data);
   ExpectFilledCreditCardFormElvis(response_data, /*has_address_fields=*/false);
 
@@ -6927,8 +6874,7 @@
   // Fill the form.
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   ExpectFilledAddressFormElvis(response_data, false);
 
@@ -6974,10 +6920,8 @@
 
   // Fill the form.
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(
-      form, form.fields[3], MakeFrontendId({.profile_id = kElvisProfileGuid}),
-      &response_data);
-
+  FillAutofillFormDataAndSaveResults(form, form.fields[3], kElvisProfileGuid,
+                                     &response_data);
   // Set the address field's value back to the default value.
   response_data.fields[3].value = u"Enter your address";
 
@@ -7004,9 +6948,8 @@
 
   // Fill the form.
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(
-      form, form.fields[3], MakeFrontendId({.profile_id = kElvisProfileGuid}),
-      &response_data);
+  FillAutofillFormDataAndSaveResults(form, form.fields[3], kElvisProfileGuid,
+                                     &response_data);
 
   FormSubmitted(response_data);
   ASSERT_EQ(1, personal_data().num_times_save_imported_profile_called());
@@ -7834,9 +7777,8 @@
   profile.set_guid(guid);
   personal_data().AddProfile(profile);
 
-  Suggestion::FrontendId id = MakeFrontendId({.profile_id = guid});
-
-  browser_autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
+  browser_autofill_manager_->RemoveAutofillProfileOrCreditCard(
+      Suggestion::BackendId(guid));
 
   EXPECT_FALSE(personal_data().GetProfileByGUID(guid));
 }
@@ -7848,9 +7790,8 @@
   credit_card.set_guid(guid);
   personal_data().AddCreditCard(credit_card);
 
-  Suggestion::FrontendId id = MakeFrontendId({.credit_card_id = guid});
-
-  browser_autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
+  browser_autofill_manager_->RemoveAutofillProfileOrCreditCard(
+      Suggestion::BackendId(guid));
 
   EXPECT_FALSE(personal_data().GetCreditCardByGUID(guid));
 }
@@ -8216,8 +8157,7 @@
   // Expect no fields filled, no form data sent to renderer.
   EXPECT_CALL(*autofill_driver_, FillOrPreviewForm(_, _, _, _)).Times(0);
 
-  FillAutofillFormData(form, *form.fields.begin(),
-                       MakeFrontendId({.profile_id = guid}));
+  FillAutofillFormData(form, *form.fields.begin(), guid);
 }
 
 TEST_F(BrowserAutofillManagerTest, ProfileDisabledDoesNotSuggest) {
@@ -8249,8 +8189,7 @@
   // Expect no fields filled, no form data sent to renderer.
   EXPECT_CALL(*autofill_driver_, FillOrPreviewForm(_, _, _, _)).Times(0);
 
-  FillAutofillFormData(form, *form.fields.begin(),
-                       MakeFrontendId({.credit_card_id = guid}));
+  FillAutofillFormData(form, *form.fields.begin(), guid);
 }
 
 TEST_F(BrowserAutofillManagerTest, CreditCardDisabledDoesNotSuggest) {
@@ -10046,8 +9985,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   EXPECT_EQ(response_data.fields[0].value, u"Elvis Aaron Presley");
   EXPECT_EQ(response_data.fields[1].value, u"Test City");
@@ -10094,8 +10032,7 @@
   features.InitAndDisableFeature(
       autofill::features::kAutofillPreventOverridingPrefilledValues);
 
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   EXPECT_EQ(response_data.fields[0].value, u"Elvis Aaron Presley");
   EXPECT_EQ(response_data.fields[1].value, u"Memphis");
@@ -10140,8 +10077,7 @@
 
   const char guid[] = "00000000-0000-0000-0000-000000000001";
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(form, form.fields[0],
-                                     MakeFrontendId({.profile_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], guid,
                                      &response_data);
   EXPECT_EQ(response_data.fields[0].value, u"Elvis Aaron Presley");
   EXPECT_EQ(response_data.fields[1].value, u"Test City");
@@ -10223,8 +10159,7 @@
 
   AutofillProfile profile = test::GetFullProfile();
   personal_data().AddProfile(profile);
-  FillAutofillFormData(form, form.fields[0],
-                       MakeFrontendId({.profile_id = profile.guid()}));
+  FillAutofillFormData(form, form.fields[0], profile.guid());
 
   FormStructure* form_structure =
       browser_autofill_manager_->FindCachedFormById(form.global_id());
@@ -10250,9 +10185,8 @@
   profile1.ClearFields({EMAIL_ADDRESS});
   personal_data().AddProfile(profile1);
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(
-      form, form.fields[0], MakeFrontendId({.profile_id = profile1.guid()}),
-      &response_data);
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], profile1.guid(),
+                                     &response_data);
 
   // Check that the email field has no filling source.
   FormStructure* form_structure =
@@ -10265,9 +10199,8 @@
   AutofillProfile profile2 = test::GetFullProfile();
   personal_data().AddProfile(profile2);
   FormData later_response_data;
-  FillAutofillFormDataAndSaveResults(
-      response_data, form.fields[3],
-      MakeFrontendId({.profile_id = profile2.guid()}), &later_response_data);
+  FillAutofillFormDataAndSaveResults(response_data, form.fields[3],
+                                     profile2.guid(), &later_response_data);
 
   // Check that the first three fields have the first profile as filling source
   // and the last field has the second profile.
@@ -10296,9 +10229,8 @@
   AutofillProfile profile = test::GetFullProfile();
   personal_data().AddProfile(profile);
   FormData response_data;
-  FillAutofillFormDataAndSaveResults(
-      form, form.fields[0], MakeFrontendId({.profile_id = profile.guid()}),
-      &response_data);
+  FillAutofillFormDataAndSaveResults(form, form.fields[0], profile.guid(),
+                                     &response_data);
 
   // Simulate editing the first field.
   response_data.fields[0].value = u"Michael";
@@ -10328,8 +10260,7 @@
   AutofillProfile profile = test::GetFullProfile();
   profile.ClearFields({EMAIL_ADDRESS});
   personal_data().AddProfile(profile);
-  FillAutofillFormData(form, form.fields[0],
-                       MakeFrontendId({.profile_id = profile.guid()}));
+  FillAutofillFormData(form, form.fields[0], profile.guid());
 
   FormStructure* form_structure =
       browser_autofill_manager_->FindCachedFormById(form.global_id());
@@ -10951,8 +10882,7 @@
   // Simulate filling and store the data to be filled in |first_fill_data|.
   const char guid[] = "00000000-0000-0000-0000-000000000004";
   FormData first_fill_data;
-  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                     MakeFrontendId({.credit_card_id = guid}),
+  FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                      &first_fill_data);
   ASSERT_EQ(3u, first_fill_data.fields.size());
   ExpectFilledField("Name on Card", "nameoncard", "Elvis Presley", "text",
@@ -11065,8 +10995,7 @@
 
     // Simulate filling and store the data to be filled in `fill_data_`.
     const char guid[] = "00000000-0000-0000-0000-000000000004";
-    FillAutofillFormDataAndSaveResults(form, *form.fields.begin(),
-                                       MakeFrontendId({.credit_card_id = guid}),
+    FillAutofillFormDataAndSaveResults(form, *form.fields.begin(), guid,
                                        &fill_data_);
     ASSERT_EQ(3u, fill_data_.fields.size());
     ExpectFilledField("Name on Card", "nameoncard", "Elvis Presley", "text",
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc
index 8b9f82e9..e216004c 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -2046,8 +2046,7 @@
     return field.origin != triggered_origin &&
            (field.origin != main_origin ||
             IsSensitiveFieldType(field.Type().GetStorableType())) &&
-           (triggered_origin == main_origin ||
-            features::kAutofillSharedAutofillRelaxedParam.Get());
+           triggered_origin == main_origin;
   };
 
   bool some_field_needs_shared_autofill = false;
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
index 58811023..66f000f 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
@@ -168,8 +168,7 @@
   void FillTestProfile(const FormData& form) {
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.profile_id = kTestProfileId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestProfileId), AutofillTriggerSource::kPopup);
   }
 
   Suggestion::FrontendId MakeFrontendId(
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index e79fe05..713107e 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -1948,8 +1948,7 @@
     base::UserActionTester user_action_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     EXPECT_EQ(1, user_action_tester.GetActionCount(
                      "Autofill_FilledCreditCardSuggestion"));
   }
@@ -2638,7 +2637,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields[2],
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -2662,11 +2661,11 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields[2],
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields[2],
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -2760,8 +2759,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
         BucketsInclude(Bucket(FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1),
@@ -2807,7 +2805,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     OnCreditCardFetchingSuccessful(u"6011000990139424");
     SubmitForm(form);
@@ -2840,7 +2838,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestFullServerCardId}),
+        Suggestion::BackendId(kTestFullServerCardId),
         AutofillTriggerSource::kPopup);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -2862,12 +2860,10 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
         BucketsInclude(Bucket(FORM_EVENT_LOCAL_SUGGESTION_FILLED, 2),
@@ -2903,8 +2899,7 @@
   base::HistogramTester histogram_tester;
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-      MakeFrontendId({.credit_card_id = local_guid}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(local_guid), AutofillTriggerSource::kPopup);
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -2945,8 +2940,7 @@
   // Local card with a duplicate server card present at index 0.
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-      MakeFrontendId({.credit_card_id = local_guid}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(local_guid), AutofillTriggerSource::kPopup);
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -2988,7 +2982,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
                     "6011000990139424");
@@ -3012,7 +3006,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kPermanentFailure,
                     std::string());
@@ -3049,7 +3043,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPanWithNonHttpOkResponse();
     histogram_tester.ExpectTotalCount(
@@ -3327,8 +3321,7 @@
   autofill_manager().OnAskForValuesToFillTest(form, form.fields[0]);
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-      MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
 
   SubmitForm(form);
   EXPECT_THAT(
@@ -3507,8 +3500,7 @@
     autofill_manager().OnAskForValuesToFillTest(form, form.fields.back());
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     SubmitForm(form);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -3593,7 +3585,7 @@
     autofill_manager().OnAskForValuesToFillTest(form, form.fields.back());
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestFullServerCardId}),
+        Suggestion::BackendId(kTestFullServerCardId),
         AutofillTriggerSource::kPopup);
     SubmitForm(form);
 
@@ -3634,7 +3626,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     OnCreditCardFetchingSuccessful(u"6011000990139424");
     SubmitForm(form);
@@ -3880,8 +3872,7 @@
     autofill_manager().OnAskForValuesToFillTest(form, form.fields[0]);
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     SubmitForm(form);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -3933,7 +3924,7 @@
     // Full server card.
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestFullServerCardId}),
+        Suggestion::BackendId(kTestFullServerCardId),
         AutofillTriggerSource::kPopup);
     SubmitForm(form);
     EXPECT_THAT(
@@ -3956,7 +3947,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     OnCreditCardFetchingSuccessful(u"6011000990139424");
     EXPECT_THAT(
@@ -4097,8 +4088,7 @@
                                           form.fields.back());
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     EXPECT_THAT(
         histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
         BucketsInclude(Bucket(FORM_EVENT_SUGGESTIONS_SHOWN, 1),
@@ -4145,7 +4135,7 @@
     // Select the masked server card with the linked offer.
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kMaskedServerCardIds[0]}),
+        Suggestion::BackendId(kMaskedServerCardIds[0]),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
                     "6011000990139424");
@@ -4193,7 +4183,7 @@
     // sub-histogram because user has another masked server card with offer.
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
+        Suggestion::BackendId(kTestMaskedCardId),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
                     "6011000990139424");
@@ -4247,7 +4237,7 @@
     // since the offer is expired.
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kMaskedServerCardIds[1]}),
+        Suggestion::BackendId(kMaskedServerCardIds[1]),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
                     "6011000990139424");
@@ -4313,7 +4303,7 @@
     // Select the masked server card with the linked offer.
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kMaskedServerCardIds[2]}),
+        Suggestion::BackendId(kMaskedServerCardIds[2]),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
                     "6011000990139424");
@@ -4367,7 +4357,7 @@
     // check.
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kMaskedServerCardIds[2]}),
+        Suggestion::BackendId(kMaskedServerCardIds[2]),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kPermanentFailure,
                     std::string());
@@ -4417,7 +4407,7 @@
                                           form.fields.back());
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kMaskedServerCardIds[2]}),
+        Suggestion::BackendId(kMaskedServerCardIds[2]),
         AutofillTriggerSource::kPopup);
     OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
                     "6011000990139424");
@@ -4428,8 +4418,7 @@
                                           form.fields.back());
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.back(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     SubmitForm(form);
     EXPECT_THAT(
         histogram_tester.GetAllSamples(
@@ -5869,8 +5858,7 @@
     base::HistogramTester histogram_tester;
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.credit_card_id = kTestLocalCardId}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(kTestLocalCardId), AutofillTriggerSource::kPopup);
     SimulateUserChangedTextField(form, form.fields.front());
     // Simulate a second keystroke; make sure we don't log the metric twice.
     SimulateUserChangedTextField(form, form.fields.front());
@@ -9023,8 +9011,7 @@
   // Simulate filling the form.
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-      is_cc_form ? MakeFrontendId({.credit_card_id = kTestLocalCardId})
-                 : MakeFrontendId({.profile_id = kTestProfileId}),
+      Suggestion::BackendId(is_cc_form ? kTestLocalCardId : kTestProfileId),
       AutofillTriggerSource::kPopup);
 
   if (GetParam().change_form_after_filling)
diff --git a/components/autofill/core/browser/metrics/form_events/address_form_event_logger_unittest.cc b/components/autofill/core/browser/metrics/form_events/address_form_event_logger_unittest.cc
index 4bcffec..10cc0836 100644
--- a/components/autofill/core/browser/metrics/form_events/address_form_event_logger_unittest.cc
+++ b/components/autofill/core/browser/metrics/form_events/address_form_event_logger_unittest.cc
@@ -98,8 +98,7 @@
     autofill_manager().OnAskForValuesToFillTest(form, form.fields.front());
     autofill_manager().FillOrPreviewForm(
         mojom::RendererFormDataAction::kFill, form, form.fields.front(),
-        MakeFrontendId({.profile_id = profile.guid()}),
-        AutofillTriggerSource::kPopup);
+        Suggestion::BackendId(profile.guid()), AutofillTriggerSource::kPopup);
   }
 
  protected:
diff --git a/components/autofill/core/browser/metrics/payments/DIR_METADATA b/components/autofill/core/browser/metrics/payments/DIR_METADATA
new file mode 100644
index 0000000..d9bf029
--- /dev/null
+++ b/components/autofill/core/browser/metrics/payments/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Browser>Autofill>Payments"
+}
diff --git a/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc b/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc
index f72fc2c..c455b7de 100644
--- a/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc
@@ -164,8 +164,7 @@
                                         form(), form().fields.back());
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form(), form().fields.back(),
-      MakeFrontendId({.credit_card_id = kCardGuid}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(kCardGuid), AutofillTriggerSource::kPopup);
 
   const bool should_log_for_metadata =
       card_issuer_available() && card_metadata_available();
@@ -204,8 +203,7 @@
   // Select the suggestion again.
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form(), form().fields.back(),
-      MakeFrontendId({.credit_card_id = kCardGuid}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(kCardGuid), AutofillTriggerSource::kPopup);
 
   EXPECT_THAT(
       histogram_tester.GetAllSamples("Autofill.FormEvents.CreditCard"),
@@ -234,8 +232,7 @@
   // Simulate filling the card.
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form(), form().fields.back(),
-      MakeFrontendId({.credit_card_id = kCardGuid}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(kCardGuid), AutofillTriggerSource::kPopup);
   autofill_manager().OnCreditCardFetchedForTest(CreditCardFetchResult::kSuccess,
                                                 &card(), u"123");
 
@@ -267,8 +264,7 @@
   autofill_manager().OnAskForValuesToFillTest(form(), form().fields.back());
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form(), form().fields.back(),
-      MakeFrontendId({.credit_card_id = kCardGuid}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(kCardGuid), AutofillTriggerSource::kPopup);
   autofill_manager().OnCreditCardFetchedForTest(CreditCardFetchResult::kSuccess,
                                                 &card(), u"123");
   SubmitForm(form());
@@ -384,8 +380,7 @@
   test_clock.SetNowTicks(now + base::Seconds(2));
   autofill_manager().FillOrPreviewForm(
       mojom::RendererFormDataAction::kFill, form(), form().fields.front(),
-      MakeFrontendId({.credit_card_id = kTestMaskedCardId}),
-      AutofillTriggerSource::kPopup);
+      Suggestion::BackendId(kTestMaskedCardId), AutofillTriggerSource::kPopup);
 
   std::string latency_histogram_prefix =
       "Autofill.CreditCard.SelectionLatencySinceShown.";
diff --git a/components/autofill/core/browser/payments/DIR_METADATA b/components/autofill/core/browser/payments/DIR_METADATA
new file mode 100644
index 0000000..d9bf029
--- /dev/null
+++ b/components/autofill/core/browser/payments/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Browser>Autofill>Payments"
+}
diff --git a/components/autofill/core/browser/ui/autofill_popup_delegate.h b/components/autofill/core/browser/ui/autofill_popup_delegate.h
index 38b9173..9527c94f 100644
--- a/components/autofill/core/browser/ui/autofill_popup_delegate.h
+++ b/components/autofill/core/browser/ui/autofill_popup_delegate.h
@@ -51,13 +51,15 @@
   // fills out |title| and |body|.
   virtual bool GetDeletionConfirmationText(const std::u16string& value,
                                            Suggestion::FrontendId frontend_id,
+                                           Suggestion::BackendId backend_id,
                                            std::u16string* title,
                                            std::u16string* body) = 0;
 
   // Delete the described suggestion. Returns true if something was deleted,
   // or false if deletion is not allowed.
   virtual bool RemoveSuggestion(const std::u16string& value,
-                                Suggestion::FrontendId frontend_id) = 0;
+                                Suggestion::FrontendId frontend_id,
+                                Suggestion::BackendId backend_id) = 0;
 
   // Informs the delegate that the Autofill previewed form should be cleared.
   virtual void ClearPreviewedForm() = 0;
diff --git a/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h b/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h
index 03a808cc..bfef70f8 100644
--- a/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h
+++ b/components/autofill/core/browser/ui/mock_autofill_popup_delegate.h
@@ -37,12 +37,15 @@
               GetDeletionConfirmationText,
               (const std::u16string& value,
                Suggestion::FrontendId frontend_id,
+               Suggestion::BackendId backend_id,
                std::u16string* title,
                std::u16string* body),
               (override));
   MOCK_METHOD(bool,
               RemoveSuggestion,
-              (const std::u16string& value, Suggestion::FrontendId frontend_id),
+              (const std::u16string& value,
+               Suggestion::FrontendId frontend_id,
+               Suggestion::BackendId backend_id),
               (override));
   MOCK_METHOD(void, ClearPreviewedForm, (), (override));
   MOCK_METHOD(PopupType, GetPopupType, (), (const, override));
diff --git a/components/autofill/core/browser/ui/payments/DIR_METADATA b/components/autofill/core/browser/ui/payments/DIR_METADATA
new file mode 100644
index 0000000..d9bf029
--- /dev/null
+++ b/components/autofill/core/browser/ui/payments/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Browser>Autofill>Payments"
+}
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index c1a8848..2d9f9b7 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -465,10 +465,6 @@
 BASE_FEATURE(kAutofillSharedAutofill,
              "AutofillSharedAutofill",
              base::FEATURE_DISABLED_BY_DEFAULT);
-// Relaxes the conditions under which a field is safe to fill.
-// See FormForest::GetRendererFormsOfBrowserForm() for details.
-const base::FeatureParam<bool> kAutofillSharedAutofillRelaxedParam{
-    &kAutofillSharedAutofill, "relax_shared_autofill", false};
 
 // Controls whether to offer a delete button for Autocomplete entries in the
 // Autofill popup.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 44039b7..4bcfc73 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -164,8 +164,6 @@
 extern const base::FeatureParam<int> kAutofillServerBehaviorsParam;
 COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillSharedAutofill);
 COMPONENT_EXPORT(AUTOFILL)
-extern const base::FeatureParam<bool> kAutofillSharedAutofillRelaxedParam;
-COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillShowAutocompleteDeleteButton);
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillShowManualFallbackInContextMenu);
diff --git a/components/autofill_payments_strings_grdp/DIR_METADATA b/components/autofill_payments_strings_grdp/DIR_METADATA
index 4ed8abe..0fe0572 100644
--- a/components/autofill_payments_strings_grdp/DIR_METADATA
+++ b/components/autofill_payments_strings_grdp/DIR_METADATA
@@ -1,4 +1,4 @@
 monorail {
-  component: "UI>Browser>Autofill"
+  component: "UI>Browser>Autofill>Payments"
 }
 team_email: "payments-autofill-team@google.com"
diff --git a/components/content_settings/core/browser/cookie_settings.cc b/components/content_settings/core/browser/cookie_settings.cc
index 7ce34161..da11f3b 100644
--- a/components/content_settings/core/browser/cookie_settings.cc
+++ b/components/content_settings/core/browser/cookie_settings.cc
@@ -42,7 +42,8 @@
     : host_content_settings_map_(host_content_settings_map),
       is_incognito_(is_incognito),
       extension_scheme_(extension_scheme),
-      block_third_party_cookies_(false) {
+      block_third_party_cookies_(
+          net::cookie_util::IsForceThirdPartyCookieBlockingEnabled()) {
   content_settings_observation_.Observe(host_content_settings_map_.get());
   pref_change_registrar_.Init(prefs);
   pref_change_registrar_.Add(
@@ -304,6 +305,10 @@
   }
 #endif
 
+  if (net::cookie_util::IsForceThirdPartyCookieBlockingEnabled()) {
+    return true;
+  }
+
   CookieControlsMode mode = static_cast<CookieControlsMode>(
       pref_change_registrar_.prefs()->GetInteger(prefs::kCookieControlsMode));
 
diff --git a/components/content_settings/core/browser/cookie_settings_unittest.cc b/components/content_settings/core/browser/cookie_settings_unittest.cc
index abef87c3..5403568 100644
--- a/components/content_settings/core/browser/cookie_settings_unittest.cc
+++ b/components/content_settings/core/browser/cookie_settings_unittest.cc
@@ -422,6 +422,41 @@
                 /*top_frame_origin=*/absl::nullopt, cookie_setting_overrides));
 }
 
+TEST_P(CookieSettingsTest, ForceThirdPartyCookieBlocking) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      net::features::kForceThirdPartyCookieBlocking);
+
+  auto cookie_setting_overrides = GetCookieSettingOverrides();
+
+  // Build new CookieSettings since `cookie_settings_` was created before
+  // ForceThirdPartyCookieBlocking was enabled.
+  scoped_refptr<CookieSettings> cookie_settings = new CookieSettings(
+      settings_map_.get(), &prefs_, false, "chrome-extension");
+
+  EXPECT_TRUE(cookie_settings->ShouldBlockThirdPartyCookies());
+
+  EXPECT_EQ(cookie_settings->IsFullCookieAccessAllowed(
+                kBlockedSite, kFirstPartySiteForCookies,
+                /*top_frame_origin=*/absl::nullopt, cookie_setting_overrides),
+            IsForceAllowThirdPartyCookies());
+
+  // Test that ForceThirdPartyCookieBlocking overrides preference changes.
+  prefs_.SetInteger(prefs::kCookieControlsMode,
+                    static_cast<int>(CookieControlsMode::kOff));
+  EXPECT_EQ(cookie_settings->IsFullCookieAccessAllowed(
+                kBlockedSite, kFirstPartySiteForCookies,
+                /*top_frame_origin=*/absl::nullopt, cookie_setting_overrides),
+            IsForceAllowThirdPartyCookies());
+
+  // Test that ForceThirdPartyCookieBlocking can be overridden by site-specific
+  // content settings.
+  cookie_settings->SetCookieSetting(kBlockedSite, CONTENT_SETTING_ALLOW);
+  EXPECT_TRUE(cookie_settings->IsFullCookieAccessAllowed(
+      kBlockedSite, kFirstPartySiteForCookies,
+      /*top_frame_origin=*/absl::nullopt, cookie_setting_overrides));
+}
+
 #if BUILDFLAG(IS_IOS)
 // Test fixture with ImprovedCookieControls disabled.
 class ImprovedCookieControlsDisabledCookieSettingsTest
diff --git a/components/history/core/browser/expire_history_backend_unittest.cc b/components/history/core/browser/expire_history_backend_unittest.cc
index c1a8108..e2470662 100644
--- a/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/components/history/core/browser/expire_history_backend_unittest.cc
@@ -208,7 +208,8 @@
   void NotifyURLsDeleted(DeletionInfo deletion_info) override {
     urls_deleted_notifications_.push_back(std::move(deletion_info));
   }
-  void NotifyVisitUpdated(const VisitRow& visit) override {}
+  void NotifyVisitUpdated(const VisitRow& visit,
+                          VisitUpdateReason reason) override {}
   void NotifyVisitDeleted(const VisitRow& visit) override {}
 };
 
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 3b3b358..7699904fe 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -714,7 +714,7 @@
       annotations.page_language = page_language;
       db_->AddContentAnnotationsForVisit(visit_id, annotations);
     }
-    NotifyVisitUpdated(visit_row);
+    NotifyVisitUpdated(visit_row, VisitUpdateReason::kSetPageLanguage);
     ScheduleCommit();
   }
 }
@@ -751,7 +751,7 @@
       annotations.password_state = password_state;
       db_->AddContentAnnotationsForVisit(visit_id, annotations);
     }
-    NotifyVisitUpdated(visit_row);
+    NotifyVisitUpdated(visit_row, VisitUpdateReason::kSetPasswordState);
     ScheduleCommit();
   }
 }
@@ -890,7 +890,7 @@
                                    ? end_ts - visit_row.visit_time
                                    : base::Microseconds(0);
     db_->UpdateVisitRow(visit_row);
-    NotifyVisitUpdated(visit_row);
+    NotifyVisitUpdated(visit_row, VisitUpdateReason::kUpdateVisitDuration);
   }
 }
 
@@ -1078,7 +1078,7 @@
             visit_row.transition = ui::PageTransitionFromInt(
                 visit_row.transition & ~ui::PAGE_TRANSITION_CHAIN_END);
             db_->UpdateVisitRow(visit_row);
-            NotifyVisitUpdated(visit_row);
+            NotifyVisitUpdated(visit_row, VisitUpdateReason::kUpdateTransition);
           }
 
           extended_redirect_chain = GetCachedRecentRedirects(request.referrer);
@@ -1807,7 +1807,7 @@
                                       content_annotations->password_state);
   }
 
-  NotifyVisitUpdated(updated_row);
+  NotifyVisitUpdated(updated_row, VisitUpdateReason::kUpdateSyncedVisit);
   ScheduleCommit();
   return updated_row.visit_id;
 }
@@ -2147,7 +2147,7 @@
   if (!db_ || !db_->GetRowForVisit(visit_id, &visit_row))
     return;
   db_->AddContextAnnotationsForVisit(visit_id, visit_context_annotations);
-  NotifyVisitUpdated(visit_row);
+  NotifyVisitUpdated(visit_row, VisitUpdateReason::kAddContextAnnotations);
   ScheduleCommit();
 }
 
@@ -2169,7 +2169,8 @@
   } else {
     db_->AddContextAnnotationsForVisit(visit_id, visit_context_annotations);
   }
-  NotifyVisitUpdated(visit_row);
+  NotifyVisitUpdated(visit_row,
+                     VisitUpdateReason::kSetOnCloseContextAnnotations);
   ScheduleCommit();
 }
 
@@ -3532,9 +3533,10 @@
   delegate_->NotifyURLsDeleted(std::move(deletion_info));
 }
 
-void HistoryBackend::NotifyVisitUpdated(const VisitRow& visit) {
+void HistoryBackend::NotifyVisitUpdated(const VisitRow& visit,
+                                        VisitUpdateReason reason) {
   for (HistoryBackendObserver& observer : observers_) {
-    observer.OnVisitUpdated(visit);
+    observer.OnVisitUpdated(visit, reason);
   }
 }
 
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index 35b0dae2..a340a5d 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -961,7 +961,8 @@
   void NotifyURLsModified(const URLRows& changed_urls,
                           bool is_from_expiration) override;
   void NotifyURLsDeleted(DeletionInfo deletion_info) override;
-  void NotifyVisitUpdated(const VisitRow& visit) override;
+  void NotifyVisitUpdated(const VisitRow& visit,
+                          VisitUpdateReason reason) override;
   void NotifyVisitDeleted(const VisitRow& visit) override;
 
   // Deleting all history ------------------------------------------------------
diff --git a/components/history/core/browser/history_backend_notifier.h b/components/history/core/browser/history_backend_notifier.h
index 039d4fb..2140730 100644
--- a/components/history/core/browser/history_backend_notifier.h
+++ b/components/history/core/browser/history_backend_notifier.h
@@ -45,7 +45,8 @@
   virtual void NotifyURLsDeleted(DeletionInfo deletion_info) = 0;
 
   // Called after a visit has been updated.
-  virtual void NotifyVisitUpdated(const VisitRow& visit) = 0;
+  virtual void NotifyVisitUpdated(const VisitRow& visit,
+                                  VisitUpdateReason reason) = 0;
 
   // Called after a visit has been deleted.
   virtual void NotifyVisitDeleted(const VisitRow& visit) = 0;
diff --git a/components/history/core/browser/history_backend_observer.h b/components/history/core/browser/history_backend_observer.h
index d9efb019..a2e23e7d 100644
--- a/components/history/core/browser/history_backend_observer.h
+++ b/components/history/core/browser/history_backend_observer.h
@@ -61,10 +61,10 @@
                              const URLRows& deleted_rows,
                              const std::set<GURL>& favicon_urls) = 0;
 
-  // Called when a visit is updated. Typically this happens when the visit
-  // duration is updated, and in some redirect cases when the transition type
-  // is updated.
-  virtual void OnVisitUpdated(const VisitRow& visit) = 0;
+  // Called when a visit, or some of its annotations, are updated. `reason`
+  // specifies what specifically was updated.
+  virtual void OnVisitUpdated(const VisitRow& visit,
+                              VisitUpdateReason reason) = 0;
 
   // Called when a visit is deleted - usually either due to expiry, or because
   // the user explicitly deleted it.
diff --git a/components/history/core/browser/history_types.h b/components/history/core/browser/history_types.h
index 7284129..6430bbe 100644
--- a/components/history/core/browser/history_types.h
+++ b/components/history/core/browser/history_types.h
@@ -174,6 +174,20 @@
 // used by HistoryBackend::AddVisits() to create new visits for a URL.
 typedef std::pair<base::Time, ui::PageTransition> VisitInfo;
 
+// Specifies the possible reasons a visit (or its annotations) can get updated.
+// Used by HistoryBackendNotifier::NotifyVisitUpdated() and
+// HistoryBackendObserver::OnVisitUpdated().
+// Only used internally and in memory (not persisted), so can be freely changed.
+enum class VisitUpdateReason {
+  kSetPageLanguage,
+  kSetPasswordState,
+  kUpdateVisitDuration,
+  kUpdateTransition,
+  kUpdateSyncedVisit,
+  kAddContextAnnotations,
+  kSetOnCloseContextAnnotations
+};
+
 // QueryResults ----------------------------------------------------------------
 
 // Encapsulates the results of a history query. It supports an ordered list of
diff --git a/components/history/core/browser/sync/history_sync_bridge.cc b/components/history/core/browser/sync/history_sync_bridge.cc
index 87daf3e8..f46fb47b 100644
--- a/components/history/core/browser/sync/history_sync_bridge.cc
+++ b/components/history/core/browser/sync/history_sync_bridge.cc
@@ -376,6 +376,10 @@
 
   // Add annotation fields. The last visit in the chain is the one that has
   // annotations attached (if any).
+  // NOTE: Currently only the "on_visit" fields of the context annotation are
+  // supported. When adding any non-"on_visit" field to sync, reconsider how
+  // VisitUpdateReason::kSetOnCloseContextAnnotations is handled (but mind
+  // additional traffic to the server!)
   const VisitContextAnnotations& context_annotations =
       redirect_visits.back().context_annotations;
   sync_pb::SyncEnums::BrowserType browser_type =
@@ -389,6 +393,7 @@
   history->set_root_task_id(context_annotations.on_visit.root_task_id);
   history->set_parent_task_id(context_annotations.on_visit.parent_task_id);
   history->set_http_response_code(context_annotations.on_visit.response_code);
+  // NOTE: Only "on_visit" fields are supported, see above.
 
   const VisitContentAnnotations& content_annotations =
       redirect_visits.back().content_annotations;
@@ -792,9 +797,26 @@
   UntrackAndClearMetadataForAllEntities();
 }
 
-void HistorySyncBridge::OnVisitUpdated(const VisitRow& visit_row) {
+void HistorySyncBridge::OnVisitUpdated(const VisitRow& visit_row,
+                                       VisitUpdateReason reason) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  switch (reason) {
+    case VisitUpdateReason::kSetPageLanguage:
+    case VisitUpdateReason::kSetPasswordState:
+    case VisitUpdateReason::kUpdateVisitDuration:
+    case VisitUpdateReason::kUpdateTransition:
+    case VisitUpdateReason::kAddContextAnnotations:
+      // Standard case: These are all interesting, process this update.
+      break;
+    case VisitUpdateReason::kUpdateSyncedVisit:
+      CHECK(processing_syncer_changes_);
+      return;
+    case VisitUpdateReason::kSetOnCloseContextAnnotations:
+      // None of the on-close context annotations are synced, so ignore this.
+      return;
+  }
+
   MaybeCommit(visit_row);
 }
 
diff --git a/components/history/core/browser/sync/history_sync_bridge.h b/components/history/core/browser/sync/history_sync_bridge.h
index 9309932..ec581a9 100644
--- a/components/history/core/browser/sync/history_sync_bridge.h
+++ b/components/history/core/browser/sync/history_sync_bridge.h
@@ -74,7 +74,8 @@
                      bool expired,
                      const URLRows& deleted_rows,
                      const std::set<GURL>& favicon_urls) override;
-  void OnVisitUpdated(const VisitRow& visit_row) override;
+  void OnVisitUpdated(const VisitRow& visit_row,
+                      VisitUpdateReason reason) override;
   void OnVisitDeleted(const VisitRow& visit_row) override;
 
   void SetSyncTransportState(syncer::SyncService::TransportState state);
diff --git a/components/history/core/browser/sync/history_sync_bridge_unittest.cc b/components/history/core/browser/sync/history_sync_bridge_unittest.cc
index 65c6057b..52fb8de 100644
--- a/components/history/core/browser/sync/history_sync_bridge_unittest.cc
+++ b/components/history/core/browser/sync/history_sync_bridge_unittest.cc
@@ -920,7 +920,7 @@
   const base::TimeDelta visit_duration = base::Seconds(10);
   visit_row.visit_duration = visit_duration;
   ASSERT_TRUE(backend()->UpdateVisit(visit_row));
-  bridge()->OnVisitUpdated(visit_row);
+  bridge()->OnVisitUpdated(visit_row, VisitUpdateReason::kUpdateVisitDuration);
 
   // The updated data should have been sent to the processor.
   EXPECT_EQ(processor()->GetEntities().size(), 1u);
@@ -931,6 +931,41 @@
       visit_duration);
 }
 
+TEST_F(HistorySyncBridgeTest, IgnoresUninterestingVisitUpdate) {
+  // Start syncing (with no data yet).
+  ApplyInitialSyncChanges({});
+
+  // Visit a URL and notify the bridge.
+  auto [url_row, visit_row] = AddVisitToBackendAndAdvanceClock(
+      GURL("https://www.url.com"), ui::PAGE_TRANSITION_TYPED);
+  bridge()->OnURLVisited(
+      /*history_backend=*/nullptr, url_row, visit_row);
+
+  const std::string storage_key =
+      HistorySyncMetadataDatabase::StorageKeyFromVisitTime(
+          visit_row.visit_time);
+
+  // The visit should've been sent to the processor. Mark it as "synced",
+  // simulating that it was sent to the server.
+  ASSERT_TRUE(processor()->IsEntityUnsynced(storage_key));
+  processor()->MarkEntitySynced(storage_key);
+  ASSERT_FALSE(processor()->IsEntityUnsynced(storage_key));
+
+  // Notify the bridge about an uninteresting visit update (uninteresting since
+  // none of the on-close context annotation fields are synced).
+  bridge()->OnVisitUpdated(visit_row,
+                           VisitUpdateReason::kSetOnCloseContextAnnotations);
+
+  // This should *not* have been sent to the processor, so the entity should not
+  // be unsynced now.
+  EXPECT_FALSE(processor()->IsEntityUnsynced(storage_key));
+
+  // Sanity check: Some other visit update *should* be sent to the processor.
+  bridge()->OnVisitUpdated(visit_row,
+                           VisitUpdateReason::kAddContextAnnotations);
+  EXPECT_TRUE(processor()->IsEntityUnsynced(storage_key));
+}
+
 TEST_F(HistorySyncBridgeTest, DoesNotUploadUpdatedForeignVisit) {
   sync_pb::HistorySpecifics remote_entity =
       CreateSpecifics(base::Time::Now() - base::Minutes(1), "remote_cache_guid",
@@ -961,7 +996,7 @@
   // might do it (probably mistakenly).
   visit_row.visit_duration = base::Seconds(10);
   ASSERT_TRUE(backend()->UpdateVisit(visit_row));
-  bridge()->OnVisitUpdated(visit_row);
+  bridge()->OnVisitUpdated(visit_row, VisitUpdateReason::kUpdateVisitDuration);
 
   // The updated visit should *not* have been sent to the processor - the entity
   // in the processor should *not* be unsynced, and its visit duration should
@@ -1141,7 +1176,7 @@
   ASSERT_TRUE(backend()->UpdateVisit(visit_row2));
   // The bridge gets notified about the updated visit, but this should have no
   // effect since it's not a chain end anymore.
-  bridge()->OnVisitUpdated(visit_row2);
+  bridge()->OnVisitUpdated(visit_row2, VisitUpdateReason::kUpdateTransition);
 
   // Two more visits get appended to the chain.
   URLRow url_row3(GURL("https://url3.com"));
@@ -1245,7 +1280,7 @@
   ASSERT_TRUE(backend()->UpdateVisit(visit_row1));
   // The bridge gets notified about the updated visit, but this should have no
   // effect since it's not a chain end anymore.
-  bridge()->OnVisitUpdated(visit_row1);
+  bridge()->OnVisitUpdated(visit_row1, VisitUpdateReason::kUpdateTransition);
 
   // A visit gets appended to the chain.
   AdvanceClock();
@@ -1287,7 +1322,7 @@
   visit_row2.transition = ui::PageTransitionFromInt(
       visit_row2.transition & ~ui::PAGE_TRANSITION_CHAIN_END);
   ASSERT_TRUE(backend()->UpdateVisit(visit_row2));
-  bridge()->OnVisitUpdated(visit_row2);
+  bridge()->OnVisitUpdated(visit_row2, VisitUpdateReason::kUpdateTransition);
 
   // A visit gets appended to the chain.
   AdvanceClock();
diff --git a/components/history/core/browser/sync/typed_url_sync_bridge.cc b/components/history/core/browser/sync/typed_url_sync_bridge.cc
index b78d8cc..67bbc6a3 100644
--- a/components/history/core/browser/sync/typed_url_sync_bridge.cc
+++ b/components/history/core/browser/sync/typed_url_sync_bridge.cc
@@ -478,7 +478,8 @@
   }
 }
 
-void TypedURLSyncBridge::OnVisitUpdated(const VisitRow& visit) {}
+void TypedURLSyncBridge::OnVisitUpdated(const VisitRow& visit,
+                                        VisitUpdateReason reason) {}
 
 void TypedURLSyncBridge::OnVisitDeleted(const VisitRow& visit) {}
 
diff --git a/components/history/core/browser/sync/typed_url_sync_bridge.h b/components/history/core/browser/sync/typed_url_sync_bridge.h
index a93bb23..8c270e5 100644
--- a/components/history/core/browser/sync/typed_url_sync_bridge.h
+++ b/components/history/core/browser/sync/typed_url_sync_bridge.h
@@ -66,7 +66,7 @@
                      bool expired,
                      const std::vector<URLRow>& deleted_rows,
                      const std::set<GURL>& favicon_urls) override;
-  void OnVisitUpdated(const VisitRow& visit) override;
+  void OnVisitUpdated(const VisitRow& visit, VisitUpdateReason reason) override;
   void OnVisitDeleted(const VisitRow& visit) override;
 
   // Must be called after creation and before any operations.
diff --git a/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc b/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
index d7a17b0..0c8ca41 100644
--- a/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
+++ b/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
@@ -29,13 +29,19 @@
 // clients from spamming GMS Core API.
 constexpr base::TimeDelta kMigrationThreshold = base::Days(1);
 
+// The required migration version. If the version saved in
+// `prefs::kCurrentMigrationVersionToGoogleMobileServices` is lower than
+// 'kRequiredMigrationVersion', passwords will be re-uploaded. Currently set to
+// the initial migration version.
+constexpr int kRequiredMigrationVersion = 1;
+
 // Returns true if the initial migration to the android backend has happened.
 // The pref is updated after any type of migration, but the initial migration
 // happens first.
 bool HasMigratedToTheAndroidBackend(PrefService* prefs) {
-  return features::kMigrationVersion.Get() <=
-         prefs->GetInteger(
-             prefs::kCurrentMigrationVersionToGoogleMobileServices);
+  return prefs->GetInteger(
+             prefs::kCurrentMigrationVersionToGoogleMobileServices) >=
+         kRequiredMigrationVersion;
 }
 
 bool IsBlacklistedFormWithValues(const PasswordForm& form) {
@@ -183,7 +189,7 @@
     // pref.
   }
   prefs_->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
-                     features::kMigrationVersion.Get());
+                     kRequiredMigrationVersion);
 }
 
 BuiltInBackendToAndroidBackendMigrator::MigrationType
@@ -199,13 +205,17 @@
     return MigrationType::kInitialForSyncUsers;
   }
 
+  // TODO(crbug.com/1445497): Re-evaluate migration code for local passwords.
+  bool upm_for_local_active = base::FeatureList::IsEnabled(
+      password_manager::features::kUnifiedPasswordManagerLocalPasswordsAndroid);
+
   // If the user enables or disables password sync, the new active backend needs
   // non-syncable data from the previously active backend, as logins are
   // already transmitted through sync.
   // Once the local storage is supported, android backend becomes the only
   // active backend and there is no need to do this migration.
   if (prefs_->GetBoolean(prefs::kRequiresMigrationAfterSyncStatusChange) &&
-      !features::ManagesLocalPasswordsInUnifiedPasswordManager()) {
+      !upm_for_local_active) {
     return IsPasswordSyncEnabled(sync_service_)
                ? MigrationType::kNonSyncableToAndroidBackend
                : MigrationType::kNonSyncableToBuiltInBackend;
@@ -213,8 +223,9 @@
 
   // Once the local storage is supported, the migration to ensure the
   // consistency of the two backends is needed.
-  if (features::ManagesLocalPasswordsInUnifiedPasswordManager())
+  if (upm_for_local_active) {
     return MigrationType::kForLocalUsers;
+  }
 
   // No other migration should be executed.
   return MigrationType::kNone;
diff --git a/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc b/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc
index 5821d4ef3..6bef4d8 100644
--- a/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc
+++ b/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc
@@ -131,9 +131,6 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        CurrentMigrationVersionIsUpdatedWhenMigrationIsNeeded_SyncOn) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
   Init();
   InitSyncService(/*is_password_sync_enabled=*/true);
 
@@ -150,9 +147,6 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        PrefsUnchangedWhenMigrationIsNeeded_SyncOff) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
   Init();
 
   InitSyncService(/*is_password_sync_enabled=*/false);
@@ -169,9 +163,8 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        AllPrefsAreUpdatedWhenMigrationIsNeeded_SyncOff) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "3"}});
+  feature_list().InitAndEnableFeature(
+      features::kUnifiedPasswordManagerLocalPasswordsAndroid);
   Init();
 
   InitSyncService(/*is_password_sync_enabled=*/false);
@@ -189,9 +182,6 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        PrefsUnchangedWhenAttemptedMigrationEarlierToday) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
   Init();
 
   prefs()->SetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt,
@@ -210,11 +200,6 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        LastAttemptUnchangedWhenRollingMigrationDisabled) {
-  // Setup the pref to indicate that the initial migration has happened already.
-  feature_list().InitWithFeaturesAndParameters(
-      /*enabled_features=*/{{features::kUnifiedPasswordManagerAndroid,
-                             {{"migration_version", "1"}, {"stage", "0"}}}},
-      /*disabled_features=*/{});
   Init(/*current_migration_version=*/1);
 
   migrator()->StartMigrationIfNecessary(
@@ -230,10 +215,8 @@
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        LastAttemptUpdatedInPrefsWhenRollingMigrationEnabled) {
   // Setup the pref to indicate that the initial migration has happened already.
-  feature_list().InitWithFeaturesAndParameters(
-      /*enabled_features=*/{{features::kUnifiedPasswordManagerAndroid,
-                             {{"migration_version", "1"}, {"stage", "3"}}}},
-      /*disabled_features=*/{});
+  feature_list().InitAndEnableFeature(
+      features::kUnifiedPasswordManagerLocalPasswordsAndroid);
   Init(/*current_migration_version=*/1);
 
   migrator()->StartMigrationIfNecessary(
@@ -252,10 +235,6 @@
   base::HistogramTester histogram_tester;
   const char kMigrationFinishedMetric[] =
       "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
-
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
   Init();
 
   histogram_tester.ExpectTotalCount(kMigrationFinishedMetric, 1);
@@ -268,36 +247,13 @@
   const char kMigrationFinishedMetric[] =
       "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
 
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
   Init(/*current_migration_version=*/1);
 
   histogram_tester.ExpectUniqueSample(kMigrationFinishedMetric, true, 1);
 }
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       InitialMigrationNeedsRestartMetrics) {
-  base::HistogramTester histogram_tester;
-  const char kMigrationFinishedMetric[] =
-      "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
-
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "2"}, {"stage", "0"}});
-
-  Init(/*current_migration_version=*/1);
-
-  histogram_tester.ExpectTotalCount(kMigrationFinishedMetric, 1);
-  histogram_tester.ExpectBucketCount(kMigrationFinishedMetric, false, 1);
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        MigrationForSyncingUserShouldMoveLocalOnlyDataToAndroidBackend) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
-
   Init();
   InitSyncService(/*is_password_sync_enabled=*/true);
 
@@ -326,9 +282,6 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        MigrationUserAfterSyncDisablingShouldMoveLocalOnlyDataToBuiltInBackend) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
   Init();
 
   // Simulate sync being recently disabled.
@@ -362,10 +315,6 @@
 // values from the built in backlend before writing to the Android backend.
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        MigrationClearsBlocklistedCredentials) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
-
   Init();
   InitSyncService(/*is_password_sync_enabled=*/true);
 
@@ -397,10 +346,6 @@
 // non-blocklisted entries.
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        MigrationDoesNotClearNonBlocklistedCredentials) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
-
   Init();
   InitSyncService(/*is_password_sync_enabled=*/true);
 
@@ -435,10 +380,6 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
        ReenrollmentAttemptShouldMoveLocalOnlyDataToAndroidBackend) {
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
-
   Init();
   InitSyncService(/*is_password_sync_enabled=*/true);
 
@@ -546,10 +487,6 @@
 
   InitSyncService(/*is_password_sync_enabled=*/true);
 
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
-
   const MigrationParam& p = GetParam();
 
   for (const auto& login : p.GetBuiltInLogins()) {
@@ -588,9 +525,8 @@
 
   InitSyncService(/*is_password_sync_enabled=*/false);
 
-  feature_list().InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "3"}});
+  feature_list().InitAndEnableFeature(
+      features::kUnifiedPasswordManagerLocalPasswordsAndroid);
 
   const MigrationParam& p = GetParam();
 
@@ -619,10 +555,8 @@
        RollingMigration) {
   // Setup the pref to indicate that the initial migration has happened already.
   // This implies that rolling migration will take place!
-  feature_list().InitWithFeaturesAndParameters(
-      /*enabled_features=*/{{features::kUnifiedPasswordManagerAndroid,
-                             {{"migration_version", "1"}, {"stage", "3"}}}},
-      /*disabled_features=*/{});
+  feature_list().InitAndEnableFeature(
+      features::kUnifiedPasswordManagerLocalPasswordsAndroid);
   BuiltInBackendToAndroidBackendMigratorTest::Init(
       /*current_migration_version=*/1);
 
@@ -723,10 +657,10 @@
     prefs()->registry()->RegisterIntegerPref(
         prefs::kTimesAttemptedToReenrollToGoogleMobileServices, 0);
 
-    // Enable UPM on the stage 'kEnableForSyncingUsers'.
-    feature_list().InitAndEnableFeatureWithParameters(
-        /*feature=*/features::kUnifiedPasswordManagerAndroid,
-        {{"migration_version", "1"}, {"stage", "2"}});
+    // // Enable UPM on the stage 'kEnableForSyncingUsers'.
+    // feature_list().InitAndEnableFeatureWithParameters(
+    //     /*feature=*/features::kUnifiedPasswordManagerAndroid, {{"stage",
+    //     "2"}});
 
     if (GetParam().migration_ran_before) {
       // Setup the pref to indicate that the initial migration has happened
@@ -873,8 +807,7 @@
     prefs()->registry()->RegisterBooleanPref(
         prefs::kRequiresMigrationAfterSyncStatusChange, false);
     feature_list().InitAndEnableFeatureWithParameters(
-        /*feature=*/features::kUnifiedPasswordManagerAndroid,
-        {{"migration_version", "1"}, {"stage", "0"}});
+        /*feature=*/features::kUnifiedPasswordManagerAndroid, {{"stage", "0"}});
 
     CreateMigrator(&built_in_backend_, &android_backend_, prefs());
   }
@@ -921,9 +854,8 @@
 TEST_F(BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest,
        DoesNotCompleteMigrationWhenWritingToAndroidBackendFails_SyncOff) {
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "3"}});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kUnifiedPasswordManagerLocalPasswordsAndroid);
 
   // Sync state doesn't affect this test, run it arbitrarily for non-sync'ing
   // users.
@@ -965,10 +897,6 @@
 
 TEST_F(BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest,
        SecondMigrationCannotStartWhileTheFirstOneHasNotCompleted) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      /*feature=*/features::kUnifiedPasswordManagerAndroid,
-      {{"migration_version", "1"}, {"stage", "0"}});
   InitSyncService(/*is_password_sync_enabled=*/true);
 
   // Add a form to the built-in backend to have something to migrate.
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 559b4223..d29b92b 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -540,6 +540,7 @@
 bool PasswordAutofillManager::GetDeletionConfirmationText(
     const std::u16string& value,
     autofill::Suggestion::FrontendId frontend_id,
+    autofill::Suggestion::BackendId backend_id,
     std::u16string* title,
     std::u16string* body) {
   return false;
@@ -547,7 +548,8 @@
 
 bool PasswordAutofillManager::RemoveSuggestion(
     const std::u16string& value,
-    autofill::Suggestion::FrontendId frontend_id) {
+    autofill::Suggestion::FrontendId frontend_id,
+    autofill::Suggestion::BackendId backend_id) {
   // Password suggestions cannot be deleted this way.
   // See http://crbug.com/329038#c15
   return false;
diff --git a/components/password_manager/core/browser/password_autofill_manager.h b/components/password_manager/core/browser/password_autofill_manager.h
index 21d0608..b51c358 100644
--- a/components/password_manager/core/browser/password_autofill_manager.h
+++ b/components/password_manager/core/browser/password_autofill_manager.h
@@ -62,10 +62,12 @@
                            int position) override;
   bool GetDeletionConfirmationText(const std::u16string& value,
                                    autofill::Suggestion::FrontendId frontend_id,
+                                   autofill::Suggestion::BackendId backend_id,
                                    std::u16string* title,
                                    std::u16string* body) override;
   bool RemoveSuggestion(const std::u16string& value,
-                        autofill::Suggestion::FrontendId frontend_id) override;
+                        autofill::Suggestion::FrontendId frontend_id,
+                        autofill::Suggestion::BackendId backend_id) override;
   void ClearPreviewedForm() override;
   autofill::PopupType GetPopupType() const override;
   absl::variant<autofill::AutofillDriver*, PasswordManagerDriver*> GetDriver()
diff --git a/components/password_manager/core/browser/sync_credentials_filter.cc b/components/password_manager/core/browser/sync_credentials_filter.cc
index 2b54c984..b6f1492e 100644
--- a/components/password_manager/core/browser/sync_credentials_filter.cc
+++ b/components/password_manager/core/browser/sync_credentials_filter.cc
@@ -39,30 +39,43 @@
   const signin::IdentityManager* identity_manager =
       client_->GetIdentityManager();
 
-  if (base::FeatureList::IsEnabled(features::kEnablePasswordsAccountStorage)) {
-    // If kEnablePasswordsAccountStorage is enabled, then don't allow saving the
-    // password if it corresponds to the primary account. Note that if the user
-    // is just signing in to the first Gaia account, then IdentityManager might
-    // not know about the account yet.
-    if (sync_util::IsGaiaCredentialPage(form.signon_realm)) {
-      CoreAccountInfo primary_account = identity_manager->GetPrimaryAccountInfo(
-          signin::ConsentLevel::kSignin);
-      if (primary_account.IsEmpty() ||
-          gaia::AreEmailsSame(base::UTF16ToUTF8(form.username_value),
-                              primary_account.email)) {
-        return false;
-      }
-    }
-  } else {
+  if (!base::FeatureList::IsEnabled(features::kEnablePasswordsAccountStorage)) {
+    // Legacy code path, subject to clean-up.
     // If kEnablePasswordsAccountStorage is NOT enabled, then don't allow saving
     // the password for the sync account specifically.
-    if (sync_util::IsSyncAccountCredential(form.url, form.username_value,
-                                           sync_service, identity_manager)) {
-      return false;
-    }
+    return !sync_util::IsSyncAccountCredential(form.url, form.username_value,
+                                               sync_service, identity_manager);
   }
 
-  return true;
+  if (!sync_util::IsGaiaCredentialPage(form.signon_realm)) {
+    return true;
+  }
+
+  // The requirement to fulfill is "don't offer to save a Gaia password inside
+  // its own account".
+  // Let's assume that if the browser is signed-in, new passwords are saved to
+  // the primary signed-in account. Per sync_util::GetAccountForSaving(), that's
+  // not always true, but let's not overcomplicate.
+  CoreAccountInfo primary_account =
+      identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
+  if (!primary_account.IsEmpty()) {
+    // This returns false when `primary_account` just signed-in on the web and
+    // already made it to the IdentityManager.
+    return !gaia::AreEmailsSame(base::UTF16ToUTF8(form.username_value),
+                                primary_account.email);
+  }
+
+  // The browser is signed-out and the web just signed-in. On desktop, this
+  // immediately leads to browser sign-in, so don't offer saving.
+  // TODO(crbug.com/1446361): The above is false if the user disabled browser
+  // sign-in. Return true then. Currently these users can't save Gaia passwords.
+
+  // On mobile, sign-in via the web page doesn't lead to browser sign-in, so
+  // offer saving.
+  // (Navigating to the Gaia web page opens Chrome UI which must be accepted to
+  // perform browser+web sign-in. The code path here is only hit if that UI was
+  // suppressed/ dismissed and the user interacted directly with the page.)
+  return BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS);
 }
 
 bool SyncCredentialsFilter::ShouldSaveGaiaPasswordHash(
diff --git a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
index fbc1513..90b307e1 100644
--- a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
+++ b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -230,14 +230,15 @@
                   ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
                   .IsEmpty());
   SetSyncingPasswords(false);
-  // If kEnablePasswordsAccountStorage is enabled, then Chrome shouldn't offer
-  // to save the password for the primary account. If there is no primary
-  // account yet, then the just-signed-in account will *become* the primary
-  // account immediately, so it shouldn't be saved either.
+  // See comments inside ShouldSave() for the justification.
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+  EXPECT_TRUE(filter_->ShouldSave(form));
+#else
   if (base::FeatureList::IsEnabled(features::kEnablePasswordsAccountStorage))
     EXPECT_FALSE(filter_->ShouldSave(form));
   else
     EXPECT_TRUE(filter_->ShouldSave(form));
+#endif
 }
 
 TEST_P(CredentialsFilterTest, ShouldSave_NotSyncCredential) {
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 65759d9..fc030b18 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -308,10 +308,6 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 #if BUILDFLAG(IS_ANDROID)
-// Current migration version to Google Mobile Services. If version saved in pref
-// is lower than 'kMigrationVersion' passwords will be re-uploaded.
-extern const base::FeatureParam<int> kMigrationVersion = {
-    &kUnifiedPasswordManagerAndroid, "migration_version", 1};
 
 // The string version to use for the save/update password prompts when the user
 // is syncing passwords. Version 1 is outdated, so the only supported versions
@@ -380,23 +376,6 @@
   return false;
 }
 
-bool ManagesLocalPasswordsInUnifiedPasswordManager() {
-  if (!base::FeatureList::IsEnabled(kUnifiedPasswordManagerAndroid)) {
-    return false;
-  }
-  UpmExperimentVariation variation = kUpmExperimentVariationParam.Get();
-  switch (variation) {
-    case UpmExperimentVariation::kEnableForSyncingUsers:
-    case UpmExperimentVariation::kShadowSyncingUsers:
-    case UpmExperimentVariation::kEnableOnlyBackendForSyncingUsers:
-      return false;
-    case UpmExperimentVariation::kEnableForAllUsers:
-      return true;
-  }
-  NOTREACHED()
-      << "Define explicitly whether local password management is supported!";
-  return false;
-}
 #endif  // IS_ANDROID
 
 #if BUILDFLAG(IS_IOS)
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 79b4739..ef7c190 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -136,7 +136,6 @@
         &kPasswordStrengthIndicator, "strength_indicator_minimized", false};
 
 #if BUILDFLAG(IS_ANDROID)
-extern const base::FeatureParam<int> kMigrationVersion;
 
 // Current list of the GMS Core API error codes that should be ignored and not
 // result in user eviction.
@@ -200,10 +199,6 @@
 // that requires migrating existing credentials. Independent of
 // whether only non-syncable data needs to be migrated or full credentials.
 bool RequiresMigrationForUnifiedPasswordManager();
-
-// Returns true if the unified password manager feature is active and in a stage
-// that uses the unified storage for passwords that remain local on the device.
-bool ManagesLocalPasswordsInUnifiedPasswordManager();
 #endif  // IS_ANDROID
 
 #if BUILDFLAG(IS_IOS)
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.h b/components/policy/core/common/cloud/cloud_policy_constants.h
index 4bd421db..c16e1dfa 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.h
+++ b/components/policy/core/common/cloud/cloud_policy_constants.h
@@ -153,6 +153,8 @@
   DM_STATUS_SERVICE_ILLEGAL_ACCOUNT_FOR_PACKAGED_EDU_LICENSE = 908,
   // Service error: Packaged license device can't enroll KIOSK.
   DM_STATUS_SERVICE_INVALID_PACKAGED_DEVICE_FOR_KIOSK = 909,
+  // TODO(b/265923216): Convert to enum class and rename this to kMaxValue.
+  DM_STATUS_SERVICE_MAX = DM_STATUS_SERVICE_INVALID_PACKAGED_DEVICE_FOR_KIOSK
 };
 
 // List of modes that the device can be locked into.
diff --git a/components/policy/core/common/cloud/enterprise_metrics.cc b/components/policy/core/common/cloud/enterprise_metrics.cc
index 95799e3..17ff6e1 100644
--- a/components/policy/core/common/cloud/enterprise_metrics.cc
+++ b/components/policy/core/common/cloud/enterprise_metrics.cc
@@ -208,4 +208,58 @@
 const char kUMASuffixInitialEnrollment[] = ".InitialEnrollment";
 const char kUMASuffixFRE[] = ".ForcedReenrollment";
 
+const char kUMAStateDeterminationDeviceIdentifierStatus[] =
+    "Enterprise.StateDetermination.DeviceIdentifierStatus";
+const char kUMAStateDeterminationEnabled[] =
+    "Enterprise.StateDetermination.Enabled";
+const char kUMAStateDeterminationEmbargoDatePassed[] =
+    "Enterprise.StateDetermination.EmbargoDatePassed";
+const char kUMAStateDeterminationKillSwitchFetchNetworkErrorCode[] =
+    "Enterprise.StateDetermination.KillSwitchFetch.NetworkErrorCode";
+const char kUMAStateDeterminationKillSwitchFetchNumTries[] =
+    "Enterprise.StateDetermination.KillSwitchFetch.NumTries";
+const char kUMAStateDeterminationOnFlex[] =
+    "Enterprise.StateDetermination.OnFlex";
+const char kUMAStateDeterminationOwnershipStatus[] =
+    "Enterprise.StateDetermination.OwnershipStatus";
+const char kUMAStateDeterminationPsmReportedAvailableState[] =
+    "Enterprise.StateDetermination.PsmReportedAvailableState";
+const char kUMAStateDeterminationPsmRlweOprfRequestDmStatusCode[] =
+    "Enterprise.StateDetermination.PsmRlweOprfRequest.DmStatusCode";
+const char kUMAStateDeterminationPsmRlweOprfRequestNetworkErrorCode[] =
+    "Enterprise.StateDetermination.PsmRlweOprfRequest.NetworkErrorCode";
+const char kUMAStateDeterminationPsmRlweQueryRequestDmStatusCode[] =
+    "Enterprise.StateDetermination.PsmRlweQueryRequest.DmStatusCode";
+const char kUMAStateDeterminationPsmRlweQueryRequestNetworkErrorCode[] =
+    "Enterprise.StateDetermination.PsmRlweQueryRequest.NetworkErrorCode";
+const char kUMAStateDeterminationStateKeysRetrieved[] =
+    "Enterprise.StateDetermination.StateKeysRetrieved";
+const char kUMAStateDeterminationStateRequestDmStatusCode[] =
+    "Enterprise.StateDetermination.StateRequest.DmStatusCode";
+const char kUMAStateDeterminationStateRequestNetworkErrorCode[] =
+    "Enterprise.StateDetermination.StateRequest.NetworkErrorCode";
+const char kUMAStateDeterminationStateReturned[] =
+    "Enterprise.StateDetermination.StateReturned";
+const char kUMAStateDeterminationStepDuration[] =
+    "Enterprise.StateDetermination.StepDuration";
+const char kUMAStateDeterminationSystemClockSynchronized[] =
+    "Enterprise.StateDetermination.SystemClockSynchronized";
+const char kUMAStateDeterminationTotalDurationByState[] =
+    "Enterprise.StateDetermination.TotalDurationByState";
+const char kUMAStateDeterminationTotalDuration[] =
+    "Enterprise.StateDetermination.TotalDuration";
+
+const char kUMASuffixConnectionError[] = ".ConnectionError";
+const char kUMASuffixDisabled[] = ".Disabled";
+const char kUMASuffixEnrollment[] = ".Enrollment";
+const char kUMASuffixNoEnrollment[] = ".NoEnrollment";
+const char kUMASuffixServerError[] = ".ServerError";
+
+const char kUMASuffixOPRFRequest[] = ".OPRFRequest";
+const char kUMASuffixOwnershipCheck[] = ".OwnershipCheck";
+const char kUMASuffixQueryRequest[] = ".QueryRequest";
+const char kUMASuffixStateKeyRetrieval[] = ".StateKeyRetrieval";
+const char kUMASuffixStateRequest[] = ".StateRequest";
+const char kUMASuffixSystemClockSync[] = ".SystemClockSync";
+
 }  // namespace policy
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h
index bfb9a922..be67a039 100644
--- a/components/policy/core/common/cloud/enterprise_metrics.h
+++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -279,6 +279,51 @@
 // Suffix for Forced Re-Enrollment.
 POLICY_EXPORT extern const char kUMASuffixFRE[];
 
+// Histograpms for the unified state determination.
+POLICY_EXPORT extern const char kUMAStateDeterminationDeviceIdentifierStatus[];
+POLICY_EXPORT extern const char kUMAStateDeterminationEmbargoDatePassed[];
+POLICY_EXPORT extern const char kUMAStateDeterminationEnabled[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationKillSwitchFetchNetworkErrorCode[];
+POLICY_EXPORT extern const char kUMAStateDeterminationKillSwitchFetchNumTries[];
+POLICY_EXPORT extern const char kUMAStateDeterminationOnFlex[];
+POLICY_EXPORT extern const char kUMAStateDeterminationOwnershipStatus[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationPsmReportedAvailableState[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationPsmRlweOprfRequestDmStatusCode[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationPsmRlweOprfRequestNetworkErrorCode[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationPsmRlweQueryRequestDmStatusCode[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationPsmRlweQueryRequestNetworkErrorCode[];
+POLICY_EXPORT extern const char kUMAStateDeterminationStateKeysRetrieved[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationStateRequestDmStatusCode[];
+POLICY_EXPORT extern const char
+    kUMAStateDeterminationStateRequestNetworkErrorCode[];
+POLICY_EXPORT extern const char kUMAStateDeterminationStateReturned[];
+POLICY_EXPORT extern const char kUMAStateDeterminationStepDuration[];
+POLICY_EXPORT extern const char kUMAStateDeterminationSystemClockSynchronized[];
+POLICY_EXPORT extern const char kUMAStateDeterminationTotalDurationByState[];
+POLICY_EXPORT extern const char kUMAStateDeterminationTotalDuration[];
+
+// Suffixes added to kUMAStateDeterminationTotalDurationByState.
+POLICY_EXPORT extern const char kUMASuffixConnectionError[];
+POLICY_EXPORT extern const char kUMASuffixDisabled[];
+POLICY_EXPORT extern const char kUMASuffixEnrollment[];
+POLICY_EXPORT extern const char kUMASuffixNoEnrollment[];
+POLICY_EXPORT extern const char kUMASuffixServerError[];
+
+// Suffixes added to kUMAStateDeterminationStepDuration.
+POLICY_EXPORT extern const char kUMASuffixOPRFRequest[];
+POLICY_EXPORT extern const char kUMASuffixOwnershipCheck[];
+POLICY_EXPORT extern const char kUMASuffixQueryRequest[];
+POLICY_EXPORT extern const char kUMASuffixStateKeyRetrieval[];
+POLICY_EXPORT extern const char kUMASuffixStateRequest[];
+POLICY_EXPORT extern const char kUMASuffixSystemClockSync[];
+
 }  // namespace policy
 
 #endif  // COMPONENTS_POLICY_CORE_COMMON_CLOUD_ENTERPRISE_METRICS_H_
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/DataLeakPreventionRulesList.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/DataLeakPreventionRulesList.yaml
index 14935185..5a6ff7a 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/DataLeakPreventionRulesList.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/DataLeakPreventionRulesList.yaml
@@ -99,6 +99,7 @@
               - PLUGIN_VM
               - DRIVE
               - USB
+              - ONEDRIVE
               type: string
             type: array
           urls:
diff --git a/components/supervised_user/core/browser/kids_external_fetcher.cc b/components/supervised_user/core/browser/kids_external_fetcher.cc
index fb74b34..ea287fe 100644
--- a/components/supervised_user/core/browser/kids_external_fetcher.cc
+++ b/components/supervised_user/core/browser/kids_external_fetcher.cc
@@ -66,12 +66,16 @@
          net::HTTP_OK;
 }
 
-int CombineNetAndHttpErrors(const network::SimpleURLLoader& loader) {
-  if (loader.NetError() != net::OK || !loader.ResponseInfo() ||
-      !loader.ResponseInfo()->headers) {
-    return loader.NetError();
+// Return HTTP status if available, or net::Error otherwise. HTTP status takes
+// precedence to avoid masking it by net::ERR_HTTP_RESPONSE_CODE_FAILURE.
+// Returned value is positive for HTTP status and negative for net::Error,
+// consistent with
+// tools/metrics/histograms/enums.xml://enum[@name='CombinedHttpResponseAndNetErrorCode']
+int HttpStatusOrNetError(const network::SimpleURLLoader& loader) {
+  if (loader.ResponseInfo() && loader.ResponseInfo()->headers) {
+    return loader.ResponseInfo()->headers->response_code();
   }
-  return loader.ResponseInfo()->headers->response_code();
+  return loader.NetError();
 }
 
 std::string CreateAuthorizationHeader(
@@ -148,9 +152,10 @@
     RecordStabilityMetrics(latency, status);
 
     // Record additional metrics for various failures.
-    if (status.state() == KidsExternalFetcherStatus::State::NET_OR_HTTP_ERROR) {
-      UmaHistogramSparse(GetMetricKey("NetOrHttpStatus"),
-                         status.net_or_http_error_code().value());
+    if (status.state() ==
+        KidsExternalFetcherStatus::State::HTTP_STATUS_OR_NET_ERROR) {
+      UmaHistogramSparse(GetMetricKey("HttpStatusOrNetError"),
+                         status.http_status_or_net_error().value());
     }
 
     DCHECK(
@@ -207,8 +212,8 @@
                                  std::unique_ptr<std::string> response_body) {
     if (!IsLoadingSuccessful(*simple_url_loader_) ||
         !HasHttpOkResponse(*simple_url_loader_)) {
-      std::move(callback).Run(KidsExternalFetcherStatus::NetOrHttpError(
-                                  CombineNetAndHttpErrors(*simple_url_loader_)),
+      std::move(callback).Run(KidsExternalFetcherStatus::HttpStatusOrNetError(
+                                  HttpStatusOrNetError(*simple_url_loader_)),
                               nullptr);
       return;
     }
@@ -244,8 +249,9 @@
   DCHECK(state != State::GOOGLE_SERVICE_AUTH_ERROR);
 }
 KidsExternalFetcherStatus::KidsExternalFetcherStatus(
-    NetOrHttpErrorType error_code)
-    : state_(State::NET_OR_HTTP_ERROR), net_or_http_error_code_(error_code) {}
+    HttpStatusOrNetErrorType http_status_or_net_error)
+    : state_(State::HTTP_STATUS_OR_NET_ERROR),
+      http_status_or_net_error_(http_status_or_net_error) {}
 KidsExternalFetcherStatus::KidsExternalFetcherStatus(
     class GoogleServiceAuthError google_service_auth_error)
     : KidsExternalFetcherStatus(GOOGLE_SERVICE_AUTH_ERROR,
@@ -263,9 +269,10 @@
     class GoogleServiceAuthError error) {
   return KidsExternalFetcherStatus(error);
 }
-KidsExternalFetcherStatus KidsExternalFetcherStatus::NetOrHttpError(
-    int net_or_http_error_code) {
-  return KidsExternalFetcherStatus(NetOrHttpErrorType(net_or_http_error_code));
+KidsExternalFetcherStatus KidsExternalFetcherStatus::HttpStatusOrNetError(
+    int http_status_or_net_error) {
+  return KidsExternalFetcherStatus(
+      HttpStatusOrNetErrorType(http_status_or_net_error));
 }
 KidsExternalFetcherStatus KidsExternalFetcherStatus::InvalidResponse() {
   return KidsExternalFetcherStatus(State::INVALID_RESPONSE);
@@ -278,7 +285,7 @@
   return state_ == State::OK;
 }
 bool KidsExternalFetcherStatus::IsTransientError() const {
-  if (state_ == State::NET_OR_HTTP_ERROR) {
+  if (state_ == State::HTTP_STATUS_OR_NET_ERROR) {
     return true;
   }
   if (state_ == State::GOOGLE_SERVICE_AUTH_ERROR) {
@@ -304,11 +311,13 @@
     case KidsExternalFetcherStatus::OK:
       return "KidsExternalFetcherStatus::OK";
     case KidsExternalFetcherStatus::GOOGLE_SERVICE_AUTH_ERROR:
-      return StrCat({"KidsExternalFetcherStatus::GOOGLE_SERVICE_AUTH_ERROR: ",
-                     google_service_auth_error().ToString()});
-    case KidsExternalFetcherStatus::NET_OR_HTTP_ERROR:
-      return StringPrintf("KidsExternalFetcherStatus::NET_OR_HTTP_ERROR: %d",
-                          net_or_http_error_code_.value());
+      return base::StrCat(
+          {"KidsExternalFetcherStatus::GOOGLE_SERVICE_AUTH_ERROR: ",
+           google_service_auth_error().ToString()});
+    case KidsExternalFetcherStatus::HTTP_STATUS_OR_NET_ERROR:
+      return base::StringPrintf(
+          "KidsExternalFetcherStatus::HTTP_STATUS_OR_NET_ERROR: %d",
+          http_status_or_net_error_.value());
     case KidsExternalFetcherStatus::INVALID_RESPONSE:
       return "KidsExternalFetcherStatus::INVALID_RESPONSE";
     case KidsExternalFetcherStatus::DATA_ERROR:
@@ -317,18 +326,18 @@
 }
 
 // The returned value must match one of the labels in
-// chromium/src/tools/metrics/histograms/enums.xml/histogram-configuration/enums/enum[@name='KidsExternalFetcherStatus'],
+// chromium/src/tools/metrics/histograms/enums.xml://enum[@name='KidsExternalFetcherStatus'],
 // and should be reflected in tokens in histogram defined for this fetcher.
 // See example at
-// chromium/src/tools/metrics/histograms/metadata/signin/histograms.xml/histogram-configuration/histograms/histogram[@name='Signin.ListFamilyMembersRequest.{Status}.*']
+// tools/metrics/histograms/metadata/signin/histograms.xml://histogram[@name='Signin.ListFamilyMembersRequest.{Status}.*']
 std::string KidsExternalFetcherStatus::ToMetricEnumLabel() const {
   switch (state_) {
     case KidsExternalFetcherStatus::OK:
       return "NoError";
     case KidsExternalFetcherStatus::GOOGLE_SERVICE_AUTH_ERROR:
       return "AuthError";
-    case KidsExternalFetcherStatus::NET_OR_HTTP_ERROR:
-      return "HttpError";
+    case KidsExternalFetcherStatus::HTTP_STATUS_OR_NET_ERROR:
+      return "HttpStatusOrNetError";
     case KidsExternalFetcherStatus::INVALID_RESPONSE:
       return "ParseError";
     case KidsExternalFetcherStatus::DATA_ERROR:
@@ -339,9 +348,9 @@
 KidsExternalFetcherStatus::State KidsExternalFetcherStatus::state() const {
   return state_;
 }
-KidsExternalFetcherStatus::NetOrHttpErrorType
-KidsExternalFetcherStatus::net_or_http_error_code() const {
-  return net_or_http_error_code_;
+KidsExternalFetcherStatus::HttpStatusOrNetErrorType
+KidsExternalFetcherStatus::http_status_or_net_error() const {
+  return http_status_or_net_error_;
 }
 
 const GoogleServiceAuthError&
diff --git a/components/supervised_user/core/browser/kids_external_fetcher.h b/components/supervised_user/core/browser/kids_external_fetcher.h
index 92a0859..b8f4b18 100644
--- a/components/supervised_user/core/browser/kids_external_fetcher.h
+++ b/components/supervised_user/core/browser/kids_external_fetcher.h
@@ -44,17 +44,18 @@
 // numeric values should never be reused.
 class KidsExternalFetcherStatus {
  public:
-  using NetOrHttpErrorType = base::StrongAlias<class NetOrHttpErrorTag, int>;
+  using HttpStatusOrNetErrorType =
+      base::StrongAlias<class HttpStatusOrNetErrorTag, int>;
 
   enum State {
     OK = 0,
     GOOGLE_SERVICE_AUTH_ERROR = 1,  // Error occurred during the access token
                                     // fetching phase. See
                                     // GetGoogleServiceAuthError for details.
-    NET_OR_HTTP_ERROR = 2,  // The request was performed, but network or http
-                            // returned errors. This is default chromium
-                            // approach to combine those two error domains.
-    INVALID_RESPONSE = 3,   // The request was performed without error, but http
+    HTTP_STATUS_OR_NET_ERROR =
+        2,  // The request was performed, but network or http returned errors.
+            // This is default chromium approach to combine those two domains.
+    INVALID_RESPONSE = 3,  // The request was performed without error, but http
                            // response could not be processed or was unexpected.
     DATA_ERROR = 4,  // The request was parsed, but did not contain all required
                      // data. Not signalled by this fetcher itself, but might be
@@ -77,9 +78,9 @@
       GoogleServiceAuthError
           error);  // The copy follows the interface of
                    // https://source.chromium.org/chromium/chromium/src/+/main:components/signin/public/identity_manager/primary_account_access_token_fetcher.h;l=241;drc=8ba1bad80dc22235693a0dd41fe55c0fd2dbdabd
-  static KidsExternalFetcherStatus NetOrHttpError(
-      int error_code = 0);  // Either net::Error (negative numbers, 0 denotes
-                            // success) or HTTP error (standard error codes).
+  static KidsExternalFetcherStatus HttpStatusOrNetError(
+      int value = 0);  // Either net::Error (negative numbers, 0 denotes
+                       // success) or HTTP status.
   static KidsExternalFetcherStatus InvalidResponse();
   static KidsExternalFetcherStatus DataError();
 
@@ -100,13 +101,14 @@
   std::string ToMetricEnumLabel() const;
 
   State state() const;
-  NetOrHttpErrorType net_or_http_error_code() const;
+  HttpStatusOrNetErrorType http_status_or_net_error() const;
   const class GoogleServiceAuthError& google_service_auth_error() const;
 
  private:
   // Disallows impossible states.
   explicit KidsExternalFetcherStatus(State state);
-  explicit KidsExternalFetcherStatus(NetOrHttpErrorType error_code);
+  explicit KidsExternalFetcherStatus(
+      HttpStatusOrNetErrorType http_status_or_net_error);
   explicit KidsExternalFetcherStatus(
       class GoogleServiceAuthError
           google_service_auth_error);  // Implies State ==
@@ -116,8 +118,8 @@
       class GoogleServiceAuthError google_service_auth_error);
 
   State state_;
-  NetOrHttpErrorType net_or_http_error_code_{
-      0};  // Meaningful iff state_ == NET_OR_HTTP_ERROR
+  HttpStatusOrNetErrorType http_status_or_net_error_{
+      0};  // Meaningful iff state_ == HTTP_STATUS_OR_NET_ERROR
   class GoogleServiceAuthError google_service_auth_error_;
 };
 
diff --git a/components/supervised_user/core/browser/kids_external_fetcher_unittest.cc b/components/supervised_user/core/browser/kids_external_fetcher_unittest.cc
index 515a369a..c48aa17 100644
--- a/components/supervised_user/core/browser/kids_external_fetcher_unittest.cc
+++ b/components/supervised_user/core/browser/kids_external_fetcher_unittest.cc
@@ -213,10 +213,10 @@
       net::HTTP_BAD_REQUEST);
   EXPECT_FALSE(receiver.GetResult().has_value());
   EXPECT_EQ(receiver.GetResult().error().state(),
-            KidsExternalFetcherStatus::State::NET_OR_HTTP_ERROR);
-  EXPECT_EQ(receiver.GetResult().error().net_or_http_error_code(),
-            KidsExternalFetcherStatus::NetOrHttpErrorType(
-                net::ERR_HTTP_RESPONSE_CODE_FAILURE));
+            KidsExternalFetcherStatus::State::HTTP_STATUS_OR_NET_ERROR);
+  EXPECT_EQ(receiver.GetResult().error().http_status_or_net_error(),
+            KidsExternalFetcherStatus::HttpStatusOrNetErrorType(
+                net::HTTP_BAD_REQUEST));
 }
 
 }  // namespace
diff --git a/components/sync/engine/sync_engine_host.h b/components/sync/engine/sync_engine_host.h
index f971f5d..bcd6242 100644
--- a/components/sync/engine/sync_engine_host.h
+++ b/components/sync/engine/sync_engine_host.h
@@ -55,6 +55,9 @@
 
   // Called when invalidations are enabled or disabled.
   virtual void OnInvalidationStatusChanged() = 0;
+
+  // Called when there are new data types with pending invalidations.
+  virtual void OnNewInvalidatedDataTypes() = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine/sync_manager_impl.cc b/components/sync/engine/sync_manager_impl.cc
index c9365b73d..0d7788c 100644
--- a/components/sync/engine/sync_manager_impl.cc
+++ b/components/sync/engine/sync_manager_impl.cc
@@ -372,6 +372,8 @@
     bool has_pending_invalidations) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   scheduler_->SetHasPendingInvalidations(type, has_pending_invalidations);
+  sync_status_tracker_->SetHasPendingInvalidations(type,
+                                                   has_pending_invalidations);
 }
 
 void SyncManagerImpl::NotifySyncStatusChanged(const SyncStatus& status) {
diff --git a/components/sync/engine/sync_manager_impl_unittest.cc b/components/sync/engine/sync_manager_impl_unittest.cc
index 08e48df..0fad75a 100644
--- a/components/sync/engine/sync_manager_impl_unittest.cc
+++ b/components/sync/engine/sync_manager_impl_unittest.cc
@@ -48,6 +48,8 @@
 #include "url/gurl.h"
 
 using testing::_;
+using testing::SaveArg;
+using testing::Sequence;
 using testing::StrictMock;
 
 namespace syncer {
@@ -133,6 +135,7 @@
                ModelTypeSet types_to_download,
                base::OnceClosure ready_task),
               (override));
+  MOCK_METHOD(void, SetHasPendingInvalidations, (ModelType, bool), (override));
 };
 
 class ComponentsFactory : public TestEngineComponentsFactory {
@@ -206,6 +209,7 @@
 
   SyncManagerImpl* sync_manager() { return &sync_manager_; }
   MockSyncScheduler* scheduler() { return scheduler_; }
+  SyncManagerObserverMock* manager_observer() { return &manager_observer_; }
 
  private:
   base::test::SingleThreadTaskEnvironment task_environment_;
@@ -238,6 +242,29 @@
       SyncManager::SyncFeatureState::ON, ready_task.Get());
 }
 
+TEST_F(SyncManagerImplTest, ShouldSetHasPendingInvalidations) {
+  Sequence s1;
+  EXPECT_CALL(*scheduler(),
+              SetHasPendingInvalidations(BOOKMARKS, /*has_invalidation=*/true))
+      .InSequence(s1);
+  EXPECT_CALL(*scheduler(),
+              SetHasPendingInvalidations(BOOKMARKS, /*has_invalidation=*/false))
+      .InSequence(s1);
+  SyncStatus status;
+  EXPECT_CALL(*manager_observer(), OnSyncStatusChanged)
+      .Times(2)
+      .WillRepeatedly(SaveArg<0>(&status));
+
+  sync_manager()->SetHasPendingInvalidations(
+      BOOKMARKS, /*has_pending_invalidations=*/true);
+  EXPECT_EQ(status.invalidated_data_types.Size(), 1u);
+  EXPECT_TRUE(status.invalidated_data_types.Has(BOOKMARKS));
+
+  sync_manager()->SetHasPendingInvalidations(
+      BOOKMARKS, /*has_pending_invalidations=*/false);
+  EXPECT_TRUE(status.invalidated_data_types.Empty());
+}
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/sync/engine/sync_status.h b/components/sync/engine/sync_status.h
index 5f182e2..dad92dce 100644
--- a/components/sync/engine/sync_status.h
+++ b/components/sync/engine/sync_status.h
@@ -75,6 +75,9 @@
   // The unique identifier for the invalidation client.
   std::string invalidator_client_id;
 
+  // Data types having pending invalidations.
+  ModelTypeSet invalidated_data_types;
+
   // Time of next retry if sync scheduler is throttled or in backoff.
   base::Time retry_time;
 
diff --git a/components/sync/engine/sync_status_tracker.cc b/components/sync/engine/sync_status_tracker.cc
index 38075db..a13ef09 100644
--- a/components/sync/engine/sync_status_tracker.cc
+++ b/components/sync/engine/sync_status_tracker.cc
@@ -171,6 +171,18 @@
   status_changed_callback_.Run(status_);
 }
 
+void SyncStatusTracker::SetHasPendingInvalidations(
+    ModelType type,
+    bool has_pending_invalidations) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (has_pending_invalidations) {
+    status_.invalidated_data_types.Put(type);
+  } else {
+    status_.invalidated_data_types.Remove(type);
+  }
+  status_changed_callback_.Run(status_);
+}
+
 void SyncStatusTracker::SetLocalBackendFolder(const std::string& folder) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   status_.local_sync_folder = folder;
diff --git a/components/sync/engine/sync_status_tracker.h b/components/sync/engine/sync_status_tracker.h
index df6b9651..78e478f4 100644
--- a/components/sync/engine/sync_status_tracker.h
+++ b/components/sync/engine/sync_status_tracker.h
@@ -64,6 +64,8 @@
 
   void SetCacheGuid(const std::string& cache_guid);
   void SetInvalidatorClientId(const std::string& invalidator_client_id);
+  void SetHasPendingInvalidations(ModelType type,
+                                  bool has_pending_invalidations);
 
   void SetLocalBackendFolder(const std::string& folder);
 
diff --git a/components/sync/model/client_tag_based_model_type_processor_unittest.cc b/components/sync/model/client_tag_based_model_type_processor_unittest.cc
index 485fe46..8f80c03 100644
--- a/components/sync/model/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model/client_tag_based_model_type_processor_unittest.cc
@@ -200,13 +200,10 @@
 
   base::OnceClosure GetDataCallback() { return std::move(data_callback_); }
 
-  void SetInitialSyncDone(bool is_done) {
+  void SetInitialSyncState(
+      sync_pb::ModelTypeState::InitialSyncState initial_sync_state) {
     ModelTypeState model_type_state(db().model_type_state());
-    model_type_state.set_initial_sync_state(
-        is_done
-            ? sync_pb::ModelTypeState_InitialSyncState_INITIAL_SYNC_DONE
-            : sync_pb::
-                  ModelTypeState_InitialSyncState_INITIAL_SYNC_STATE_UNSPECIFIED);
+    model_type_state.set_initial_sync_state(initial_sync_state);
     model_type_state.set_cache_guid(kCacheGuid);
     model_type_state.mutable_progress_marker()->set_data_type_id(
         GetSpecificsFieldNumberFromModelType(type()));
@@ -344,9 +341,12 @@
     histogram_tester_ = std::make_unique<base::HistogramTester>();
   }
 
-  void InitializeToMetadataLoaded(bool set_initial_sync_done = true) {
-    if (set_initial_sync_done) {
-      bridge()->SetInitialSyncDone(true);
+  void InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::InitialSyncState initial_sync_state =
+          sync_pb::ModelTypeState::INITIAL_SYNC_DONE) {
+    if (initial_sync_state !=
+        sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED) {
+      bridge()->SetInitialSyncState(initial_sync_state);
     }
     ModelReadyToSync();
   }
@@ -756,7 +756,7 @@
 
 // Test that subsequent starts don't call MergeFullSyncData.
 TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldApplyIncrementalUpdates) {
-  // This sets initial_sync_done to true.
+  // This sets initial_sync_state to "done".
   InitializeToMetadataLoaded();
 
   // Write an item before sync connects.
@@ -2072,7 +2072,8 @@
 // storage" for historical reasons) result in reporting setup duration.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldReportEphemeralConfigurationTime) {
-  InitializeToMetadataLoaded(/*set_initial_sync_done=*/false);
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED);
   OnSyncStarting(kDefaultAuthenticatedAccountId, kCacheGuid,
                  SyncMode::kTransportOnly);
 
@@ -2097,7 +2098,8 @@
 // for historical reasons) do not result in reporting setup duration.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldReportPersistentConfigurationTime) {
-  InitializeToMetadataLoaded(/*set_initial_sync_done=*/false);
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED);
   OnSyncStarting();
 
   base::HistogramTester histogram_tester;
@@ -2166,7 +2168,8 @@
 // for historical reasons) result in reporting setup duration.
 TEST_F(FullUpdateClientTagBasedModelTypeProcessorTest,
        ShouldReportEphemeralConfigurationTimeOnlyForFirstFullUpdate) {
-  InitializeToMetadataLoaded(/*set_initial_sync_done=*/false);
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED);
   OnSyncStarting(kDefaultAuthenticatedAccountId, kCacheGuid,
                  SyncMode::kTransportOnly);
 
@@ -2489,7 +2492,7 @@
   ResetState(/*keep_db=*/true);
 
   // A new processor loads the metadata after changing the cache GUID.
-  bridge()->SetInitialSyncDone(true);
+  bridge()->SetInitialSyncState(sync_pb::ModelTypeState::INITIAL_SYNC_DONE);
 
   std::unique_ptr<MetadataBatch> metadata_batch = db()->CreateMetadataBatch();
   sync_pb::ModelTypeState model_type_state(metadata_batch->GetModelTypeState());
@@ -2523,7 +2526,7 @@
   ResetState(/*keep_db=*/true);
 
   // A new processor loads the metadata after changing the data type id.
-  bridge()->SetInitialSyncDone(true);
+  bridge()->SetInitialSyncState(sync_pb::ModelTypeState::INITIAL_SYNC_DONE);
 
   std::unique_ptr<MetadataBatch> metadata_batch = db()->CreateMetadataBatch();
   sync_pb::ModelTypeState model_type_state(metadata_batch->GetModelTypeState());
@@ -2974,26 +2977,23 @@
        ShouldResetForEntityMetadataWithoutInitialSyncDone) {
   base::HistogramTester histogram_tester;
 
-  const syncer::ClientTagHash kClientTagHash =
-      ClientTagHash::FromUnhashed(AUTOFILL, "tag");
   sync_pb::EntityMetadata entity_metadata1;
-  entity_metadata1.set_client_tag_hash(kClientTagHash.value());
+  entity_metadata1.set_client_tag_hash(
+      ClientTagHash::FromUnhashed(GetModelType(), "tag1").value());
   entity_metadata1.set_creation_time(0);
   sync_pb::EntityMetadata entity_metadata2;
-  entity_metadata2.set_client_tag_hash(kClientTagHash.value());
+  entity_metadata2.set_client_tag_hash(
+      ClientTagHash::FromUnhashed(GetModelType(), "tag2").value());
   entity_metadata2.set_creation_time(0);
-  sync_pb::EntityMetadata entity_metadata3;
-  entity_metadata3.set_client_tag_hash(kClientTagHash.value());
-  entity_metadata3.set_creation_time(0);
 
   db()->PutMetadata(kKey1, std::move(entity_metadata1));
   db()->PutMetadata(kKey2, std::move(entity_metadata2));
-  db()->PutMetadata(kKey3, std::move(entity_metadata3));
 
-  InitializeToMetadataLoaded(/*set_initial_sync_done=*/false);
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED);
   OnSyncStarting();
 
-  // Since initial_sync_done was false, metadata should have been cleared.
+  // Since initial_sync_state was not set, metadata should have been cleared.
   EXPECT_EQ(0U, db()->metadata_count());
   EXPECT_EQ(0U, ProcessorEntityCount());
   EXPECT_FALSE(type_processor()->IsTrackingMetadata());
@@ -3001,20 +3001,50 @@
   worker()->UpdateFromServer();
   EXPECT_TRUE(type_processor()->IsTrackingMetadata());
 
-  // There were three entities with the same client-tag-hash which indicates
-  // that two of them were metadata oprhans.
   histogram_tester.ExpectBucketCount(
       "Sync.ModelTypeEntityMetadataWithoutInitialSync",
       /*sample=*/ModelTypeHistogramValue(GetModelType()),
       /*expected_count=*/1);
 }
 
+// Regression test for crbug.com/1427000.
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldNotResetWhenInitialSyncPartiallyDone) {
+  base::HistogramTester histogram_tester;
+
+  sync_pb::EntityMetadata entity_metadata1;
+  entity_metadata1.set_client_tag_hash(
+      ClientTagHash::FromUnhashed(GetModelType(), "tag1").value());
+  entity_metadata1.set_creation_time(0);
+  sync_pb::EntityMetadata entity_metadata2;
+  entity_metadata2.set_client_tag_hash(
+      ClientTagHash::FromUnhashed(GetModelType(), "tag2").value());
+  entity_metadata2.set_creation_time(0);
+
+  db()->PutMetadata(kKey1, std::move(entity_metadata1));
+  db()->PutMetadata(kKey2, std::move(entity_metadata2));
+
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_PARTIALLY_DONE);
+  OnSyncStarting();
+
+  // The initial_sync_state was *partially* done, which is enough to keep the
+  // (meta)data and carry on.
+  EXPECT_EQ(2U, db()->metadata_count());
+  EXPECT_EQ(2U, ProcessorEntityCount());
+  EXPECT_TRUE(type_processor()->IsTrackingMetadata());
+
+  histogram_tester.ExpectTotalCount(
+      "Sync.ModelTypeEntityMetadataWithoutInitialSync",
+      /*expected_count=*/0);
+}
+
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldResetForDuplicateClientTagHash) {
   base::HistogramTester histogram_tester;
 
   const syncer::ClientTagHash kClientTagHash =
-      ClientTagHash::FromUnhashed(AUTOFILL, "tag");
+      ClientTagHash::FromUnhashed(GetModelType(), "tag");
   sync_pb::EntityMetadata entity_metadata1;
   entity_metadata1.set_client_tag_hash(kClientTagHash.value());
   entity_metadata1.set_creation_time(0);
@@ -3069,7 +3099,8 @@
 
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldNotProcessInvalidRemoteFullUpdate) {
-  InitializeToMetadataLoaded(/*set_initial_sync_done=*/false);
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED);
   OnSyncStarting();
 
   UpdateResponseDataList updates;
@@ -3240,7 +3271,8 @@
 
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldNotClearMetadataWhileStoppedWithoutMetadataInitially) {
-  InitializeToMetadataLoaded(/*set_initial_sync_done=*/false);
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED);
   ASSERT_FALSE(type_processor()->IsTrackingMetadata());
 
   base::HistogramTester histogram_tester;
@@ -3260,7 +3292,8 @@
   // Called before ModelReadyToSync().
   type_processor()->ClearMetadataWhileStopped();
 
-  InitializeToMetadataLoaded(/*set_initial_sync_done=*/false);
+  InitializeToMetadataLoaded(
+      sync_pb::ModelTypeState::INITIAL_SYNC_STATE_UNSPECIFIED);
   ASSERT_FALSE(type_processor()->IsTrackingMetadata());
   // Nothing recorded to the histograms.
   histogram_tester.ExpectTotalCount(
diff --git a/components/sync/service/data_type_manager.h b/components/sync/service/data_type_manager.h
index 8edc969..f6f0b790 100644
--- a/components/sync/service/data_type_manager.h
+++ b/components/sync/service/data_type_manager.h
@@ -109,6 +109,10 @@
   // actively ongoing or queued).
   virtual ModelTypeSet GetTypesWithPendingDownloadForInitialSync() const = 0;
 
+  // Returns the datatypes with datatype errors (e.g. errors while loading from
+  // the disk).
+  virtual ModelTypeSet GetDataTypesWithPermanentErrors() const = 0;
+
   // The current state of the data type manager.
   virtual State state() const = 0;
 };
diff --git a/components/sync/service/data_type_manager_impl.cc b/components/sync/service/data_type_manager_impl.cc
index 8f16709..1103f1a 100644
--- a/components/sync/service/data_type_manager_impl.cc
+++ b/components/sync/service/data_type_manager_impl.cc
@@ -735,6 +735,10 @@
   return Difference(GetEnabledTypes(), downloaded_types_);
 }
 
+ModelTypeSet DataTypeManagerImpl::GetDataTypesWithPermanentErrors() const {
+  return data_type_status_table_.GetFatalErrorTypes();
+}
+
 ModelTypeSet DataTypeManagerImpl::GetPurgedDataTypes() const {
   ModelTypeSet purged_types;
 
diff --git a/components/sync/service/data_type_manager_impl.h b/components/sync/service/data_type_manager_impl.h
index a0939ec..9d446c3 100644
--- a/components/sync/service/data_type_manager_impl.h
+++ b/components/sync/service/data_type_manager_impl.h
@@ -48,8 +48,9 @@
   ModelTypeSet GetActiveDataTypes() const override;
   ModelTypeSet GetPurgedDataTypes() const override;
   ModelTypeSet GetActiveProxyDataTypes() const override;
-  State state() const override;
   ModelTypeSet GetTypesWithPendingDownloadForInitialSync() const override;
+  ModelTypeSet GetDataTypesWithPermanentErrors() const override;
+  State state() const override;
 
   // `ModelLoadManagerDelegate` implementation.
   void OnAllDataTypesReadyForConfigure() override;
diff --git a/components/sync/service/glue/sync_engine_impl.cc b/components/sync/service/glue/sync_engine_impl.cc
index 53af193..4e80ec8 100644
--- a/components/sync/service/glue/sync_engine_impl.cc
+++ b/components/sync/service/glue/sync_engine_impl.cc
@@ -546,6 +546,9 @@
       (status.backed_off_types != cached_status_.backed_off_types);
   const bool invalidation_status_changed =
       (status.notifications_enabled != cached_status_.notifications_enabled);
+  const bool has_new_invalidated_data_types =
+      !cached_status_.invalidated_data_types.HasAll(
+          status.invalidated_data_types);
   cached_status_ = status;
   if (backed_off_types_changed) {
     host_->OnBackedOffTypesChanged();
@@ -553,6 +556,13 @@
   if (invalidation_status_changed) {
     host_->OnInvalidationStatusChanged();
   }
+  if (has_new_invalidated_data_types) {
+    // Notify about any new data types having pending invalidations. When there
+    // are less such data types, this basically means that sync cycle has been
+    // finished, and |host_| will be notified via OnSyncCycleCompleted(), so
+    // there is no point in duplicating it.
+    host_->OnNewInvalidatedDataTypes();
+  }
 }
 
 void SyncEngineImpl::OnCookieJarChanged(bool account_mismatch,
diff --git a/components/sync/service/glue/sync_engine_impl_unittest.cc b/components/sync/service/glue/sync_engine_impl_unittest.cc
index cb3290b7..04e6c40 100644
--- a/components/sync/service/glue/sync_engine_impl_unittest.cc
+++ b/components/sync/service/glue/sync_engine_impl_unittest.cc
@@ -50,6 +50,7 @@
 using testing::ByMove;
 using testing::NiceMock;
 using testing::Return;
+using testing::Sequence;
 
 namespace syncer {
 
@@ -84,6 +85,7 @@
               (override));
   MOCK_METHOD(void, OnBackedOffTypesChanged, (), (override));
   MOCK_METHOD(void, OnInvalidationStatusChanged, (), (override));
+  MOCK_METHOD(void, OnNewInvalidatedDataTypes, (), (override));
 };
 
 class FakeSyncManagerFactory : public SyncManagerFactory {
@@ -885,6 +887,34 @@
   EXPECT_NE(kTestBirthday, transport_data_prefs.GetBirthday());
 }
 
+TEST_F(SyncEngineImplTest, ShouldNotifyOnNewInvalidatedDataTypes) {
+  InitializeBackend();
+  ConfigureDataTypes();
+
+  // Use OnInvalidationStatusChanged() to verify that
+  // OnNewInvalidatedDataTypes() is caled only once in the beginning, and all
+  // the next invalidated data types updates should not notify.
+  Sequence seq;
+  EXPECT_CALL(mock_host_, OnNewInvalidatedDataTypes).InSequence(seq);
+  EXPECT_CALL(mock_host_, OnInvalidationStatusChanged).InSequence(seq);
+
+  SyncStatus sync_status;
+  sync_status.invalidated_data_types.Put(BOOKMARKS);
+  fake_manager_->NotifySyncStatusChanged(sync_status);
+  fake_manager_->WaitForSyncThread();
+
+  // Turn on notifications to trigger OnInvalidationStatusChanged().
+  sync_status.notifications_enabled = true;
+  fake_manager_->NotifySyncStatusChanged(sync_status);
+  fake_manager_->WaitForSyncThread();
+
+  // Removing an invalidated data type shouldn't invoke
+  // OnNewInvalidatedDataTypes().
+  sync_status.invalidated_data_types.Remove(BOOKMARKS);
+  fake_manager_->NotifySyncStatusChanged(sync_status);
+  fake_manager_->WaitForSyncThread();
+}
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/sync/service/sync_service_impl.cc b/components/sync/service/sync_service_impl.cc
index 57ae025..9bd4b87 100644
--- a/components/sync/service/sync_service_impl.cc
+++ b/components/sync/service/sync_service_impl.cc
@@ -696,6 +696,8 @@
       result.Put(DISABLE_REASON_ENTERPRISE_POLICY);
     }
     if (!IsSignedIn()) {
+      // TODO(crbug.com/1447377): additionally, check for refresh tokens to be
+      // loaded.
       result.Put(DISABLE_REASON_NOT_SIGNED_IN);
     }
   }
@@ -1040,6 +1042,10 @@
   NotifyObservers();
 }
 
+void SyncServiceImpl::OnNewInvalidatedDataTypes() {
+  NotifyObservers();
+}
+
 void SyncServiceImpl::OnConfigureDone(
     const DataTypeManager::ConfigureResult& result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -1838,8 +1844,43 @@
 
 SyncService::ModelTypeDownloadStatus SyncServiceImpl::GetDownloadStatusFor(
     ModelType type) const {
-  NOTREACHED() << "Download status API is not implemented.";
-  return ModelTypeDownloadStatus::kWaitingForUpdates;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!auth_manager_->IsActiveAccountInfoFullyLoaded()) {
+    // Wait for refresh tokens to be loaded from the disk. GetDisableReasons()
+    // won't be empty until then.
+    return ModelTypeDownloadStatus::kWaitingForUpdates;
+  }
+
+  // TODO(crbug.com/1425026): check whether this works when local sync is
+  // enabled.
+  if (!GetDisableReasons().Empty() || !GetDataTypesToConfigure().Has(type)) {
+    // Sync is disabled hence updates won't be downloaded from the server.
+    return ModelTypeDownloadStatus::kError;
+  }
+
+  if (!data_type_manager_) {
+    // Wait for the sync engine to be fully initialized.
+    return ModelTypeDownloadStatus::kWaitingForUpdates;
+  }
+  CHECK(engine_);
+
+  if (data_type_manager_->GetDataTypesWithPermanentErrors().Has(type)) {
+    return ModelTypeDownloadStatus::kError;
+  }
+
+  if (!GetActiveDataTypes().Has(type) ||
+      !engine_->GetDetailedStatus().notifications_enabled) {
+    return ModelTypeDownloadStatus::kWaitingForUpdates;
+  }
+
+  if (engine_->GetDetailedStatus().invalidated_data_types.Has(type)) {
+    return ModelTypeDownloadStatus::kWaitingForUpdates;
+  }
+
+  // TODO(crbug.com/1425026): check for upcoming polling request.
+  NOTREACHED() << "Download status API is not fully implemented yet.";
+  return ModelTypeDownloadStatus::kUpToDate;
 }
 
 CoreAccountInfo SyncServiceImpl::GetAccountInfo() const {
diff --git a/components/sync/service/sync_service_impl.h b/components/sync/service/sync_service_impl.h
index 178027f..28a0bed 100644
--- a/components/sync/service/sync_service_impl.h
+++ b/components/sync/service/sync_service_impl.h
@@ -161,6 +161,7 @@
   void OnActionableProtocolError(const SyncProtocolError& error) override;
   void OnBackedOffTypesChanged() override;
   void OnInvalidationStatusChanged() override;
+  void OnNewInvalidatedDataTypes() override;
 
   // DataTypeManagerObserver implementation.
   void OnConfigureDone(const DataTypeManager::ConfigureResult& result) override;
diff --git a/components/sync/service/sync_service_impl_unittest.cc b/components/sync/service/sync_service_impl_unittest.cc
index 0d0572fb..b5b6286 100644
--- a/components/sync/service/sync_service_impl_unittest.cc
+++ b/components/sync/service/sync_service_impl_unittest.cc
@@ -52,6 +52,8 @@
 using testing::AtLeast;
 using testing::ByMove;
 using testing::Eq;
+using testing::Invoke;
+using testing::IsNull;
 using testing::Not;
 using testing::Return;
 
@@ -65,6 +67,11 @@
 
 constexpr char kTestUser[] = "test_user@gmail.com";
 
+class MockSyncServiceObserver : public SyncServiceObserver {
+ public:
+  MOCK_METHOD(void, OnStateChanged, (SyncService * sync), (override));
+};
+
 class TestSyncServiceObserver : public SyncServiceObserver {
  public:
   TestSyncServiceObserver() = default;
@@ -1351,5 +1358,104 @@
   EXPECT_EQ(1, get_controller(BOOKMARKS)->model()->clear_metadata_call_count());
 }
 
+TEST_F(SyncServiceImplTest, ShouldReturnErrorDownloadStatus) {
+  SignIn();
+  CreateService();
+  InitializeForNthSync();
+
+  data_type_manager()->OnSingleDataTypeWillStop(
+      syncer::BOOKMARKS,
+      SyncError(FROM_HERE, SyncError::ErrorType::DATATYPE_ERROR,
+                "Data type failure", syncer::BOOKMARKS));
+  EXPECT_EQ(service()->GetDownloadStatusFor(syncer::BOOKMARKS),
+            SyncService::ModelTypeDownloadStatus::kError);
+}
+
+TEST_F(SyncServiceImplTest, ShouldReturnErrorDownloadStatusWhenSyncDisabled) {
+  prefs()->SetManagedPref(prefs::internal::kSyncManaged, base::Value(true));
+  SignIn();
+  CreateService();
+  InitializeForNthSync();
+
+  EXPECT_EQ(service()->GetDownloadStatusFor(syncer::BOOKMARKS),
+            SyncService::ModelTypeDownloadStatus::kError);
+}
+
+TEST_F(SyncServiceImplTest, ShouldReturnWaitingDownloadStatus) {
+  SignIn();
+  CreateService();
+
+  ASSERT_THAT(data_type_manager(), IsNull());
+
+  bool met_configuring_data_type_manager = false;
+  testing::NiceMock<MockSyncServiceObserver> mock_sync_service_observer;
+  ON_CALL(mock_sync_service_observer, OnStateChanged)
+      .WillByDefault(Invoke([this, &met_configuring_data_type_manager](
+                                SyncService* service) {
+        // TODO(crbug.com/1425026): verify that there are no errors during
+        // backend initialization.
+        if (!data_type_manager()) {
+          return;
+        }
+        if (data_type_manager()->state() ==
+            DataTypeManager::State::CONFIGURING) {
+          met_configuring_data_type_manager = true;
+          EXPECT_EQ(service->GetDownloadStatusFor(syncer::BOOKMARKS),
+                    SyncService::ModelTypeDownloadStatus::kWaitingForUpdates);
+        }
+      }));
+
+  // Observers must be added after initialization has been started.
+  InitializeForNthSync(false);
+
+  // GetDownloadStatusFor() must be called only after Initialize(), see
+  // SyncServiceImpl::Initialize().
+  EXPECT_EQ(service()->GetDownloadStatusFor(syncer::BOOKMARKS),
+            SyncService::ModelTypeDownloadStatus::kWaitingForUpdates);
+
+  service()->AddObserver(&mock_sync_service_observer);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(met_configuring_data_type_manager);
+  // TODO(crbug.com/1425026): add check for up-to-date status.
+  service()->RemoveObserver(&mock_sync_service_observer);
+}
+
+TEST_F(SyncServiceImplTest, ShouldReturnErrorWhenDataTypeDisabled) {
+  SignIn();
+  CreateService();
+  InitializeForNthSync(/*run_until_idle=*/false);
+
+  UserSelectableTypeSet enabled_types =
+      service()->GetUserSettings()->GetSelectedTypes();
+  enabled_types.Remove(UserSelectableType::kBookmarks);
+  service()->GetUserSettings()->SetSelectedTypes(/*sync_everything=*/false,
+                                                 enabled_types);
+
+  EXPECT_EQ(service()->GetDownloadStatusFor(syncer::BOOKMARKS),
+            SyncService::ModelTypeDownloadStatus::kError);
+
+  // Finish initialization and double check that the status hasn't changed.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(service()->GetDownloadStatusFor(syncer::BOOKMARKS),
+            SyncService::ModelTypeDownloadStatus::kError);
+}
+
+TEST_F(SyncServiceImplTest, ShouldWaitUntilNoInvalidations) {
+  SignIn();
+  CreateService();
+  InitializeForNthSync();
+
+  SyncStatus status;
+  status.invalidated_data_types.Put(BOOKMARKS);
+  engine()->SetDetailedStatus(status);
+
+  EXPECT_EQ(service()->GetDownloadStatusFor(syncer::BOOKMARKS),
+            SyncService::ModelTypeDownloadStatus::kWaitingForUpdates);
+  // TODO(crbug.com/1425026): uncomment once up-to-date status is supported.
+  // EXPECT_EQ(service()->GetDownloadStatusFor(syncer::PASSWORDS),
+  //           SyncService::ModelTypeDownloadStatus::kUpToDate);
+}
+
 }  // namespace
 }  // namespace syncer
diff --git a/components/sync/test/data_type_manager_mock.h b/components/sync/test/data_type_manager_mock.h
index 29a0cbe..05838c5 100644
--- a/components/sync/test/data_type_manager_mock.h
+++ b/components/sync/test/data_type_manager_mock.h
@@ -30,6 +30,10 @@
               GetTypesWithPendingDownloadForInitialSync,
               (),
               (const override));
+  MOCK_METHOD(ModelTypeSet,
+              GetDataTypesWithPermanentErrors,
+              (),
+              (const override));
   MOCK_METHOD(State, state, (), (const override));
 
  private:
diff --git a/components/sync/test/fake_sync_engine.cc b/components/sync/test/fake_sync_engine.cc
index fbbe117..bd05182 100644
--- a/components/sync/test/fake_sync_engine.cc
+++ b/components/sync/test/fake_sync_engine.cc
@@ -35,6 +35,10 @@
   host_->OnEngineInitialized(success, is_first_time_sync_configure_);
 }
 
+void FakeSyncEngine::SetDetailedStatus(const SyncStatus& status) {
+  sync_status_ = status;
+}
+
 void FakeSyncEngine::Initialize(InitParams params) {
   DCHECK(params.host);
 
@@ -112,7 +116,7 @@
 void FakeSyncEngine::SetProxyTabsDatatypeEnabled(bool enabled) {}
 
 const SyncStatus& FakeSyncEngine::GetDetailedStatus() const {
-  return default_sync_status_;
+  return sync_status_;
 }
 
 void FakeSyncEngine::HasUnsyncedItemsForTest(
diff --git a/components/sync/test/fake_sync_engine.h b/components/sync/test/fake_sync_engine.h
index 6bf1e85..335017a 100644
--- a/components/sync/test/fake_sync_engine.h
+++ b/components/sync/test/fake_sync_engine.h
@@ -47,6 +47,8 @@
   // in the constructor.
   void TriggerInitializationCompletion(bool success);
 
+  void SetDetailedStatus(const SyncStatus& status);
+
   // Immediately calls params.host->OnEngineInitialized.
   void Initialize(InitParams params) override;
 
@@ -114,7 +116,7 @@
   // DanglingUntriaged because it is assigned a DanglingUntriaged pointer.
   raw_ptr<SyncEngineHost, DanglingUntriaged> host_ = nullptr;
   bool initialized_ = false;
-  const SyncStatus default_sync_status_;
+  SyncStatus sync_status_;
   CoreAccountId authenticated_account_id_;
   bool started_handling_invalidations_ = false;
 };
diff --git a/components/sync/test/fake_sync_manager.cc b/components/sync/test/fake_sync_manager.cc
index d54cc90..988c444a 100644
--- a/components/sync/test/fake_sync_manager.cc
+++ b/components/sync/test/fake_sync_manager.cc
@@ -27,7 +27,9 @@
     : initial_sync_ended_types_(initial_sync_ended_types),
       progress_marker_types_(progress_marker_types),
       configure_fail_types_(configure_fail_types),
-      last_configure_reason_(CONFIGURE_REASON_UNKNOWN) {}
+      last_configure_reason_(CONFIGURE_REASON_UNKNOWN) {
+  sync_task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
+}
 
 FakeSyncManager::~FakeSyncManager() = default;
 
@@ -61,8 +63,20 @@
   run_loop.Run();
 }
 
+void FakeSyncManager::NotifySyncStatusChanged(const SyncStatus& status) {
+  sync_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&FakeSyncManager::DoNotifySyncStatusChanged,
+                                base::Unretained(this), status));
+}
+
+void FakeSyncManager::DoNotifySyncStatusChanged(const SyncStatus& status) {
+  DCHECK(sync_task_runner_->RunsTasksInCurrentSequence());
+  for (Observer& observer : observers_) {
+    observer.OnSyncStatusChanged(status);
+  }
+}
+
 void FakeSyncManager::Init(InitArgs* args) {
-  sync_task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
   cache_guid_ = args->cache_guid;
   birthday_ = args->birthday;
   bag_of_chips_ = args->bag_of_chips;
@@ -113,10 +127,12 @@
 }
 
 void FakeSyncManager::AddObserver(Observer* observer) {
+  DCHECK(sync_task_runner_->RunsTasksInCurrentSequence());
   observers_.AddObserver(observer);
 }
 
 void FakeSyncManager::RemoveObserver(Observer* observer) {
+  DCHECK(sync_task_runner_->RunsTasksInCurrentSequence());
   observers_.RemoveObserver(observer);
 }
 
diff --git a/components/sync/test/fake_sync_manager.h b/components/sync/test/fake_sync_manager.h
index 1462f9bb..e01ef9c9 100644
--- a/components/sync/test/fake_sync_manager.h
+++ b/components/sync/test/fake_sync_manager.h
@@ -68,6 +68,9 @@
 
   bool IsInvalidatorEnabled() const { return invalidator_enabled_; }
 
+  // Notifies all observers about the changed |status|.
+  void NotifySyncStatusChanged(const SyncStatus& status);
+
   // SyncManager implementation.
   // Note: we treat whatever message loop this is called from as the sync
   // loop for purposes of callbacks.
@@ -105,6 +108,8 @@
       ActiveDevicesInvalidationInfo active_devices_invalidation_info) override;
 
  private:
+  void DoNotifySyncStatusChanged(const SyncStatus& status);
+
   scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
 
   base::ObserverList<SyncManager::Observer>::Unchecked observers_;
diff --git a/components/webauthn/android/webauthn_cred_man_delegate.cc b/components/webauthn/android/webauthn_cred_man_delegate.cc
index 5fe069e..6b03cc1 100644
--- a/components/webauthn/android/webauthn_cred_man_delegate.cc
+++ b/components/webauthn/android/webauthn_cred_man_delegate.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <utility>
+#include "base/android/build_info.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
@@ -62,7 +63,8 @@
 
 // static
 bool WebAuthnCredManDelegate::IsCredManEnabled() {
-  return base::FeatureList::IsEnabled(device::kWebAuthnAndroidCredMan);
+  return base::android::BuildInfo::GetInstance()->is_at_least_u() &&
+         base::FeatureList::IsEnabled(device::kWebAuthnAndroidCredMan);
 }
 
 // static
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index e22a8e0..d60a819 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -225,6 +225,9 @@
         return FailedMigrationTo(next_version);
       }
     }
+    base::UmaHistogramExactLinear("WebDatabase.SucceededMigrationToVersion",
+                                  next_version,
+                                  WebDatabase::kCurrentVersionNumber + 1);
   }
   return sql::INIT_OK;
 }
diff --git a/content/browser/back_forward_cache_no_store_browsertest.cc b/content/browser/back_forward_cache_no_store_browsertest.cc
index 4d9d46a..e1b4dbdd 100644
--- a/content/browser/back_forward_cache_no_store_browsertest.cc
+++ b/content/browser/back_forward_cache_no_store_browsertest.cc
@@ -102,8 +102,9 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
-    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache,
-                              "level", "store-and-evict");
+    EnableFeatureAndSetParams(
+        features::kCacheControlNoStoreEnterBackForwardCache, "level",
+        "store-and-evict");
     BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
   }
 };
@@ -937,8 +938,9 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
-    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache,
-                              "level", "restore-unless-cookie-change");
+    EnableFeatureAndSetParams(
+        features::kCacheControlNoStoreEnterBackForwardCache, "level",
+        "restore-unless-cookie-change");
     BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
   }
 };
@@ -1426,9 +1428,9 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
-    EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache,
-                              "level",
-                              "restore-unless-http-only-cookie-change");
+    EnableFeatureAndSetParams(
+        features::kCacheControlNoStoreEnterBackForwardCache, "level",
+        "restore-unless-http-only-cookie-change");
     BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
   }
 };
diff --git a/content/browser/geolocation/geolocation_service_impl.cc b/content/browser/geolocation/geolocation_service_impl.cc
index efaa068f..e0fc994f 100644
--- a/content/browser/geolocation/geolocation_service_impl.cc
+++ b/content/browser/geolocation/geolocation_service_impl.cc
@@ -12,6 +12,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
+#include "services/device/public/cpp/geolocation/geolocation_manager.h"
 #include "third_party/blink/public/common/permissions/permission_utils.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h"
 
@@ -58,12 +59,24 @@
   DCHECK(render_frame_host);
 }
 
-GeolocationServiceImpl::~GeolocationServiceImpl() {}
+GeolocationServiceImpl::~GeolocationServiceImpl() {
+  if (device::GeolocationManager* geolocation_manager =
+          device::GeolocationManager::GetInstance();
+      geolocation_manager) {
+    // One call here is enough as the calls are grouped by app name
+    geolocation_manager->AppCeasesToUseGeolocation();
+  }
+}
 
 void GeolocationServiceImpl::Bind(
     mojo::PendingReceiver<blink::mojom::GeolocationService> receiver) {
   receiver_set_.Add(this, std::move(receiver),
                     std::make_unique<GeolocationServiceImplContext>());
+  if (device::GeolocationManager* geolocation_manager =
+          device::GeolocationManager::GetInstance();
+      geolocation_manager) {
+    geolocation_manager->AppAttemptsToUseGeolocation();
+  }
 }
 
 void GeolocationServiceImpl::CreateGeolocation(
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc
index 9615a72..c47ecf3 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -381,7 +381,7 @@
          "restore-unless-http-only-cookie-change"},
 };
 const base::FeatureParam<CacheControlNoStoreExperimentLevel>
-    cache_control_level{&kCacheControlNoStoreEnterBackForwardCache,
+    cache_control_level{&features::kCacheControlNoStoreEnterBackForwardCache,
                         kCacheControlNoStoreExperimentLevelName,
                         CacheControlNoStoreExperimentLevel::kDoNotStore,
                         &cache_control_levels};
@@ -389,7 +389,7 @@
 CacheControlNoStoreExperimentLevel GetCacheControlNoStoreLevel() {
   if (!IsBackForwardCacheEnabled() ||
       !base::FeatureList::IsEnabled(
-          kCacheControlNoStoreEnterBackForwardCache)) {
+          features::kCacheControlNoStoreEnterBackForwardCache)) {
     return CacheControlNoStoreExperimentLevel::kDoNotStore;
   }
   return cache_control_level.Get();
diff --git a/content/browser/renderer_host/back_forward_cache_impl.h b/content/browser/renderer_host/back_forward_cache_impl.h
index 73511d5..2350280 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.h
+++ b/content/browser/renderer_host/back_forward_cache_impl.h
@@ -57,14 +57,6 @@
              "BackForwardCacheNoTimeEviction",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Allows pages with cache-control:no-store to enter the back/forward cache.
-// Feature params can specify whether pages with cache-control:no-store can be
-// restored if cookies change / if HTTPOnly cookies change.
-// TODO(crbug.com/1228611): Enable this feature.
-BASE_FEATURE(kCacheControlNoStoreEnterBackForwardCache,
-             "CacheControlNoStoreEnterBackForwardCache",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kBackForwardCacheSize);
 CONTENT_EXPORT extern const base::FeatureParam<int>
     kBackForwardCacheSizeCacheSize;
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index c2231384..cf3c0c18 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -307,6 +307,7 @@
     // Browser command-line switches to propagate to the utility process.
     static const char* const kSwitchNames[] = {
       network::switches::kAdditionalTrustTokenKeyCommitments,
+      network::switches::kBlockThirdPartyCookies,
       network::switches::kForceEffectiveConnectionType,
       network::switches::kHostResolverRules,
       network::switches::kIgnoreCertificateErrorsSPKIList,
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 0c8a8ad..eef5b0b 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -225,6 +225,14 @@
              "BrowserVerifiedUserActivationMouse",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Allows pages with cache-control:no-store to enter the back/forward cache.
+// Feature params can specify whether pages with cache-control:no-store can be
+// restored if cookies change / if HTTPOnly cookies change.
+// TODO(crbug.com/1228611): Enable this feature.
+BASE_FEATURE(kCacheControlNoStoreEnterBackForwardCache,
+             "CacheControlNoStoreEnterBackForwardCache",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // If Canvas2D Image Chromium is allowed, this feature controls whether it is
 // enabled.
 BASE_FEATURE(kCanvas2DImageChromium,
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 281c0c57..338d0c9 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -51,6 +51,7 @@
     kBrokerFileOperationsOnDiskCacheInNetworkService);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kBrowserVerifiedUserActivationKeyboard);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kBrowserVerifiedUserActivationMouse);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kCacheControlNoStoreEnterBackForwardCache);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kCanvas2DImageChromium);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(
     kClearCrossSiteCrossBrowsingContextGroupWindowName);
diff --git a/content/public/common/content_switch_dependent_feature_overrides.cc b/content/public/common/content_switch_dependent_feature_overrides.cc
index 24f3169c0..ff9dbe7 100644
--- a/content/public/common/content_switch_dependent_feature_overrides.cc
+++ b/content/public/common/content_switch_dependent_feature_overrides.cc
@@ -119,6 +119,11 @@
      std::cref(net::features::kPartitionedCookies),
      base::FeatureList::OVERRIDE_ENABLE_FEATURE},
 
+    // Override third-party cookie blocking.
+    {network::switches::kBlockThirdPartyCookies,
+     std::cref(net::features::kForceThirdPartyCookieBlocking),
+     base::FeatureList::OVERRIDE_ENABLE_FEATURE},
+
     // Overrides for --isolation-by-default.
     {switches::kIsolationByDefault,
      std::cref(features::kEmbeddingRequiresOptIn),
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 9443923..1bfd5fb 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -2807,8 +2807,9 @@
     rules_registry->ready().Post(
         FROM_HERE,
         base::BindOnce(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
-                       base::Unretained(this), browser_context, event_name,
-                       request->id, request_stage));
+                       base::Unretained(this),
+                       base::UnsafeDanglingUntriaged(browser_context),
+                       event_name, request->id, request_stage));
     BlockedRequest& blocked_request = blocked_requests_[request->id];
     blocked_request.num_handlers_blocking++;
     blocked_request.request = request;
diff --git a/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Builder/properties.json b/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Builder/properties.json
index 9f57f19..689c3dc2 100644
--- a/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Builder/properties.json
+++ b/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Builder/properties.json
@@ -95,5 +95,5 @@
   "builder_group": "chromium.webrtc",
   "perf_dashboard_machine_group": "ChromiumWebRTC",
   "recipe": "chromium",
-  "xcode_build_version": "14c18"
+  "xcode_build_version": "14e222b"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Tester/properties.json b/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Tester/properties.json
index 5c6c749..c8eb757 100644
--- a/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Tester/properties.json
+++ b/infra/config/generated/builders/webrtc/WebRTC Chromium Mac Tester/properties.json
@@ -87,5 +87,5 @@
   "builder_group": "chromium.webrtc",
   "perf_dashboard_machine_group": "ChromiumWebRTC",
   "recipe": "chromium",
-  "xcode_build_version": "14c18"
+  "xcode_build_version": "14e222b"
 }
\ No newline at end of file
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 478a465..af0c72c 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -89795,8 +89795,8 @@
         '}'
       execution_timeout_secs: 7200
       caches {
-        name: "xcode_ios_14c18"
-        path: "xcode_ios_14c18.app"
+        name: "xcode_ios_14e222b"
+        path: "xcode_ios_14e222b.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -89845,8 +89845,8 @@
         '}'
       execution_timeout_secs: 7200
       caches {
-        name: "xcode_ios_14c18"
-        path: "xcode_ios_14c18.app"
+        name: "xcode_ios_14e222b"
+        path: "xcode_ios_14e222b.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/infra/config/generated/testing/gn_isolate_map.pyl b/infra/config/generated/testing/gn_isolate_map.pyl
index c22943e..566f4b93 100644
--- a/infra/config/generated/testing/gn_isolate_map.pyl
+++ b/infra/config/generated/testing/gn_isolate_map.pyl
@@ -207,14 +207,6 @@
     "label": "//android_webview/support_library/boundary_interfaces:boundary_interface_example_apk",
     "type": "additional_compile_target",
   },
-  "devtools_web_tests": {
-    "label": "//:devtools_web_tests",
-    "type": "generated_script",
-    "args": [
-      "--results-directory",
-      "${ISOLATED_OUTDIR}",
-    ],
-  },
   "boringssl_crypto_tests": {
     "label": "//third_party/boringssl:boringssl_crypto_tests",
     "type": "console_test_launcher",
diff --git a/infra/config/subprojects/webrtc/webrtc.star b/infra/config/subprojects/webrtc/webrtc.star
index f1a78a4..f8c494d 100644
--- a/infra/config/subprojects/webrtc/webrtc.star
+++ b/infra/config/subprojects/webrtc/webrtc.star
@@ -155,7 +155,7 @@
         build_gs_bucket = "chromium-webrtc",
     ),
     os = os.MAC_ANY,
-    xcode = xcode.x14main,
+    xcode = xcode.x14betabots,
 )
 
 builder(
@@ -176,7 +176,7 @@
         ),
         build_gs_bucket = "chromium-webrtc",
     ),
-    xcode = xcode.x14main,
+    xcode = xcode.x14betabots,
 )
 
 builder(
diff --git a/infra/config/targets/targets.star b/infra/config/targets/targets.star
index e5edd09..d5f82194 100644
--- a/infra/config/targets/targets.star
+++ b/infra/config/targets/targets.star
@@ -259,15 +259,6 @@
 #     executable = "browser_tests",
 # )
 
-targets.generated_script(
-    name = "devtools_web_tests",
-    label = "//:devtools_web_tests",
-    args = [
-        "--results-directory",
-        "${ISOLATED_OUTDIR}",
-    ],
-)
-
 targets.console_test_launcher(
     name = "boringssl_crypto_tests",
     label = "//third_party/boringssl:boringssl_crypto_tests",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 4da0677..d3a18cb 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1483,6 +1483,10 @@
      flag_descriptions::kAutofillEnableCardArtImageDescription,
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillEnableCardArtImage)},
+    {"replace-sync-promos-with-sign-in-promos",
+     flag_descriptions::kReplaceSyncPromosWithSignInPromosName,
+     flag_descriptions::kReplaceSyncPromosWithSignInPromosDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kReplaceSyncPromosWithSignInPromos)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 0e92e4a9..aa86f0f 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -848,6 +848,11 @@
     "When enabled, extra tabs with the New Tab Page open and no navigation "
     "history will be removed.";
 
+const char kReplaceSyncPromosWithSignInPromosName[] =
+    "Replace all sync-related UI with sign-in ones";
+const char kReplaceSyncPromosWithSignInPromosDescription[] =
+    "When enabled, all sync-related promos will be replaced by sign-in ones.";
+
 const char kRestoreSessionFromCacheName[] =
     "Use native WKWebView sesion restoration (iOS15 only).";
 const char kRestoreSessionFromCacheDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 40aa629..cc4d396 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -751,6 +751,11 @@
 extern const char kRemoveExcessNTPsExperimentName[];
 extern const char kRemoveExcessNTPsExperimentDescription[];
 
+// Title and description for the flag to replace all sync-related UI with
+// sign-in ones.
+extern const char kReplaceSyncPromosWithSignInPromosName[];
+extern const char kReplaceSyncPromosWithSignInPromosDescription[];
+
 // Title and description for the flag that makes Safe Browsing available.
 extern const char kSafeBrowsingAvailableName[];
 extern const char kSafeBrowsingAvailableDescription[];
diff --git a/ios/chrome/browser/history/history_client_impl.cc b/ios/chrome/browser/history/history_client_impl.cc
index 5aab8bf3..2c3f6ebc2 100644
--- a/ios/chrome/browser/history/history_client_impl.cc
+++ b/ios/chrome/browser/history/history_client_impl.cc
@@ -65,12 +65,14 @@
 std::unique_ptr<history::HistoryBackendClient>
 HistoryClientImpl::CreateBackendClient() {
   std::vector<scoped_refptr<bookmarks::ModelLoader>> model_loaders;
-  if (local_or_syncable_bookmark_model_ &&
-      local_or_syncable_bookmark_model_->model_loader()) {
-    model_loaders.push_back(local_or_syncable_bookmark_model_->model_loader());
-  }
-  if (account_bookmark_model_ && account_bookmark_model_->model_loader()) {
-    model_loaders.push_back(account_bookmark_model_->model_loader());
+  for (bookmarks::BookmarkModel* model :
+       {local_or_syncable_bookmark_model_, account_bookmark_model_}) {
+    if (!model) {
+      continue;
+    }
+    scoped_refptr<bookmarks::ModelLoader> loader = model->model_loader();
+    CHECK(loader);
+    model_loaders.push_back(std::move(loader));
   }
   return std::make_unique<HistoryBackendClientImpl>(std::move(model_loaders));
 }
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h
index d63a5d5..b4347797 100644
--- a/ios/chrome/browser/shared/public/features/features.h
+++ b/ios/chrome/browser/shared/public/features/features.h
@@ -191,4 +191,7 @@
 // synchronous clipboard access will always return nil/false.
 BASE_DECLARE_FEATURE(kOnlyAccessClipboardAsync);
 
+// Feature flag to replace all sync-related UI with sign-in ones.
+BASE_DECLARE_FEATURE(kReplaceSyncPromosWithSignInPromos);
+
 #endif  // IOS_CHROME_BROWSER_SHARED_PUBLIC_FEATURES_FEATURES_H_
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm
index ee43fea..9051f8a 100644
--- a/ios/chrome/browser/shared/public/features/features.mm
+++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -171,6 +171,10 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 bool IsTabGridSortedByRecency() {
+  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
+    return false;
+  }
+
   return base::FeatureList::IsEnabled(kTabGridRecencySort);
 }
 
@@ -251,3 +255,7 @@
 BASE_FEATURE(kOnlyAccessClipboardAsync,
              "OnlyAccessClipboardAsync",
              base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kReplaceSyncPromosWithSignInPromos,
+             "ReplaceSyncPromosWithSignInPromos",
+             base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm b/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
index b7d3887..e6683d542 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
@@ -919,8 +919,7 @@
   [ChromeEarlGrey clearBrowsingHistory];
 
   // Clear the pasteboard in case there is a URL copied.
-  UIPasteboard* pasteboard = UIPasteboard.generalPasteboard;
-  [pasteboard setValue:@"" forPasteboardType:UIPasteboardNameGeneral];
+  [ChromeEarlGrey clearPasteboard];
 }
 
 // Copy button should be hidden when the omnibox is empty otherwise it should be
@@ -934,13 +933,6 @@
     EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 15.");
   }
 
-#if !TARGET_IPHONE_SIMULATOR
-  // TODO(crbug.com/1446075): This test fails on iOS 16.4 devices too.
-  if (@available(iOS 16.4, *)) {
-    EARL_GREY_TEST_DISABLED(@"crbug.com/1446075: Fails on iOS 16.4+ devices.");
-  }
-#endif
-
   // Focus omnibox.
   [self focusFakebox];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
@@ -1036,13 +1028,6 @@
 // If the selected text is the entire omnibox field, select & SelectAll button
 // should be hidden.
 - (void)testSelection {
-#if !TARGET_IPHONE_SIMULATOR
-  // TODO(crbug.com/1446075): This test fails on iOS 16.4 devices.
-  if (@available(iOS 16.4, *)) {
-    EARL_GREY_TEST_DISABLED(@"crbug.com/1446075: Fails on iOS 16.4+ devices.");
-  }
-#endif
-
   // Focus omnibox.
   [self focusFakebox];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
@@ -1072,12 +1057,24 @@
   [[EarlGrey selectElementWithMatcher:SelectAllButton()]
       assertWithMatcher:grey_notNil()];
 
+  // Wait for UIMenuController to appear or timeout after 2 seconds.
+  GREYCondition* CopyButtonIsDisplayed = [GREYCondition
+      conditionWithName:@"Copy button display condition"
+                  block:^BOOL {
+                    NSError* error = nil;
+                    [[EarlGrey selectElementWithMatcher:
+                                   chrome_test_util::
+                                       SystemSelectionCalloutCopyButton()]
+                        assertWithMatcher:grey_notNil()
+                                    error:&error];
+                    return error == nil;
+                  }];
   // Pressing select should allow copy.
   // select should be hidden.
   [[EarlGrey selectElementWithMatcher:SelectButton()] performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::
-                                          SystemSelectionCalloutCopyButton()]
-      assertWithMatcher:grey_notNil()];
+  GREYAssertTrue([CopyButtonIsDisplayed
+                     waitWithTimeout:kWaitForUIElementTimeout.InSecondsF()],
+                 @"Copy button display failed");
   [[EarlGrey selectElementWithMatcher:SelectButton()]
       assertWithMatcher:grey_nil()];
 
@@ -1085,9 +1082,9 @@
   // selectAll should be hidden.
   [[EarlGrey selectElementWithMatcher:SelectAllButton()]
       performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::
-                                          SystemSelectionCalloutCopyButton()]
-      assertWithMatcher:grey_notNil()];
+  GREYAssertTrue([CopyButtonIsDisplayed
+                     waitWithTimeout:kWaitForUIElementTimeout.InSecondsF()],
+                 @"Copy button display failed");
   [[EarlGrey selectElementWithMatcher:SelectAllButton()]
       assertWithMatcher:grey_nil()];
 }
@@ -1099,28 +1096,12 @@
     EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 15.");
   }
 
-#if !TARGET_IPHONE_SIMULATOR
-  // TODO(crbug.com/1446075): This test fails on iOS 16.4 devices too.
-  if (@available(iOS 16.4, *)) {
-    EARL_GREY_TEST_DISABLED(@"crbug.com/1446075: Fails on iOS 16.4+ devices.");
-  }
-#endif
-
   NSString* copiedText = @"test no default match1";
 
   // Put some text in pasteboard.
-  UIPasteboard.generalPasteboard.string = copiedText;
+  [ChromeEarlGrey copyTextToPasteboard:copiedText];
 
-  // Copying can take a while, wait for it to happen.
-  GREYCondition* copyCondition =
-      [GREYCondition conditionWithName:@"test text copied condition"
-                                 block:^BOOL {
-                                   return [UIPasteboard.generalPasteboard.string
-                                       isEqualToString:copiedText];
-                                 }];
-  // Wait for copy to happen or timeout after 5 seconds.
-  GREYAssertTrue([copyCondition waitWithTimeout:5],
-                 @"Copying test text failed");
+  [ChromeEarlGrey verifyStringCopied:copiedText];
 
   // Focus the omnibox.
   [self focusFakebox];
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
index f1a6b724..a2a7059 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -114,12 +114,7 @@
                        tracker:feature_engagement::TrackerFactory::
                                    GetForBrowserState(
                                        self.browser->GetBrowserState())];
-  // TODO(crbug.com/1045047): Use HandlerForProtocol after commands protocol
-  // clean up.
-  self.mediator.dispatcher =
-      static_cast<id<BrowserCommands>>(self.browser->GetCommandDispatcher());
 
-  self.mediator.webStateList = self.browser->GetWebStateList();
   TemplateURLService* templateURLService =
       ios::TemplateURLServiceFactory::GetForBrowserState(
           self.browser->GetBrowserState());
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h
index 822c260..14225e5 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h
@@ -21,7 +21,6 @@
 #import "ui/base/window_open_disposition.h"
 
 @protocol ApplicationCommands;
-@protocol BrowserCommands;
 @class BrowserActionFactory;
 @class CarouselItem;
 @protocol CarouselItemConsumer;
@@ -31,16 +30,15 @@
 @class OmniboxPopupMediator;
 @class OmniboxPopupPresenter;
 @protocol SnackbarCommands;
-class WebStateList;
 class AutocompleteController;
 
 namespace image_fetcher {
 class ImageDataFetcher;
-}  // namespace
+}  // namespace image_fetcher
 
 namespace feature_engagement {
 class Tracker;
-}
+}  // namespace feature_engagement
 
 class OmniboxPopupMediatorDelegate {
  public:
@@ -91,7 +89,6 @@
 - (void)setSemanticContentAttribute:
     (UISemanticContentAttribute)semanticContentAttribute;
 
-@property(nonatomic, weak) id<BrowserCommands> dispatcher;
 @property(nonatomic, weak) id<AutocompleteResultConsumer> consumer;
 /// Consumer for debug info.
 @property(nonatomic, weak) id<PopupDebugInfoConsumer,
@@ -108,8 +105,6 @@
 /// Presenter for the popup, handling the positioning and the presentation
 /// animations.
 @property(nonatomic, strong) OmniboxPopupPresenter* presenter;
-/// The web state list this mediator is handling.
-@property(nonatomic, assign) WebStateList* webStateList;
 /// Whether the default search engine is Google impacts which icon is used in
 /// some cases
 @property(nonatomic, assign) BOOL defaultSearchEngineIsGoogle;
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm
index 960ab596..eea096d 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm
@@ -30,7 +30,6 @@
 #import "ios/chrome/browser/net/crurl.h"
 #import "ios/chrome/browser/ntp/new_tab_page_util.h"
 #import "ios/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent.h"
-#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/shared/public/commands/application_commands.h"
 #import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/shared/ui/util/pasteboard_util.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_pedal_egtest.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_pedal_egtest.mm
index 696dd23..5ca944a2 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_pedal_egtest.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_pedal_egtest.mm
@@ -284,6 +284,39 @@
   [ChromeEarlGrey closeCurrentTab];
 }
 
+// Tests that safety check pedal is present and it opens the safety check page.
+- (void)testSafetyCheckPedal {
+  // Focus omnibox from Web.
+  [ChromeEarlGrey loadURL:GURL("about:blank")];
+  [ChromeEarlGreyUI focusOmniboxAndType:@"pedalsafetycheck"];
+
+  NSString* safetyCheckPedalString = l10n_util::GetNSString(
+      IDS_IOS_OMNIBOX_PEDAL_SUBTITLE_RUN_CHROME_SAFETY_CHECK);
+
+  // Matcher for safety check pedal suggestion.
+  id<GREYMatcher> safetyCheckPedal = popupRowWithString(safetyCheckPedalString);
+
+  // Safety check pedal should be visible.
+  [ChromeEarlGrey waitForUIElementToAppearWithMatcher:safetyCheckPedal];
+
+  // Tap on safety check pedal.
+  [[EarlGrey selectElementWithMatcher:safetyCheckPedal]
+      performAction:grey_tap()];
+
+  // Safety check page should be displayed.
+  [ChromeEarlGrey waitForUIElementToAppearWithMatcher:
+                      chrome_test_util::SafetyCheckTableViewMatcher()];
+
+  // Close the safety check page.
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
+      performAction:grey_tap()];
+  [ChromeEarlGrey waitForUIElementToDisappearWithMatcher:
+                      chrome_test_util::SafetyCheckTableViewMatcher()];
+
+  [ChromeEarlGrey closeCurrentTab];
+}
+
 // Tests that the dino pedal does not appear when the search suggestion is below
 // the top 3.
 - (void)testNoPedal {
diff --git a/ios/chrome/test/data/omnibox/fake_suggestions_pedal.json b/ios/chrome/test/data/omnibox/fake_suggestions_pedal.json
index dc03e89a..30888a3 100644
--- a/ios/chrome/test/data/omnibox/fake_suggestions_pedal.json
+++ b/ios/chrome/test/data/omnibox/fake_suggestions_pedal.json
@@ -333,5 +333,46 @@
       "google:verbatimrelevance": 1300
     }
     ],
+  [
+  "pedalsafetycheck",
+  [
+    "Run Chrome Safety Check",
+    "nopedal1",
+    "nopedal2"
+  ],
+  [
+    "",
+    "",
+    "",
+  ],
+  [],
+  {
+    "google:clientdata": {
+      "bpc": false,
+      "tlw": false
+    },
+    "google:suggestdetail": [
+      {},
+      {},
+      {},
+    ],
+    "google:suggestrelevance": [
+      1253,
+      1252,
+      1251,
+    ],
+    "google:suggestsubtypes": [
+      [],
+      [],
+      [],
+    ],
+    "google:suggesttype": [
+      "QUERY",
+      "QUERY",
+      "QUERY",
+    ],
+    "google:verbatimrelevance": 1300
+  }
+  ],
 ]
 
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h
index 5acf13fe..fb18f32056 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -578,6 +578,9 @@
 // Returns a mather for default browser settings table view.
 id<GREYMatcher> DefaultBrowserSettingsTableViewMatcher();
 
+// Returns a matcher for safety check table view.
+id<GREYMatcher> SafetyCheckTableViewMatcher();
+
 #pragma mark - Promo style view controller
 
 // Returns matcher for the primary action button.
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm
index acd7a3d..440caaa 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -717,6 +717,10 @@
   return [ChromeMatchersAppInterface defaultBrowserSettingsTableViewMatcher];
 }
 
+id<GREYMatcher> SafetyCheckTableViewMatcher() {
+  return [ChromeMatchersAppInterface safetyCheckTableViewMatcher];
+}
+
 #pragma mark - Overflow Menu Destinations
 
 id<GREYMatcher> BookmarksDestinationButton() {
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
index 24e9f9bb..10149b7 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
@@ -544,6 +544,9 @@
 // Returns a matcher to default browser settings table view.
 + (id<GREYMatcher>)defaultBrowserSettingsTableViewMatcher;
 
+// Returns a matcher to safety check table view.
++ (id<GREYMatcher>)safetyCheckTableViewMatcher;
+
 #pragma mark - Overflow Menu Destinations
 
 // Returns matcher for the bookmarks destination button in the overflow menu
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
index cad9f41..7f1c646 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -1096,6 +1096,11 @@
   return grey_accessibilityID(kDefaultBrowserSettingsTableViewId);
 }
 
++ (id<GREYMatcher>)safetyCheckTableViewMatcher {
+  return grey_accessibilityID(
+      SafetyCheckTableViewController.accessibilityIdentifier);
+}
+
 #pragma mark - Overflow Menu Destinations
 
 + (id<GREYMatcher>)bookmarksDestinationButton {
diff --git a/net/base/features.cc b/net/base/features.cc
index b50811b4..c1f7597 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -365,4 +365,9 @@
              "EnableSchemeBoundCookies",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enable third-party cookie blocking from the command line.
+BASE_FEATURE(kForceThirdPartyCookieBlocking,
+             "ForceThirdPartyCookieBlockingEnabled",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 }  // namespace net::features
diff --git a/net/base/features.h b/net/base/features.h
index 168fea0..e29fc8e4 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -383,6 +383,9 @@
 // Enables binding of cookies to the scheme that originally set them.
 NET_EXPORT BASE_DECLARE_FEATURE(kEnableSchemeBoundCookies);
 
+// Enables enabling third-party cookie blocking from the command line.
+NET_EXPORT BASE_DECLARE_FEATURE(kForceThirdPartyCookieBlocking);
+
 }  // namespace net::features
 
 #endif  // NET_BASE_FEATURES_H_
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
index 683eabd..edc57c10 100644
--- a/net/cookies/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -1002,4 +1002,8 @@
       base::ranges::is_sorted(included_cookies, CookieWithAccessResultSorter));
 }
 
+NET_EXPORT bool IsForceThirdPartyCookieBlockingEnabled() {
+  return base::FeatureList::IsEnabled(features::kForceThirdPartyCookieBlocking);
+}
+
 }  // namespace net::cookie_util
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
index d02b6177..8c7ecff 100644
--- a/net/cookies/cookie_util.h
+++ b/net/cookies/cookie_util.h
@@ -331,6 +331,11 @@
     const CookieAccessResultList& included_cookies,
     const CookieAccessResultList& excluded_cookies);
 
+// Returns the default third-party cookie blocking setting, which is false
+// unless you enable ForceThirdPartyCookieBlocking with the command line switch
+// --block-third-party-cookies.
+NET_EXPORT bool IsForceThirdPartyCookieBlockingEnabled();
+
 }  // namespace cookie_util
 
 }  // namespace net
diff --git a/remoting/host/chromeos/features.cc b/remoting/host/chromeos/features.cc
index 3cf69ec6..a2ce667 100644
--- a/remoting/host/chromeos/features.cc
+++ b/remoting/host/chromeos/features.cc
@@ -16,10 +16,6 @@
              "EnableCrdAdminRemoteAccessV2",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kForceCrdAdminRemoteAccess,
-             "ForceCrdAdminRemoteAccess",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kEnableFrameSinkDesktopCapturerInCrd,
              "EnableFrameSinkDesktopCapturerInCrd",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/remoting/host/chromeos/features.h b/remoting/host/chromeos/features.h
index 2db3232..b299a50 100644
--- a/remoting/host/chromeos/features.h
+++ b/remoting/host/chromeos/features.h
@@ -17,11 +17,6 @@
 // to GA.
 BASE_DECLARE_FEATURE(kEnableCrdAdminRemoteAccessV2);
 
-// Force all enterprise remote connections to be remote access connections.
-// Only used for local testing until the DPanel UI supports sending remote
-// access requests.
-BASE_DECLARE_FEATURE(kForceCrdAdminRemoteAccess);
-
 // Enable to allow FrameSinkDesktopCapturer to be used for CRD video streaming.
 BASE_DECLARE_FEATURE(kEnableFrameSinkDesktopCapturerInCrd);
 
diff --git a/services/device/public/cpp/geolocation/geolocation_manager.cc b/services/device/public/cpp/geolocation/geolocation_manager.cc
index 8774e41..15a0d940 100644
--- a/services/device/public/cpp/geolocation/geolocation_manager.cc
+++ b/services/device/public/cpp/geolocation/geolocation_manager.cc
@@ -47,6 +47,14 @@
 
 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS)
 
+void GeolocationManager::AppAttemptsToUseGeolocation() {
+  system_geolocation_source_->AppAttemptsToUseGeolocation();
+}
+
+void GeolocationManager::AppCeasesToUseGeolocation() {
+  system_geolocation_source_->AppCeasesToUseGeolocation();
+}
+
 GeolocationManager::GeolocationManager(
     std::unique_ptr<SystemGeolocationSource> system_geolocation_source)
     : system_geolocation_source_(std::move(system_geolocation_source)),
@@ -97,18 +105,16 @@
   return observers_;
 }
 
-void GeolocationManager::AppAttemptsToUseGeolocation() {
-  system_geolocation_source_->AppAttemptsToUseGeolocation();
-}
-
-void GeolocationManager::AppCeasesToUseGeolocation() {
-  system_geolocation_source_->AppCeasesToUseGeolocation();
-}
-
 SystemGeolocationSource& GeolocationManager::SystemGeolocationSourceForTest() {
   return *system_geolocation_source_;
 }
 
+#else
+
+void GeolocationManager::AppAttemptsToUseGeolocation() {}
+
+void GeolocationManager::AppCeasesToUseGeolocation() {}
+
 #endif
 
 }  // namespace device
diff --git a/services/device/public/cpp/geolocation/geolocation_manager.h b/services/device/public/cpp/geolocation/geolocation_manager.h
index 796840c6..3550912e 100644
--- a/services/device/public/cpp/geolocation/geolocation_manager.h
+++ b/services/device/public/cpp/geolocation/geolocation_manager.h
@@ -33,6 +33,9 @@
   // Sets the global instance of the Geolocation Manager.
   static void SetInstance(std::unique_ptr<GeolocationManager> manager);
 
+  void AppAttemptsToUseGeolocation();
+  void AppCeasesToUseGeolocation();
+
 #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_CHROMEOS)
 // Default empty implementation of Geolocation Manager. It is used on operation
 // systems for which we don't support system-level geolocation. A separate class
@@ -77,9 +80,6 @@
   // Returns the list of permission observers.
   scoped_refptr<PermissionObserverList> GetObserverList() const;
 
-  void AppAttemptsToUseGeolocation();
-  void AppCeasesToUseGeolocation();
-
 #if BUILDFLAG(IS_APPLE)
   // Starts the system level process for watching position updates. These
   // updates will trigger a call to and observers in the |position_observers_|
diff --git a/services/network/cookie_settings.h b/services/network/cookie_settings.h
index 3db52b6..c15cf6f 100644
--- a/services/network/cookie_settings.h
+++ b/services/network/cookie_settings.h
@@ -17,6 +17,7 @@
 #include "net/base/network_delegate.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_setting_override.h"
+#include "net/cookies/cookie_util.h"
 #include "net/first_party_sets/first_party_set_metadata.h"
 #include "services/network/public/cpp/session_cookie_delete_predicate.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -247,7 +248,8 @@
                                              const GURL& first_party_url) const;
 
   ContentSettingsForOneType content_settings_;
-  bool block_third_party_cookies_ = false;
+  bool block_third_party_cookies_ =
+      net::cookie_util::IsForceThirdPartyCookieBlockingEnabled();
   std::set<std::string> secure_origin_cookies_allowed_schemes_;
   std::set<std::string> matching_scheme_cookies_allowed_schemes_;
   std::set<std::string> third_party_cookies_allowed_schemes_;
diff --git a/services/network/cookie_settings_unittest.cc b/services/network/cookie_settings_unittest.cc
index 384ea9b9..a53131c0 100644
--- a/services/network/cookie_settings_unittest.cc
+++ b/services/network/cookie_settings_unittest.cc
@@ -5,6 +5,7 @@
 #include "services/network/cookie_settings.h"
 
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "net/base/features.h"
@@ -1288,6 +1289,15 @@
   EXPECT_THAT(excluded_cookies, IsEmpty());
 }
 
+TEST_P(CookieSettingsTest, ForceThirdPartyCookieBlocking) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      net::features::kForceThirdPartyCookieBlocking);
+
+  CookieSettings settings;
+  EXPECT_TRUE(settings.are_third_party_cookies_blocked());
+}
+
 INSTANTIATE_TEST_SUITE_P(
     /* no prefix */,
     CookieSettingsTest,
diff --git a/services/network/public/cpp/network_switches.cc b/services/network/public/cpp/network_switches.cc
index 38cab2d..c1f7f6ef 100644
--- a/services/network/public/cpp/network_switches.cc
+++ b/services/network/public/cpp/network_switches.cc
@@ -6,6 +6,8 @@
 
 namespace network::switches {
 
+const char kBlockThirdPartyCookies[] = "block-third-party-cookies";
+
 // Forces Network Quality Estimator (NQE) to return a specific effective
 // connection type.
 const char kForceEffectiveConnectionType[] = "force-effective-connection-type";
diff --git a/services/network/public/cpp/network_switches.h b/services/network/public/cpp/network_switches.h
index cd7b482..3b3f067 100644
--- a/services/network/public/cpp/network_switches.h
+++ b/services/network/public/cpp/network_switches.h
@@ -11,6 +11,7 @@
 
 namespace switches {
 
+COMPONENT_EXPORT(NETWORK_CPP) extern const char kBlockThirdPartyCookies[];
 COMPONENT_EXPORT(NETWORK_CPP) extern const char kForceEffectiveConnectionType[];
 COMPONENT_EXPORT(NETWORK_CPP)
 extern const char kHostResolverRules[];
diff --git a/testing/buildbot/chromium.devtools-frontend.json b/testing/buildbot/chromium.devtools-frontend.json
index 9d7a2cc..ac8cf94 100644
--- a/testing/buildbot/chromium.devtools-frontend.json
+++ b/testing/buildbot/chromium.devtools-frontend.json
@@ -116,36 +116,6 @@
           "shards": 7
         },
         "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/",
-          "http/tests/devtools"
-        ],
-        "isolate_name": "devtools_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "webkit_layout_from_devtools",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://:devtools_web_tests/"
       }
     ]
   }
diff --git a/testing/buildbot/client.devtools-frontend.integration.json b/testing/buildbot/client.devtools-frontend.integration.json
index 897a801e..bb8c8c1 100644
--- a/testing/buildbot/client.devtools-frontend.integration.json
+++ b/testing/buildbot/client.devtools-frontend.integration.json
@@ -104,36 +104,6 @@
           "shards": 7
         },
         "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/",
-          "http/tests/devtools"
-        ],
-        "isolate_name": "devtools_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "webkit_layout_from_devtools",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://:devtools_web_tests/"
       }
     ]
   },
@@ -240,36 +210,6 @@
           "shards": 7
         },
         "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/",
-          "http/tests/devtools"
-        ],
-        "isolate_name": "devtools_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "webkit_layout_from_devtools",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://:devtools_web_tests/"
       }
     ]
   }
diff --git a/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter b/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter
index 89f8bf9..dc5b42d 100644
--- a/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter
+++ b/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter
@@ -130,3 +130,6 @@
 # TODO(b/256212431): Re-enable when linux-lacros-rel support
 # signin::MakePrimaryAccountAvailable().
 -AccessCodeCastHandlerBrowserTest.ExpectProfileSynErrorWhenNoSync
+
+# TODO(1447067): Autofill account migration popup, investigate the flakiness
+-MigrateToProfileAddressProfileTest.SaveWithEdit
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index c22943e..566f4b93 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -207,14 +207,6 @@
     "label": "//android_webview/support_library/boundary_interfaces:boundary_interface_example_apk",
     "type": "additional_compile_target",
   },
-  "devtools_web_tests": {
-    "label": "//:devtools_web_tests",
-    "type": "generated_script",
-    "args": [
-      "--results-directory",
-      "${ISOLATED_OUTDIR}",
-    ],
-  },
   "boringssl_crypto_tests": {
     "label": "//third_party/boringssl:boringssl_crypto_tests",
     "type": "console_test_launcher",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 82f2a42e..075d433 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -2036,31 +2036,6 @@
           'shards': 7,
         }
       },
-      'webkit_layout_from_devtools': {
-        # TODO(crbug.com/816629) - Move these args into //BUILD.gn .
-        # layout test failures are retried 3 times when '--test-list' is not
-        # passed, but 0 times when '--test-list' is passed. We want to always
-        # retry 3 times, so we explicitly specify it.
-        'args': [
-          '--num-retries=3',
-          '--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/',
-          'http/tests/devtools',
-        ],
-        'isolate_name': 'devtools_web_tests',
-        'merge': {
-          'args': [
-            '--verbose',
-          ],
-          'script': '//third_party/blink/tools/merge_web_test_results.py',
-        },
-        'resultdb': {
-          'enable': True,
-        },
-        'results_handler': 'layout tests',
-        'swarming': {
-          'shards': 4,
-        }
-      },
     },
 
     'devtools_webkit_isolated_scripts': {
@@ -2118,31 +2093,6 @@
           'shards': 7,
         }
       },
-      'webkit_layout_from_devtools': {
-        # TODO(crbug.com/816629) - Move these args into //BUILD.gn .
-        # layout test failures are retried 3 times when '--test-list' is not
-        # passed, but 0 times when '--test-list' is passed. We want to always
-        # retry 3 times, so we explicitly specify it.
-        'args': [
-          '--num-retries=3',
-          '--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/',
-          'http/tests/devtools',
-        ],
-        'isolate_name': 'devtools_web_tests',
-        'merge': {
-          'args': [
-            '--verbose',
-          ],
-          'script': '//third_party/blink/tools/merge_web_test_results.py',
-        },
-        'resultdb': {
-          'enable': True,
-        },
-        'results_handler': 'layout tests',
-        'swarming': {
-          'shards': 4,
-        }
-      },
     },
 
     'fieldtrial_android_tests': {
diff --git a/testing/buildbot/tryserver.devtools-frontend.json b/testing/buildbot/tryserver.devtools-frontend.json
index c6f6724..76571be 100644
--- a/testing/buildbot/tryserver.devtools-frontend.json
+++ b/testing/buildbot/tryserver.devtools-frontend.json
@@ -55,36 +55,6 @@
           "shards": 2
         },
         "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/",
-          "http/tests/devtools"
-        ],
-        "isolate_name": "devtools_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "webkit_layout_from_devtools",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://:devtools_web_tests/"
       }
     ]
   },
@@ -142,36 +112,6 @@
           "shards": 2
         },
         "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/",
-          "http/tests/devtools"
-        ],
-        "isolate_name": "devtools_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "webkit_layout_from_devtools",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://:devtools_web_tests/"
       }
     ]
   },
@@ -236,36 +176,6 @@
           "shards": 7
         },
         "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--layout-tests-directory=../../third_party/devtools-frontend/src/test/webtests/",
-          "http/tests/devtools"
-        ],
-        "isolate_name": "devtools_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "webkit_layout_from_devtools",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://:devtools_web_tests/"
       }
     ]
   }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 090af124..549191c 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -10653,7 +10653,7 @@
                 {
                     "name": "DriftEnabled",
                     "params": {
-                        "ClockDriftSampleDistance": "2s",
+                        "ClockDriftSampleDistance": "3600s",
                         "ClockDriftSamples": "2",
                         "FetchBehavior": "background-and-on-demand",
                         "RandomQueryProbability": "0.0394"
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 39b6563..72e14c2 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -1382,6 +1382,20 @@
       string text
       # Value range in the underlying resource (if available).
       optional SourceRange range
+      # Specificity of the selector.
+      experimental optional Specificity specificity
+
+  # Specificity:
+  # https://drafts.csswg.org/selectors/#specificity-rules
+  experimental type Specificity extends object
+    properties
+      # The a component, which represents the number of ID selectors.
+      integer a
+      # The b component, which represents the number of class selectors, attributes selectors, and
+      # pseudo-classes.
+      integer b
+      # The c component, which represents the number of type selectors and pseudo-elements.
+      integer c
 
   # Selector list data.
   type SelectorList extends object
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index 363f0f6..261dbd5 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -3823,7 +3823,7 @@
   kExecutedEmptyJavaScriptURLFromFrame = 4483,
   kExecutedJavaScriptURLFromFrame = 4484,
   kServiceWorkerBypassFetchHandlerForSubResource = 4485,
-  kCSSAtRuleInitial = 4486,
+  kCSSAtRuleStartingStyle = 4486,
   kPrivateAggregationApiFledgeExtensions = 4487,
   kDeprecatedInterestGroupDailyUpdateUrl = 4488,
   kCSSColorGradientColorSpace = 4489,
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
index 58a178a..f2e79e1 100644
--- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
+++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -1319,44 +1319,11 @@
 }
 ```
 
-### [CheckSecurity] _(i, m, a)_
+### [CheckSecurity] _(m, a)_
 
 Summary: Check whether a given access is allowed or not in terms of the
 same-origin security policy.
 
-*** note
-It is very important to use this attribute for interfaces and properties that
-are exposed cross-origin!
-***
-
-Usage for interfaces: `[CheckSecurity=Receiver]` enables a security check for
-all methods of an interface. The security check verifies that the caller still
-has access to the receiver object of the method when it is invoked. This is
-security-critical for interfaces that can be returned cross-origin, such as the
-Location or Window interface.
-
-```webidl
-[
-    CheckSecurity=Receiver
-] interface DOMWindow {
-    Selection? getSelection();
-};
-```
-
-Forgetting this attribute would make it possible to cache a method reference and
-invoke it on a cross-origin object:
-
-```js
-var iframe = document.body.appendChild(document.createElement('iframe'));
-var addEventListenerMethod = iframe.contentWindow.addEventListener;
-iframe.src = 'https://example.com';
-iframe.onload = function () {
-  addEventListenerMethod('pointermove', function (event) {
-    event.target.ownerDocument.body.innerText = 'Text from a different origin.';
-  });
-};
-```
-
 Usage for attributes and methods: `[CheckSecurity=ReturnValue]` enables a
 security check on that property. The security check verifies that the caller is
 allowed to access the returned value. If access is denied, the return value will
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
index 7848421..0a8a963 100644
--- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
+++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
@@ -38,7 +38,7 @@
 CachedAccessor=*
 CachedAttribute=*
 CallWith=ExecutionContext|Isolate|ScriptState|ThisValue
-CheckSecurity=Receiver|ReturnValue
+CheckSecurity=ReturnValue
 Clamp
 Constructor
 ContextEnabled=*
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni
index a0efdde..7eb9994 100644
--- a/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -695,8 +695,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_image_value.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_import_rule.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_import_rule.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_initial_rule.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_initial_rule.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_keyframe_rule.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_keyframe_rule.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_keyframes_rule.cc",
@@ -761,6 +759,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_skew_x.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_skew_y.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_skew_y.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_starting_style_rule.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_starting_style_rule.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_style_declaration.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_style_declaration.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_css_style_rule.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni
index 0c727f2..ad7d76a 100644
--- a/third_party/blink/renderer/bindings/idl_in_core.gni
+++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -44,7 +44,6 @@
           "//third_party/blink/renderer/core/css/css_font_feature_values_rule.idl",
           "//third_party/blink/renderer/core/css/css_grouping_rule.idl",
           "//third_party/blink/renderer/core/css/css_import_rule.idl",
-          "//third_party/blink/renderer/core/css/css_initial_rule.idl",
           "//third_party/blink/renderer/core/css/css_keyframe_rule.idl",
           "//third_party/blink/renderer/core/css/css_keyframes_rule.idl",
           "//third_party/blink/renderer/core/css/css_layer_block_rule.idl",
@@ -57,6 +56,7 @@
           "//third_party/blink/renderer/core/css/css_rule.idl",
           "//third_party/blink/renderer/core/css/css_rule_list.idl",
           "//third_party/blink/renderer/core/css/css_scope_rule.idl",
+          "//third_party/blink/renderer/core/css/css_starting_style_rule.idl",
           "//third_party/blink/renderer/core/css/css_style_declaration.idl",
           "//third_party/blink/renderer/core/css/css_style_rule.idl",
           "//third_party/blink/renderer/core/css/css_style_sheet.idl",
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 4f665c3..078a4e2 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -892,6 +892,13 @@
          effect->Affects(PropertyHandle(property));
 }
 
+AnimationTimeline* Animation::timeline() {
+  if (AnimationTimeline* timeline = TimelineInternal()) {
+    return timeline->ExposedTimeline();
+  }
+  return nullptr;
+}
+
 void Animation::setTimeline(AnimationTimeline* timeline) {
   // https://www.w3.org/TR/web-animations-1/#setting-the-timeline
 
@@ -1158,8 +1165,8 @@
     new_effect->Attach(this);
 
   // Resolve timeline offsets for new effect.
-  ResolveTimelineOffsets(timeline() ? timeline()->GetTimelineRange()
-                                    : TimelineRange());
+  ResolveTimelineOffsets(timeline_ ? timeline_->GetTimelineRange()
+                                   : TimelineRange());
 
   SetOutdated();
 
@@ -1960,7 +1967,7 @@
   //    Set animation's start time to the result of evaluating:
   //        associated effect end - start time
   bool preserve_current_time =
-      timeline() && timeline()->IsMonotonicallyIncreasing();
+      timeline_ && timeline_->IsMonotonicallyIncreasing();
 
   bool reversal = (EffectivePlaybackRate() < 0) != (playback_rate < 0);
   pending_playback_rate_ = absl::nullopt;
@@ -1970,7 +1977,7 @@
     setCurrentTime(previous_current_time, exception_state);
   }
 
-  if (timeline() && !timeline()->IsMonotonicallyIncreasing() && reversal &&
+  if (timeline_ && !timeline_->IsMonotonicallyIncreasing() && reversal &&
       start_time_) {
     start_time_ = EffectEnd() - start_time_.value();
   }
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index 96a2204..da57ba7 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -201,9 +201,16 @@
 
   double playbackRate() const;
   void setPlaybackRate(double, ExceptionState& = ASSERT_NO_EXCEPTION);
-  // TODO(crbug.com/1425939): Do not expose DeferredTimelines here.
-  AnimationTimeline* timeline() { return timeline_; }
-  AnimationTimeline* timeline() const { return timeline_; }
+
+  AnimationTimeline* TimelineInternal() { return timeline_; }
+  AnimationTimeline* TimelineInternal() const { return timeline_; }
+
+  // Note that this function returns the *exposed* timeline, which may be
+  // different from the the timeline the Animation is actually attached to.
+  //
+  // See AnimationTimeline::ExposedTimeline.
+  AnimationTimeline* timeline();
+
   virtual void setTimeline(AnimationTimeline* timeline);
 
   // Animation options for ViewTimelines.
diff --git a/third_party/blink/renderer/core/animation/animation_effect.cc b/third_party/blink/renderer/core/animation/animation_effect.cc
index fb0ee51f..40f2e43c 100644
--- a/third_party/blink/renderer/core/animation/animation_effect.cc
+++ b/third_party/blink/renderer/core/animation/animation_effect.cc
@@ -67,7 +67,7 @@
 
 AnimationTimeDelta AnimationEffect::IntrinsicIterationDuration() const {
   if (auto* animation = GetAnimation()) {
-    auto* timeline = animation->timeline();
+    auto* timeline = animation->TimelineInternal();
     if (timeline) {
       return timeline->CalculateIntrinsicIterationDuration(animation, timing_);
     }
@@ -259,8 +259,8 @@
 
 void AnimationEffect::updateTiming(OptionalEffectTiming* optional_timing,
                                    ExceptionState& exception_state) {
-  if (GetAnimation() && GetAnimation()->timeline() &&
-      GetAnimation()->timeline()->IsProgressBased()) {
+  if (GetAnimation() && GetAnimation()->TimelineInternal() &&
+      GetAnimation()->TimelineInternal()->IsProgressBased()) {
     if (optional_timing->hasDuration()) {
       if (optional_timing->duration()->IsUnrestrictedDouble()) {
         double duration =
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index 3e9577e..5793221 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -2467,7 +2467,7 @@
 
   // The no-effect animation doesn't count. The one animation is
   // AnimationAnimationTestCompositing::animation_.
-  EXPECT_EQ(1u, animation->timeline()->AnimationsNeedingUpdateCount());
+  EXPECT_EQ(1u, animation->TimelineInternal()->AnimationsNeedingUpdateCount());
 
   // The next effect change should be at the end because the animation does not
   // tick while hidden.
@@ -2485,7 +2485,7 @@
       CompositorAnimations::kNoFailure);
   EXPECT_FALSE(animation->CompositorPropertyAnimationsHaveNoEffectForTesting());
   EXPECT_FALSE(animation->AnimationHasNoEffect());
-  EXPECT_EQ(2u, animation->timeline()->AnimationsNeedingUpdateCount());
+  EXPECT_EQ(2u, animation->TimelineInternal()->AnimationsNeedingUpdateCount());
 
   // The next effect change should be at the end because the animation is
   // running on the compositor.
diff --git a/third_party/blink/renderer/core/animation/animation_timeline.h b/third_party/blink/renderer/core/animation/animation_timeline.h
index b21a1e6e..1df4d69 100644
--- a/third_party/blink/renderer/core/animation/animation_timeline.h
+++ b/third_party/blink/renderer/core/animation/animation_timeline.h
@@ -58,6 +58,10 @@
   virtual bool IsScrollTimeline() const { return false; }
   virtual bool IsViewTimeline() const { return false; }
 
+  // Determines which AnimationTimeline instance we should return
+  // from Animation.timeline.
+  virtual AnimationTimeline* ExposedTimeline() { return this; }
+
   virtual bool IsActive() const = 0;
   virtual bool IsResolved() const { return true; }
   virtual AnimationTimeDelta ZeroTime() = 0;
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index c3fafb2d..6cadd1ed 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -2372,7 +2372,7 @@
   EXPECT_TRUE(animation.GetCompositorAnimation());
 
   cc::AnimationTimeline* compositor_timeline =
-      animation.timeline()->CompositorTimeline();
+      animation.TimelineInternal()->CompositorTimeline();
   ASSERT_TRUE(compositor_timeline);
   int id = compositor_timeline->id();
   ASSERT_TRUE(host->GetTimelineById(id));
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index e094100..648e630 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -199,7 +199,7 @@
 
     // In most cases, current time is preserved on an animation update.
     inherited_time = animation->UnlimitedCurrentTime();
-    previous_timeline = animation->timeline();
+    previous_timeline = animation->TimelineInternal();
     resets_current_time_on_resume = animation->ResetsCurrentTimeOnResume();
   }
 
@@ -1413,14 +1413,14 @@
   if (!element)
     return nullptr;
   const TimelineData* timeline_data = GetTimelineData(*element);
-  if (ViewTimeline* timeline =
-          FindTimelineForElement<ViewTimeline>(name, timeline_data, update)) {
-    return timeline;
-  }
   if (ScrollTimeline* timeline =
           FindTimelineForElement<ScrollTimeline>(name, timeline_data, update)) {
     return timeline;
   }
+  if (ViewTimeline* timeline =
+          FindTimelineForElement<ViewTimeline>(name, timeline_data, update)) {
+    return timeline;
+  }
   return FindTimelineForElement<DeferredTimeline>(name, timeline_data, update);
 }
 
@@ -2209,7 +2209,7 @@
       effect->UpdateSpecifiedTiming(entry.effect->SpecifiedTiming());
     }
     CSSAnimation& css_animation = To<CSSAnimation>(*entry.animation);
-    if (css_animation.timeline() != entry.timeline) {
+    if (css_animation.TimelineInternal() != entry.timeline) {
       css_animation.setTimeline(entry.timeline);
       css_animation.ResetIgnoreCSSTimeline();
     }
@@ -2705,11 +2705,11 @@
       << "Should always pass nullptr instead of ensured styles";
   const ComputedStyle* scope_old_style =
       PostStyleUpdateScope::GetOldStyle(animating_element);
-  bool is_initial_style = old_style && old_style->IsPseudoInitialStyle();
-  DCHECK(old_style == scope_old_style || !scope_old_style && is_initial_style)
+  bool is_starting_style = old_style && old_style->IsStartingStyle();
+  DCHECK(old_style == scope_old_style || !scope_old_style && is_starting_style)
       << "The old_style passed in should be the style for the element at the "
-         "beginning of the lifecycle update, or a style based on the :initial "
-         "style";
+         "beginning of the lifecycle update, or a style based on the "
+         "@starting-style style";
 #endif
 
   if (!animation_style_recalc && old_style) {
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.h b/third_party/blink/renderer/core/animation/css/css_animations.h
index d67ca7b..006898d 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.h
+++ b/third_party/blink/renderer/core/animation/css/css_animations.h
@@ -154,7 +154,9 @@
           style_rule_version(new_animation.style_rule_version),
           play_state_list(new_animation.play_state_list) {}
 
-    AnimationTimeline* Timeline() const { return animation->timeline(); }
+    AnimationTimeline* Timeline() const {
+      return animation->TimelineInternal();
+    }
     const absl::optional<TimelineOffset>& RangeStart() const {
       return animation->GetRangeStartInternal();
     }
diff --git a/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc b/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
index 49346e45..3454f71 100644
--- a/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
+++ b/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
@@ -96,16 +96,22 @@
 
   // The animations associated with anim1 and anim2 should share the same
   // timeline instance, also across elements.
-  EXPECT_EQ(animations1[0]->timeline(), animations1[1]->timeline());
-  EXPECT_EQ(animations1[1]->timeline(), animations2[0]->timeline());
-  EXPECT_EQ(animations2[0]->timeline(), animations2[1]->timeline());
+  EXPECT_EQ(animations1[0]->TimelineInternal(),
+            animations1[1]->TimelineInternal());
+  EXPECT_EQ(animations1[1]->TimelineInternal(),
+            animations2[0]->TimelineInternal());
+  EXPECT_EQ(animations2[0]->TimelineInternal(),
+            animations2[1]->TimelineInternal());
 
   // The animation associated with anim3 uses a different timeline
   // from anim1/2.
-  EXPECT_EQ(animations1[2]->timeline(), animations2[2]->timeline());
+  EXPECT_EQ(animations1[2]->TimelineInternal(),
+            animations2[2]->TimelineInternal());
 
-  EXPECT_NE(animations2[2]->timeline(), animations1[0]->timeline());
-  EXPECT_NE(animations2[2]->timeline(), animations1[1]->timeline());
+  EXPECT_NE(animations2[2]->TimelineInternal(),
+            animations1[0]->TimelineInternal());
+  EXPECT_NE(animations2[2]->TimelineInternal(),
+            animations1[1]->TimelineInternal());
 }
 
 TEST_F(CSSScrollTimelineTest, MultipleLifecyclePasses) {
@@ -228,7 +234,8 @@
 
 absl::optional<ScrollTimeline::ScrollAxis> GetTimelineAxis(
     const Animation& animation) {
-  if (auto* scroll_timeline = DynamicTo<ScrollTimeline>(animation.timeline())) {
+  if (auto* scroll_timeline =
+          DynamicTo<ScrollTimeline>(animation.TimelineInternal())) {
     return scroll_timeline->GetAxis();
   }
   return absl::nullopt;
diff --git a/third_party/blink/renderer/core/animation/deferred_timeline.h b/third_party/blink/renderer/core/animation/deferred_timeline.h
index 1a0093a..7169252 100644
--- a/third_party/blink/renderer/core/animation/deferred_timeline.h
+++ b/third_party/blink/renderer/core/animation/deferred_timeline.h
@@ -17,6 +17,10 @@
  public:
   explicit DeferredTimeline(Document*);
 
+  AnimationTimeline* ExposedTimeline() override {
+    return SingleAttachedTimeline();
+  }
+
   void AttachTimeline(ScrollSnapshotTimeline*);
   void DetachTimeline(ScrollSnapshotTimeline*);
 
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.cc b/third_party/blink/renderer/core/animation/keyframe_effect.cc
index 50a7ac5..d4e70ff 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -302,7 +302,7 @@
     ScriptState* script_state) {
   if (Animation* animation = GetAnimation()) {
     animation->FlushPendingUpdates();
-    if (AnimationTimeline* timeline = animation->timeline()) {
+    if (AnimationTimeline* timeline = animation->TimelineInternal()) {
       animation->ResolveTimelineOffsets(timeline->GetTimelineRange());
     }
   }
@@ -775,8 +775,8 @@
 }
 
 absl::optional<AnimationTimeDelta> KeyframeEffect::TimelineDuration() const {
-  if (GetAnimation() && GetAnimation()->timeline()) {
-    return GetAnimation()->timeline()->GetDuration();
+  if (GetAnimation() && GetAnimation()->TimelineInternal()) {
+    return GetAnimation()->TimelineInternal()->GetDuration();
   }
   return absl::nullopt;
 }
diff --git a/third_party/blink/renderer/core/animation/pending_animations.cc b/third_party/blink/renderer/core/animation/pending_animations.cc
index 5f641693..7441621 100644
--- a/third_party/blink/renderer/core/animation/pending_animations.cc
+++ b/third_party/blink/renderer/core/animation/pending_animations.cc
@@ -81,19 +81,22 @@
         started_synchronized_on_compositor = true;
       }
 
-      if (!animation->timeline() || !animation->timeline()->IsActive())
+      if (!animation->TimelineInternal() ||
+          !animation->TimelineInternal()->IsActive()) {
         continue;
+      }
 
       if (animation->Playing() && !animation->StartTimeInternal()) {
         waiting_for_start_time.push_back(animation.Get());
       } else if (animation->PendingInternal()) {
-        DCHECK(animation->timeline()->IsActive() &&
-               animation->timeline()->CurrentTime());
+        DCHECK(animation->TimelineInternal()->IsActive() &&
+               animation->TimelineInternal()->CurrentTime());
         // A pending animation that is not waiting on a start time does not need
         // to be synchronized with animations that are starting up. Nonetheless,
         // it needs to notify the animation to resolve the ready promise and
         // commit the pending state.
-        animation->NotifyReady(animation->timeline()->CurrentTime().value());
+        animation->NotifyReady(
+            animation->TimelineInternal()->CurrentTime().value());
       }
     } else {
       deferred.push_back(animation);
@@ -110,9 +113,10 @@
   } else {
     for (auto& animation : waiting_for_start_time) {
       DCHECK(!animation->StartTimeInternal());
-      DCHECK(animation->timeline()->IsActive() &&
-             animation->timeline()->CurrentTime());
-      animation->NotifyReady(animation->timeline()->CurrentTime().value());
+      DCHECK(animation->TimelineInternal()->IsActive() &&
+             animation->TimelineInternal()->CurrentTime());
+      animation->NotifyReady(
+          animation->TimelineInternal()->CurrentTime().value());
     }
   }
 
@@ -156,7 +160,8 @@
 
   for (auto animation : animations) {
     if (animation->StartTimeInternal() || !animation->PendingInternal() ||
-        !animation->timeline() || !animation->timeline()->IsActive()) {
+        !animation->TimelineInternal() ||
+        !animation->TimelineInternal()->IsActive()) {
       // Already started or no longer relevant.
       continue;
     }
@@ -165,13 +170,14 @@
       waiting_for_compositor_animation_start_.push_back(animation);
       continue;
     }
-    if (!animation->timeline()->IsMonotonicallyIncreasing()) {
+    if (!animation->TimelineInternal()->IsMonotonicallyIncreasing()) {
       animation->NotifyReady(
-          animation->timeline()->CurrentTime().value_or(AnimationTimeDelta()));
+          animation->TimelineInternal()->CurrentTime().value_or(
+              AnimationTimeDelta()));
     } else {
       animation->NotifyReady(
           ANIMATION_TIME_DELTA_FROM_SECONDS(monotonic_animation_start_time) -
-          animation->timeline()->ZeroTime());
+          animation->TimelineInternal()->ZeroTime());
     }
   }
 }
@@ -200,9 +206,11 @@
   for (auto& animation : animations) {
     if (animation->HasActiveAnimationsOnCompositor()) {
       waiting_for_compositor_animation_start_.push_back(animation);
-    } else if (animation->timeline() && animation->timeline()->IsActive() &&
-               animation->timeline()->CurrentTime().has_value()) {
-      animation->NotifyReady(animation->timeline()->CurrentTime().value());
+    } else if (animation->TimelineInternal() &&
+               animation->TimelineInternal()->IsActive() &&
+               animation->TimelineInternal()->CurrentTime().has_value()) {
+      animation->NotifyReady(
+          animation->TimelineInternal()->CurrentTime().value());
     }
   }
 }
diff --git a/third_party/blink/renderer/core/css/build.gni b/third_party/blink/renderer/core/css/build.gni
index 08dadd5..af4ee00 100644
--- a/third_party/blink/renderer/core/css/build.gni
+++ b/third_party/blink/renderer/core/css/build.gni
@@ -165,8 +165,6 @@
   "css_inherited_value.h",
   "css_initial_color_value.cc",
   "css_initial_color_value.h",
-  "css_initial_rule.cc",
-  "css_initial_rule.h",
   "css_initial_value.cc",
   "css_initial_value.h",
   "css_invalid_variable_value.cc",
@@ -263,6 +261,8 @@
   "css_selector_watch.h",
   "css_shadow_value.cc",
   "css_shadow_value.h",
+  "css_starting_style_rule.cc",
+  "css_starting_style_rule.h",
   "css_string_value.cc",
   "css_string_value.h",
   "css_style_declaration.cc",
diff --git a/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc b/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc
index 1719623e..563d818 100644
--- a/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc
+++ b/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc
@@ -206,4 +206,52 @@
       WebFeature::kCSSGetComputedWebkitFontSmoothingAnimationDurationZero));
 }
 
+TEST_F(CSSComputedStyleDeclarationTest, ScrollTimelineShorthandWithAttachment) {
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    GetDocument().body()->SetInlineStyleProperty(CSSPropertyID::kScrollTimeline,
+                                                 "--foo inline");
+    UpdateAllLifecyclePhasesForTest();
+    auto* style =
+        MakeGarbageCollected<CSSComputedStyleDeclaration>(GetDocument().body());
+    EXPECT_EQ("--foo inline",
+              style->GetPropertyValue(CSSPropertyID::kScrollTimeline));
+  }
+
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    GetDocument().body()->SetInlineStyleProperty(CSSPropertyID::kScrollTimeline,
+                                                 "--foo inline defer");
+    UpdateAllLifecyclePhasesForTest();
+    auto* style =
+        MakeGarbageCollected<CSSComputedStyleDeclaration>(GetDocument().body());
+    EXPECT_EQ("--foo inline defer",
+              style->GetPropertyValue(CSSPropertyID::kScrollTimeline));
+  }
+}
+
+TEST_F(CSSComputedStyleDeclarationTest, ViewTimelineShorthandWithAttachment) {
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    GetDocument().body()->SetInlineStyleProperty(CSSPropertyID::kViewTimeline,
+                                                 "--foo inline");
+    UpdateAllLifecyclePhasesForTest();
+    auto* style =
+        MakeGarbageCollected<CSSComputedStyleDeclaration>(GetDocument().body());
+    EXPECT_EQ("--foo inline",
+              style->GetPropertyValue(CSSPropertyID::kViewTimeline));
+  }
+
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    GetDocument().body()->SetInlineStyleProperty(CSSPropertyID::kViewTimeline,
+                                                 "--foo inline defer");
+    UpdateAllLifecyclePhasesForTest();
+    auto* style =
+        MakeGarbageCollected<CSSComputedStyleDeclaration>(GetDocument().body());
+    EXPECT_EQ("--foo inline defer",
+              style->GetPropertyValue(CSSPropertyID::kViewTimeline));
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_initial_rule.h b/third_party/blink/renderer/core/css/css_initial_rule.h
deleted file mode 100644
index e10d416e..0000000
--- a/third_party/blink/renderer/core/css/css_initial_rule.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_INITIAL_RULE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_INITIAL_RULE_H_
-
-#include "third_party/blink/renderer/core/css/css_condition_rule.h"
-#include "third_party/blink/renderer/platform/wtf/casting.h"
-
-namespace blink {
-
-class StyleRuleInitial;
-
-class CSSInitialRule final : public CSSConditionRule {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  CSSInitialRule(StyleRuleInitial*, CSSStyleSheet*);
-  ~CSSInitialRule() override = default;
-
-  String cssText() const override;
-
- private:
-  CSSRule::Type GetType() const override { return kInitialRule; }
-};
-
-template <>
-struct DowncastTraits<CSSInitialRule> {
-  static bool AllowFrom(const CSSRule& rule) {
-    return rule.GetType() == CSSRule::kInitialRule;
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_INITIAL_RULE_H_
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 73cbb11b..d0fe5b7 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -4561,7 +4561,7 @@
       type_name: "Vector<TimelineAttachment>",
       converter: "ConvertViewTimelineAttachment",
       separator: ",",
-      runtime_flag: "ScrollTimeline",
+      runtime_flag: "ScrollTimelineAttachment",
     },
     {
       name: "scroll-timeline-axis",
@@ -5345,7 +5345,7 @@
       type_name: "Vector<TimelineAttachment>",
       converter: "ConvertViewTimelineAttachment",
       separator: ",",
-      runtime_flag: "ScrollTimeline",
+      runtime_flag: "ScrollTimelineAttachment",
     },
     {
       name: "view-timeline-axis",
diff --git a/third_party/blink/renderer/core/css/css_property_value_set_test.cc b/third_party/blink/renderer/core/css/css_property_value_set_test.cc
index 91f5744..6ba42458 100644
--- a/third_party/blink/renderer/core/css/css_property_value_set_test.cc
+++ b/third_party/blink/renderer/core/css/css_property_value_set_test.cc
@@ -84,8 +84,8 @@
   StyleRule* rule = RuleAt(style_sheet, 0);
 
   EXPECT_EQ(
-      "offset-position: initial; offset-distance: initial; "
-      "offset-rotate: reverse 2turn; offset-anchor: initial; "
+      "offset-position: auto; offset-distance: 0px; "
+      "offset-rotate: reverse 2turn; offset-anchor: auto; "
       "offset-path: initial;",
       rule->Properties().AsText());
 }
diff --git a/third_party/blink/renderer/core/css/css_rule.h b/third_party/blink/renderer/core/css/css_rule.h
index ca20dce..764ba2a 100644
--- a/third_party/blink/renderer/core/css/css_rule.h
+++ b/third_party/blink/renderer/core/css/css_rule.h
@@ -79,7 +79,7 @@
     kPositionFallbackRule = 22,
     kTryRule = 23,
     kFontFeatureRule = 24,
-    kInitialRule = 25,
+    kStartingStyleRule = 25,
   };
 
   virtual Type GetType() const = 0;
diff --git a/third_party/blink/renderer/core/css/css_selector.cc b/third_party/blink/renderer/core/css/css_selector.cc
index a27aa87..c9d836b 100644
--- a/third_party/blink/renderer/core/css/css_selector.cc
+++ b/third_party/blink/renderer/core/css/css_selector.cc
@@ -96,14 +96,8 @@
 }
 
 unsigned CSSSelector::Specificity() const {
-  // make sure the result doesn't overflow
-  static const unsigned kMaxValueMask = 0xffffff;
-  static const unsigned kIdMask = 0xff0000;
-  static const unsigned kClassMask = 0x00ff00;
-  static const unsigned kElementMask = 0x0000ff;
-
   if (IsForPage()) {
-    return SpecificityForPage() & kMaxValueMask;
+    return SpecificityForPage() & CSSSelector::kMaxValueMask;
   }
 
   unsigned total = 0;
@@ -126,6 +120,16 @@
   return total;
 }
 
+std::array<uint8_t, 3> CSSSelector::SpecificityTuple() const {
+  unsigned specificity = Specificity();
+
+  uint8_t a = (specificity & kIdMask) >> 16;
+  uint8_t b = (specificity & kClassMask) >> 8;
+  uint8_t c = (specificity & kElementMask);
+
+  return {a, b, c};
+}
+
 inline unsigned CSSSelector::SpecificityForOneSelector() const {
   // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity.
   // This function isn't quite correct.
diff --git a/third_party/blink/renderer/core/css/css_selector.h b/third_party/blink/renderer/core/css/css_selector.h
index 95d637cd..ab38689b 100644
--- a/third_party/blink/renderer/core/css/css_selector.h
+++ b/third_party/blink/renderer/core/css/css_selector.h
@@ -130,9 +130,16 @@
   static constexpr unsigned kClassLikeSpecificity = 0x000100;
   static constexpr unsigned kTagSpecificity = 0x000001;
 
+  static constexpr unsigned kMaxValueMask = 0xffffff;
+  static constexpr unsigned kIdMask = 0xff0000;
+  static constexpr unsigned kClassMask = 0x00ff00;
+  static constexpr unsigned kElementMask = 0x0000ff;
+
   // http://www.w3.org/TR/css3-selectors/#specificity
   // We use 256 as the base of the specificity number system.
   unsigned Specificity() const;
+  // Returns specificity components in decreasing order of significance.
+  std::array<uint8_t, 3> SpecificityTuple() const;
 
   /* how the attribute value has to match.... Default is Exact */
   enum MatchType {
diff --git a/third_party/blink/renderer/core/css/css_initial_rule.cc b/third_party/blink/renderer/core/css/css_starting_style_rule.cc
similarity index 61%
rename from third_party/blink/renderer/core/css/css_initial_rule.cc
rename to third_party/blink/renderer/core/css/css_starting_style_rule.cc
index 6e17545..1923d01e 100644
--- a/third_party/blink/renderer/core/css/css_initial_rule.cc
+++ b/third_party/blink/renderer/core/css/css_starting_style_rule.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 "third_party/blink/renderer/core/css/css_initial_rule.h"
+#include "third_party/blink/renderer/core/css/css_starting_style_rule.h"
 
 #include "third_party/blink/renderer/core/css/css_rule.h"
 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
@@ -11,14 +11,15 @@
 
 namespace blink {
 
-CSSInitialRule::CSSInitialRule(StyleRuleInitial* initial_rule,
-                               CSSStyleSheet* parent)
-    : CSSConditionRule(initial_rule, parent) {}
+CSSStartingStyleRule::CSSStartingStyleRule(
+    StyleRuleStartingStyle* starting_style_rule,
+    CSSStyleSheet* parent)
+    : CSSConditionRule(starting_style_rule, parent) {}
 
-String CSSInitialRule::cssText() const {
+String CSSStartingStyleRule::cssText() const {
   StringBuilder result;
 
-  result.Append("@initial ");
+  result.Append("@starting-style ");
   AppendCSSTextForItems(result);
 
   return result.ReleaseString();
diff --git a/third_party/blink/renderer/core/css/css_starting_style_rule.h b/third_party/blink/renderer/core/css/css_starting_style_rule.h
new file mode 100644
index 0000000..fdb2917
--- /dev/null
+++ b/third_party/blink/renderer/core/css/css_starting_style_rule.h
@@ -0,0 +1,37 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_STARTING_STYLE_RULE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_STARTING_STYLE_RULE_H_
+
+#include "third_party/blink/renderer/core/css/css_condition_rule.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+
+namespace blink {
+
+class StyleRuleStartingStyle;
+
+class CSSStartingStyleRule final : public CSSConditionRule {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  CSSStartingStyleRule(StyleRuleStartingStyle*, CSSStyleSheet*);
+  ~CSSStartingStyleRule() override = default;
+
+  String cssText() const override;
+
+ private:
+  CSSRule::Type GetType() const override { return kStartingStyleRule; }
+};
+
+template <>
+struct DowncastTraits<CSSStartingStyleRule> {
+  static bool AllowFrom(const CSSRule& rule) {
+    return rule.GetType() == CSSRule::kStartingStyleRule;
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_STARTING_STYLE_RULE_H_
diff --git a/third_party/blink/renderer/core/css/css_initial_rule.idl b/third_party/blink/renderer/core/css/css_starting_style_rule.idl
similarity index 78%
rename from third_party/blink/renderer/core/css/css_initial_rule.idl
rename to third_party/blink/renderer/core/css/css_starting_style_rule.idl
index e25e88b..f26dd4b8 100644
--- a/third_party/blink/renderer/core/css/css_initial_rule.idl
+++ b/third_party/blink/renderer/core/css/css_starting_style_rule.idl
@@ -4,5 +4,5 @@
 
 [
   Exposes=Window, RuntimeEnabled = CSSInitialPseudo
-] interface CSSInitialRule : CSSConditionRule {
+] interface CSSStartingStyleRule : CSSConditionRule {
 };
diff --git a/third_party/blink/renderer/core/css/css_style_declaration_test.cc b/third_party/blink/renderer/core/css/css_style_declaration_test.cc
index 9d176faf..1c523ac7 100644
--- a/third_party/blink/renderer/core/css/css_style_declaration_test.cc
+++ b/third_party/blink/renderer/core/css/css_style_declaration_test.cc
@@ -103,4 +103,60 @@
   }
 }
 
+TEST(CSSStyleDeclarationTest, ScrollTimelineShorthandWithAttachment) {
+  V8TestingScope v8_testing_scope;
+
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set = css_test_helpers::ParseDeclarationBlock(
+        "scroll-timeline: --foo inline");
+    ASSERT_TRUE(set);
+    auto* style = static_cast<CSSStyleDeclaration*>(
+        MakeGarbageCollected<PropertySetCSSStyleDeclaration>(
+            v8_testing_scope.GetExecutionContext(), *set->MutableCopy()));
+    EXPECT_EQ(AtomicString("--foo inline"),
+              style->getPropertyValue("scroll-timeline"));
+  }
+
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set = css_test_helpers::ParseDeclarationBlock(
+        "scroll-timeline: --foo inline defer");
+    ASSERT_TRUE(set);
+    auto* style = static_cast<CSSStyleDeclaration*>(
+        MakeGarbageCollected<PropertySetCSSStyleDeclaration>(
+            v8_testing_scope.GetExecutionContext(), *set->MutableCopy()));
+    EXPECT_EQ(AtomicString("--foo inline defer"),
+              style->getPropertyValue("scroll-timeline"));
+  }
+}
+
+TEST(CSSStyleDeclarationTest, ViewTimelineShorthandWithAttachment) {
+  V8TestingScope v8_testing_scope;
+
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock("view-timeline: --foo inline");
+    ASSERT_TRUE(set);
+    auto* style = static_cast<CSSStyleDeclaration*>(
+        MakeGarbageCollected<PropertySetCSSStyleDeclaration>(
+            v8_testing_scope.GetExecutionContext(), *set->MutableCopy()));
+    EXPECT_EQ(AtomicString("--foo inline"),
+              style->getPropertyValue("view-timeline"));
+  }
+
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set = css_test_helpers::ParseDeclarationBlock(
+        "view-timeline: --foo inline defer");
+    ASSERT_TRUE(set);
+    auto* style = static_cast<CSSStyleDeclaration*>(
+        MakeGarbageCollected<PropertySetCSSStyleDeclaration>(
+            v8_testing_scope.GetExecutionContext(), *set->MutableCopy()));
+    EXPECT_EQ(AtomicString("--foo inline defer"),
+              style->getPropertyValue("view-timeline"));
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index fefaf81..3832de1 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -472,7 +472,7 @@
       selector_statistics_collector.EndCollectionForCurrentRule();
       selector_statistics_collector.BeginCollectionForRule(&rule_data);
     }
-    if (!is_initial && rule_data.IsInitial()) {
+    if (!is_initial && rule_data.IsStartingStyle()) {
       continue;
     }
     if (can_use_fast_reject_ &&
@@ -985,8 +985,9 @@
   for (unsigned i = 0; i < matched_rules_.size(); i++) {
     const MatchedRule& matched_rule = matched_rules_[i];
     const RuleData* rule_data = matched_rule.GetRuleData();
-    if (rule_data->IsInitial()) {
-      result_.AddFlags(static_cast<MatchFlags>(MatchFlag::kAffectedByInitial));
+    if (rule_data->IsStartingStyle()) {
+      result_.AddFlags(
+          static_cast<MatchFlags>(MatchFlag::kAffectedByStartingStyle));
     }
     result_.AddMatchedProperties(
         &rule_data->Rule()->Properties(),
diff --git a/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc b/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
index 38d848a..cf73579 100644
--- a/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
@@ -295,7 +295,7 @@
     case StyleRule::kSupports:
     case StyleRule::kPositionFallback:
     case StyleRule::kTry:
-    case StyleRule::kInitial:
+    case StyleRule::kStartingStyle:
       // TODO(andruud): Handle other descriptor types here.
       NOTREACHED();
       return nullptr;
diff --git a/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc b/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
index 2d19761..e84f46d 100644
--- a/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
+++ b/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
@@ -112,9 +112,9 @@
     }
     return CSSAtRuleID::kCSSAtRuleInvalid;
   }
-  if (EqualIgnoringASCIICase(name, "initial")) {
+  if (EqualIgnoringASCIICase(name, "starting-style")) {
     if (RuntimeEnabledFeatures::CSSInitialPseudoEnabled()) {
-      return CSSAtRuleID::kCSSAtRuleInitial;
+      return CSSAtRuleID::kCSSAtRuleStartingStyle;
     }
     return CSSAtRuleID::kCSSAtRuleInvalid;
   }
@@ -142,8 +142,6 @@
       return WebFeature::kCSSAtRuleFontFeatureValues;
     case CSSAtRuleID::kCSSAtRuleImport:
       return WebFeature::kCSSAtRuleImport;
-    case CSSAtRuleID::kCSSAtRuleInitial:
-      return WebFeature::kCSSAtRuleInitial;
     case CSSAtRuleID::kCSSAtRuleKeyframes:
       return WebFeature::kCSSAtRuleKeyframes;
     case CSSAtRuleID::kCSSAtRuleLayer:
@@ -164,6 +162,8 @@
       return WebFeature::kCSSAtRuleOrnaments;
     case CSSAtRuleID::kCSSAtRuleScope:
       return WebFeature::kCSSAtRuleScope;
+    case CSSAtRuleID::kCSSAtRuleStartingStyle:
+      return WebFeature::kCSSAtRuleStartingStyle;
     case CSSAtRuleID::kCSSAtRuleStyleset:
       return WebFeature::kCSSAtRuleStylistic;
     case CSSAtRuleID::kCSSAtRuleStylistic:
diff --git a/third_party/blink/renderer/core/css/parser/css_at_rule_id.h b/third_party/blink/renderer/core/css/parser/css_at_rule_id.h
index dbf1f14..9978b20 100644
--- a/third_party/blink/renderer/core/css/parser/css_at_rule_id.h
+++ b/third_party/blink/renderer/core/css/parser/css_at_rule_id.h
@@ -17,7 +17,6 @@
   kCSSAtRuleFontFace,
   kCSSAtRuleFontPaletteValues,
   kCSSAtRuleImport,
-  kCSSAtRuleInitial,
   kCSSAtRuleKeyframes,
   kCSSAtRuleLayer,
   kCSSAtRuleMedia,
@@ -28,6 +27,7 @@
   kCSSAtRuleContainer,
   kCSSAtRuleCounterStyle,
   kCSSAtRuleScope,
+  kCSSAtRuleStartingStyle,
   kCSSAtRuleSupports,
   kCSSAtRuleTry,
   kCSSAtRuleWebkitKeyframes,
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
index e319704..3d55b1ac 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
@@ -677,7 +677,7 @@
     if (id != CSSAtRuleID::kCSSAtRuleMedia &&      // [css-conditional-3]
         id != CSSAtRuleID::kCSSAtRuleSupports &&   // [css-conditional-3]
         id != CSSAtRuleID::kCSSAtRuleContainer &&  // [css-contain-3]
-        id != CSSAtRuleID::kCSSAtRuleInitial) {
+        id != CSSAtRuleID::kCSSAtRuleStartingStyle) {
       ConsumeErroneousAtRule(stream);
       return nullptr;
     }
@@ -743,9 +743,9 @@
       case CSSAtRuleID::kCSSAtRuleSupports:
         return ConsumeSupportsRule(stream, nesting_type,
                                    parent_rule_for_nesting);
-      case CSSAtRuleID::kCSSAtRuleInitial:
-        return ConsumeInitialRule(stream, nesting_type,
-                                  parent_rule_for_nesting);
+      case CSSAtRuleID::kCSSAtRuleStartingStyle:
+        return ConsumeStartingStyleRule(stream, nesting_type,
+                                        parent_rule_for_nesting);
       case CSSAtRuleID::kCSSAtRuleFontFace:
         return ConsumeFontFaceRule(stream);
       case CSSAtRuleID::kCSSAtRuleFontPaletteValues:
@@ -1104,7 +1104,7 @@
       std::move(rules));
 }
 
-StyleRuleInitial* CSSParserImpl::ConsumeInitialRule(
+StyleRuleStartingStyle* CSSParserImpl::ConsumeStartingStyleRule(
     CSSParserTokenStream& stream,
     CSSNestingType nesting_type,
     StyleRule* parent_rule_for_nesting) {
@@ -1117,11 +1117,11 @@
   CSSParserTokenStream::BlockGuard guard(stream);
 
   if (!prelude.AtEnd()) {
-    return nullptr;  // Parse error; @initial prelude should be empty
+    return nullptr;  // Parse error; @starting-style prelude should be empty
   }
 
   if (observer_) {
-    observer_->StartRuleHeader(StyleRule::kInitial, prelude_offset_start);
+    observer_->StartRuleHeader(StyleRule::kStartingStyle, prelude_offset_start);
     observer_->EndRuleHeader(prelude_offset_end);
     observer_->StartRuleBody(stream.Offset());
   }
@@ -1153,7 +1153,7 @@
 
   // NOTE: There will be a copy of rules here, to deal with the different inline
   // size.
-  return MakeGarbageCollected<StyleRuleInitial>(std::move(rules));
+  return MakeGarbageCollected<StyleRuleStartingStyle>(std::move(rules));
 }
 
 StyleRuleFontFace* CSSParserImpl::ConsumeFontFaceRule(
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl.h b/third_party/blink/renderer/core/css/parser/css_parser_impl.h
index ea6843c..8af8676 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_impl.h
+++ b/third_party/blink/renderer/core/css/parser/css_parser_impl.h
@@ -206,9 +206,10 @@
   StyleRuleSupports* ConsumeSupportsRule(CSSParserTokenStream& stream,
                                          CSSNestingType,
                                          StyleRule* parent_rule_for_nesting);
-  StyleRuleInitial* ConsumeInitialRule(CSSParserTokenStream& stream,
-                                       CSSNestingType,
-                                       StyleRule* parent_rule_for_nesting);
+  StyleRuleStartingStyle* ConsumeStartingStyleRule(
+      CSSParserTokenStream& stream,
+      CSSNestingType,
+      StyleRule* parent_rule_for_nesting);
   StyleRuleFontFace* ConsumeFontFaceRule(CSSParserTokenStream&);
   StyleRuleFontPaletteValues* ConsumeFontPaletteValuesRule(
       CSSParserTokenStream&);
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index e448c58..3241de82 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -6415,7 +6415,8 @@
                                                       wind_rule);
 }
 
-CSSValue* ConsumePathFunction(CSSParserTokenRange& range) {
+CSSValue* ConsumePathFunction(CSSParserTokenRange& range,
+                              EmptyPathStringHandling empty_handling) {
   // FIXME: Add support for <url>, <basic-shape>, <geometry-box>.
   if (range.Peek().FunctionId() != CSSValueID::kPath) {
     return nullptr;
@@ -6429,10 +6430,19 @@
     return nullptr;
   }
 
-  range = function_range;
+  // https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-path
+  // A path data string that does not conform to the to the grammar
+  // and parsing rules of SVG 1.1, or that does conform but defines
+  // an empty path, is invalid and causes the entire path() to be invalid.
   if (byte_stream->IsEmpty()) {
-    return CSSIdentifierValue::Create(CSSValueID::kNone);
+    if (empty_handling == EmptyPathStringHandling::kTreatAsNone) {
+      range = function_range;
+      return CSSIdentifierValue::Create(CSSValueID::kNone);
+    }
+    return nullptr;
   }
+  range = function_range;
+
   return MakeGarbageCollected<cssvalue::CSSPathValue>(std::move(byte_stream));
 }
 
@@ -6592,7 +6602,7 @@
     offset_path = ConsumeUrl(range, context);
   }
   if (!offset_path) {
-    offset_path = ConsumePathFunction(range);
+    offset_path = ConsumePathFunction(range, EmptyPathStringHandling::kFailure);
   }
 
   if (!coord_box && RuntimeEnabledFeatures::CSSOffsetPathCoordBoxEnabled()) {
@@ -6623,7 +6633,7 @@
     return ConsumeIdent(range);
   }
 
-  return ConsumePathFunction(range);
+  return ConsumePathFunction(range, EmptyPathStringHandling::kTreatAsNone);
 }
 
 CSSValue* ConsumeOffsetRotate(CSSParserTokenRange& range,
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index 2585a3e8..85466b4 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -61,6 +61,7 @@
 };
 enum class UnitlessQuirk { kAllow, kForbid };
 enum class AllowedColorKeywords { kAllowSystemColor, kNoSystemColor };
+enum class EmptyPathStringHandling { kFailure, kTreatAsNone };
 
 using ConsumeAnimationItemValue = CSSValue* (*)(CSSPropertyID,
                                                 CSSParserTokenRange&,
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
index 4afca3d..b8376d7 100644
--- a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -2655,7 +2655,7 @@
   } else if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
     css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetPosition, CSSPropertyID::kOffset,
-        *CSSInitialValue::Create(), important,
+        *CSSIdentifierValue::Create(CSSValueID::kAuto), important,
         css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
@@ -2667,7 +2667,7 @@
   } else {
     css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetPath, CSSPropertyID::kOffset,
-        *CSSInitialValue::Create(), important,
+        *CSSIdentifierValue::Create(CSSValueID::kNone), important,
         css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
@@ -2679,8 +2679,10 @@
   } else {
     css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetDistance, CSSPropertyID::kOffset,
-        *CSSInitialValue::Create(), important,
-        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+        *CSSNumericLiteralValue::Create(0,
+                                        CSSPrimitiveValue::UnitType::kPixels),
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
+        properties);
   }
 
   if (offset_rotate) {
@@ -2691,7 +2693,7 @@
   } else {
     css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetRotate, CSSPropertyID::kOffset,
-        *CSSInitialValue::Create(), important,
+        *CSSIdentifierValue::Create(CSSValueID::kAuto), important,
         css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
@@ -2703,7 +2705,7 @@
   } else if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
     css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetAnchor, CSSPropertyID::kOffset,
-        *CSSInitialValue::Create(), important,
+        *CSSIdentifierValue::Create(CSSValueID::kAuto), important,
         css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
@@ -3220,8 +3222,11 @@
     if (!axis && (axis = ConsumeSingleTimelineAxis(range))) {
       continue;
     }
-    if (!attachment && (attachment = ConsumeSingleTimelineAttachment(range))) {
-      continue;
+    if (RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled()) {
+      if (!attachment &&
+          (attachment = ConsumeSingleTimelineAttachment(range))) {
+        continue;
+      }
     }
     break;
   }
@@ -3251,8 +3256,6 @@
   using css_parsing_utils::ConsumeCommaIncludingWhitespace;
   using css_parsing_utils::IsImplicitProperty;
 
-  DCHECK_EQ(3u, shorthand.length());
-
   CSSValueList* name_list = CSSValueList::CreateCommaSeparated();
   CSSValueList* axis_list = CSSValueList::CreateCommaSeparated();
   CSSValueList* attachment_list = CSSValueList::CreateCommaSeparated();
@@ -3270,13 +3273,17 @@
   DCHECK_EQ(name_list->length(), axis_list->length());
   DCHECK_EQ(name_list->length(), attachment_list->length());
 
+  DCHECK_GE(shorthand.length(), 2u);
   AddProperty(shorthand.properties()[0]->PropertyID(), shorthand_id, *name_list,
               important, IsImplicitProperty::kNotImplicit, properties);
   AddProperty(shorthand.properties()[1]->PropertyID(), shorthand_id, *axis_list,
               important, IsImplicitProperty::kNotImplicit, properties);
-  AddProperty(shorthand.properties()[2]->PropertyID(), shorthand_id,
-              *attachment_list, important, IsImplicitProperty::kNotImplicit,
-              properties);
+  if (RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled()) {
+    DCHECK_EQ(shorthand.length(), 3u);
+    AddProperty(shorthand.properties()[2]->PropertyID(), shorthand_id,
+                *attachment_list, important, IsImplicitProperty::kNotImplicit,
+                properties);
+  }
 
   return range.AtEnd();
 }
@@ -3409,7 +3416,10 @@
                                  : HeapVector<Member<const ScopedCSSName>>{};
   const Vector<TimelineAxis>& axis_vector = style.ScrollTimelineAxis();
   const Vector<TimelineAttachment>& attachment_vector =
-      style.ScrollTimelineAttachment();
+      RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled()
+          ? style.ScrollTimelineAttachment()
+          : Vector<TimelineAttachment>(name_vector.size(),
+                                       TimelineAttachment::kLocal);
   return CSSValueForTimelineShorthand(name_vector, axis_vector,
                                       attachment_vector);
 }
@@ -3577,7 +3587,10 @@
                                : HeapVector<Member<const ScopedCSSName>>{};
   const Vector<TimelineAxis>& axis_vector = style.ViewTimelineAxis();
   const Vector<TimelineAttachment>& attachment_vector =
-      style.ViewTimelineAttachment();
+      RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled()
+          ? style.ViewTimelineAttachment()
+          : Vector<TimelineAttachment>(name_vector.size(),
+                                       TimelineAttachment::kLocal);
   return CSSValueForTimelineShorthand(name_vector, axis_vector,
                                       attachment_vector);
 }
diff --git a/third_party/blink/renderer/core/css/resolver/match_flags.h b/third_party/blink/renderer/core/css/resolver/match_flags.h
index 2f30915..acd8d2c 100644
--- a/third_party/blink/renderer/core/css/resolver/match_flags.h
+++ b/third_party/blink/renderer/core/css/resolver/match_flags.h
@@ -22,8 +22,8 @@
   kAffectedByHover = 1 << 2,
   // :active
   kAffectedByActive = 1 << 3,
-  // :initial
-  kAffectedByInitial = 1 << 4,
+  // @starting-style
+  kAffectedByStartingStyle = 1 << 4,
 };
 
 using MatchFlags = uint8_t;
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index e523a71..a208420 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1837,6 +1837,12 @@
     const CSSValue& value) {
   StyleOffsetRotation result(0, OffsetRotationType::kFixed);
 
+  if (auto* identifier = DynamicTo<CSSIdentifierValue>(value)) {
+    DCHECK_EQ(identifier->GetValueID(), CSSValueID::kAuto);
+    result.type = OffsetRotationType::kAuto;
+    return result;
+  }
+
   const auto& list = To<CSSValueList>(value);
   DCHECK(list.length() == 1 || list.length() == 2);
   for (const auto& item : list) {
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index deb512c..f969535 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1447,8 +1447,8 @@
   if (match_result.HasFlag(MatchFlag::kAffectedByActive)) {
     state.StyleBuilder().SetAffectedByActive();
   }
-  if (match_result.HasFlag(MatchFlag::kAffectedByInitial)) {
-    state.StyleBuilder().SetIsPseudoInitialStyle();
+  if (match_result.HasFlag(MatchFlag::kAffectedByStartingStyle)) {
+    state.StyleBuilder().SetIsStartingStyle();
   }
   if (match_result.DependsOnSizeContainerQueries()) {
     state.StyleBuilder().SetDependsOnSizeContainerQueries(true);
diff --git a/third_party/blink/renderer/core/css/rule_set.cc b/third_party/blink/renderer/core/css/rule_set.cc
index 6f9472b..4cae142 100644
--- a/third_party/blink/renderer/core/css/rule_set.cc
+++ b/third_party/blink/renderer/core/css/rule_set.cc
@@ -123,7 +123,7 @@
       is_entirely_covered_by_bucketing_(
           false),  // Will be computed in ComputeEntirelyCoveredByBucketing().
       is_easy_(false),  // Ditto.
-      is_initial_((add_rule_flags & kRuleIsInitial) != 0),
+      is_starting_style_((add_rule_flags & kRuleIsStartingStyle) != 0),
       descendant_selector_identifier_hashes_() {}
 
 void RuleData::ComputeEntirelyCoveredByBucketing() {
@@ -697,9 +697,9 @@
       }
       AddChildRules(scope_rule->ChildRules(), medium, add_rule_flags,
                     container_query, cascade_layer, inner_style_scope);
-    } else if (auto* initial_rule = DynamicTo<StyleRuleInitial>(rule)) {
+    } else if (auto* initial_rule = DynamicTo<StyleRuleStartingStyle>(rule)) {
       AddChildRules(initial_rule->ChildRules(), medium,
-                    add_rule_flags | kRuleIsInitial, container_query,
+                    add_rule_flags | kRuleIsStartingStyle, container_query,
                     cascade_layer, style_scope);
     }
   }
diff --git a/third_party/blink/renderer/core/css/rule_set.h b/third_party/blink/renderer/core/css/rule_set.h
index 67e1004..a28fad8 100644
--- a/third_party/blink/renderer/core/css/rule_set.h
+++ b/third_party/blink/renderer/core/css/rule_set.h
@@ -50,7 +50,7 @@
 enum AddRuleFlag {
   kRuleHasNoSpecialState = 0,
   kRuleIsVisitedDependent = 1 << 0,
-  kRuleIsInitial = 1 << 1,
+  kRuleIsStartingStyle = 1 << 1,
 };
 
 // Some CSS properties do not apply to certain pseudo-elements, and need to be
@@ -127,7 +127,7 @@
   void ComputeEntirelyCoveredByBucketing();
   void ResetEntirelyCoveredByBucketing();
   bool SelectorIsEasy() const { return is_easy_; }
-  bool IsInitial() const { return is_initial_; }
+  bool IsStartingStyle() const { return is_starting_style_; }
 
   bool ContainsUncommonAttributeSelector() const {
     return contains_uncommon_attribute_selector_;
@@ -197,8 +197,8 @@
   unsigned link_match_type_ : 2;
   unsigned valid_property_filter_ : 3;
   unsigned is_entirely_covered_by_bucketing_ : 1;
-  unsigned is_easy_ : 1;     // See EasySelectorChecker.
-  unsigned is_initial_ : 1;  // Inside @initial {}.
+  unsigned is_easy_ : 1;            // See EasySelectorChecker.
+  unsigned is_starting_style_ : 1;  // Inside @starting-style {}.
   // 32 bits above
   union {
     // Used by RuleMap before compaction, to hold what bucket this RuleData
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index bae7e3d..8aa7b184 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -6095,12 +6095,138 @@
   EXPECT_EQ("0s", ComputedValue(target3, "animation-duration")->CssText());
 }
 
+TEST_F(StyleEngineTest, ScrollTimelineAttachmentFlags) {
+  String css = "scroll-timeline-attachment: initial";
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(0u, set->PropertyCount());
+  }
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(1u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineAttachment));
+  }
+}
+
+TEST_F(StyleEngineTest, ViewTimelineAttachmentFlags) {
+  String css = "view-timeline-attachment: initial";
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(0u, set->PropertyCount());
+  }
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(1u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineAttachment));
+  }
+}
+
+TEST_F(StyleEngineTest, ScrollTimelineShorthandFlagsInitial) {
+  String css = "scroll-timeline: initial";
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(2u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineName));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineAxis));
+  }
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(3u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineName));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineAxis));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineAttachment));
+  }
+}
+
+TEST_F(StyleEngineTest, ScrollTimelineShorthandFlags) {
+  String css = "scroll-timeline: --foo block defer";
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(0u, set->PropertyCount());
+  }
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(3u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineName));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineAxis));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kScrollTimelineAttachment));
+  }
+}
+
+TEST_F(StyleEngineTest, ViewTimelineShorthandFlagsInitial) {
+  String css = "view-timeline: initial";
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(2u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineName));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineAxis));
+  }
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(3u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineName));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineAxis));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineAttachment));
+  }
+}
+
+TEST_F(StyleEngineTest, ViewTimelineShorthandFlags) {
+  String css = "view-timeline: --foo block defer";
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(false);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(0u, set->PropertyCount());
+  }
+  {
+    ScopedScrollTimelineAttachmentForTest enabled(true);
+    const CSSPropertyValueSet* set =
+        css_test_helpers::ParseDeclarationBlock(css);
+    ASSERT_TRUE(set);
+    EXPECT_EQ(3u, set->PropertyCount());
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineName));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineAxis));
+    EXPECT_TRUE(set->HasProperty(CSSPropertyID::kViewTimelineAttachment));
+  }
+}
+
 TEST_F(StyleEngineTest, InitialStyle_Recalc) {
   GetDocument().body()->setInnerHTML(R"HTML(
     <style>
       #target {
         background-color: green;
-        @initial { background-color: red; }
+        @starting-style { background-color: red; }
       }
     </style>
     <div id="target"></div>
@@ -6118,12 +6244,12 @@
   UpdateAllLifecyclePhasesForTest();
 
   EXPECT_EQ(GetStyleEngine().StyleForElementCount() - before_count, 1u)
-      << "The style recalc should not do a separate @initial pass since the "
-         "element already has a style";
+      << "The style recalc should not do a separate @starting-style pass since "
+         "the element already has a style";
   EXPECT_EQ(target->ComputedStyleRef().VisitedDependentColor(
                 GetCSSPropertyBackgroundColor()),
             green)
-      << "Make sure @initial rules do not apply for the second pass";
+      << "Make sure @starting-style rules do not apply for the second pass";
   EXPECT_EQ(
       target->ComputedStyleRef().VisitedDependentColor(GetCSSPropertyColor()),
       lime)
@@ -6135,7 +6261,7 @@
     <style>
       #target {
         background-color: green;
-        @initial { background-color: red; }
+        @starting-style { background-color: red; }
       }
     </style>
     <div id="target" style="display:none"></div>
@@ -6153,11 +6279,11 @@
 
   EXPECT_EQ(GetStyleEngine().StyleForElementCount() - before_count, 2u)
       << "The style recalc needs to do two passes because the element was "
-         "display:none and @initial styles are matching";
+         "display:none and @starting-style styles are matching";
   EXPECT_EQ(target->ComputedStyleRef().VisitedDependentColor(
                 GetCSSPropertyBackgroundColor()),
             green)
-      << "Make sure @initial do not apply for the second pass";
+      << "Make sure @starting-style do not apply for the second pass";
 }
 
 TEST_F(StyleEngineTest, InitialStyleCount_EnsureComputedStyle) {
@@ -6166,7 +6292,7 @@
       #target {
         background-color: green;
         transition: background-color 100s step-end;
-        @initial { background-color: red; }
+        @starting-style { background-color: red; }
       }
     </style>
     <div id="target" style="display:none"></div>
@@ -6186,12 +6312,12 @@
   ASSERT_TRUE(none_style);
 
   EXPECT_EQ(GetStyleEngine().StyleForElementCount() - before_count, 1u)
-      << "No @initial pass for EnsureComputedStyle";
+      << "No @starting-style pass for EnsureComputedStyle";
 
   EXPECT_EQ(target->ComputedStyleRef().VisitedDependentColor(
                 GetCSSPropertyBackgroundColor()),
             green)
-      << "Transitions are not started and @initial does not apply in "
+      << "Transitions are not started and @starting-style does not apply in "
          "display:none";
 }
 
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.cc b/third_party/blink/renderer/core/css/style_property_serializer.cc
index 95962f2d..a0968e1 100644
--- a/third_party/blink/renderer/core/css/style_property_serializer.cc
+++ b/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -396,7 +396,6 @@
     case CSSPropertyID::kGridArea:
     case CSSPropertyID::kGap:
     case CSSPropertyID::kListStyle:
-    case CSSPropertyID::kOffset:
     case CSSPropertyID::kTextDecoration:
     case CSSPropertyID::kTextEmphasis:
     case CSSPropertyID::kWebkitMask:
@@ -870,18 +869,31 @@
   return list;
 }
 
+// TODO(crbug.com/1446702): Remove scroll/view-timeline-attachment.
+CSSValueList* DefaultAttachments(wtf_size_t size) {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  for (wtf_size_t i = 0; i < size; ++i) {
+    list->Append(*CSSIdentifierValue::Create(CSSValueID::kLocal));
+  }
+  return list;
+}
+
 }  // namespace
 
 String StylePropertySerializer::TimelineValue(
     const StylePropertyShorthand& shorthand) const {
-  CHECK_EQ(shorthand.length(), 3u);
+  CHECK_EQ(shorthand.length(),
+           RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled() ? 3u : 2u);
 
   const CSSValueList& name_list = To<CSSValueList>(
       *property_set_.GetPropertyCSSValue(*shorthand.properties()[0]));
   const CSSValueList& axis_list = To<CSSValueList>(
       *property_set_.GetPropertyCSSValue(*shorthand.properties()[1]));
-  const CSSValueList& attachment_list = To<CSSValueList>(
-      *property_set_.GetPropertyCSSValue(*shorthand.properties()[2]));
+  const CSSValueList& attachment_list =
+      RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled()
+          ? *To<CSSValueList>(
+                property_set_.GetPropertyCSSValue(*shorthand.properties()[2]))
+          : *DefaultAttachments(name_list.length());
 
   // The scroll/view-timeline shorthand can not expand to longhands of two
   // different lengths, so we can also not contract two different-longhands
@@ -903,24 +915,30 @@
 }
 
 String StylePropertySerializer::ScrollTimelineValue() const {
-  CHECK_EQ(scrollTimelineShorthand().length(), 3u);
+  CHECK_GE(scrollTimelineShorthand().length(), 2u);
   CHECK_EQ(scrollTimelineShorthand().properties()[0],
            &GetCSSPropertyScrollTimelineName());
   CHECK_EQ(scrollTimelineShorthand().properties()[1],
            &GetCSSPropertyScrollTimelineAxis());
-  CHECK_EQ(scrollTimelineShorthand().properties()[2],
-           &GetCSSPropertyScrollTimelineAttachment());
+  if (RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled()) {
+    CHECK_EQ(scrollTimelineShorthand().length(), 3u);
+    CHECK_EQ(scrollTimelineShorthand().properties()[2],
+             &GetCSSPropertyScrollTimelineAttachment());
+  }
   return TimelineValue(scrollTimelineShorthand());
 }
 
 String StylePropertySerializer::ViewTimelineValue() const {
-  CHECK_EQ(viewTimelineShorthand().length(), 3u);
+  CHECK_GE(viewTimelineShorthand().length(), 2u);
   CHECK_EQ(viewTimelineShorthand().properties()[0],
            &GetCSSPropertyViewTimelineName());
   CHECK_EQ(viewTimelineShorthand().properties()[1],
            &GetCSSPropertyViewTimelineAxis());
-  CHECK_EQ(viewTimelineShorthand().properties()[2],
-           &GetCSSPropertyViewTimelineAttachment());
+  if (RuntimeEnabledFeatures::ScrollTimelineAttachmentEnabled()) {
+    CHECK_EQ(viewTimelineShorthand().length(), 3u);
+    CHECK_EQ(viewTimelineShorthand().properties()[2],
+             &GetCSSPropertyViewTimelineAttachment());
+  }
   return TimelineValue(viewTimelineShorthand());
 }
 
@@ -1342,44 +1360,72 @@
 }
 
 String StylePropertySerializer::OffsetValue() const {
-  StringBuilder result;
-  if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
-    const CSSValue* position =
-        property_set_.GetPropertyCSSValue(GetCSSPropertyOffsetPosition());
-    if (!position->IsInitialValue()) {
-      result.Append(position->CssText());
-    }
-  }
+  const CSSValue* position =
+      property_set_.GetPropertyCSSValue(GetCSSPropertyOffsetPosition());
   const CSSValue* path =
       property_set_.GetPropertyCSSValue(GetCSSPropertyOffsetPath());
   const CSSValue* distance =
       property_set_.GetPropertyCSSValue(GetCSSPropertyOffsetDistance());
   const CSSValue* rotate =
       property_set_.GetPropertyCSSValue(GetCSSPropertyOffsetRotate());
-  if (!path->IsInitialValue()) {
+  const CSSValue* anchor =
+      property_set_.GetPropertyCSSValue(GetCSSPropertyOffsetAnchor());
+
+  auto is_initial_identifier_value = [](const CSSValue* value, CSSValueID id) {
+    return value->IsIdentifierValue() &&
+           DynamicTo<CSSIdentifierValue>(value)->GetValueID() == id;
+  };
+
+  bool use_distance =
+      !(distance->IsNumericLiteralValue() &&
+        To<CSSNumericLiteralValue>(*distance).DoubleValue() == 0.0);
+  const auto* rotate_list_value = DynamicTo<CSSValueList>(rotate);
+  bool is_rotate_auto = rotate_list_value && rotate_list_value->length() == 1 &&
+                        is_initial_identifier_value(&rotate_list_value->First(),
+                                                    CSSValueID::kAuto);
+  bool is_rotate_zero =
+      rotate_list_value && rotate_list_value->length() == 1 &&
+      rotate_list_value->First().IsNumericLiteralValue() &&
+      (To<CSSNumericLiteralValue>(rotate_list_value->First()).DoubleValue() ==
+       0.0);
+  bool is_rotate_auto_zero =
+      rotate_list_value && rotate_list_value->length() == 2 &&
+      rotate_list_value->Item(1).IsNumericLiteralValue() &&
+      (To<CSSNumericLiteralValue>(rotate_list_value->Item(1)).DoubleValue() ==
+       0.0) &&
+      is_initial_identifier_value(&rotate_list_value->Item(0),
+                                  CSSValueID::kAuto);
+  bool use_rotate = (use_distance && is_rotate_zero) ||
+                    (!is_initial_identifier_value(rotate, CSSValueID::kAuto) &&
+                     !is_rotate_auto && !is_rotate_auto_zero);
+  bool use_path = use_rotate || use_distance ||
+                  !is_initial_identifier_value(path, CSSValueID::kNone);
+  bool use_position =
+      !use_path || !is_initial_identifier_value(position, CSSValueID::kAuto);
+  bool use_anchor = !is_initial_identifier_value(anchor, CSSValueID::kAuto);
+
+  StringBuilder result;
+  if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
+    if (use_position) {
+      result.Append(position->CssText());
+    }
+  }
+  if (use_path) {
     if (!result.empty()) {
       result.Append(" ");
     }
     result.Append(path->CssText());
-    if (!distance->IsInitialValue()) {
-      result.Append(" ");
-      result.Append(distance->CssText());
-    }
-    if (!rotate->IsInitialValue()) {
-      result.Append(" ");
-      result.Append(rotate->CssText());
-    }
-  } else {
-    // The longhand values cannot be serialized as a valid shorthand value.
-    // Serialize them as individual longhands instead.
-    if (!distance->IsInitialValue() || !rotate->IsInitialValue()) {
-      return String();
-    }
+  }
+  if (use_distance) {
+    result.Append(" ");
+    result.Append(distance->CssText());
+  }
+  if (use_rotate) {
+    result.Append(" ");
+    result.Append(rotate->CssText());
   }
   if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
-    const CSSValue* anchor =
-        property_set_.GetPropertyCSSValue(GetCSSPropertyOffsetAnchor());
-    if (!anchor->IsInitialValue()) {
+    if (use_anchor) {
       result.Append(" / ");
       result.Append(anchor->CssText());
     }
diff --git a/third_party/blink/renderer/core/css/style_recalc_context.h b/third_party/blink/renderer/core/css/style_recalc_context.h
index 4413f700..e550f016 100644
--- a/third_party/blink/renderer/core/css/style_recalc_context.h
+++ b/third_party/blink/renderer/core/css/style_recalc_context.h
@@ -65,7 +65,8 @@
   StyleScopeFrame* style_scope_frame = nullptr;
 
   // The style for the element at the start of the lifecycle update, or the
-  // :initial styles for the second pass when transitioning from display:none.
+  // @starting-style styles for the second pass when transitioning from
+  // display:none.
   const ComputedStyle* old_style = nullptr;
 
   // If true, something about the parent's style (e.g., that it has
diff --git a/third_party/blink/renderer/core/css/style_rule.cc b/third_party/blink/renderer/core/css/style_rule.cc
index 0853a47..a03dfae 100644
--- a/third_party/blink/renderer/core/css/style_rule.cc
+++ b/third_party/blink/renderer/core/css/style_rule.cc
@@ -29,7 +29,6 @@
 #include "third_party/blink/renderer/core/css/css_font_palette_values_rule.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_import_rule.h"
-#include "third_party/blink/renderer/core/css/css_initial_rule.h"
 #include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
 #include "third_party/blink/renderer/core/css/css_layer_block_rule.h"
 #include "third_party/blink/renderer/core/css/css_layer_statement_rule.h"
@@ -39,6 +38,7 @@
 #include "third_party/blink/renderer/core/css/css_position_fallback_rule.h"
 #include "third_party/blink/renderer/core/css/css_property_rule.h"
 #include "third_party/blink/renderer/core/css/css_scope_rule.h"
+#include "third_party/blink/renderer/core/css/css_starting_style_rule.h"
 #include "third_party/blink/renderer/core/css/css_style_rule.h"
 #include "third_party/blink/renderer/core/css/css_supports_rule.h"
 #include "third_party/blink/renderer/core/css/css_try_rule.h"
@@ -141,8 +141,8 @@
     case kTry:
       To<StyleRuleTry>(this)->TraceAfterDispatch(visitor);
       return;
-    case kInitial:
-      To<StyleRuleInitial>(this)->TraceAfterDispatch(visitor);
+    case kStartingStyle:
+      To<StyleRuleStartingStyle>(this)->TraceAfterDispatch(visitor);
       return;
   }
   NOTREACHED();
@@ -213,8 +213,8 @@
     case kTry:
       To<StyleRuleTry>(this)->~StyleRuleTry();
       return;
-    case kInitial:
-      To<StyleRuleInitial>(this)->~StyleRuleInitial();
+    case kStartingStyle:
+      To<StyleRuleStartingStyle>(this)->~StyleRuleStartingStyle();
       return;
   }
   NOTREACHED();
@@ -264,8 +264,8 @@
       return To<StyleRuleCounterStyle>(this)->Copy();
     case kPositionFallback:
       return To<StyleRulePositionFallback>(this)->Copy();
-    case kInitial:
-      return To<StyleRuleInitial>(this)->Copy();
+    case kStartingStyle:
+      return To<StyleRuleStartingStyle>(this)->Copy();
     case kTry:
       NOTREACHED();
       return nullptr;
@@ -348,9 +348,9 @@
       rule = MakeGarbageCollected<CSSPositionFallbackRule>(
           To<StyleRulePositionFallback>(self), parent_sheet);
       break;
-    case kInitial:
-      rule = MakeGarbageCollected<CSSInitialRule>(To<StyleRuleInitial>(self),
-                                                  parent_sheet);
+    case kStartingStyle:
+      rule = MakeGarbageCollected<CSSStartingStyleRule>(
+          To<StyleRuleStartingStyle>(self), parent_sheet);
       break;
     case kFontFeature:
     case kTry:
@@ -483,7 +483,7 @@
     case kContainer:
     case kMedia:
     case kSupports:
-    case kInitial:
+    case kStartingStyle:
       for (StyleRuleBase* child :
            DynamicTo<StyleRuleGroup>(this)->ChildRules()) {
         child->Reparent(old_parent, new_parent);
@@ -766,7 +766,8 @@
   StyleRuleCondition::TraceAfterDispatch(visitor);
 }
 
-StyleRuleInitial::StyleRuleInitial(HeapVector<Member<StyleRuleBase>> rules)
-    : StyleRuleCondition(kInitial, "", std::move(rules)) {}
+StyleRuleStartingStyle::StyleRuleStartingStyle(
+    HeapVector<Member<StyleRuleBase>> rules)
+    : StyleRuleCondition(kStartingStyle, "", std::move(rules)) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_rule.h b/third_party/blink/renderer/core/css/style_rule.h
index 1c2a8ab..6710c8d 100644
--- a/third_party/blink/renderer/core/css/style_rule.h
+++ b/third_party/blink/renderer/core/css/style_rule.h
@@ -67,7 +67,7 @@
     kSupports,
     kPositionFallback,
     kTry,
-    kInitial,
+    kStartingStyle,
   };
 
   // Name of a cascade layer as given by an @layer rule, split at '.' into a
@@ -103,10 +103,10 @@
   bool IsImportRule() const { return GetType() == kImport; }
   bool IsPositionFallbackRule() const { return GetType() == kPositionFallback; }
   bool IsTryRule() const { return GetType() == kTry; }
-  bool IsInitialRule() const { return GetType() == kInitial; }
+  bool IsStartingStyleRule() const { return GetType() == kStartingStyle; }
   bool IsConditionRule() const {
     return GetType() == kContainer || GetType() == kMedia ||
-           GetType() == kSupports || GetType() == kInitial;
+           GetType() == kSupports || GetType() == kStartingStyle;
   }
 
   StyleRuleBase* Copy() const;
@@ -539,14 +539,14 @@
   Member<ContainerQuery> container_query_;
 };
 
-class StyleRuleInitial : public StyleRuleCondition {
+class StyleRuleStartingStyle : public StyleRuleCondition {
  public:
-  explicit StyleRuleInitial(HeapVector<Member<StyleRuleBase>> rules);
-  StyleRuleInitial(const StyleRuleInitial&) = default;
+  explicit StyleRuleStartingStyle(HeapVector<Member<StyleRuleBase>> rules);
+  StyleRuleStartingStyle(const StyleRuleStartingStyle&) = default;
 
   bool ConditionIsSupported() const { return true; }
-  StyleRuleInitial* Copy() const {
-    return MakeGarbageCollected<StyleRuleInitial>(*this);
+  StyleRuleStartingStyle* Copy() const {
+    return MakeGarbageCollected<StyleRuleStartingStyle>(*this);
   }
 
   void SetConditionText(const ExecutionContext*, String);
@@ -652,9 +652,9 @@
 };
 
 template <>
-struct DowncastTraits<StyleRuleInitial> {
+struct DowncastTraits<StyleRuleStartingStyle> {
   static bool AllowFrom(const StyleRuleBase& rule) {
-    return rule.IsInitialRule();
+    return rule.IsStartingStyleRule();
   }
 };
 
diff --git a/third_party/blink/renderer/core/css/style_sheet_contents.cc b/third_party/blink/renderer/core/css/style_sheet_contents.cc
index 9dfd55a..13b44799 100644
--- a/third_party/blink/renderer/core/css/style_sheet_contents.cc
+++ b/third_party/blink/renderer/core/css/style_sheet_contents.cc
@@ -628,7 +628,7 @@
       case StyleRuleBase::kMedia:
       case StyleRuleBase::kLayerBlock:
       case StyleRuleBase::kScope:
-      case StyleRuleBase::kInitial:
+      case StyleRuleBase::kStartingStyle:
         if (ChildRulesHaveFailedOrCanceledSubresources(
                 To<StyleRuleGroup>(rule)->ChildRules())) {
           return true;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index a6ab227..fb304a3 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3053,10 +3053,10 @@
     DCHECK(IsPseudoElement());
     return nullptr;
   }
-  if (style->IsPseudoInitialStyle()) {
-    // @initial pseudo styles matched. We need to compute the style a second
-    // time to compute the actual style and trigger transitions using the
-    // starting from the :initial style.
+  if (style->IsStartingStyle()) {
+    // @starting-style styles matched. We need to compute the style a second
+    // time to compute the actual style and trigger transitions starting from
+    // style with @starting-style applied.
     new_style_recalc_context.old_style =
         style->Display() == EDisplay::kNone ? nullptr : style.get();
     style = HasCustomStyleCallbacks()
diff --git a/third_party/blink/renderer/core/dom/events/event_target.idl b/third_party/blink/renderer/core/dom/events/event_target.idl
index f80e0071..a3944cb 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.idl
+++ b/third_party/blink/renderer/core/dom/events/event_target.idl
@@ -21,7 +21,6 @@
 // https://dom.spec.whatwg.org/#interface-eventtarget
 
 [
-    CheckSecurity=Receiver,
     Exposed=(Window,Worker,AudioWorklet),
     ImmutablePrototype
 ] interface EventTarget {
diff --git a/third_party/blink/renderer/core/frame/frame_serializer.cc b/third_party/blink/renderer/core/frame/frame_serializer.cc
index 948d8bd..d82e399 100644
--- a/third_party/blink/renderer/core/frame/frame_serializer.cc
+++ b/third_party/blink/renderer/core/frame/frame_serializer.cc
@@ -437,7 +437,7 @@
     case CSSRule::kContainerRule:
     case CSSRule::kLayerBlockRule:
     case CSSRule::kScopeRule:
-    case CSSRule::kInitialRule: {
+    case CSSRule::kStartingStyleRule: {
       CSSRuleList* rule_list = rule->cssRules();
       for (unsigned i = 0; i < rule_list->length(); ++i)
         SerializeCSSRule(rule_list->item(i));
diff --git a/third_party/blink/renderer/core/frame/location.idl b/third_party/blink/renderer/core/frame/location.idl
index de03a720..62e5480 100644
--- a/third_party/blink/renderer/core/frame/location.idl
+++ b/third_party/blink/renderer/core/frame/location.idl
@@ -29,7 +29,6 @@
 // https://html.spec.whatwg.org/C/#the-location-interface
 
 [
-    CheckSecurity=Receiver,
     Exposed=Window
 ] interface Location {
     [CallWith=Isolate, RaisesException, LegacyUnforgeable] void assign(USVString url);
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl
index 4e4acc6..1770002 100644
--- a/third_party/blink/renderer/core/frame/window.idl
+++ b/third_party/blink/renderer/core/frame/window.idl
@@ -28,7 +28,6 @@
 
 // FIXME: explain all uses of [CrossOrigin]
 [
-    CheckSecurity=Receiver,
     ImplementedAs=DOMWindow,
     Global=Window,
     Exposed=Window
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index e2348c37..b6c83c3 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -648,6 +648,11 @@
 
 bool HTMLMediaElement::ShouldReusePlayer(Document& old_document,
                                          Document& new_document) const {
+  // A NULL frame implies a NULL domWindow, so just check one of them
+  if (!old_document.GetFrame() || !new_document.GetFrame()) {
+    return false;
+  }
+
   // Don't reuse player if the Document Picture-in-Picture API is disabled for
   // both documents.
   if (!RuntimeEnabledFeatures::DocumentPictureInPictureAPIEnabled(
@@ -657,10 +662,6 @@
     return false;
   }
 
-  if (!old_document.GetFrame() || !new_document.GetFrame()) {
-    return false;
-  }
-
   auto* new_origin = new_document.GetFrame()
                          ->LocalFrameRoot()
                          .GetSecurityContext()
diff --git a/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
index c65eeac2..309c603 100644
--- a/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
@@ -247,7 +247,7 @@
     animation = it->value;
 
   *current_time = Timing::NullValue();
-  if (animation->Paused() || !animation->timeline()->IsActive()) {
+  if (animation->Paused() || !animation->TimelineInternal()->IsActive()) {
     absl::optional<AnimationTimeDelta> animation_current_time =
         animation->CurrentTimeInternal();
     if (animation_current_time) {
@@ -259,7 +259,7 @@
         animation->StartTimeInternal();
     if (animation_start_time) {
       absl::optional<AnimationTimeDelta> timeline_time =
-          animation->timeline()->CurrentTime();
+          animation->TimelineInternal()->CurrentTime();
       // TODO(crbug.com/916117): Handle NaN values for scroll linked animations.
       if (timeline_time) {
         *current_time = timeline_time.value().InMillisecondsF() -
@@ -286,14 +286,14 @@
     if (paused && !clone->Paused()) {
       // Ensure we restore a current time if the animation is limited.
       absl::optional<AnimationTimeDelta> current_time;
-      if (!clone->timeline()->IsActive()) {
+      if (!clone->TimelineInternal()->IsActive()) {
         current_time = clone->CurrentTimeInternal();
       } else {
         absl::optional<AnimationTimeDelta> start_time =
             clone->StartTimeInternal();
         if (start_time) {
           absl::optional<AnimationTimeDelta> timeline_time =
-              clone->timeline()->CurrentTime();
+              clone->TimelineInternal()->CurrentTime();
           // TODO(crbug.com/916117): Handle NaN values.
           if (timeline_time) {
             current_time = timeline_time.value() - start_time.value();
@@ -344,7 +344,7 @@
       old_effect->EffectTarget(), new_model, old_effect->SpecifiedTiming());
   is_cloning_ = true;
   blink::Animation* clone =
-      blink::Animation::Create(new_effect, animation->timeline());
+      blink::Animation::Create(new_effect, animation->TimelineInternal());
   is_cloning_ = false;
   id_to_animation_clone_.Set(id, clone);
   id_to_animation_.Set(String::Number(clone->SequenceNumber()), clone);
@@ -572,7 +572,8 @@
     time_ms = start_time.value().InMillisecondsF();
   }
 
-  auto* document_timeline = DynamicTo<DocumentTimeline>(animation.timeline());
+  auto* document_timeline =
+      DynamicTo<DocumentTimeline>(animation.TimelineInternal());
   if (document_timeline) {
     if (ReferenceTimeline().PlaybackRate() == 0) {
       time_ms += ReferenceTimeline().CurrentTimeMilliseconds().value_or(
diff --git a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
index b82939f..e95aba0 100644
--- a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
@@ -1808,12 +1808,16 @@
 
 std::unique_ptr<protocol::Array<protocol::CSS::Value>>
 InspectorStyleSheet::SelectorsFromSource(CSSRuleSourceData* source_data,
-                                         const String& sheet_text) {
+                                         const String& sheet_text,
+                                         CSSStyleRule* rule) {
   auto* comment = MakeGarbageCollected<ScriptRegexp>(
       "/\\*[^]*?\\*/", kTextCaseSensitive, MultilineMode::kMultilineEnabled);
   auto result = std::make_unique<protocol::Array<protocol::CSS::Value>>();
   const Vector<SourceRange>& ranges = source_data->selector_ranges;
-  for (wtf_size_t i = 0, size = ranges.size(); i < size; ++i) {
+  const CSSSelector* obj_selector = rule->GetStyleRule()->FirstSelector();
+
+  for (wtf_size_t i = 0, size = ranges.size(); i < size && obj_selector;
+       ++i, obj_selector = CSSSelectorList::Next(*obj_selector)) {
     const SourceRange& range = ranges.at(i);
     String selector = sheet_text.Substring(range.start, range.length());
 
@@ -1829,6 +1833,14 @@
             .setText(selector.StripWhiteSpace())
             .build();
     simple_selector->setRange(BuildSourceRangeObject(range));
+
+    std::array<uint8_t, 3> specificity_tuple = obj_selector->SpecificityTuple();
+    simple_selector->setSpecificity(protocol::CSS::Specificity::create()
+                                        .setA(specificity_tuple[0])
+                                        .setB(specificity_tuple[1])
+                                        .setC(specificity_tuple[2])
+                                        .build());
+
     result->emplace_back(std::move(simple_selector));
   }
   return result;
@@ -1844,14 +1856,27 @@
   String selector_text = rule->selectorText();
 
   if (source_data) {
-    selectors = SelectorsFromSource(source_data, text_);
+    selectors = SelectorsFromSource(source_data, text_, rule);
   } else {
     selectors = std::make_unique<protocol::Array<protocol::CSS::Value>>();
     for (const CSSSelector* selector = rule->GetStyleRule()->FirstSelector();
          selector; selector = CSSSelectorList::Next(*selector)) {
-      selectors->emplace_back(protocol::CSS::Value::create()
-                                  .setText(selector->SelectorText())
-                                  .build());
+      std::array<uint8_t, 3> specificity_tuple = selector->SpecificityTuple();
+
+      std::unique_ptr<protocol::CSS::Specificity> reworked_specificity =
+          protocol::CSS::Specificity::create()
+              .setA(specificity_tuple[0])
+              .setB(specificity_tuple[1])
+              .setC(specificity_tuple[2])
+              .build();
+
+      std::unique_ptr<protocol::CSS::Value> simple_selector =
+          protocol::CSS::Value::create()
+              .setText(selector->SelectorText())
+              .setSpecificity(std::move(reworked_specificity))
+              .build();
+
+      selectors->emplace_back(std::move(simple_selector));
     }
   }
   return protocol::CSS::SelectorList::create()
diff --git a/third_party/blink/renderer/core/inspector/inspector_style_sheet.h b/third_party/blink/renderer/core/inspector/inspector_style_sheet.h
index 1e19ce7..ba090c21 100644
--- a/third_party/blink/renderer/core/inspector/inspector_style_sheet.h
+++ b/third_party/blink/renderer/core/inspector/inspector_style_sheet.h
@@ -242,9 +242,9 @@
   bool InspectorStyleSheetText(String* result);
   String CollectStyleSheetRules();
   bool CSSOMStyleSheetText(String* result);
-  std::unique_ptr<protocol::Array<protocol::CSS::Value>> SelectorsFromSource(
-      CSSRuleSourceData*,
-      const String&);
+  std::unique_ptr<protocol::Array<protocol::CSS::Value>>
+  SelectorsFromSource(CSSRuleSourceData*, const String&, CSSStyleRule*);
+  Vector<const CSSSelector*> SelectorsFromRule(CSSStyleRule* rule);
   String Url();
   bool HasSourceURL();
   bool StartsAtZero();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
index e8caca4b..f840a03 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -106,6 +106,9 @@
   bool IsBisectLineBreakDisabled() const {
     return Data().IsBisectLineBreakDisabled();
   }
+  // True if this node can't use the `NGScorehLineBreaker`, that can be
+  // determined by `CollectInlines`. Conditions that can change without
+  // `CollectInlines` are in `NGLineBreaker::ShouldDisableScoreLineBreak()`.
   bool IsScoreLineBreakDisabled() const {
     return Data().IsScoreLineBreakDisabled();
   }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
index 0d83c17..c3cba8eb 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
@@ -32,6 +32,9 @@
   bool IsBisectLineBreakDisabled() const {
     return is_bisect_line_break_disabled_;
   }
+  // True if this node can't use the `NGScorehLineBreaker`, that can be
+  // determined by `CollectInlines`. Conditions that can change without
+  // `CollectInlines` are in `NGLineBreaker::ShouldDisableScoreLineBreak()`.
   bool IsScoreLineBreakDisabled() const {
     return is_score_line_break_disabled_;
   }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 376504d7..e2fcea5e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -547,6 +547,7 @@
   for (const NGInlineItem* item : open_items) {
     if (item->Style()->BoxDecorationBreak() == EBoxDecorationBreak::kClone) {
       has_cloned_box_decorations_ = true;
+      disable_score_line_break_ = true;
       ++cloned_box_decorations_count_;
       NGInlineItemResult item_result;
       ComputeOpenTagResult(*item, constraint_space_, is_svg_text_,
@@ -691,6 +692,8 @@
   // regardless of 'text-indent'.
   position_ = line_info->TextIndent();
 
+  disable_score_line_break_ = false;
+
   has_cloned_box_decorations_ = false;
   if (UNLIKELY((break_token_ && break_token_->HasClonedBoxDecorations()) ||
                cloned_box_decorations_count_))
@@ -2875,6 +2878,7 @@
   if (UNLIKELY(style.BoxDecorationBreak() == EBoxDecorationBreak::kClone)) {
     // Compute even when no margins/borders/padding to ensure correct counting.
     has_cloned_box_decorations_ = true;
+    disable_score_line_break_ = true;
     ++cloned_box_decorations_count_;
     cloned_box_decorations_end_size_ += item_result->margins.inline_end +
                                         item_result->borders.inline_end +
@@ -3080,8 +3084,12 @@
   // Reaching here means that the rewind point was not found.
 
   if (!override_break_anywhere_ && has_break_anywhere_if_overflow) {
+    // Overflow occurred but `overflow-wrap` is set. Change the break type and
+    // retry the line breaking.
     override_break_anywhere_ = true;
     break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
+    // `NGScoreLineBreaker` doesn't support multi-pass line breaking.
+    disable_score_line_break_ = true;
     state_ = LineBreakState::kContinue;
     // TODO(kojii): Not all items need to rewind, but such case is rare and
     // rewinding all items simplifes the code.
@@ -3094,6 +3102,12 @@
   // Let this line overflow.
   line_info->SetHasOverflow();
 
+  // TODO(kojii): `NGScoreLineBreaker::ComputeScores` gets confused if there're
+  // overflowing lines. Disable the score line break for now. E.g.:
+  //   css2.1/t1601-c547-indent-01-d.html
+  //   virtual/text-antialias/international/bdi-neutral-wrapped.html
+  disable_score_line_break_ = true;
+
   // Restore the hyphenation states to before the loop if needed.
   DCHECK(!HasHyphen());
   if (UNLIKELY(hyphen_index_before))
@@ -3408,6 +3422,7 @@
 
     if (style.ShouldBreakSpaces()) {
       break_iterator_.SetBreakSpace(BreakSpaceType::kAfterEverySpace);
+      disable_score_line_break_ = true;
     }
 
     break_iterator_.SetLocale(style.LocaleForLineBreakIterator());
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index ac186df..b9791c15 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -63,6 +63,12 @@
 
   bool IsFinished() const { return current_.item_index >= Items().size(); }
 
+  // True if there are items that `NGScoreLineBreaker` doesn't support.
+  // Conditions that can be determined by `CollectInlines` are done by
+  // `NGInlineNode::IsScoreLineBreakDisabled()`, but some conditions can change
+  // withoiut `CollectInlines`. They are determined by this.
+  bool ShouldDisableScoreLineBreak() const { return disable_score_line_break_; }
+
   // Override the available width to compute line breaks. This is reset after
   // each `NextLine`.
   void OverrideAvailableWidth(LayoutUnit available_width);
@@ -304,6 +310,8 @@
   // True when breaking at soft hyphens (U+00AD) is allowed.
   bool enable_soft_hyphen_ = true;
 
+  bool disable_score_line_break_ = false;
+
   // True when the line should be non-empty if |IsLastLine|..
   bool force_non_empty_if_last_line_ = false;
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker.cc
index de2e66a77..259419c 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker.cc
@@ -47,6 +47,10 @@
   for (;;) {
     NGLineInfo& line_info = line_info_list.Append();
     line_breaker.NextLine(&line_info);
+    if (UNLIKELY(line_breaker.ShouldDisableScoreLineBreak())) {
+      context.SuspendUntilConsumed();
+      return;
+    }
     if (!line_info.BreakToken() || line_info.HasForcedBreak()) {
       context.SuspendUntilConsumed();
       break;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker_test.cc
index a47d4be6..31ecf59e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_score_line_breaker_test.cc
@@ -138,4 +138,118 @@
   EXPECT_NE(line_info_list.Size(), 3u);
 }
 
+struct DisabledByLineBreakerData {
+  bool disabled;
+  const char* html;
+} disabled_by_line_breaker_data[] = {
+    // Normal, should not be disabled.
+    {false, R"HTML(
+      <div id="target">
+        0123 5678
+        1234 6789
+        234 67890
+        45
+      </div>
+    )HTML"},
+    // Overflowing lines should disable.
+    {true, R"HTML(
+      <div id="target">
+        0123 5678
+        123456789012
+        23 567 90
+        45
+      </div>
+    )HTML"},
+    // `overflow-wrap` should be ok, except...
+    {false, R"HTML(
+      <div id="target" style="overflow-wrap: anywhere">
+        0123 5678
+        1234 6789
+        23 567 90
+        45
+      </div>
+    )HTML"},
+    {false, R"HTML(
+      <div id="target" style="overflow-wrap: break-word">
+        0123 5678
+        1234 6789
+        23 567 90
+        45
+      </div>
+    )HTML"},
+    // ...when there're overflows.
+    {true, R"HTML(
+      <div id="target" style="overflow-wrap: anywhere">
+        0123 5678
+        123456789012
+        23 567 90
+        45
+      </div>
+    )HTML"},
+    {true, R"HTML(
+      <div id="target" style="overflow-wrap: break-word">
+        0123 5678
+        123456789012
+        23 567 90
+        45
+      </div>
+    )HTML"},
+    // `break-sapces` is not supported.
+    {true, R"HTML(
+      <div id="target" style="white-space: break-spaces">
+        0123 5678
+        1234 6789
+        23 567 90
+        45
+      </div>
+    )HTML"},
+    // `box-decoration-break: clone` is not supported.
+    {true, R"HTML(
+      <div id="target">
+        0123 5678
+        1234 6789
+        23 <span style="-webkit-box-decoration-break: clone">567</span> 90
+        45
+      </div>
+    )HTML"}};
+
+class DisabledByLineBreakerTest
+    : public NGScoreLineBreakerTest,
+      public testing::WithParamInterface<DisabledByLineBreakerData> {};
+
+INSTANTIATE_TEST_SUITE_P(NGScoreLineBreakerTest,
+                         DisabledByLineBreakerTest,
+                         testing::ValuesIn(disabled_by_line_breaker_data));
+
+TEST_P(DisabledByLineBreakerTest, Data) {
+  const auto& data = GetParam();
+  LoadAhem();
+  SetBodyInnerHTML(String(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #target {
+      font-family: Ahem;
+      font-size: 10px;
+      width: 10ch;
+    }
+    </style>
+  )HTML") + data.html);
+  const NGInlineNode node = GetInlineNodeByElementId("target");
+  const NGPhysicalBoxFragment* fragment =
+      node.GetLayoutBox()->GetPhysicalFragment(0);
+  const LayoutUnit width = fragment->Size().width;
+  NGConstraintSpace space = ConstraintSpaceForAvailableSize(width);
+  NGLineLayoutOpportunity line_opportunity(width);
+  NGScoreLineBreakContext context;
+  NGScoreLineBreaker optimizer(node, space, line_opportunity);
+  const NGInlineBreakToken* break_token = nullptr;
+  optimizer.OptimalBreakPoints(break_token, context);
+  EXPECT_FALSE(context.IsActive());
+  if (data.disabled) {
+    EXPECT_EQ(context.LineBreakPoints().size(), 0u);
+  } else {
+    EXPECT_NE(context.LineBreakPoints().size(), 0u);
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index f2b78ed..750c9a4 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -1174,7 +1174,7 @@
       default_value: "false",
     },
     {
-      name: "IsPseudoInitialStyle",
+      name: "IsStartingStyle",
       field_template: "monotonic_flag",
       type_name: "bool",
       field_group: "*",
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 15055e8c..51886f1 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3100,6 +3100,20 @@
       implied_by: ["AnimationWorklet", "ScrollTimelineCurrentTime"]
     },
     {
+      // Support for scroll/view-timeline-attachment.
+      //
+      // This feature was intially specified in scroll-animations-1,
+      // but was since removed by a resolution in Issue 7759.
+      //
+      // The properties will remain available behind this flag until
+      // all WPTs are adjusted to the new API (see feature TimelineScope).
+      //
+      // https://github.com/w3c/csswg-drafts/issues/7759
+      // https://crbug.com/1446702
+      name: "ScrollTimelineAttachment",
+      status: "test"
+    },
+    {
       // Separate flag for crbug.com/1426506 (getCurrentTime API change) which
       // is expected to land after the initial launch of ScrollTimeline.
       name: "ScrollTimelineCurrentTime",
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 423989b..5a3ec79 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -346,7 +346,8 @@
 crbug.com/1081534 [ Mac10.15 Release ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-transformclip.html [ Slow ]
 crbug.com/1081534 [ Mac11 Release ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-transformclip.html [ Slow ]
 crbug.com/1081534 [ Mac12 ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-transformclip.html [ Slow ]
-crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow.html [ Slow ]
+crbug.com/1081534 [ Debug Mac12 ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow.html [ Slow ]
+crbug.com/1081534 [ Mac10.14 Release ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow.html [ Slow ]
 crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-video.html [ Slow ]
 crbug.com/1081534 [ Debug Mac12 ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-gradient-over-image.html [ Slow ]
 crbug.com/1081534 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-gradient-over-pattern.html [ Slow ]
@@ -1038,7 +1039,6 @@
 crbug.com/886566 [ Mac11 Release ] http/tests/csspaint/invalidation-background-image.html [ Slow ]
 crbug.com/886566 [ Mac12 ] http/tests/csspaint/invalidation-background-image.html [ Slow ]
 crbug.com/886566 [ Mac12-arm64 Release ] http/tests/csspaint/invalidation-background-image.html [ Slow ]
-crbug.com/886566 [ Debug Mac13-arm64 ] http/tests/csspaint/invalidation-content-image.html [ Slow ]
 crbug.com/886566 [ Linux ] http/tests/csspaint/invalidation-content-image.html [ Slow ]
 crbug.com/886566 [ Mac10.15 Release ] http/tests/csspaint/invalidation-content-image.html [ Slow ]
 crbug.com/886566 [ Mac11 Release ] http/tests/csspaint/invalidation-content-image.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 86657ef..bd6ee2b 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -883,7 +883,6 @@
 crbug.com/1042783 external/wpt/css/css-backgrounds/background-size/background-size-near-zero-svg.html [ Failure ]
 
 # Passes with the WPT runner but not the internal one. (???)
-crbug.com/1175040 external/wpt/css/css-backgrounds/background-repeat-space-1c.html [ Failure Pass ]
 crbug.com/1175040 external/wpt/css/css-backgrounds/background-repeat-space-4.html [ Failure Pass ]
 
 # Off-by-one in some components.
@@ -1824,7 +1823,7 @@
 
 # Popover test timeout/flakiness
 crbug.com/1416284 external/wpt/html/semantics/popovers/popover-attribute-basic.html [ Pass Timeout ]
-crbug.com/1443372 external/wpt/html/semantics/popovers/popover-hover-hide.tentative.html [ Failure Pass ]
+crbug.com/1443372 [ Mac ] external/wpt/html/semantics/popovers/popover-hover-hide.tentative.html [ Failure Pass ]
 
 # Only virtual/threaded version of these tests pass (or running them with --enable-threaded-compositing).
 crbug.com/936891 fast/scrolling/document-level-touchmove-event-listener-passive-by-default.html [ Failure ]
@@ -2061,7 +2060,6 @@
 crbug.com/1218716 external/wpt/trust-tokens/trust-token-parameter-validation.tentative.https.html [ Failure ]
 crbug.com/1218716 external/wpt/feature-policy/experimental-features/trust-token-redemption-default-feature-policy.tentative.https.sub.html [ Failure ]
 crbug.com/1218716 external/wpt/feature-policy/experimental-features/trust-token-redemption-supported-by-feature-policy.tentative.html [ Failure ]
-crbug.com/1218716 external/wpt/permissions-policy/experimental-features/trust-token-redemption-default-permissions-policy.tentative.https.sub.html [ Failure ]
 
 # Sheriff 2020-02-06
 
@@ -2898,6 +2896,8 @@
 crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac12 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/animation-timeline-view-functional-notation.tentative.html [ Timeout ]
+crbug.com/626703 [ Mac12 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/scroll-timeline-dynamic.tentative.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/tables/table-bordercolor-001.html [ Failure ]
 crbug.com/626703 [ Mac13 ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
@@ -5380,7 +5380,9 @@
 
 # Sheriff 2021-11-29
 crbug.com/1274458 external/wpt/audio-output/selectAudioOutput-permissions-policy.https.sub.html [ Failure Pass ]
-crbug.com/1239485 [ Mac ] fast/frames/iframe-plugin-load-remove-document-crash.html [ Failure Pass ]
+crbug.com/1239485 [ Debug Mac12 ] fast/frames/iframe-plugin-load-remove-document-crash.html [ Failure Pass ]
+crbug.com/1239485 [ Debug Mac13-arm64 ] fast/frames/iframe-plugin-load-remove-document-crash.html [ Failure Pass ]
+crbug.com/1239485 [ Mac Release ] fast/frames/iframe-plugin-load-remove-document-crash.html [ Failure Pass ]
 
 # Sheriff 2021-12-01
 crbug.com/1275658 http/tests/misc/script-after-slow-stylesheet-removed.html [ Failure Pass ]
@@ -5438,8 +5440,7 @@
 
 # Sheriff 2022-01-17
 crbug.com/1233938 http/tests/notifications/click-shared-worker.html [ Pass Timeout ]
-# Temporarily disable test to allow fixing of devtools path escaping
-crbug.com/1094436 http/tests/devtools/overrides/project-added-with-existing-files-bind.js [ Failure Timeout ]
+crbug.com/1094436 [ Win ] http/tests/devtools/overrides/project-added-with-existing-files-bind.js [ Failure Timeout ]
 crbug.com/1256763 virtual/gpu-rasterization/images/color-profile-background-image-cover.html [ Failure Pass ]
 
 # Sheriff 2022-01-18
@@ -5998,7 +5999,7 @@
 
 crbug.com/1370050 http/tests/devtools/sources/debugger-ui/debugger-save-to-temp-var.js [ Crash Failure Pass Timeout ]
 
-crbug.com/1279220 [ Win ] virtual/percent-based-scrolling/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html [ Pass Timeout ]
+crbug.com/1279220 [ Win10.20h2 ] virtual/percent-based-scrolling/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html [ Pass Timeout ]
 crbug.com/1279220 [ Linux ] fast/scrolling/non-composited-scroller-in-position-fixed-scroller.html [ Failure Pass ]
 
 # Sheriff 2022-10-12
diff --git a/third_party/blink/web_tests/css-parser/offset-path-parsing.html b/third_party/blink/web_tests/css-parser/offset-path-parsing.html
index 29618b0..9a55d372 100644
--- a/third_party/blink/web_tests/css-parser/offset-path-parsing.html
+++ b/third_party/blink/web_tests/css-parser/offset-path-parsing.html
@@ -8,7 +8,7 @@
 assert_valid_value("offset-path", "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z')",
                                   "path(\"M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z\")");
 assert_valid_value("offset-path", "none");
-assert_valid_value("offset-path", "path('')", "none");
+assert_invalid_value("offset-path", "path('')");
 assert_invalid_value("offset-path", "path('M 20 30 A 60 70 80')");
 
 assert_valid_value("offset-path", "ray(45deg closest-side)", "ray(45deg)");
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 7c296af..f274d3f4 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -272644,11 +272644,11 @@
   "support": {
    ".cache": {
     "gitignore2.json": [
-     "42968047be3e44ee65274686cc2e3a1bb5fa8606",
+     "d4c040145f13b144ecaf45886be5b591f643219f",
      []
     ],
     "mtime.json": [
-     "d6f12464231664ed4dc4e35783d2404b911d0c25",
+     "e78affcda8cd07af74fcd2f203c9dd53682c577b",
      []
     ]
    },
@@ -287812,7 +287812,7 @@
        []
       ],
       "mix-blend-mode-blended-element-overflow-scroll.html.ini": [
-       "053f4729ef2a7f1d42253a93d30aea86716f659e",
+       "568f0e7abc4646cd0566dce948867e0bc0dc9273",
        []
       ],
       "mix-blend-mode-blended-with-3D-transform.html.ini": [
@@ -293058,6 +293058,10 @@
       "a8157aa752192e39da0911705d61fb863dba20df",
       []
      ],
+     "at-supports-005.html.ini": [
+      "66b03e7c3776b2a7f3e188e78c27ba437b9e6d1f",
+      []
+     ],
      "at-supports-020.html.ini": [
       "7e3b32f278a62b45cd7587c3f7aca705c2f5bef1",
       []
@@ -329884,7 +329888,7 @@
        []
       ],
       "kind-of-widget-fallback-color-input-border-left-width-001.html.ini": [
-       "790ec0a2515cffe6f8324353c2a9273a6a1ebb11",
+       "08861083c05fd6e1fb2d809a3e5e8dddb53b63a6",
        []
       ],
       "kind-of-widget-fallback-color-input-border-right-width-001.html.ini": [
@@ -330036,7 +330040,7 @@
        []
       ],
       "kind-of-widget-fallback-input-reset-border-inline-end-color-001.html.ini": [
-       "57c6eb8f88bb60ce4dac4ee4d4727c8597a0c812",
+       "66c7da025d0886badcf669df11d4f89fe7ea4e98",
        []
       ],
       "kind-of-widget-fallback-input-reset-border-inline-end-style-001.html.ini": [
@@ -330360,7 +330364,7 @@
        []
       ],
       "kind-of-widget-fallback-input-submit-border-end-end-radius-001.html.ini": [
-       "1b2c05ec9c382ccf8393e5320fc0a5827c88ab81",
+       "9fb5aa8b0650b8c93494d521c3bb94d17e6b018e",
        []
       ],
       "kind-of-widget-fallback-input-submit-border-end-start-radius-001.html.ini": [
@@ -337613,7 +337617,7 @@
       []
      ],
      "css-backdrop-filters-animation-invert.html.ini": [
-      "492c00de3346a4aef908b76632552234314f2ef7",
+      "ec644098dbfc8d1054429c056933ed78e5ff623e",
       []
      ],
      "css-backdrop-filters-animation-opacity-ref.html": [
@@ -368814,6 +368818,14 @@
         "9354d4270305882f80a7110aa1fd6adb2ffc7295",
         []
        ],
+       "script-type-whitespace-expected.txt": [
+        "9fbeb3c045a2c82913225ff58e231d9a1860e0f8",
+        []
+       ],
+       "script-type-whitespace.html.ini": [
+        "d929799f1482dce79f4a9a5eee916ba7d1829003",
+        []
+       ],
        "serve-json-then-js.py": [
         "9610734d4449794d1eb10032a1bac75cd4523b40",
         []
@@ -380422,7 +380434,7 @@
      []
     ],
     "modulepreload-as.html.ini": [
-     "344d5e663f13d94b5326ee18fcd7f2ac344a97c6",
+     "acb7550601585efe5b4d6502a95624d4556562c7",
      []
     ],
     "modulepreload-expected.txt": [
@@ -561252,6 +561264,13 @@
          {}
         ]
        ],
+       "script-type-whitespace.html": [
+        "5e8acb1a17bace7ad5f55ac9a3545bbb1220ae10",
+        [
+         null,
+         {}
+        ]
+       ],
        "scripting-enabled.html": [
         "a2671a78f69c1f0065892fbeba81e872163c756e",
         [
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-scroll.html.ini b/third_party/blink/web_tests/external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-scroll.html.ini
index 053f4729..568f0e7 100644
--- a/third_party/blink/web_tests/external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-scroll.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-scroll.html.ini
@@ -1,6 +1,7 @@
 [mix-blend-mode-blended-element-overflow-scroll.html]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
-    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-005.html.ini b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-005.html.ini
new file mode 100644
index 0000000..66b03e7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-005.html.ini
@@ -0,0 +1,3 @@
+[at-supports-005.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-left-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-left-width-001.html.ini
index 790ec0a..0886108 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-left-width-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-left-width-001.html.ini
@@ -1,3 +1,4 @@
 [kind-of-widget-fallback-color-input-border-left-width-001.html]
   expected:
+    if (product == "content_shell") and (os == "linux"): FAIL
     if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-inline-end-color-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-inline-end-color-001.html.ini
index 57c6eb8f..66c7da0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-inline-end-color-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-inline-end-color-001.html.ini
@@ -1,3 +1,4 @@
 [kind-of-widget-fallback-input-reset-border-inline-end-color-001.html]
   expected:
+    if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
     if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-end-end-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-end-end-radius-001.html.ini
index 1b2c05e..9fb5aa8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-end-end-radius-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-end-end-radius-001.html.ini
@@ -1,3 +1,3 @@
 [kind-of-widget-fallback-input-submit-border-end-end-radius-001.html]
   expected:
-    if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): FAIL
+    if (product == "content_shell") and (os == "win"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/css-backdrop-filters-animation-invert.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/css-backdrop-filters-animation-invert.html.ini
index 492c00de..ec64409 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/css-backdrop-filters-animation-invert.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/css-backdrop-filters-animation-invert.html.ini
@@ -1,4 +1,5 @@
 [css-backdrop-filters-animation-invert.html]
   expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid-expected.txt
index 973c0d1..82b61e30 100644
--- a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-parsing-valid-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS e.style['offset'] = "100px none auto 90deg" should set the property value
 PASS e.style['offset'] = "100px" should set the property value
-FAIL e.style['offset'] = "auto none reverse" should set the property value assert_equals: serialization should be canonical expected "none reverse" but got "auto none reverse"
+PASS e.style['offset'] = "auto none reverse" should set the property value
 PASS e.style['offset'] = "auto" should set the property value
 PASS e.style['offset'] = "center bottom path(\"M 1 2 V 3 Z\")" should set the property value
 PASS e.style['offset'] = "center center path(\"M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z\") 100% 90deg / left bottom" should set the property value
@@ -9,18 +9,18 @@
 PASS e.style['offset'] = "left top" should set the property value
 PASS e.style['offset'] = "none 30deg reverse" should set the property value
 PASS e.style['offset'] = "none 50px reverse 30deg" should set the property value
-FAIL e.style['offset'] = "none calc(10px + 20%) auto" should set the property value assert_equals: serialization should be canonical expected "none calc(20% + 10px)" but got "none calc(10px + 20%) auto"
+FAIL e.style['offset'] = "none calc(10px + 20%) auto" should set the property value assert_equals: serialization should be canonical expected "none calc(20% + 10px)" but got "none calc(10px + 20%)"
 PASS e.style['offset'] = "none reverse" should set the property value
-FAIL e.style['offset'] = "path(\"M 0 0 H 1\") -200% auto" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\") -200%" but got "path(\"M 0 0 H 1\") -200% auto"
+PASS e.style['offset'] = "path(\"M 0 0 H 1\") -200% auto" should set the property value
 PASS e.style['offset'] = "path(\"M 0 0 H 1\") -200%" should set the property value
 PASS e.style['offset'] = "path('M 0 0 H 1') 50px" should set the property value
-FAIL e.style['offset'] = "path(\"M 0 0 H 1\") auto" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\")" but got "path(\"M 0 0 H 1\") auto"
-FAIL e.style['offset'] = "path(\"M 0 0 H 1\") auto 0deg" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\")" but got "path(\"M 0 0 H 1\") auto 0deg"
-FAIL e.style['offset'] = "path(\"M 0 0 H 1\") auto 0rad" should set the property value assert_equals: serialization should be canonical expected "path(\"M 0 0 H 1\")" but got "path(\"M 0 0 H 1\") auto 0rad"
+PASS e.style['offset'] = "path(\"M 0 0 H 1\") auto" should set the property value
+PASS e.style['offset'] = "path(\"M 0 0 H 1\") auto 0deg" should set the property value
+PASS e.style['offset'] = "path(\"M 0 0 H 1\") auto 0rad" should set the property value
 PASS e.style['offset'] = "path(\"M 0 0 H 1\") auto 0.5turn" should set the property value
 PASS e.style['offset'] = "path('M 0 0 H 1') reverse 30deg 50px" should set the property value
 PASS e.style['offset'] = "path(\"M 0 0 H 1\")" should set the property value
-FAIL e.style['offset'] = "path('m 20 0 h 100') -7rad 8px / auto" should set the property value assert_equals: serialization should be canonical expected "path(\"m 20 0 h 100\") 8px -7rad" but got "path(\"m 20 0 h 100\") 8px -7rad / auto"
+PASS e.style['offset'] = "path('m 20 0 h 100') -7rad 8px / auto" should set the property value
 PASS e.style['offset'] = "path('m 0 30 v 100') -7rad 8px / left top" should set the property value
 PASS e.style['offset'] = "path('m 0 0 h 100') -7rad 8px" should set the property value
 PASS e.style['offset'] = "path(\"M 0 0 H 100\") 100px 0deg" should set the property value
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-path-parsing-invalid-expected.txt b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-path-parsing-invalid-expected.txt
deleted file mode 100644
index e59f46f7..0000000
--- a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-path-parsing-invalid-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-PASS e.style['offset-path'] = "path(\"M 20 30 A 60 70 80\")" should not set the property value
-FAIL e.style['offset-path'] = "path(\"\")" should not set the property value assert_equals: expected "" but got "none"
-FAIL e.style['offset-path'] = "path(\" \")" should not set the property value assert_equals: expected "" but got "none"
-PASS e.style['offset-path'] = "ray(0 sides)" should not set the property value
-PASS e.style['offset-path'] = "ray(closest-side)" should not set the property value
-PASS e.style['offset-path'] = "ray(closest-side 0deg closest-side)" should not set the property value
-PASS e.style['offset-path'] = "ray(0deg closest-side 0deg)" should not set the property value
-PASS e.style['offset-path'] = "ray(contain 0deg closest-side contain)" should not set the property value
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-shorthand-expected.txt b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-shorthand-expected.txt
deleted file mode 100644
index f588c32..0000000
--- a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-shorthand-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This is a testharness.js-based test.
-PASS e.style['offset'] = "left bottom ray(0rad closest-corner) 10px auto 30deg / right bottom" should set offset-anchor
-PASS e.style['offset'] = "left bottom ray(0rad closest-corner) 10px auto 30deg / right bottom" should set offset-distance
-PASS e.style['offset'] = "left bottom ray(0rad closest-corner) 10px auto 30deg / right bottom" should set offset-path
-PASS e.style['offset'] = "left bottom ray(0rad closest-corner) 10px auto 30deg / right bottom" should set offset-position
-PASS e.style['offset'] = "left bottom ray(0rad closest-corner) 10px auto 30deg / right bottom" should set offset-rotate
-PASS e.style['offset'] = "left bottom ray(0rad closest-corner) 10px auto 30deg / right bottom" should not set unrelated longhands
-PASS e.style['offset'] = "top right / top left" should set offset-anchor
-FAIL e.style['offset'] = "top right / top left" should set offset-distance assert_equals: offset-distance should be canonical expected "0px" but got "initial"
-FAIL e.style['offset'] = "top right / top left" should set offset-path assert_equals: offset-path should be canonical expected "none" but got "initial"
-PASS e.style['offset'] = "top right / top left" should set offset-position
-FAIL e.style['offset'] = "top right / top left" should set offset-rotate assert_equals: offset-rotate should be canonical expected "auto" but got "initial"
-PASS e.style['offset'] = "top right / top left" should not set unrelated longhands
-FAIL e.style['offset'] = "path(\"M 0 0 H 2\") reverse 50%" should set offset-anchor assert_equals: offset-anchor should be canonical expected "auto" but got "initial"
-PASS e.style['offset'] = "path(\"M 0 0 H 2\") reverse 50%" should set offset-distance
-PASS e.style['offset'] = "path(\"M 0 0 H 2\") reverse 50%" should set offset-path
-FAIL e.style['offset'] = "path(\"M 0 0 H 2\") reverse 50%" should set offset-position assert_equals: offset-position should be canonical expected "auto" but got "initial"
-PASS e.style['offset'] = "path(\"M 0 0 H 2\") reverse 50%" should set offset-rotate
-PASS e.style['offset'] = "path(\"M 0 0 H 2\") reverse 50%" should not set unrelated longhands
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace-expected.txt
new file mode 100644
index 0000000..9fbeb3c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Script shouldn't run with type="text/javascript&#x000B;" (parser-inserted) assert_false: expected false got true
+PASS Script shouldn't run with type="text/javascript&#x0085;" (parser-inserted)
+PASS Script shouldn't run with type="text/javascript&#x00A0;" (parser-inserted)
+FAIL Script shouldn't run with type="text/javascript&#x1680;" (parser-inserted) assert_false: expected false got true
+FAIL Script shouldn't run with type="text/javascript&#x3000;" (parser-inserted) assert_false: expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace.html
new file mode 100644
index 0000000..5e8acb1a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<title>&lt;script type> non-ASCII whitespace handling</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+function testParserInsertedDidNotRun(description) {
+  test(() => assert_false(window.ran),
+       "Script shouldn't run with " + description + " (parser-inserted)");
+  window.ran = false;
+}
+</script>
+
+<script>window.ran = false;</script>
+<script type="text/javascript&#x000B;">window.ran = true;</script>
+<script>testParserInsertedDidNotRun("type=\"text/javascript&#x000B;\"");</script>
+
+<script type="text/javascript&#x0085;">window.ran = true;</script>
+<script>testParserInsertedDidNotRun("type=\"text/javascript&#x0085;\"");</script>
+
+<script type="text/javascript&#x00A0;">window.ran = true;</script>
+<script>testParserInsertedDidNotRun("type=\"text/javascript&#x00A0;\"");</script>
+
+<script type="text/javascript&#x1680;">window.ran = true;</script>
+<script>testParserInsertedDidNotRun("type=\"text/javascript&#x1680;\"");</script>
+
+<script type="text/javascript&#x3000;">window.ran = true;</script>
+<script>testParserInsertedDidNotRun("type=\"text/javascript&#x3000;\"");</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace.html.ini b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace.html.ini
new file mode 100644
index 0000000..d929799
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-type-whitespace.html.ini
@@ -0,0 +1,9 @@
+[script-type-whitespace.html]
+  [Script shouldn't run with type="text/javascript&#x000B;" (parser-inserted)]
+    expected: FAIL
+
+  [Script shouldn't run with type="text/javascript&#x1680;" (parser-inserted)]
+    expected: FAIL
+
+  [Script shouldn't run with type="text/javascript&#x3000;" (parser-inserted)]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html.ini b/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html.ini
index 344d5e6..acb7550 100644
--- a/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html.ini
+++ b/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html.ini
@@ -1,174 +1,171 @@
 [modulepreload-as.html]
   expected:
+    if (product == "content_shell") and (os == "win") and (port == "win11"): [TIMEOUT, ERROR]
     if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): TIMEOUT
-    if (product == "content_shell") and (os == "mac") and (port == "mac11"): OK
     if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): OK
     if (product == "content_shell") and (os == "mac") and (port == "mac12"): OK
-    if product == "chrome": [ERROR, TIMEOUT]
+    if (product == "content_shell") and (os == "mac") and (port == "mac11"): OK
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [ERROR, OK]
+    if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [ERROR, TIMEOUT]
     ERROR
-  [Modulepreload with as=""]
-    expected:
-      if product == "chrome": [PASS, TIMEOUT]
-
   [Modulepreload with as="audio"]
     expected:
-      if product == "chrome": [FAIL, NOTRUN]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS]
       FAIL
 
   [Modulepreload with as="audioworklet"]
-    expected:
-      if product == "chrome": [FAIL, NOTRUN]
-      FAIL
+    expected: FAIL
 
   [Modulepreload with as="document"]
     expected:
-      if product == "chrome": [FAIL, NOTRUN]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [FAIL, PASS]
       FAIL
 
   [Modulepreload with as="embed"]
     expected:
-      if (product == "content_shell") and (os == "linux"): PASS
-      if product == "chrome": [FAIL, NOTRUN, PASS]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [FAIL, PASS]
       FAIL
 
   [Modulepreload with as="fetch"]
     expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): PASS
-      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): PASS
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
       if (product == "content_shell") and (os == "linux"): PASS
-      if product == "chrome": [PASS, NOTRUN]
+      if product == "chrome": PASS
       FAIL
 
   [Modulepreload with as="font"]
     expected:
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
       if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
-      if product == "chrome": [PASS, NOTRUN, FAIL]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
+      if product == "chrome": PASS
       FAIL
 
   [Modulepreload with as="frame"]
     expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
-      if product == "chrome": [PASS, NOTRUN, FAIL]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
+      if product == "chrome": PASS
+      FAIL
 
   [Modulepreload with as="iMaGe"]
     expected:
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
       if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
       if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
-      if product == "chrome": [PASS, NOTRUN]
 
   [Modulepreload with as="iframe"]
     expected:
-      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
       if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
-      if (product == "content_shell") and (os == "win") and (port == "win11"): PASS
       if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): PASS
-      if product == "chrome": [PASS, NOTRUN]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
+      if product == "chrome": PASS
       FAIL
 
   [Modulepreload with as="image"]
     expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
-      if product == "chrome": [PASS, NOTRUN]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
+      if product == "chrome": PASS
+      FAIL
 
   [Modulepreload with as="invalid-dest"]
-    expected:
-      if product == "chrome": [FAIL, NOTRUN]
-      FAIL
+    expected: FAIL
 
   [Modulepreload with as="manifest"]
     expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
-      if product == "chrome": [PASS, NOTRUN]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): PASS
+      if product == "chrome": PASS
+      FAIL
 
   [Modulepreload with as="object"]
     expected:
       if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
-      if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
       if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
       if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
-      if product == "chrome": [PASS, NOTRUN]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
 
   [Modulepreload with as="paintworklet"]
-    expected:
-      if product == "chrome": [FAIL, NOTRUN]
-      FAIL
+    expected: FAIL
 
   [Modulepreload with as="report"]
     expected:
-      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
       if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
+      if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
       if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
-      if product == "chrome": [PASS, NOTRUN]
-
-  [Modulepreload with as="sCrIpT"]
-    expected:
-      if product == "chrome": [PASS, NOTRUN]
-
-  [Modulepreload with as="script"]
-    expected:
-      if product == "chrome": [PASS, NOTRUN]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL]
 
   [Modulepreload with as="serviceworker"]
-    expected:
-      if product == "chrome": [FAIL, NOTRUN]
-      FAIL
+    expected: FAIL
 
   [Modulepreload with as="sharedworker"]
-    expected:
-      if product == "chrome": [FAIL, NOTRUN]
-      FAIL
+    expected: FAIL
 
   [Modulepreload with as="style"]
     expected:
-      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS]
       if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
-      if product == "chrome": [PASS, NOTRUN, FAIL]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
+      if product == "chrome": PASS
       FAIL
 
   [Modulepreload with as="track"]
     expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): PASS
-      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS
       if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
-      if product == "chrome": [PASS, NOTRUN]
+      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS]
+      if product == "chrome": PASS
       FAIL
 
   [Modulepreload with as="video"]
     expected:
-      if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS
-      if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
-      if product == "chrome": [PASS, NOTRUN]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux"): PASS
+      if product == "chrome": PASS
       FAIL
 
   [Modulepreload with as="webidentity"]
     expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
       if (product == "content_shell") and (os == "linux"): PASS
-      if product == "chrome": [PASS, NOTRUN]
+      if product == "chrome": PASS
       FAIL
 
   [Modulepreload with as="worker"]
-    expected:
-      if product == "chrome": [FAIL, NOTRUN]
-      FAIL
+    expected: FAIL
 
   [Modulepreload with as="xslt"]
     expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): PASS
+      if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS]
       if (product == "content_shell") and (os == "linux"): PASS
-      if product == "chrome": [PASS, NOTRUN]
+      if product == "chrome": PASS
       FAIL
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-timeline-deferred.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-timeline-deferred.html
new file mode 100644
index 0000000..d0671e5f2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-timeline-deferred.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<title>Deferred timelines via Animation.timeline</title>
+<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/7759">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/web-animations/testcommon.js"></script>
+
+<main id=main></main>
+<script>
+  function inflate(t, template) {
+    t.add_cleanup(() => main.replaceChildren());
+    main.append(template.content.cloneNode(true));
+    main.offsetTop;
+  }
+
+  async function scrollTop(e, value) {
+    e.scrollTop = value;
+    await waitForNextFrame();
+  }
+</script>
+<style>
+  @keyframes anim {
+    from { width: 0px; }
+    to { width: 200px; }
+  }
+  .scroller {
+    overflow-y: hidden;
+    width: 200px;
+    height: 200px;
+  }
+  .scroller > .content {
+    margin: 400px 0px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+  }
+  .animating {
+    background-color: coral;
+    width: 0px;
+    animation: anim auto linear;
+    animation-timeline: --t1;
+  }
+  .timeline {
+    scroll-timeline-name: --t1;
+  }
+  .scope {
+    timeline-scope: --t1;
+  }
+</style>
+
+<template id=animation_timeline_attached>
+  <div class="scope">
+    <div class=animating>Test</div>
+    <div class="scroller timeline">
+      <div class="content animating"></div>
+    </div>
+  </div>
+</template>
+<script>
+  promise_test(async (t) => {
+    inflate(t, animation_timeline_attached);
+    let scroller = main.querySelector('.scroller');
+    let animating = Array.from(main.querySelectorAll('.animating'));
+
+    assert_equals(animating.length, 2);
+    let animations = animating.map((e) => e.getAnimations()[0]);
+    assert_equals(animations.length, 2);
+
+    // animations[0] is attached via deferred timeline (timeline-scope),
+    // and animations[1] is attached directly.
+    assert_equals(animations[0].timeline, animations[1].timeline);
+  }, 'Animation.timeline returns attached timeline');
+</script>
+
+<template id=animation_timeline_inactive>
+  <div class="scope">
+    <div class=animating>Test</div>
+  </div>
+</template>
+<script>
+  promise_test(async (t) => {
+    inflate(t, animation_timeline_inactive);
+    let scroller = main.querySelector('.scroller');
+    let animating = main.querySelector('.animating');
+
+    assert_equals(animating.getAnimations()[0].timeline, null);
+  }, 'Animation.timeline returns null for inactive deferred timeline');
+</script>
+
+<template id=animation_timeline_overattached>
+  <div class="scope">
+    <div class=animating>Test</div>
+    <div class="scroller timeline">
+      <div class="content"></div>
+    </div>
+    <div class="scroller timeline">
+      <div class="content"></div>
+    </div>
+  </div>
+</template>
+<script>
+  promise_test(async (t) => {
+    inflate(t, animation_timeline_overattached);
+    let scroller = main.querySelector('.scroller');
+    let animating = main.querySelector('.animating');
+
+    assert_equals(animating.getAnimations()[0].timeline, null);
+  }, 'Animation.timeline returns null for inactive (overattached) deferred timeline');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup-expected.txt b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup-expected.txt
deleted file mode 100644
index 90b79f2..0000000
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-PASS view-timeline on self
-PASS view-timeline on preceding sibling
-PASS view-timeline on ancestor
-PASS view-timeline on ancestor sibling
-PASS view-timeline on ancestor sibling, conflict remains unresolved
-PASS view-timeline on ancestor sibling, closer timeline wins
-FAIL view-timeline on ancestor sibling, scroll-timeline wins on same element assert_equals: expected "0" but got "75"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https-expected.txt
index 60a94de..488fa40 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https-expected.txt
@@ -2,6 +2,6 @@
 PASS not negotiating BUNDLE creates two separate ice and dtls transports
 PASS bundles on the first transport and closes the second
 FAIL max-bundle with an offer without bundle only negotiates the first m-line promise_test: Unhandled rejection with value: object "InvalidAccessError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: max-bundle is used but no bundle group found."
-FAIL sRD(offer) works with no transport attributes in a bundle-only m-section promise_test: Unhandled rejection with value: object "InvalidAccessError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: rtcp-mux must be enabled when BUNDLE is enabled."
+PASS sRD(offer) works with no transport attributes in a bundle-only m-section
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html b/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html
index 3d2b835..73ea477 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/bundle.https.html
@@ -135,7 +135,7 @@
 a=mid:audio
 a=rtpmap:111 opus/48000/2
 a=setup:actpass
-m=video 9 UDP/TLS/RTP/SAVPF 100
+m=video 0 UDP/TLS/RTP/SAVPF 100
 c=IN IP4 0.0.0.0
 a=bundle-only
 a=sendonly
diff --git a/third_party/blink/web_tests/http/tests/devtools/overrides/can-edit-iframe-html.js b/third_party/blink/web_tests/http/tests/devtools/overrides/can-edit-iframe-html.js
index b40618c..f3ab5ea3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/overrides/can-edit-iframe-html.js
+++ b/third_party/blink/web_tests/http/tests/devtools/overrides/can-edit-iframe-html.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {BindingsTestRunner} from 'bindings_test_runner';
+
 (async function() {
   TestRunner.addResult(`Ensures iframes are overridable if overrides are setup.\n`);
-  await TestRunner.loadTestModule('bindings_test_runner');
   await TestRunner.loadLegacyModule('sources');
   await TestRunner.loadLegacyModule('sources');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/overrides/files-save-without-hash.js b/third_party/blink/web_tests/http/tests/devtools/overrides/files-save-without-hash.js
index 12d6edc..d667cc0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/overrides/files-save-without-hash.js
+++ b/third_party/blink/web_tests/http/tests/devtools/overrides/files-save-without-hash.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {BindingsTestRunner} from 'bindings_test_runner';
+
 (async function() {
   TestRunner.addResult(`Ensures iframes are overridable if overrides are setup.\n`);
-  await TestRunner.loadTestModule('bindings_test_runner');
   await TestRunner.loadLegacyModule('sources');
 
   var fileSystemPath = 'file:///tmp/';
diff --git a/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind-expected.txt b/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind-expected.txt
index cbd5468..0cc8165 100644
--- a/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind-expected.txt
@@ -1,6 +1,6 @@
 Ensures that when a project is added with already existing files they bind.
 
 Bound Files:
-http://127.0.0.1:8000/devtools/network/resources/empty.html <=> file:///tmp/127.0.0.1%3a8000/devtools/network/resources/empty.html
+http://127.0.0.1:8000/devtools/network/resources/empty.html <=> file:///tmp/127.0.0.1:8000/devtools/network/resources/empty.html
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind.js b/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind.js
index 43a1847..78a6457a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind.js
+++ b/third_party/blink/web_tests/http/tests/devtools/overrides/project-added-with-existing-files-bind.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {BindingsTestRunner} from 'bindings_test_runner';
+
 (async function() {
   TestRunner.addResult(`Ensures that when a project is added with already existing files they bind.\n`);
-  await TestRunner.loadTestModule('bindings_test_runner');
 
   await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/network/resources/empty.html');
 
@@ -17,7 +19,7 @@
   });
 
   const { testFileSystem } = await BindingsTestRunner.createOverrideProject('file:///tmp');
-  testFileSystem.addFile('127.0.0.1%3a8000/devtools/network/resources/empty.html', 'New Content');
+  testFileSystem.addFile('127.0.0.1:8000/devtools/network/resources/empty.html', 'New Content');
 
   BindingsTestRunner.setOverridesEnabled(true);
 })();
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-expected.txt b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-expected.txt
deleted file mode 100644
index 155f9a6..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-expected.txt
+++ /dev/null
@@ -1,108 +0,0 @@
-Tests the Timeline API instrumentation of a network resource load
-
-
-ResourceSendRequest Properties:
-{
-    data : {
-        frame : <string>
-        priority : "VeryHigh"
-        requestId : <string>
-        requestMethod : "GET"
-        url : .../devtools/tracing/resources/hello.html
-    }
-    endTime : <number>
-    frameId : <string>
-    startTime : <number>
-    type : "ResourceSendRequest"
-}
-Text details for ResourceSendRequest: hello.html
-
-ResourceReceiveResponse Properties:
-{
-    data : {
-        encodedDataLength : <number>
-        frame : <string>
-        fromCache : false
-        fromServiceWorker : false
-        mimeType : "text/html"
-        requestId : <string>
-        responseTime : <number>
-        statusCode : 200
-        timing : <object>
-    }
-    endTime : <number>
-    frameId : <string>
-    startTime : <number>
-    type : "ResourceReceiveResponse"
-}
-Text details for ResourceReceiveResponse: hello.html
-
-ResourceFinish Properties:
-{
-    data : {
-        decodedBodyLength : 20
-        didFail : false
-        encodedDataLength : <number>
-        finishTime : <number>
-        requestId : <string>
-    }
-    endTime : <number>
-    startTime : <number>
-    type : "ResourceFinish"
-}
-Text details for ResourceFinish: hello.html
-
-ResourceSendRequest Properties:
-{
-    data : {
-        frame : <string>
-        priority : "Low"
-        renderBlocking : "non_blocking"
-        requestId : <string>
-        requestMethod : "GET"
-        stackTrace : <object>
-        url : .../devtools/tracing/resources/timeline-network-resource.js
-    }
-    endTime : <number>
-    frameId : <string>
-    stackTrace : <object>
-    startTime : <number>
-    type : "ResourceSendRequest"
-}
-Text details for ResourceSendRequest: timeline-network-resource.js
-
-ResourceReceiveResponse Properties:
-{
-    data : {
-        encodedDataLength : <number>
-        frame : <string>
-        fromCache : false
-        fromServiceWorker : false
-        mimeType : "application/x-javascript"
-        requestId : <string>
-        responseTime : <number>
-        statusCode : 200
-        timing : <object>
-    }
-    endTime : <number>
-    frameId : <string>
-    startTime : <number>
-    type : "ResourceReceiveResponse"
-}
-Text details for ResourceReceiveResponse: timeline-network-resource.js
-
-ResourceFinish Properties:
-{
-    data : {
-        decodedBodyLength : 223
-        didFail : false
-        encodedDataLength : <number>
-        finishTime : <number>
-        requestId : <string>
-    }
-    endTime : <number>
-    startTime : <number>
-    type : "ResourceFinish"
-}
-Text details for ResourceFinish: timeline-network-resource.js
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.js b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.js
deleted file mode 100644
index ac83908d..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.js
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Tests the Timeline API instrumentation of a network resource load\n`);
-  await TestRunner.loadLegacyModule('timeline'); await TestRunner.loadTestModule('performance_test_runner');
-  await TestRunner.showPanel('timeline');
-  await TestRunner.NetworkAgent.setCacheDisabled(true);
-
-  await PerformanceTestRunner.startTimeline();
-  await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/tracing/resources/hello.html');
-  await TestRunner.evaluateInPagePromise(`
-      var scriptUrl = "timeline-network-resource.js";
-
-      function performActions()
-      {
-          var promise = new Promise((fulfill) => window.timelineNetworkResourceEvaluated = fulfill);
-          var script = document.createElement("script");
-          script.src = scriptUrl;
-          document.body.appendChild(script);
-          return promise;
-      }
-  `);
-
-  var requestId;
-  var scriptUrl = 'timeline-network-resource.js';
-
-  await TestRunner.callFunctionInPageAsync('performActions');
-  await PerformanceTestRunner.stopTimeline();
-
-  const sendRequests = PerformanceTestRunner.mainTrackEvents().
-      filter(e => e.name === TimelineModel.TimelineModel.RecordType.ResourceSendRequest);
-  for (let event of sendRequests) {
-    await printEvent(event);
-    await printEventsWithId(event.args['data'].requestId);
-  }
-  TestRunner.completeTest();
-
-  async function printEventsWithId(id) {
-    var model = PerformanceTestRunner.timelineModel();
-    for (const event of PerformanceTestRunner.mainTrackEvents()) {
-      if (event.name !== TimelineModel.TimelineModel.RecordType.ResourceReceiveResponse &&
-          event.name !== TimelineModel.TimelineModel.RecordType.ResourceFinish) {
-        continue;
-      }
-      if (event.args['data'].requestId !== id)
-        continue;
-      await printEvent(event);
-    }
-  }
-
-  async function printEvent(event) {
-    TestRunner.addResult('');
-    PerformanceTestRunner.printTraceEventProperties(event);
-    TestRunner.addResult(
-        `Text details for ${event.name}: ` + await Timeline.TimelineUIUtils.buildDetailsTextForTraceEvent(event));
-  }
-})();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/css/selector-specificity-information-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/css/selector-specificity-information-expected.txt
new file mode 100644
index 0000000..2ee235d
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/css/selector-specificity-information-expected.txt
@@ -0,0 +1,5 @@
+Test that specificity information is passed to DevTools.
+body: 0,0,1
+.class: 0,1,0
+#id: 1,0,0
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/css/selector-specificity-information.js b/third_party/blink/web_tests/http/tests/inspector-protocol/css/selector-specificity-information.js
new file mode 100644
index 0000000..a38dae22
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/css/selector-specificity-information.js
@@ -0,0 +1,44 @@
+(async function(testRunner) {
+  const {dp} = await testRunner.startHTML(`
+    <style>
+      body {
+        color: red;
+      }
+      .class {
+        color: red;
+      }
+      #id {
+        color: red;
+      }
+    </style>
+    <body>
+      <span class="class"></span>
+      <span id="id"></span>
+    </body>
+  `, 'Test that specificity information is passed to DevTools.');
+
+  await dp.DOM.enable();
+  await dp.CSS.enable();
+
+  async function requestDocumentNodeId() {
+    const {result} = await dp.DOM.getDocument({});
+    return result.root.nodeId;
+  }
+  async function requestNodeId(nodeId, selector) {
+    const {result} = await dp.DOM.querySelector({nodeId, selector});
+    return result.nodeId;
+  }
+
+  const documentNodeId = await requestDocumentNodeId();
+
+  for (const selector of ['body', '.class', '#id']) {
+    const nodeId = await requestNodeId(documentNodeId, selector);
+    const { result: matchedStylesForNode } = await dp.CSS.getMatchedStylesForNode({ nodeId });
+
+    const specificity = matchedStylesForNode.matchedCSSRules[0].rule.selectorList.selectors[0].specificity;
+    testRunner.log(`${selector}: ${specificity.a},${specificity.b},${specificity.c}`);
+  }
+
+  testRunner.completeTest();
+});
+
diff --git a/third_party/blink/web_tests/printing/numberOfPages-expected.txt b/third_party/blink/web_tests/printing/numberOfPages-expected.txt
index b821e78..95cd5dc 100644
--- a/third_party/blink/web_tests/printing/numberOfPages-expected.txt
+++ b/third_party/blink/web_tests/printing/numberOfPages-expected.txt
@@ -4,7 +4,7 @@
 
 
 PASS: number of pages is 2
-PASS: number of pages is 1
+PASS: number of pages is 2
 All tests passed
 
 PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/printing/resources/paged-media-test-utils.js b/third_party/blink/web_tests/printing/resources/paged-media-test-utils.js
index 73745af7..9ae76a9 100644
--- a/third_party/blink/web_tests/printing/resources/paged-media-test-utils.js
+++ b/third_party/blink/web_tests/printing/resources/paged-media-test-utils.js
@@ -60,17 +60,11 @@
     output.appendChild(resultElement);
 }
 
-function ratioToPageHeightToPixels(heightInRatioToPageHeight)
-{
-  var pageHeightInPixels = 600 * 1.333;
-  return Math.floor(pageHeightInPixels * heightInRatioToPageHeight);
-}
-
 function createBlockWithRatioToPageHeight(id, heightInRatioToPageHeight)
 {
     var element = document.createElement("div");
     element.id = id;
-    element.style.height = ratioToPageHeightToPixels(heightInRatioToPageHeight) + "px";
+    element.style.height = (heightInRatioToPageHeight * 100) + "vh";
     document.getElementById("sandbox").appendChild(element);
     return element;
 }
@@ -84,7 +78,7 @@
         element.appendChild(document.createElement("br"));
     }
     // Make sure that one page has about 20 lines.
-    element.style.lineHeight = ratioToPageHeightToPixels(0.05) + "px";
+    element.style.lineHeight = "5vh";
     document.getElementById("sandbox").appendChild(element);
     return element;
 }
diff --git a/third_party/blink/web_tests/printing/script-tests/numberOfPages.js b/third_party/blink/web_tests/printing/script-tests/numberOfPages.js
index 55efa87d..69ca749 100644
--- a/third_party/blink/web_tests/printing/script-tests/numberOfPages.js
+++ b/third_party/blink/web_tests/printing/script-tests/numberOfPages.js
@@ -6,7 +6,7 @@
     createBlockWithRatioToPageHeight("secondPage", 0.6);
 
     numberOfPagesShouldBe(2);
-    numberOfPagesShouldBe(1, 1000, 10000);
+    numberOfPagesShouldBe(2, 1000, 10000);
 
     document.body.removeChild(document.getElementById("sandbox"));
 }
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
index 4c3f690..75daf80 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
@@ -375,7 +375,6 @@
 scrollSnapStop
 scrollSnapType
 scrollTimeline
-scrollTimelineAttachment
 scrollTimelineAxis
 scrollTimelineName
 scrollbarGutter
@@ -447,7 +446,6 @@
 vectorEffect
 verticalAlign
 viewTimeline
-viewTimelineAttachment
 viewTimelineAxis
 viewTimelineInset
 viewTimelineName
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
index 54e2e2e..87ee971 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
@@ -329,7 +329,6 @@
     scroll-snap-align
     scroll-snap-stop
     scroll-snap-type
-    scroll-timeline-attachment
     scroll-timeline-axis
     scroll-timeline-name
     scrollbar-gutter
@@ -388,7 +387,6 @@
     user-select
     vector-effect
     vertical-align
-    view-timeline-attachment
     view-timeline-axis
     view-timeline-inset
     view-timeline-name
@@ -751,7 +749,6 @@
         scroll-padding-inline-end
         scroll-padding-inline-start
     scroll-timeline
-        scroll-timeline-attachment
         scroll-timeline-axis
         scroll-timeline-name
     text-decoration
@@ -768,7 +765,6 @@
         transition-property
         transition-timing-function
     view-timeline
-        view-timeline-attachment
         view-timeline-axis
         view-timeline-name
     white-space
diff --git a/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt b/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
index 06724605..fd1429b 100644
--- a/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
+++ b/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
@@ -42,6 +42,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html
                             }
                         ]
@@ -78,6 +83,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 0
+                                }
                                 text : :root
                             }
                         ]
@@ -119,6 +129,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition
                                     }
                                 ]
@@ -180,6 +195,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -224,6 +244,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -264,6 +289,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-group(root)
                                     }
                                 ]
@@ -310,6 +340,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -354,6 +389,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -394,6 +434,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-group(shared)
                                     }
                                 ]
@@ -442,6 +487,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-group(shared)
                                     }
                                 ]
@@ -500,6 +550,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-image-pair()
                                     }
                                 ]
@@ -556,6 +611,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair()
                                     }
                                 ]
@@ -596,6 +656,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair(root)
                                     }
                                 ]
@@ -638,6 +703,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-image-pair()
                                     }
                                 ]
@@ -694,6 +764,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair()
                                     }
                                 ]
@@ -734,6 +809,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair(shared)
                                     }
                                 ]
@@ -776,9 +856,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -827,6 +917,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-old()
                                     }
                                 ]
@@ -871,6 +966,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-old(root)
                                     }
                                 ]
@@ -913,6 +1013,11 @@
                                             startColumn : 1
                                             startLine : 0
                                         }
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old(*)
                                     }
                                 ]
@@ -1059,9 +1164,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -1110,6 +1225,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-old()
                                     }
                                 ]
@@ -1154,6 +1274,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-old(shared)
                                     }
                                 ]
@@ -1196,6 +1321,11 @@
                                             startColumn : 1
                                             startLine : 0
                                         }
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old(*)
                                     }
                                 ]
@@ -1342,9 +1472,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -1393,6 +1533,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-new()
                                     }
                                 ]
@@ -1437,6 +1582,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-new(root)
                                     }
                                 ]
@@ -1479,9 +1629,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -1530,6 +1690,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-new()
                                     }
                                 ]
@@ -1574,6 +1739,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-new(shared)
                                     }
                                 ]
@@ -1616,6 +1786,11 @@
                                             startColumn : 1
                                             startLine : 0
                                         }
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 0
+                                        }
                                         text : ::view-transition-new(shared)
                                     }
                                 ]
@@ -1688,6 +1863,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition
                             }
                         ]
@@ -1754,6 +1934,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -1798,6 +1983,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -1838,6 +2028,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-group(root)
                             }
                         ]
@@ -1888,6 +2083,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-image-pair()
                             }
                         ]
@@ -1944,6 +2144,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair()
                             }
                         ]
@@ -1984,6 +2189,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair(root)
                             }
                         ]
@@ -2030,9 +2240,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -2081,6 +2301,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-old()
                             }
                         ]
@@ -2125,6 +2350,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-old(root)
                             }
                         ]
@@ -2167,6 +2397,11 @@
                                     startColumn : 1
                                     startLine : 0
                                 }
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old(*)
                             }
                         ]
@@ -2317,9 +2552,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -2368,6 +2613,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-new()
                             }
                         ]
@@ -2412,6 +2662,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-new(root)
                             }
                         ]
@@ -2458,6 +2713,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -2502,6 +2762,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -2542,6 +2807,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-group(shared)
                             }
                         ]
@@ -2590,6 +2860,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-group(shared)
                             }
                         ]
@@ -2652,6 +2927,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-image-pair()
                             }
                         ]
@@ -2708,6 +2988,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair()
                             }
                         ]
@@ -2748,6 +3033,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair(shared)
                             }
                         ]
@@ -2794,9 +3084,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -2845,6 +3145,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-old()
                             }
                         ]
@@ -2889,6 +3194,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-old(shared)
                             }
                         ]
@@ -2931,6 +3241,11 @@
                                     startColumn : 1
                                     startLine : 0
                                 }
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old(*)
                             }
                         ]
@@ -3081,9 +3396,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -3132,6 +3457,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-new()
                             }
                         ]
@@ -3176,6 +3506,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-new(shared)
                             }
                         ]
@@ -3218,6 +3553,11 @@
                                     startColumn : 1
                                     startLine : 0
                                 }
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 0
+                                }
                                 text : ::view-transition-new(shared)
                             }
                         ]
diff --git a/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt b/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
index 06724605..fd1429b 100644
--- a/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
+++ b/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
@@ -42,6 +42,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html
                             }
                         ]
@@ -78,6 +83,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 0
+                                }
                                 text : :root
                             }
                         ]
@@ -119,6 +129,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition
                                     }
                                 ]
@@ -180,6 +195,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -224,6 +244,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -264,6 +289,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-group(root)
                                     }
                                 ]
@@ -310,6 +340,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -354,6 +389,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-group()
                                     }
                                 ]
@@ -394,6 +434,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-group(shared)
                                     }
                                 ]
@@ -442,6 +487,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-group(shared)
                                     }
                                 ]
@@ -500,6 +550,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-image-pair()
                                     }
                                 ]
@@ -556,6 +611,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair()
                                     }
                                 ]
@@ -596,6 +656,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair(root)
                                     }
                                 ]
@@ -638,6 +703,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-image-pair()
                                     }
                                 ]
@@ -694,6 +764,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair()
                                     }
                                 ]
@@ -734,6 +809,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-image-pair(shared)
                                     }
                                 ]
@@ -776,9 +856,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -827,6 +917,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-old()
                                     }
                                 ]
@@ -871,6 +966,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-old(root)
                                     }
                                 ]
@@ -913,6 +1013,11 @@
                                             startColumn : 1
                                             startLine : 0
                                         }
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old(*)
                                     }
                                 ]
@@ -1059,9 +1164,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -1110,6 +1225,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-old()
                                     }
                                 ]
@@ -1154,6 +1274,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-old(shared)
                                     }
                                 ]
@@ -1196,6 +1321,11 @@
                                             startColumn : 1
                                             startLine : 0
                                         }
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old(*)
                                     }
                                 ]
@@ -1342,9 +1472,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -1393,6 +1533,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-new()
                                     }
                                 ]
@@ -1437,6 +1582,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-new(root)
                                     }
                                 ]
@@ -1479,9 +1629,19 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-new()
                                     }
                                     [1] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 0
+                                        }
                                         text : ::view-transition-old()
                                     }
                                 ]
@@ -1530,6 +1690,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 0
+                                            c : 1
+                                        }
                                         text : html::view-transition-new()
                                     }
                                 ]
@@ -1574,6 +1739,11 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 1
+                                        }
                                         text : html::view-transition-new(shared)
                                     }
                                 ]
@@ -1616,6 +1786,11 @@
                                             startColumn : 1
                                             startLine : 0
                                         }
+                                        specificity : {
+                                            a : 0
+                                            b : 1
+                                            c : 0
+                                        }
                                         text : ::view-transition-new(shared)
                                     }
                                 ]
@@ -1688,6 +1863,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition
                             }
                         ]
@@ -1754,6 +1934,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -1798,6 +1983,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -1838,6 +2028,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-group(root)
                             }
                         ]
@@ -1888,6 +2083,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-image-pair()
                             }
                         ]
@@ -1944,6 +2144,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair()
                             }
                         ]
@@ -1984,6 +2189,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair(root)
                             }
                         ]
@@ -2030,9 +2240,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -2081,6 +2301,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-old()
                             }
                         ]
@@ -2125,6 +2350,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-old(root)
                             }
                         ]
@@ -2167,6 +2397,11 @@
                                     startColumn : 1
                                     startLine : 0
                                 }
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old(*)
                             }
                         ]
@@ -2317,9 +2552,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -2368,6 +2613,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-new()
                             }
                         ]
@@ -2412,6 +2662,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-new(root)
                             }
                         ]
@@ -2458,6 +2713,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -2502,6 +2762,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-group()
                             }
                         ]
@@ -2542,6 +2807,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-group(shared)
                             }
                         ]
@@ -2590,6 +2860,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-group(shared)
                             }
                         ]
@@ -2652,6 +2927,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-image-pair()
                             }
                         ]
@@ -2708,6 +2988,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair()
                             }
                         ]
@@ -2748,6 +3033,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-image-pair(shared)
                             }
                         ]
@@ -2794,9 +3084,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -2845,6 +3145,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-old()
                             }
                         ]
@@ -2889,6 +3194,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-old(shared)
                             }
                         ]
@@ -2931,6 +3241,11 @@
                                     startColumn : 1
                                     startLine : 0
                                 }
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old(*)
                             }
                         ]
@@ -3081,9 +3396,19 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-new()
                             }
                             [1] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 0
+                                }
                                 text : ::view-transition-old()
                             }
                         ]
@@ -3132,6 +3457,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 0
+                                    c : 1
+                                }
                                 text : html::view-transition-new()
                             }
                         ]
@@ -3176,6 +3506,11 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 1
+                                }
                                 text : html::view-transition-new(shared)
                             }
                         ]
@@ -3218,6 +3553,11 @@
                                     startColumn : 1
                                     startLine : 0
                                 }
+                                specificity : {
+                                    a : 0
+                                    b : 1
+                                    c : 0
+                                }
                                 text : ::view-transition-new(shared)
                             }
                         ]
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-basic.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-basic.html
similarity index 87%
rename from third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-basic.html
rename to third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-basic.html
index 7bb9ddf..828f7b0 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-basic.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-basic.html
@@ -12,7 +12,7 @@
     color: green;
     background-color: white;
   }
-  @initial {
+  @starting-style {
     #target {
       background-color: black;
     }
@@ -27,7 +27,7 @@
     assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)",
                   "No transition of color");
     assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from @initial value black to white");
+                  "Background transition from @starting-style value black to white");
   }, "Triggered transition from first style update");
 
   promise_test(async t => {
@@ -42,7 +42,7 @@
     target.style.display = "block";
     await waitForAnimationFrames(2);
     assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from @initial value black to white");
+                  "Background transition from @starting-style value black to white");
   }, "Triggered transition from display:none to display:block");
 
   promise_test(async t => {
@@ -52,6 +52,6 @@
     document.body.appendChild(removed);
     await waitForAnimationFrames(2);
     assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from @initial value black to white");
+                  "Background transition from @starting-style value black to white");
   }, "Triggered transition on DOM insertion");
 </script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-none.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-none.html
similarity index 81%
rename from third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-none.html
rename to third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-none.html
index 8c7d650..c1d56e5eb 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-none.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-none.html
@@ -11,7 +11,7 @@
     transition-timing-function: steps(2, start);
     background-color: green;
   }
-  @initial {
+  @starting-style {
     #target {
       display: none;
       background-color: red;
@@ -22,6 +22,6 @@
   promise_test(async t => {
     await waitForAnimationFrames(2);
     assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 128, 0)",
-                  "No transition of background-color when @initial display is 'none'");
-  }, "@initial with display:none");
+                  "No transition of background-color when @starting-style display is 'none'");
+  }, "@starting-style with display:none");
 </script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-pseudo-elements.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-pseudo-elements.html
similarity index 88%
rename from third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-pseudo-elements.html
rename to third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-pseudo-elements.html
index af50a05d..9816155 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-rule-pseudo-elements.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-transitions/starting-style-rule-pseudo-elements.html
@@ -13,7 +13,7 @@
     background-color: white;
     content: "";
   }
-  @initial {
+  @starting-style {
     #target::before {
       background-color: black;
     }
@@ -28,7 +28,7 @@
     assert_equals(getComputedStyle(target, "::before").color, "rgb(0, 128, 0)",
                   "No transition of color");
     assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from @initial value black to white");
+                  "Background transition from @starting-style value black to white");
   }, "Triggered transition from first style update");
 
   promise_test(async t => {
@@ -43,7 +43,7 @@
     target.style.display = "block";
     await waitForAnimationFrames(2);
     assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from @initial value black to white");
+                  "Background transition from @starting-style value black to white");
   }, "Triggered transition from display:none to display:block");
 
   promise_test(async t => {
@@ -53,6 +53,6 @@
     document.body.appendChild(removed);
     await waitForAnimationFrames(2);
     assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from @initial value black to white");
+                  "Background transition from @starting-style value black to white");
   }, "Triggered transition on DOM insertion");
 </script>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a58e309c..f4eff444 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -26225,6 +26225,13 @@
   <int value="2" label="Error - Video Capturer Service crashed"/>
 </enum>
 
+<enum name="DeviceIdentifierStatus">
+  <int value="0" label="all device identifiers are present"/>
+  <int value="1" label="serial number is missing"/>
+  <int value="2" label="rlz_brand_code is missing"/>
+  <int value="3" label="all device identifiers are missing"/>
+</enum>
+
 <enum name="DeviceIdMismatch">
   <int value="0" label="BOTH_NONEMPTY"/>
   <int value="1" label="SYNC_EMPTY"/>
@@ -27392,6 +27399,19 @@
   <int value="10" label="Selector from context menu"/>
 </enum>
 
+<enum name="DevToolsSwatchActivated">
+  <int value="0" label="Variable link"/>
+  <int value="1" label="Animation name link"/>
+  <int value="2" label="Color"/>
+  <int value="3" label="Animation timing"/>
+  <int value="4" label="Shadow"/>
+  <int value="5" label="Grid editor"/>
+  <int value="6" label="Flex editor"/>
+  <int value="7" label="Angle"/>
+  <int value="8" label="Length"/>
+  <int value="9" label="Position fallback link"/>
+</enum>
+
 <enum name="DevToolsSyncSetting">
   <int value="1" label="Chrome Sync disabled"/>
   <int value="2" label="Chrome Sync 'Settings' ModelType disabled"/>
@@ -42453,7 +42473,7 @@
   <int value="4483" label="ExecutedEmptyJavaScriptURLFromFrame"/>
   <int value="4484" label="ExecutedJavaScriptURLFromFrame"/>
   <int value="4485" label="ServiceWorkerBypassFetchHandlerForSubResource"/>
-  <int value="4486" label="CSSAtRuleInitial"/>
+  <int value="4486" label="CSSAtRuleStartingStyle"/>
   <int value="4487" label="PrivateAggregationApiFledgeExtensions"/>
   <int value="4488" label="DeprecatedInterestGroupDailyUpdateUrl"/>
   <int value="4489" label="CSSColorGradientColorSpace"/>
@@ -55900,7 +55920,7 @@
 <enum name="KidsExternalFetcherStatus">
   <int value="0" label="NoError"/>
   <int value="1" label="AuthError"/>
-  <int value="2" label="HttpError"/>
+  <int value="2" label="HttpStatusOrNetError"/>
   <int value="3" label="ParseError"/>
   <int value="4" label="DataError"/>
 </enum>
@@ -79021,6 +79041,12 @@
   <int value="26" label="StoredPolicyFail">Failed to store policies.</int>
 </enum>
 
+<enum name="OwnershipStatus">
+  <int value="0" label="ownership unknown"/>
+  <int value="1" label="not yet owned"/>
+  <int value="2" label="ownership taken"/>
+</enum>
+
 <enum name="P2PLookupResult">
   <int value="0" label="Found"/>
   <int value="1" label="Not Found"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index c897b3c7..e055aa4 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -964,6 +964,26 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.ExtraDiskSpaceOccupied"
+    units="MB" expires_after="M121">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The size of disk space occupied by files/dirs created during the migration.
+  </summary>
+</histogram>
+
+<histogram
+    name="Ash.BrowserDataMigrator.MoveMigrator.ExtraDiskSpaceOccupied.DiffWithEstimate"
+    units="MB" expires_after="M121">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The difference between the estimate and the actual size of disk space
+    occupied by files/dirs created during the migration.
+  </summary>
+</histogram>
+
 <histogram name="Ash.BrowserDataMigrator.MoveMigrator.ExtraSpaceRequiredMB"
     units="MB" expires_after="M121">
   <owner>ythjkt@chromium.org</owner>
@@ -1089,6 +1109,24 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.TmpProfileDirSize"
+    units="MB" expires_after="M121">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The size of temporary profile directory created during the migration.
+  </summary>
+</histogram>
+
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.TmpSplitDirSize"
+    units="MB" expires_after="M121">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The size of temporary split directory created during the migration.
+  </summary>
+</histogram>
+
 <histogram name="Ash.BrowserDataMigrator.NoCopyDataSizeMB" units="MB"
     expires_after="M121">
   <owner>ythjkt@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/dev/histograms.xml b/tools/metrics/histograms/metadata/dev/histograms.xml
index 4026ce6..bbc1b9b 100644
--- a/tools/metrics/histograms/metadata/dev/histograms.xml
+++ b/tools/metrics/histograms/metadata/dev/histograms.xml
@@ -490,6 +490,14 @@
   <summary>Recorded when certain style text is copied in DevTools.</summary>
 </histogram>
 
+<histogram name="DevTools.SwatchActivated" enum="DevToolsSwatchActivated"
+    expires_after="2023-12-01">
+  <owner>ergunsh@chromium.org</owner>
+  <owner>changhaohan@chromium.org</owner>
+  <owner>bmeurer@chromium.org</owner>
+  <summary>Records the swatch usages in the Styles pane.</summary>
+</histogram>
+
 <histogram name="DevTools.SyncSetting" enum="DevToolsSyncSetting"
     expires_after="2023-12-01">
   <owner>bmeurer@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml
index 478d461..858cb3d 100644
--- a/tools/metrics/histograms/metadata/enterprise/histograms.xml
+++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -22,6 +22,14 @@
 
 <histograms>
 
+<variants name="AutoEnrollmentStates">
+  <variant name="ConnectionError" summary="connection error"/>
+  <variant name="Disabled" summary="disabled"/>
+  <variant name="Enrollment" summary="enrollment"/>
+  <variant name="NoEnrollment" summary="no enrollment"/>
+  <variant name="ServerError" summary="server error"/>
+</variants>
+
 <variants name="CleanupHandler">
   <variant name="Browser"
       summary="Handler for open browser windows and browsing data"/>
@@ -99,6 +107,21 @@
   <variant name="Recommended" summary="Recommended Policy"/>
 </variants>
 
+<variants name="StateDeterminationDmRequestTypes">
+  <variant name="PsmRlweOprf" summary="PSM RLWE OPRF"/>
+  <variant name="PsmRlweQuery" summary="PSM RLWE Query"/>
+  <variant name="State" summary="state"/>
+</variants>
+
+<variants name="StateDeterminationSteps">
+  <variant name="OPRFRequest" summary="PSM OPRF request"/>
+  <variant name="OwnershipCheck" summary="ownership check"/>
+  <variant name="QueryRequest" summary="PSM Query request"/>
+  <variant name="StateKeyRetrieval" summary="state key retrieval"/>
+  <variant name="StateRequest" summary="state request"/>
+  <variant name="SystemClockSync" summary="system clock sync"/>
+</variants>
+
 <variants name="WmiSystemSignal">
   <variant name="AntiVirus" summary="AntiVirus info"/>
   <variant name="Hotfixes" summary="Hotfix info"/>
@@ -2501,6 +2524,157 @@
   </summary>
 </histogram>
 
+<histogram name="Enterprise.StateDetermination.DeviceIdentifierStatus"
+    enum="DeviceIdentifierStatus" expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Captures state of device identifiers during state determination.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.EmbargoDatePassed"
+    enum="Boolean" expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Tracks whether embargo date has passed during state determination.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.Enabled" enum="Boolean"
+    expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>Captures situations when state determination is enabled.</summary>
+</histogram>
+
+<histogram
+    name="Enterprise.StateDetermination.KillSwitchFetch.NetworkErrorCode"
+    enum="NetErrorCodes" expires_after="2024-05-10">
+  <owner>sergiyb@chromium.org</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Network error code for unified state determination kill switch config
+    requests.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.KillSwitchFetch.NumTries"
+    enum="NetErrorCodes" expires_after="2024-05-10">
+  <owner>sergiyb@chromium.org</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Number of tries for fetching unified state determination kill switch config.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.OnFlex" enum="Boolean"
+    expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Captures situations when state determination takes place on Flex devices.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.OwnershipStatus"
+    enum="OwnershipStatus" expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Captures ownership state of device during state determination.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.PsmReportedAvailableState"
+    enum="Boolean" expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Tracks whether PSM has reported that state is available during state
+    determination.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.StateKeysRetrieved"
+    enum="Boolean" expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Tracks whether state keys were retrieved during state determination.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.StateReturned" enum="Boolean"
+    expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Tracks whether state request returned state during state determination.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.StepDuration.{Step}" units="ms"
+    expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Tracks the duration of the {Step} as part of state determination.
+  </summary>
+  <token key="Step" variants="StateDeterminationSteps"/>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.SystemClockSynchronized"
+    enum="Boolean" expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Tracks whether system clock was synchronized during state determination.
+  </summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.TotalDuration" units="ms"
+    expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>Tracks the total duration of state determination.</summary>
+</histogram>
+
+<histogram name="Enterprise.StateDetermination.TotalDurationByState.{State}"
+    units="ms" expires_after="2024-05-10">
+  <owner>sergiyb@google.com</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Tracks the total duration of state determination when it results in {State}
+    state.
+  </summary>
+  <token key="State" variants="AutoEnrollmentStates"/>
+</histogram>
+
+<histogram
+    name="Enterprise.StateDetermination.{RequestType}Request.DmStatusCode"
+    enum="EnterpriseDeviceManagementStatus" expires_after="2024-05-10">
+  <owner>sergiyb@chromium.org</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Device management server request status for {RequestType} requests to Device
+    Management server.
+  </summary>
+  <token key="RequestType" variants="StateDeterminationDmRequestTypes"/>
+</histogram>
+
+<histogram
+    name="Enterprise.StateDetermination.{RequestType}Request.NetworkErrorCode"
+    enum="NetErrorCodes" expires_after="2024-05-10">
+  <owner>sergiyb@chromium.org</owner>
+  <owner>chromeos-commercial-remote-management@google.com</owner>
+  <summary>
+    Network error code for {RequestType} requests to Device Management server.
+  </summary>
+  <token key="RequestType" variants="StateDeterminationDmRequestTypes"/>
+</histogram>
+
 <histogram name="Enterprise.SystemFeaturesDisableList" enum="SystemFeature"
     expires_after="2023-06-01">
   <owner>ayaelattar@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index edbf12e2..59c33ec 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -14267,6 +14267,16 @@
   </summary>
 </histogram>
 
+<histogram name="WebDatabase.SucceededMigrationToVersion" units="version"
+    expires_after="2023-12-01">
+  <owner>battre@chromium.org</owner>
+  <owner>fleimgruber@google.com</owner>
+  <summary>
+    If a migration to a new WebDatabase schema succeeds, this histogram records
+    the target version to which the migration failed.
+  </summary>
+</histogram>
+
 <histogram name="WebFont.BlankTextShownTime" units="ms"
     expires_after="2023-10-01">
   <owner>kenjibaheux@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 720d41a23f..af52280 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -832,14 +832,7 @@
   </summary>
 </histogram>
 
-<histogram name="Signin.ListFamilyMembersRequest.Latency" units="ms"
-    expires_after="2023-11-01">
-  <owner>tju@google.com</owner>
-  <owner>chrome-kids-eng@google.com</owner>
-  <summary>Tracks the latency of calls to the Kids Management API.</summary>
-</histogram>
-
-<histogram name="Signin.ListFamilyMembersRequest.NetOrHttpStatus"
+<histogram name="Signin.ListFamilyMembersRequest.HttpStatusOrNetError"
     enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-11-01">
   <owner>tju@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
@@ -850,6 +843,13 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.ListFamilyMembersRequest.Latency" units="ms"
+    expires_after="2023-11-01">
+  <owner>tju@google.com</owner>
+  <owner>chrome-kids-eng@google.com</owner>
+  <summary>Tracks the latency of calls to the Kids Management API.</summary>
+</histogram>
+
 <histogram name="Signin.ListFamilyMembersRequest.Status"
     enum="KidsExternalFetcherStatus" expires_after="2023-11-01">
   <owner>tju@google.com</owner>
@@ -870,7 +870,8 @@
     <variant name="DataError"
         summary="contract error (data in the response missing despite
                  succesful parsing)"/>
-    <variant name="HttpError" summary="transport error"/>
+    <variant name="HttpStatusOrNetError"
+        summary="transport error or HTTP status"/>
     <variant name="NoError" summary="no error recorded"/>
     <variant name="ParseError" summary="parsing error"/>
   </token>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index bb9451a3..f435d4c 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -383,7 +383,7 @@
  <item id="password_sync_token_fetcher" added_in_milestone="110" content_hash_code="0268c983" os_list="chromeos" file_path="chrome/browser/ash/login/saml/password_sync_token_fetcher.cc" />
  <item id="projector_xhr_loader" added_in_milestone="110" content_hash_code="07e102c2" os_list="chromeos" file_path="ash/webui/projector_app/projector_xhr_sender.cc" />
  <item id="cloud_speech_recognition" added_in_milestone="110" content_hash_code="00d56fd8" os_list="linux,windows,chromeos" file_path="components/live_caption/live_translate_controller.cc" />
- <item id="bruschetta_installer_download" added_in_milestone="110" content_hash_code="073f0263" os_list="chromeos" file_path="chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc" />
+ <item id="bruschetta_installer_download" added_in_milestone="110" content_hash_code="073f0263" os_list="chromeos" file_path="chrome/browser/ash/bruschetta/bruschetta_download.cc" />
  <item id="quick_start_session_auth_requester" added_in_milestone="110" content_hash_code="08353e70" os_list="chromeos" file_path="chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc" />
  <item id="network_diagnostics_routines" added_in_milestone="110" content_hash_code="0007b237" os_list="chromeos" file_path="chrome/browser/ash/net/network_diagnostics/http_request_manager.cc" />
  <item id="trial_group_lookup" added_in_milestone="110" content_hash_code="047aeeca" os_list="chromeos" file_path="chromeos/ash/components/trial_group/trial_group_checker.cc" />
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index 2991fb9..660f419f 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -1740,6 +1740,9 @@
   <message name="IDS_FILE_BROWSER_DLP_COMPONENT_VM" desc="PluginVM component label.">
     virtual machine
   </message>
+  <message name="IDS_FILE_BROWSER_DLP_COMPONENT_MICROSOFT_ONEDRIVE" desc="Microsoft OneDrive component label.">
+    Microsoft OneDrive
+  </message>
   <message name="IDS_FILE_BROWSER_ONE_DRIVE_MOVED_FILE_NUDGE" desc="Educational text that appears in the navigation tree when a file is automatically moved to OneDrive by the Office Cloud Upload feature/dialog.">
     Recently opened Microsoft files have moved to OneDrive
   </message>
@@ -1779,6 +1782,9 @@
   <message name="IDS_FILE_BROWSER_BULK_PINNING_TURN_ON" desc="Text in the Continue button of the dialog offering the Google Drive bulk pinning feature">
     Turn on
   </message>
+  <message name="IDS_FILE_BROWSER_BULK_PINNING_PREPARING_TO_SYNC" desc="Text in the progress panel indicating the bulk pinning operations is preparing files to sync">
+    Preparing to sync Drive files...
+  </message>
   <!-- TODO(b/276126188): Remove the translateable="false" when the copy has been landed on. -->
   <message name="IDS_FILE_BROWSER_BULK_PINNING_OFFLINE_LABEL" translateable="false" desc="The text used when the device is in an offline mode and has paused syncing.">
     You are currently offline. Sync will resume when the connection is back on.
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_PREPARING_TO_SYNC.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_PREPARING_TO_SYNC.png.sha1
new file mode 100644
index 0000000..abf2ccf
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_PREPARING_TO_SYNC.png.sha1
@@ -0,0 +1 @@
+8798e73adf8e8a5e820f29aad31803959137b565
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_DLP_COMPONENT_MICROSOFT_ONEDRIVE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_DLP_COMPONENT_MICROSOFT_ONEDRIVE.png.sha1
new file mode 100644
index 0000000..b621f16
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_DLP_COMPONENT_MICROSOFT_ONEDRIVE.png.sha1
@@ -0,0 +1 @@
+c76e33e8ec69f5b2fa9849be0fa567a6d4ed783a
\ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index 2f3cc4d..3ab15d8 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -825,7 +825,9 @@
     checkmark.className = 'detail-checkmark';
     detailIcon.appendChild(checkmark);
     bottom.appendChild(detailIcon);
-    bottom.appendChild(filelist.renderIconBadge(li.ownerDocument));
+    if (util.isDriveShortcutsEnabled()) {
+      bottom.appendChild(filelist.renderIconBadge(li.ownerDocument));
+    }
     bottom.appendChild(
         filelist.renderFileNameLabel(li.ownerDocument, entry, locationInfo));
     frame.appendChild(bottom);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index 7eede5955..cb36ae4 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -823,8 +823,9 @@
     }
     icon.appendChild(this.renderCheckmark_());
     label.appendChild(icon);
-    label.appendChild(filelist.renderIconBadge(this.ownerDocument));
-
+    if (util.isDriveShortcutsEnabled()) {
+      label.appendChild(filelist.renderIconBadge(this.ownerDocument));
+    }
     label.entry = entry;
     label.className = 'detail-name';
     label.appendChild(
diff --git a/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts b/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts
index 6499547..90f9ed8 100644
--- a/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts
+++ b/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts
@@ -169,6 +169,9 @@
   override render() {
     return html`<cr-action-menu>
       <div class="body">
+        <div class="static progress" id="progress-preparing">
+          ${str('DRIVE_PREPARING_TO_SYNC')}
+        </div>
         <div id="progress-state">
           <div class="progress">${
         this.items && this.items > 1 ?
@@ -224,6 +227,7 @@
 
     :host(:not([items][percentage])) #progress-state,
     :host([percentage="100"]) #progress-state,
+    :host([percentage="0"]) #progress-state,
     :host([type]) #progress-state {
       display: none;
     }
@@ -233,6 +237,11 @@
       display: none;
     }
 
+    :host(:not([items][percentage="0"])) #progress-preparing,
+    :host([type]) #progress-preparing {
+      display: none;
+    }
+
     :host(:not([type="offline"])) #progress-offline {
       display: none;
     }
@@ -302,6 +311,11 @@
       width: calc(100% - 32px);
     }
 
+    #progress-preparing {
+      align-self: start;
+      padding-bottom: 20px;
+    }
+
     progress::-webkit-progress-bar {
       background-color: var(--cros-sys-primary_container);
       border-radius: 10px;
diff --git a/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.ts b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.ts
index c3531ad..8261476 100644
--- a/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.ts
+++ b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.ts
@@ -198,6 +198,8 @@
         return str('DLP_COMPONENT_PLAY');
       case chrome.fileManagerPrivate.VolumeType.GUEST_OS:
         return str('DLP_COMPONENT_VM');
+      case chrome.fileManagerPrivate.VolumeType.DOCUMENTS_PROVIDER:
+        return str('DLP_COMPONENT_MICROSOFT_ONEDRIVE');
       default:
         console.warn(`Got unexpected VolumeType value ${component}.`);
         return '';
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 289f366..979da600 100644
--- a/ui/file_manager/integration_tests/file_manager/drive_specific.js
+++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -737,8 +737,11 @@
   await remoteCall.waitUntilSelected(appId, 'G');
   await remoteCall.waitForElement(appId, '.table-row[selected]');
 
-  // Ensure the "G" directory has the shortcut class applied.
-  await remoteCall.waitForElement(appId, '#file-list [file-name="G"].shortcut');
+  if ((await sendTestMessage({name: 'isDriveShortcutsEnabled'})) === 'true') {
+    // Ensure the "G" directory has the shortcut class applied.
+    await remoteCall.waitForElement(
+        appId, '#file-list [file-name="G"].shortcut');
+  }
 
   // Open the link
   chrome.test.assertTrue(
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index db8cb1f..2c2554ab 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -111,6 +111,7 @@
             Widget::ClosedReason::kCloseButtonClicked);
       },
       this));
+  close->SetProperty(views::kElementIdentifierKey, kCloseButtonElementId);
   close->SetVisible(false);
   close_ = AddChildView(std::move(close));
 
@@ -121,6 +122,7 @@
         view->GetWidget()->Minimize();
       },
       this));
+  minimize->SetProperty(views::kElementIdentifierKey, kMinimizeButtonElementId);
   minimize->SetVisible(false);
   minimize_ = AddChildView(std::move(minimize));
 
@@ -1127,4 +1129,8 @@
 ADD_PROPERTY_METADATA(SkColor, BackgroundColor, ui::metadata::SkColorConverter)
 END_METADATA
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(BubbleFrameView,
+                                      kMinimizeButtonElementId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(BubbleFrameView, kCloseButtonElementId);
+
 }  // namespace views
diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h
index 9bd59e7..469d0d0 100644
--- a/ui/views/bubble/bubble_frame_view.h
+++ b/ui/views/bubble/bubble_frame_view.h
@@ -59,6 +59,9 @@
  public:
   METADATA_HEADER(BubbleFrameView);
 
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMinimizeButtonElementId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kCloseButtonElementId);
+
   enum class PreferredArrowAdjustment { kMirror, kOffset };
 
   BubbleFrameView(const gfx::Insets& title_margins,
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc
index e57e76d8..22f5e5a 100644
--- a/ui/views/window/dialog_client_view.cc
+++ b/ui/views/window/dialog_client_view.cc
@@ -12,8 +12,10 @@
 #include "base/memory/raw_ptr.h"
 #include "base/ranges/algorithm.h"
 #include "build/build_config.h"
+#include "ui/base/interaction/element_identifier.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/ui_base_types.h"
 #include "ui/color/color_id.h"
 #include "ui/color/color_provider.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -27,6 +29,7 @@
 #include "ui/views/layout/table_layout.h"
 #include "ui/views/metadata/view_factory.h"
 #include "ui/views/style/platform_style.h"
+#include "ui/views/view_class_properties.h"
 #include "ui/views/view_observer.h"
 #include "ui/views/view_tracker.h"
 #include "ui/views/view_utils.h"
@@ -55,6 +58,19 @@
                    size1.height() + size2.height());
 }
 
+constexpr ui::ElementIdentifier kNoElementId;
+
+ui::ElementIdentifier GetButtonId(ui::DialogButton type) {
+  switch (type) {
+    case ui::DialogButton::DIALOG_BUTTON_OK:
+      return DialogClientView::kOkButtonElementId;
+    case ui::DialogButton::DIALOG_BUTTON_CANCEL:
+      return DialogClientView::kCancelButtonElementId;
+    default:
+      return kNoElementId;
+  }
+}
+
 }  // namespace
 
 // Simple container to bubble child view changes up the view hierarchy.
@@ -292,6 +308,7 @@
               .SetCallback(base::BindRepeating(&DialogClientView::ButtonPressed,
                                                base::Unretained(this), type))
               .SetText(title)
+              .SetProperty(views::kElementIdentifierKey, GetButtonId(type))
               .SetStyle(style)
               .SetProminent(is_default)
               .SetIsDefault(is_default)
@@ -478,4 +495,7 @@
 BEGIN_METADATA(DialogClientView, ClientView)
 END_METADATA
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(DialogClientView, kOkButtonElementId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(DialogClientView, kCancelButtonElementId);
+
 }  // namespace views
diff --git a/ui/views/window/dialog_client_view.h b/ui/views/window/dialog_client_view.h
index ebddfcd2..4a546b70 100644
--- a/ui/views/window/dialog_client_view.h
+++ b/ui/views/window/dialog_client_view.h
@@ -11,6 +11,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ptr_exclusion.h"
+#include "ui/base/interaction/element_identifier.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/views/input_event_activation_protector.h"
 #include "ui/views/metadata/view_factory.h"
@@ -41,6 +42,9 @@
  public:
   METADATA_HEADER(DialogClientView);
 
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kOkButtonElementId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kCancelButtonElementId);
+
   DialogClientView(Widget* widget, View* contents_view);
 
   DialogClientView(const DialogClientView&) = delete;
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn
index 5fabf301..d66ec98 100644
--- a/weblayer/BUILD.gn
+++ b/weblayer/BUILD.gn
@@ -186,6 +186,11 @@
     "browser/bluetooth/weblayer_bluetooth_delegate_impl_client.h",
     "browser/browser_context_impl.cc",
     "browser/browser_context_impl.h",
+    "browser/browser_fragment_impl.cc",
+    "browser/browser_fragment_impl.h",
+    "browser/browser_fragment_list.cc",
+    "browser/browser_fragment_list.h",
+    "browser/browser_fragment_list_observer.h",
     "browser/browser_impl.cc",
     "browser/browser_impl.h",
     "browser/browser_list.cc",
diff --git a/weblayer/browser/android/metrics/metrics_browsertest.cc b/weblayer/browser/android/metrics/metrics_browsertest.cc
index c0c5e86..7c20a13 100644
--- a/weblayer/browser/android/metrics/metrics_browsertest.cc
+++ b/weblayer/browser/android/metrics/metrics_browsertest.cc
@@ -16,6 +16,7 @@
 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
 #include "weblayer/browser/android/metrics/metrics_test_helper.h"
 #include "weblayer/browser/android/metrics/weblayer_metrics_service_client.h"
+#include "weblayer/browser/browser_fragment_list.h"
 #include "weblayer/browser/browser_list.h"
 #include "weblayer/browser/profile_impl.h"
 #include "weblayer/public/navigation_controller.h"
@@ -220,7 +221,8 @@
                        IsInForegroundWhenConsentGiven) {
   // There should be at least one browser which is resumed. This is the trigger
   // for whether the MetricsService is considered in the foreground.
-  EXPECT_TRUE(BrowserList::GetInstance()->HasAtLeastOneResumedBrowser());
+  EXPECT_TRUE(
+      BrowserFragmentList::GetInstance()->HasAtLeastOneResumedBrowser());
   RunConsentCallback(true);
   // RunConsentCallback() should trigger the MetricsService to start.
   EXPECT_TRUE(WebLayerMetricsServiceClient::GetInstance()
diff --git a/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc b/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc
index 86d9d00..f21298a8 100644
--- a/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc
+++ b/weblayer/browser/android/metrics/weblayer_metrics_service_client.cc
@@ -20,7 +20,7 @@
 #include "content/public/browser/browser_context.h"
 #include "google_apis/google_api_keys.h"
 #include "weblayer/browser/browser_context_impl.h"
-#include "weblayer/browser/browser_list.h"
+#include "weblayer/browser/browser_fragment_list.h"
 #include "weblayer/browser/browser_process.h"
 #include "weblayer/browser/java/jni/MetricsServiceClient_jni.h"
 #include "weblayer/browser/system_network_context_manager.h"
@@ -82,11 +82,11 @@
 
 WebLayerMetricsServiceClient::WebLayerMetricsServiceClient() {
   ProfileImpl::AddProfileObserver(this);
-  BrowserList::GetInstance()->AddObserver(this);
+  BrowserFragmentList::GetInstance()->AddObserver(this);
 }
 
 WebLayerMetricsServiceClient::~WebLayerMetricsServiceClient() {
-  BrowserList::GetInstance()->RemoveObserver(this);
+  BrowserFragmentList::GetInstance()->RemoveObserver(this);
   ProfileImpl::RemoveProfileObserver(this);
 }
 
@@ -199,7 +199,7 @@
 
 void WebLayerMetricsServiceClient::ApplyForegroundStateToServices() {
   const bool is_in_foreground =
-      BrowserList::GetInstance()->HasAtLeastOneResumedBrowser();
+      BrowserFragmentList::GetInstance()->HasAtLeastOneResumedBrowser();
   if (auto* metrics_service = WebLayerMetricsServiceClient::GetInstance()
                                   ->GetMetricsServiceIfStarted()) {
     if (is_in_foreground)
@@ -224,8 +224,8 @@
   UpdateUkmService();
 }
 
-void WebLayerMetricsServiceClient::OnHasAtLeastOneResumedBrowserStateChanged(
-    bool new_value) {
+void WebLayerMetricsServiceClient::
+    OnHasAtLeastOneResumedBrowserFragmentStateChanged(bool new_value) {
   ApplyForegroundStateToServices();
 }
 
diff --git a/weblayer/browser/android/metrics/weblayer_metrics_service_client.h b/weblayer/browser/android/metrics/weblayer_metrics_service_client.h
index 4461e81e..da8469b 100644
--- a/weblayer/browser/android/metrics/weblayer_metrics_service_client.h
+++ b/weblayer/browser/android/metrics/weblayer_metrics_service_client.h
@@ -16,7 +16,7 @@
 #include "components/metrics/metrics_service_client.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "weblayer/browser/browser_list_observer.h"
+#include "weblayer/browser/browser_fragment_list_observer.h"
 #include "weblayer/browser/profile_impl.h"
 
 namespace weblayer {
@@ -24,7 +24,7 @@
 class WebLayerMetricsServiceClient
     : public ::metrics::AndroidMetricsServiceClient,
       public ProfileImpl::ProfileObserver,
-      public BrowserListObserver {
+      public BrowserFragmentListObserver {
   friend class base::NoDestructor<WebLayerMetricsServiceClient>;
 
  public:
@@ -71,7 +71,8 @@
   void ProfileDestroyed(ProfileImpl* profile) override;
 
   // BrowserListObserver:
-  void OnHasAtLeastOneResumedBrowserStateChanged(bool new_value) override;
+  void OnHasAtLeastOneResumedBrowserFragmentStateChanged(
+      bool new_value) override;
 
   std::vector<base::OnceClosure> post_start_tasks_;
 };
diff --git a/weblayer/browser/browser_fragment_impl.cc b/weblayer/browser/browser_fragment_impl.cc
new file mode 100644
index 0000000..5d44518
--- /dev/null
+++ b/weblayer/browser/browser_fragment_impl.cc
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "weblayer/browser/browser_fragment_impl.h"
+
+#include "weblayer/browser/browser_fragment_list.h"
+#include "weblayer/browser/java/jni/BrowserFragmentImpl_jni.h"
+
+namespace weblayer {
+
+BrowserFragmentImpl::BrowserFragmentImpl() {
+  BrowserFragmentList::GetInstance()->AddBrowserFragment(this);
+}
+
+BrowserFragmentImpl::~BrowserFragmentImpl() {
+  BrowserFragmentList::GetInstance()->RemoveBrowserFragment(this);
+}
+
+void BrowserFragmentImpl::OnFragmentResume(JNIEnv* env) {
+  UpdateFragmentResumedState(true);
+}
+
+void BrowserFragmentImpl::OnFragmentPause(JNIEnv* env) {
+  UpdateFragmentResumedState(false);
+}
+
+void BrowserFragmentImpl::DeleteBrowserFragment(JNIEnv* env) {
+  delete this;
+}
+
+void BrowserFragmentImpl::UpdateFragmentResumedState(bool state) {
+  const bool old_has_at_least_one_active_browser =
+      BrowserFragmentList::GetInstance()->HasAtLeastOneResumedBrowser();
+  fragment_resumed_ = state;
+  if (old_has_at_least_one_active_browser !=
+      BrowserFragmentList::GetInstance()->HasAtLeastOneResumedBrowser()) {
+    BrowserFragmentList::GetInstance()
+        ->NotifyHasAtLeastOneResumedBrowserFragmentChanged();
+  }
+}
+
+static jlong JNI_BrowserFragmentImpl_CreateBrowserFragment(JNIEnv* env) {
+  return reinterpret_cast<intptr_t>(new BrowserFragmentImpl());
+}
+
+}  // namespace weblayer
diff --git a/weblayer/browser/browser_fragment_impl.h b/weblayer/browser/browser_fragment_impl.h
new file mode 100644
index 0000000..5e158f9e
--- /dev/null
+++ b/weblayer/browser/browser_fragment_impl.h
@@ -0,0 +1,34 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_BROWSER_BROWSER_FRAGMENT_IMPL_H_
+#define WEBLAYER_BROWSER_BROWSER_FRAGMENT_IMPL_H_
+
+#include "base/android/jni_android.h"
+
+namespace weblayer {
+
+class BrowserFragmentImpl {
+ public:
+  BrowserFragmentImpl();
+  ~BrowserFragmentImpl();
+  BrowserFragmentImpl(const BrowserFragmentImpl&) = delete;
+  BrowserFragmentImpl& operator=(const BrowserFragmentImpl&) = delete;
+
+  void OnFragmentResume(JNIEnv* env);
+  void OnFragmentPause(JNIEnv* env);
+
+  void DeleteBrowserFragment(JNIEnv* env);
+
+  bool fragment_resumed() { return fragment_resumed_; }
+
+ private:
+  void UpdateFragmentResumedState(bool state);
+
+  bool fragment_resumed_ = false;
+};
+
+}  // namespace weblayer
+
+#endif  // WEBLAYER_BROWSER_BROWSER_FRAGMENT_IMPL_H_
diff --git a/weblayer/browser/browser_fragment_list.cc b/weblayer/browser/browser_fragment_list.cc
new file mode 100644
index 0000000..b54cda2b3
--- /dev/null
+++ b/weblayer/browser/browser_fragment_list.cc
@@ -0,0 +1,55 @@
+// 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 "weblayer/browser/browser_fragment_list.h"
+
+#include "base/no_destructor.h"
+#include "weblayer/browser/browser_fragment_impl.h"
+#include "weblayer/browser/browser_fragment_list_observer.h"
+
+namespace weblayer {
+
+inline BrowserFragmentList::BrowserFragmentList() = default;
+inline BrowserFragmentList::~BrowserFragmentList() = default;
+
+// static
+BrowserFragmentList* BrowserFragmentList::GetInstance() {
+  static base::NoDestructor<BrowserFragmentList> browser_fragment_list;
+  return browser_fragment_list.get();
+}
+
+void BrowserFragmentList::AddBrowserFragment(
+    BrowserFragmentImpl* browser_fragment) {
+  CHECK(!browser_fragments_.contains(browser_fragment));
+  browser_fragments_.insert(browser_fragment);
+}
+
+void BrowserFragmentList::RemoveBrowserFragment(
+    BrowserFragmentImpl* browser_fragment) {
+  CHECK(browser_fragments_.contains(browser_fragment));
+  browser_fragments_.erase(browser_fragment);
+}
+
+void BrowserFragmentList::AddObserver(BrowserFragmentListObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void BrowserFragmentList::RemoveObserver(
+    BrowserFragmentListObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool BrowserFragmentList::HasAtLeastOneResumedBrowser() {
+  return base::ranges::any_of(browser_fragments_,
+                              &BrowserFragmentImpl::fragment_resumed);
+}
+
+void BrowserFragmentList::NotifyHasAtLeastOneResumedBrowserFragmentChanged() {
+  const bool value = HasAtLeastOneResumedBrowser();
+  for (BrowserFragmentListObserver& observer : observers_) {
+    observer.OnHasAtLeastOneResumedBrowserFragmentStateChanged(value);
+  }
+}
+
+}  // namespace weblayer
diff --git a/weblayer/browser/browser_fragment_list.h b/weblayer/browser/browser_fragment_list.h
new file mode 100644
index 0000000..740ee1a
--- /dev/null
+++ b/weblayer/browser/browser_fragment_list.h
@@ -0,0 +1,54 @@
+// 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 WEBLAYER_BROWSER_BROWSER_FRAGMENT_LIST_H_
+#define WEBLAYER_BROWSER_BROWSER_FRAGMENT_LIST_H_
+
+#include "base/containers/flat_set.h"
+#include "base/no_destructor.h"
+#include "base/observer_list.h"
+
+namespace weblayer {
+
+class BrowserFragmentImpl;
+class BrowserFragmentListObserver;
+
+// Tracks the set of browsers.
+class BrowserFragmentList {
+ public:
+  BrowserFragmentList();
+  ~BrowserFragmentList();
+
+  BrowserFragmentList(const BrowserFragmentList&) = delete;
+  BrowserFragmentList& operator=(const BrowserFragmentList&) = delete;
+
+  static BrowserFragmentList* GetInstance();
+
+  const base::flat_set<BrowserFragmentImpl*>& browser_fragments() {
+    return browser_fragments_;
+  }
+
+  // Returns true if there is at least one BrowserFragmentImpl in a resumed
+  // state.
+  bool HasAtLeastOneResumedBrowser();
+
+  void AddObserver(BrowserFragmentListObserver* observer);
+  void RemoveObserver(BrowserFragmentListObserver* observer);
+
+ private:
+  friend class BrowserFragmentImpl;
+  friend class base::NoDestructor<BrowserFragmentList>;
+
+  void AddBrowserFragment(BrowserFragmentImpl* browser_fragment);
+  void RemoveBrowserFragment(BrowserFragmentImpl* browser_fragment);
+
+  void NotifyHasAtLeastOneResumedBrowserFragmentChanged();
+
+  base::flat_set<BrowserFragmentImpl*> browser_fragments_;
+  base::ObserverList<BrowserFragmentListObserver> observers_;
+};
+
+}  // namespace weblayer
+
+#endif  // WEBLAYER_BROWSER_BROWSER_FRAGMENT_LIST_H_
diff --git a/weblayer/browser/browser_fragment_list_observer.h b/weblayer/browser/browser_fragment_list_observer.h
new file mode 100644
index 0000000..86e7acd
--- /dev/null
+++ b/weblayer/browser/browser_fragment_list_observer.h
@@ -0,0 +1,26 @@
+// 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 WEBLAYER_BROWSER_BROWSER_FRAGMENT_LIST_OBSERVER_H_
+#define WEBLAYER_BROWSER_BROWSER_FRAGMENT_LIST_OBSERVER_H_
+
+#include "base/observer_list_types.h"
+#include "build/build_config.h"
+
+namespace weblayer {
+
+class BrowserFragmentListObserver : public base::CheckedObserver {
+ public:
+  // Called when the value of BrowserFragmentList::HasAtLeastOneResumedBrowser()
+  // changes.
+  virtual void OnHasAtLeastOneResumedBrowserFragmentStateChanged(
+      bool new_value) {}
+
+ protected:
+  ~BrowserFragmentListObserver() override = default;
+};
+
+}  // namespace weblayer
+
+#endif  // WEBLAYER_BROWSER_BROWSER_FRAGMENT_LIST_OBSERVER_H_
diff --git a/weblayer/browser/browser_impl.cc b/weblayer/browser/browser_impl.cc
index 91b532e..6bfccd1e 100644
--- a/weblayer/browser/browser_impl.cc
+++ b/weblayer/browser/browser_impl.cc
@@ -24,7 +24,6 @@
 #include "weblayer/public/browser_observer.h"
 #include "weblayer/public/browser_restore_observer.h"
 
-#if BUILDFLAG(IS_ANDROID)
 #include "base/android/callback_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
@@ -36,11 +35,9 @@
 using base::android::AttachCurrentThread;
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
-#endif
 
 namespace weblayer {
 
-#if BUILDFLAG(IS_ANDROID)
 // This MUST match the values defined in
 // org.chromium.weblayer_private.interfaces.DarkModeStrategy.
 enum class DarkModeStrategy {
@@ -48,7 +45,6 @@
   kUserAgentDarkeningOnly = 1,
   kPreferWebThemeOverUserAgentDarkening = 2,
 };
-#endif
 
 // static
 constexpr char BrowserImpl::kPersistenceFilePrefix[];
@@ -61,25 +57,22 @@
       base::WrapUnique(new BrowserImpl(static_cast<ProfileImpl*>(profile)));
   if (persistence_info)
     browser->RestoreStateIfNecessary(*persistence_info);
+
+  DCHECK(FeatureListCreator::GetInstance());
+  FeatureListCreator::GetInstance()->OnBrowserCreated();
+
   return browser;
 }
 
 BrowserImpl::~BrowserImpl() {
-#if BUILDFLAG(IS_ANDROID)
   // Android side should always remove tabs first (because the Java Tab class
   // owns the C++ Tab). See BrowserImpl.destroy() (in the Java BrowserImpl
   // class).
   DCHECK(tabs_.empty());
-#else
-  while (!tabs_.empty())
-    DestroyTab(tabs_.back().get());
-#endif
   BrowserList::GetInstance()->RemoveBrowser(this);
 
-#if BUILDFLAG(IS_ANDROID)
   if (BrowserList::GetInstance()->browsers().empty())
     BrowserProcess::GetInstance()->StopSafeBrowsingService();
-#endif
 }
 
 TabImpl* BrowserImpl::CreateTabForSessionRestore(
@@ -92,10 +85,8 @@
   }
   std::unique_ptr<TabImpl> tab =
       std::make_unique<TabImpl>(profile_, std::move(web_contents), guid);
-#if BUILDFLAG(IS_ANDROID)
   Java_BrowserImpl_createJavaTabForNativeTab(
       AttachCurrentThread(), java_impl_, reinterpret_cast<jlong>(tab.get()));
-#endif
   return AddTab(std::move(tab));
 }
 
@@ -104,7 +95,6 @@
   return CreateTabForSessionRestore(std::move(web_contents), std::string());
 }
 
-#if BUILDFLAG(IS_ANDROID)
 bool BrowserImpl::CompositorHasSurface() {
   return Java_BrowserImpl_compositorHasSurface(AttachCurrentThread(),
                                                java_impl_);
@@ -161,24 +151,7 @@
   OnWebPreferenceChanged(std::string());
 }
 
-void BrowserImpl::OnFragmentStart(JNIEnv* env) {
-  // FeatureListCreator is created before any Browsers.
-  DCHECK(FeatureListCreator::GetInstance());
-  FeatureListCreator::GetInstance()->OnBrowserFragmentStarted();
-}
-
-void BrowserImpl::OnFragmentResume(JNIEnv* env) {
-  UpdateFragmentResumedState(true);
-}
-
-void BrowserImpl::OnFragmentPause(JNIEnv* env) {
-  UpdateFragmentResumedState(false);
-}
-
-#endif
-
 void BrowserImpl::SetWebPreferences(blink::web_pref::WebPreferences* prefs) {
-#if BUILDFLAG(IS_ANDROID)
   PrefService* pref_service = profile()->GetBrowserContext()->pref_service();
   prefs->password_echo_enabled = Java_BrowserImpl_getPasswordEchoEnabled(
       AttachCurrentThread(), java_impl_);
@@ -219,16 +192,13 @@
     prefs->preferred_color_scheme = blink::mojom::PreferredColorScheme::kLight;
     prefs->force_dark_mode_enabled = false;
   }
-#endif
 }
 
-#if BUILDFLAG(IS_ANDROID)
 void BrowserImpl::RemoveTabBeforeDestroyingFromJava(Tab* tab) {
   // The java side owns the Tab, and is going to delete it shortly. See
   // JNI_TabImpl_DeleteTab.
   RemoveTab(tab).release();
 }
-#endif
 
 void BrowserImpl::AddTab(Tab* tab) {
   DCHECK(tab);
@@ -242,13 +212,9 @@
 }
 
 void BrowserImpl::DestroyTab(Tab* tab) {
-#if BUILDFLAG(IS_ANDROID)
   // Route destruction through the java side.
   Java_BrowserImpl_destroyTabImpl(AttachCurrentThread(), java_impl_,
                                   static_cast<TabImpl*>(tab)->GetJavaTab());
-#else
-  RemoveTab(tab);
-#endif
 }
 
 void BrowserImpl::SetActiveTab(Tab* tab) {
@@ -259,11 +225,9 @@
   // TODO: currently the java side sets visibility, this code likely should
   // too and it should be removed from the java side.
   active_tab_ = static_cast<TabImpl*>(tab);
-#if BUILDFLAG(IS_ANDROID)
   Java_BrowserImpl_onActiveTabChanged(
       AttachCurrentThread(), java_impl_,
       active_tab_ ? active_tab_->GetJavaTab() : nullptr);
-#endif
   VisibleSecurityStateOfActiveTabChanged();
   for (BrowserObserver& obs : browser_observers_)
     obs.OnActiveTabChanged(active_tab_);
@@ -289,9 +253,7 @@
 void BrowserImpl::OnRestoreCompleted() {
   for (BrowserRestoreObserver& obs : browser_restore_observers_)
     obs.OnRestoreCompleted();
-#if BUILDFLAG(IS_ANDROID)
   Java_BrowserImpl_onRestoreCompleted(AttachCurrentThread(), java_impl_);
-#endif
 }
 
 void BrowserImpl::PrepareForShutdown() {
@@ -327,16 +289,13 @@
   if (visible_security_state_changed_callback_for_tests_)
     std::move(visible_security_state_changed_callback_for_tests_).Run();
 
-#if BUILDFLAG(IS_ANDROID)
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_BrowserImpl_onVisibleSecurityStateOfActiveTabChanged(env, java_impl_);
-#endif
 }
 
 BrowserImpl::BrowserImpl(ProfileImpl* profile) : profile_(profile) {
   BrowserList::GetInstance()->AddBrowser(this);
 
-#if BUILDFLAG(IS_ANDROID)
   profile_pref_change_registrar_.Init(
       profile_->GetBrowserContext()->pref_service());
   auto pref_change_callback = base::BindRepeating(
@@ -345,7 +304,6 @@
                                      pref_change_callback);
   profile_pref_change_registrar_.Add(browser_ui::prefs::kWebKitForceEnableZoom,
                                      pref_change_callback);
-#endif
 }
 
 void BrowserImpl::RestoreStateIfNecessary(
@@ -362,10 +320,8 @@
   DCHECK(!tab_impl->browser());
   tabs_.push_back(std::move(tab));
   tab_impl->set_browser(this);
-#if BUILDFLAG(IS_ANDROID)
   Java_BrowserImpl_onTabAdded(AttachCurrentThread(), java_impl_,
                               tab_impl->GetJavaTab());
-#endif
   for (BrowserObserver& obs : browser_observers_)
     obs.OnTabAdded(tab_impl);
   return tab_impl;
@@ -383,10 +339,8 @@
   if (active_tab_changed)
     SetActiveTab(nullptr);
 
-#if BUILDFLAG(IS_ANDROID)
   Java_BrowserImpl_onTabRemoved(AttachCurrentThread(), java_impl_,
                                 tab ? tab_impl->GetJavaTab() : nullptr);
-#endif
   for (BrowserObserver& obs : browser_observers_)
     obs.OnTabRemoved(tab, active_tab_changed);
   return owned_tab;
@@ -404,17 +358,6 @@
   }
 }
 
-#if BUILDFLAG(IS_ANDROID)
-void BrowserImpl::UpdateFragmentResumedState(bool state) {
-  const bool old_has_at_least_one_active_browser =
-      BrowserList::GetInstance()->HasAtLeastOneResumedBrowser();
-  fragment_resumed_ = state;
-  if (old_has_at_least_one_active_browser !=
-      BrowserList::GetInstance()->HasAtLeastOneResumedBrowser()) {
-    BrowserList::GetInstance()->NotifyHasAtLeastOneResumedBrowserChanged();
-  }
-}
-
 // This function is friended. JNI_BrowserImpl_CreateBrowser can not be
 // friended, as it requires browser_impl.h to include BrowserImpl_jni.h, which
 // is problematic (meaning not really supported and generates compile errors).
@@ -446,6 +389,5 @@
 static void JNI_BrowserImpl_DeleteBrowser(JNIEnv* env, jlong browser) {
   delete reinterpret_cast<BrowserImpl*>(browser);
 }
-#endif
 
 }  // namespace weblayer
diff --git a/weblayer/browser/browser_impl.h b/weblayer/browser/browser_impl.h
index ab513fab..b58cdcb7 100644
--- a/weblayer/browser/browser_impl.h
+++ b/weblayer/browser/browser_impl.h
@@ -15,9 +15,7 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "weblayer/public/browser.h"
 
-#if BUILDFLAG(IS_ANDROID)
 #include "base/android/scoped_java_ref.h"
-#endif
 
 namespace base {
 class FilePath;
@@ -64,7 +62,6 @@
 
   const std::string& GetPackageName() { return package_name_; }
 
-#if BUILDFLAG(IS_ANDROID)
   bool CompositorHasSurface();
 
   base::android::ScopedJavaGlobalRef<jobject> java_browser() {
@@ -85,16 +82,11 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jstring>& j_persistence_id);
   void WebPreferencesChanged(JNIEnv* env);
-  void OnFragmentStart(JNIEnv* env);
-  void OnFragmentResume(JNIEnv* env);
-  void OnFragmentPause(JNIEnv* env);
+
   bool IsRestoringPreviousState(JNIEnv* env) {
     return IsRestoringPreviousState();
   }
 
-  bool fragment_resumed() { return fragment_resumed_; }
-#endif
-
   // Used in tests to specify a non-default max (0 means use the default).
   std::vector<uint8_t> GetMinimalPersistenceState(int max_navigations_per_tab,
                                                   int max_size_in_bytes);
@@ -109,13 +101,11 @@
   bool GetPasswordEchoEnabled();
   void SetWebPreferences(blink::web_pref::WebPreferences* prefs);
 
-#if BUILDFLAG(IS_ANDROID)
   // On Android the Java Tab class owns the C++ Tab. DestroyTab() calls to the
   // Java Tab class to initiate deletion. This function is called from the Java
   // side to remove the tab from the browser and shortly followed by deleting
   // the tab.
   void RemoveTabBeforeDestroyingFromJava(Tab* tab);
-#endif
 
   // Browser:
   void AddTab(Tab* tab) override;
@@ -137,12 +127,10 @@
   // For creation.
   friend class Browser;
 
-#if BUILDFLAG(IS_ANDROID)
   friend BrowserImpl* CreateBrowserForAndroid(
       ProfileImpl*,
       const std::string&,
       const base::android::JavaParamRef<jobject>&);
-#endif
 
   explicit BrowserImpl(ProfileImpl* profile);
 
@@ -156,12 +144,7 @@
 
   void OnWebPreferenceChanged(const std::string& pref_name);
 
-#if BUILDFLAG(IS_ANDROID)
-  void UpdateFragmentResumedState(bool state);
-
-  bool fragment_resumed_ = false;
   base::android::ScopedJavaGlobalRef<jobject> java_impl_;
-#endif
   base::ObserverList<BrowserObserver> browser_observers_;
   base::ObserverList<BrowserRestoreObserver> browser_restore_observers_;
   const raw_ptr<ProfileImpl> profile_;
diff --git a/weblayer/browser/browser_list.cc b/weblayer/browser/browser_list.cc
index 76bb2436..5ab5a16 100644
--- a/weblayer/browser/browser_list.cc
+++ b/weblayer/browser/browser_list.cc
@@ -12,9 +12,7 @@
 #include "weblayer/browser/browser_impl.h"
 #include "weblayer/browser/browser_list_observer.h"
 
-#if BUILDFLAG(IS_ANDROID)
 #include "weblayer/browser/browser_list_proxy.h"
-#endif
 
 namespace weblayer {
 
@@ -24,12 +22,6 @@
   return browser_list.get();
 }
 
-#if BUILDFLAG(IS_ANDROID)
-bool BrowserList::HasAtLeastOneResumedBrowser() {
-  return base::ranges::any_of(browsers_, &BrowserImpl::fragment_resumed);
-}
-#endif
-
 void BrowserList::AddObserver(BrowserListObserver* observer) {
   observers_.AddObserver(observer);
 }
@@ -39,24 +31,16 @@
 }
 
 BrowserList::BrowserList() {
-#if BUILDFLAG(IS_ANDROID)
   browser_list_proxy_ = std::make_unique<BrowserListProxy>();
   AddObserver(browser_list_proxy_.get());
-#endif
 }
 
 BrowserList::~BrowserList() {
-#if BUILDFLAG(IS_ANDROID)
   RemoveObserver(browser_list_proxy_.get());
-#endif
 }
 
 void BrowserList::AddBrowser(BrowserImpl* browser) {
   DCHECK(!browsers_.contains(browser));
-#if BUILDFLAG(IS_ANDROID)
-  // Browsers should not start out resumed.
-  DCHECK(!browser->fragment_resumed());
-#endif
   browsers_.insert(browser);
   for (BrowserListObserver& observer : observers_)
     observer.OnBrowserCreated(browser);
@@ -64,22 +48,10 @@
 
 void BrowserList::RemoveBrowser(BrowserImpl* browser) {
   DCHECK(browsers_.contains(browser));
-#if BUILDFLAG(IS_ANDROID)
-  // Browsers should not be resumed when being destroyed.
-  DCHECK(!browser->fragment_resumed());
-#endif
   browsers_.erase(browser);
 
   for (BrowserListObserver& observer : observers_)
     observer.OnBrowserDestroyed(browser);
 }
 
-#if BUILDFLAG(IS_ANDROID)
-void BrowserList::NotifyHasAtLeastOneResumedBrowserChanged() {
-  const bool value = HasAtLeastOneResumedBrowser();
-  for (BrowserListObserver& observer : observers_)
-    observer.OnHasAtLeastOneResumedBrowserStateChanged(value);
-}
-#endif
-
 }  // namespace weblayer
diff --git a/weblayer/browser/browser_list.h b/weblayer/browser/browser_list.h
index 5c5e786..cb07546c 100644
--- a/weblayer/browser/browser_list.h
+++ b/weblayer/browser/browser_list.h
@@ -15,9 +15,7 @@
 class BrowserImpl;
 class BrowserListObserver;
 
-#if BUILDFLAG(IS_ANDROID)
 class BrowserListProxy;
-#endif
 
 // Tracks the set of browsers.
 class BrowserList {
@@ -53,9 +51,7 @@
 
   base::flat_set<BrowserImpl*> browsers_;
   base::ObserverList<BrowserListObserver> observers_;
-#if BUILDFLAG(IS_ANDROID)
   std::unique_ptr<BrowserListProxy> browser_list_proxy_;
-#endif
 };
 
 }  // namespace weblayer
diff --git a/weblayer/browser/browser_list_observer.h b/weblayer/browser/browser_list_observer.h
index 20cedd6c..5cfbb1d 100644
--- a/weblayer/browser/browser_list_observer.h
+++ b/weblayer/browser/browser_list_observer.h
@@ -14,12 +14,6 @@
 
 class BrowserListObserver : public base::CheckedObserver {
  public:
-#if BUILDFLAG(IS_ANDROID)
-  // Called when the value of BrowserList::HasAtLeastOneResumedBrowser()
-  // changes.
-  virtual void OnHasAtLeastOneResumedBrowserStateChanged(bool new_value) {}
-#endif
-
   virtual void OnBrowserCreated(Browser* browser) {}
 
   virtual void OnBrowserDestroyed(Browser* browser) {}
diff --git a/weblayer/browser/feature_list_creator.cc b/weblayer/browser/feature_list_creator.cc
index 082f6012..c353807 100644
--- a/weblayer/browser/feature_list_creator.cc
+++ b/weblayer/browser/feature_list_creator.cc
@@ -72,17 +72,18 @@
 #endif
 }
 
-void FeatureListCreator::OnBrowserFragmentStarted() {
-  if (has_browser_fragment_started_)
+void FeatureListCreator::OnBrowserCreated() {
+  if (has_browser_created_) {
     return;
+  }
 
-  has_browser_fragment_started_ = true;
+  has_browser_created_ = true;
   // It is expected this is called after SetUpFieldTrials().
   DCHECK(variations_service_);
 
-  // This function is called any time a BrowserFragment is started.
+  // This function is called any time a Browser is started.
   // OnAppEnterForeground() really need only be called once, and because our
-  // notion of a fragment doesn't really map to the Application as a whole,
+  // notion of a browser doesn't really map to the Application as a whole,
   // call this function once.
   variations_service_->OnAppEnterForeground();
 }
diff --git a/weblayer/browser/feature_list_creator.h b/weblayer/browser/feature_list_creator.h
index 8965f6e..8ed788a5 100644
--- a/weblayer/browser/feature_list_creator.h
+++ b/weblayer/browser/feature_list_creator.h
@@ -45,7 +45,7 @@
   void PerformPreMainMessageLoopStartup();
 
   // Calls through to the VariationService.
-  void OnBrowserFragmentStarted();
+  void OnBrowserCreated();
 
   variations::VariationsService* variations_service() const {
     return variations_service_.get();
@@ -64,8 +64,8 @@
 
   WebLayerFieldTrials weblayer_field_trials_;
 
-  // Set to true the first time OnBrowserFragmentStarted() is called.
-  bool has_browser_fragment_started_ = false;
+  // Set to true the first time OnBrowserCreated() is called.
+  bool has_browser_created_ = false;
 };
 
 }  // namespace weblayer
diff --git a/weblayer/browser/java/BUILD.gn b/weblayer/browser/java/BUILD.gn
index 766e456..8544319 100644
--- a/weblayer/browser/java/BUILD.gn
+++ b/weblayer/browser/java/BUILD.gn
@@ -442,6 +442,7 @@
   sources = [
     "org/chromium/weblayer_private/ApplicationInfoHelper.java",
     "org/chromium/weblayer_private/AutocompleteSchemeClassifierImpl.java",
+    "org/chromium/weblayer_private/BrowserFragmentImpl.java",
     "org/chromium/weblayer_private/BrowserImpl.java",
     "org/chromium/weblayer_private/BrowserList.java",
     "org/chromium/weblayer_private/ContentViewRenderView.java",
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/BrowserFragmentImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/BrowserFragmentImpl.java
index dc43aa6..0062a03 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/BrowserFragmentImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/BrowserFragmentImpl.java
@@ -20,6 +20,8 @@
 import androidx.annotation.RequiresApi;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.components.embedder_support.application.ClassLoaderContextWrapperFactory;
 import org.chromium.components.embedder_support.view.ContentView;
@@ -31,7 +33,10 @@
 /**
  * Implementation of RemoteFragmentImpl which provides the Fragment implementation for BrowserImpl.
  */
+@JNINamespace("weblayer")
 public class BrowserFragmentImpl extends FragmentHostingRemoteFragmentImpl {
+    private long mNativeBrowserFragmentImpl;
+
     private static int sResumedCount;
     private static long sSessionStartTimeMs;
 
@@ -72,6 +77,8 @@
 
         mBrowser = browser;
         mWindowAndroid = new FragmentWindowAndroid(getWebLayerContext(), this);
+
+        mNativeBrowserFragmentImpl = BrowserFragmentImplJni.get().createBrowserFragment();
     }
 
     private void createAttachmentState(Context embedderContext) {
@@ -107,7 +114,6 @@
     protected void onStart() {
         StrictModeWorkaround.apply();
         super.onStart();
-        mBrowser.notifyFragmentInit();
         mBrowser.updateAllTabs();
     }
 
@@ -119,7 +125,7 @@
             long deltaMs = SystemClock.uptimeMillis() - sSessionStartTimeMs;
             RecordHistogram.recordLongTimesHistogram("Session.TotalDuration", deltaMs);
         }
-        mBrowser.notifyFragmentPause();
+        BrowserFragmentImplJni.get().onFragmentPause(mNativeBrowserFragmentImpl);
     }
 
     @Override
@@ -127,7 +133,8 @@
         super.onResume();
         sResumedCount++;
         if (sResumedCount == 1) sSessionStartTimeMs = SystemClock.uptimeMillis();
-        mBrowser.notifyFragmentResume();
+        WebLayerAccessibilityUtil.get().onBrowserResumed(mBrowser.getProfile());
+        BrowserFragmentImplJni.get().onFragmentResume(mNativeBrowserFragmentImpl);
     }
 
     @Override
@@ -280,6 +287,7 @@
             mWindowAndroid.destroy();
             mWindowAndroid = null;
         }
+        BrowserFragmentImplJni.get().deleteBrowserFragment(mNativeBrowserFragmentImpl);
     }
 
     @Override
@@ -290,4 +298,12 @@
                 new ContextThemeWrapper(wrappedContext, R.style.Theme_WebLayer_Settings);
         return new FragmentHostingRemoteFragmentImpl.RemoteFragmentContext(themedContext);
     }
+
+    @NativeMethods
+    interface Natives {
+        long createBrowserFragment();
+        void onFragmentResume(long nativeBrowserFragmentImpl);
+        void onFragmentPause(long nativeBrowserFragmentImpl);
+        void deleteBrowserFragment(long nativeBrowserFragmentImpl);
+    }
 }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
index a99b3a4..71d9168 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
@@ -126,8 +126,6 @@
         mNativeBrowser = BrowserImplJni.get().createBrowser(
                 mProfile.getNativeProfile(), serviceContext.getPackageName(), this);
         mPasswordEchoEnabled = null;
-
-        notifyFragmentInit(); // TODO(swestphal): Perhaps move to createBrowserFragmentImpl()?
     }
 
     @Override
@@ -298,20 +296,6 @@
         return ids;
     }
 
-    void notifyFragmentInit() {
-        // TODO(crbug.com/1378606): rename this.
-        BrowserImplJni.get().onFragmentStart(mNativeBrowser);
-    }
-
-    void notifyFragmentResume() {
-        WebLayerAccessibilityUtil.get().onBrowserResumed(mProfile);
-        BrowserImplJni.get().onFragmentResume(mNativeBrowser);
-    }
-
-    void notifyFragmentPause() {
-        BrowserImplJni.get().onFragmentPause(mNativeBrowser);
-    }
-
     boolean isExternalIntentsEnabled() {
         return mIsExternalIntentsEnabled;
     }
@@ -449,9 +433,6 @@
         void prepareForShutdown(long nativeBrowserImpl);
         void restoreStateIfNecessary(long nativeBrowserImpl, String persistenceId);
         void webPreferencesChanged(long nativeBrowserImpl);
-        void onFragmentStart(long nativeBrowserImpl);
-        void onFragmentResume(long nativeBrowserImpl);
-        void onFragmentPause(long nativeBrowserImpl);
         boolean isRestoringPreviousState(long nativeBrowserImpl);
     }
 }